DEV Community

Cover image for When the Coding Agent Builds the World It Gets Judged In
Alex
Alex

Posted on

When the Coding Agent Builds the World It Gets Judged In

Many years ago I had lots of discussions about AI with a former colleague.

He was a theoretical physicist and he really loved to dive deep into complex topics and thinking. This was around the time of AlphaGo and Leela Chess.

We talked about decision making, world models and also consciousness.

Of course I am not trying to connect software testing to consciousness here. The part that stayed with me was much simpler:

A decision only makes sense relative to some model of the world.

I never connected this thought to testing until coding agents started writing the implementation, fixtures and tests themselves.

Then it suddenly became very practical.

Test data is part of the world

Give an agent a requirement.

It writes the implementation.

Then some fixtures.

Then the tests.

Everything is green.

What if the agent misunderstood the requirement at the beginning?

The implementation follows interpretation A.

The fixtures represent interpretation A.

The expectations are based on interpretation A.

And finally the tests prove that interpretation A is internally consistent.

Nothing necessarily disagrees.

The system can still be wrong.

This is where I started thinking differently about test data.

Test data is not just some input required to execute a test.

It defines part of the world in which the implementation has to behave.

For a small isolated function this distinction may not matter much.

For a business process with state, relationships, existing data, several systems and rules nobody fully remembers anymore, it matters a lot.

Independent test world vs implementation defines its own world

The implementation should not define the world that proves it correct

I have no problem with an agent generating test data.

A capable agent can write a Python script, execute it and create very good data.

Someone pushed back on this with exactly that point:

A smart agent can just write the generation code first and execute it.

Yes. Absolutely.

Code vs model is not really what I care about.

I care about where the information comes from.

Ideally the agent building the test world gets things like:

  • the spec
  • schema
  • domain constraints
  • contracts
  • relevant information from the real environment

But not the implementation it will later judge.

Otherwise there is a shortcut.

The agent can generate data that fits what the implementation actually does instead of challenging it against what it should do.

It doesn't even need to do this consciously. The same assumption can simply move from implementation to fixture to expectation.

The result is self-consistent.

Still wrong.

Why I prefer a model over generation code

Generated code can work.

But when I review arbitrary fixture code I have to understand two things at the same time:

What world is this trying to create?

And how does the code create it?

I prefer separating those questions.

With a model-driven approach I can look at the world itself:

  • entities
  • relationships
  • cardinalities
  • allowed values
  • ranges
  • distributions
  • foreign keys
  • composite keys
  • expectations

The engine owns the mechanics.

That makes the test world easier to inspect and discuss.

Not magically correct. Just more visible.

This is also one reason why we changed the authoring workflow in DATAMIMIC CE 4.1.

DATAMIMIC CE 4.1

I build DATAMIMIC, so my interest here is pretty obvious.

But the idea itself does not depend on DATAMIMIC. You could build the same separation with Python, SQL or any another data generator.

What I want from DATAMIMIC is simpler:

I want to see what world we are building, reproduce it, and keep it separated from the implementation.

In CE 4.1 an agent can preserve that intent in a typed model.dm.json.

A simplified shape looks like this:

{
  "version": "1",
  "seed": 42,
  "products": [...],
  "expectations": [...]
}
Enter fullscreen mode Exit fullscreen mode

Take a small requirement:

Create 4 customers. Each customer has exactly 2 orders. Customer IDs are unique. Every order references its real customer. Amounts are between 10 and 500.

The model can make those assumptions explicit:

customers = exactly 4
orders per customer = exactly 2
customer.id = unique
order.customer_id -> customer.id
amount = 10..500
Enter fullscreen mode Exit fullscreen mode

DATAMIMIC compiles the model, validates it, performs a bounded execution and checks the declared expectations.

If something is wrong, the agent gets structured diagnostics back.

It changes the model and tries again.

A successful authoring cycle ends with:

verified=true
Enter fullscreen mode Exit fullscreen mode

This is much more useful to me than:

Generate some realistic customers and orders.

What is realistic?

Four customers or four million?

Can an order exist without a customer?

Can the same customer ID appear twice?

Are negative amounts valid?

The model forces some of these assumptions into something we can actually inspect.

You can try the CE yourself:

pip install datamimic-ce
datamimic capabilities
Enter fullscreen mode Exit fullscreen mode

https://github.com/rapiddweller/datamimic

A deterministic wrong world is still wrong

This is also where I need to be careful with the claim.

We can build a perfectly deterministic wrong world.

If the spec is wrong, the model can be wrong.

If the expectation is wrong, verified=true can correctly verify the wrong expectation.

That actually came up in a Hacker News discussion around this topic.

Someone described a test where the expectation itself was fabricated. The implementation failed the test, but later they found that the assertion was wrong because the real algorithm behaved globally, not locally as assumed.

That is exactly the problem.

Independence from the implementation removes one source of bias.

It does not make the oracle correct.

Determinism lets me reproduce the same world.

It does not tell me whether this is the right world.

And an explicit model lets me review the assumptions.

It doesn't prove them.

Real systems are ugly

There is another useful pushback I got:

A few rows from a real staging database can sometimes teach you more than a thousand beautiful synthetic fixtures.

I agree.

Real systems contain things nobody put into the original spec.

Nulls.

Weird string lengths.

Duplicates.

Old records.

Unexpected distributions.

Broken historical state.

Some migration from six years ago which technically should not exist anymore but still affects today's system.

So I don't see synthetic data and real data as opposites.

What I want is closer to:

observe the real environment, combine this with the spec and domain constraints, make the assumptions explicit, and then create a deterministic world from that.

This is also where things become different between a small app and a larger enterprise system.

CE is enough to test the idea. Enterprise systems get harder.

In a small greenfield application, the agent may already know almost everything it needs.

The schema is small.

The dependencies are obvious.

There may be one database.

Now take a system that has been running for 15 years.

Several databases.

MongoDB somewhere.

Services owned by different teams.

Existing customer data.

Permissions.

Schemas that changed over time.

Business rules nobody fully remembers.

In that kind of system I want more disagreement between implementation and test world.

Not less.

With our DATAMIMIC EE 4.0 release we moved further into this direction.

The platform has services that analyse connected environments like SQL databases and MongoDB.

They inspect schemas and relationships, do planning around dependencies, recommend generators and converters, and use this information to help build the DATAMIMIC model.

The coding agent does not need to invent the world from scratch.

There is already evidence.

The platform gives it access to that evidence under the same project and permission model used by the other DATAMIMIC clients.

The web UI, IDE integration and agents work against the same project.

For me that becomes much more interesting than just asking an LLM to generate fixture code.

There is still a bigger problem

Even if the test world is independent from the implementation, where does its truth come from?

The spec?

The database?

Production observations?

Customer examples?

An API contract?

Another agent?

A human domain expert?

Probably some combination.

And these sources can disagree.

This is why I don't think the problem is solved by simply running the test-data generation in another agent.

It removes one dangerous feedback loop.

That's useful.

But then we still have to ask whether the evidence used to build that world is good enough.

The experiment I want to run

The experiment I am preparing is quite simple.

Agent A gets:

  • the spec
  • schema
  • relevant domain information

It builds the test world.

It does not see the implementation.

Agent B gets the implementation task.

Then we test B's implementation against the world built independently by A.

After that we compare it with the normal setup where implementation, tests and fixtures are created from the same context.

The question is not whether the independent approach feels cleaner.

I want to know if it actually catches more errors.

I have been discussing this experiment here:

https://github.com/BeyondQuality/beyondquality/discussions/48

And the earlier field report that pushed me further into this topic is here:

https://datamimic.io/blog/deterministic-test-data-ai-coding-agents/

Where I am now

Coding agents are getting very good at producing software.

Generation is becoming cheap.

Knowing whether the generated system is actually right is not.

My current hypothesis is that independence removes one dangerous shortcut. Determinism lets us reproduce the result. The explicit model makes the assumptions visible.

But none of this proves that the world itself is right.

I also don't know yet how independent it needs to be before it catches materially more implementation errors.

That's the experiment I want to run.

Top comments (0)