A developer gives a coding agent a detailed instruction:
Add cancellation support to the order API. Follow the existing architecture, preserve backward compatibility, add validation, and include unit and integration tests.
The agent inspects the repository, implements the feature, and generates passing tests.
Then code review discovers that the cancellation rule belongs in another service. The agent duplicated existing business logic, and its tests encode the same incorrect assumption as the implementation.
The AI coding prompt was not necessarily the problem. The agent was making engineering decisions that depended on information it did not have. As coding agents move from generating isolated functions toward making repository-scale changes, this distinction becomes increasingly important.
A useful way to think about reliable AI-assisted development is:
Prompt engineering → What should the agent do?
Context engineering → What must the agent know to make the right decisions?
Validation → How do we establish that the result is correct?
Good prompts matter. But they solve only the first problem.
A Precise Prompt Cannot Supply Missing Knowledge
Consider a simple instruction:
Add retry logic when the payment provider times out.
Before writing code, an engineer should probably ask several questions.
Can the operation safely be retried?
Does the provider support idempotency?
Does a timeout mean the payment failed, or only that the application did not receive a response?
Is retry behavior already implemented elsewhere?
What happens if the payment succeeds remotely but the response is lost?
A more detailed prompt could answer these questions.
But there is a catch: someone must first know which questions need answering.
This is where prompt engineering for coding reaches a practical limit. If every task requires a developer to reconstruct the relevant architecture, business rules, integration constraints, and historical decisions inside the prompt, the prompt becomes a manually assembled context package.
Repository Access Is Not the Same as System Knowledge
Giving coding agents repository access helps enormously, but the repository is still only one source of engineering knowledge. Code can often tell an agent what the system currently does. It may not explain why.
The repository might not reveal that:
- an API must remain compatible with an older client
- a service is scheduled for retirement
- another application reads the same database table
- an apparently redundant check handles an operational edge case
- an external integration behaves differently from its nominal contract
Even when all relevant information is documented, another problem appears: which source is authoritative?
Suppose the code follows one pattern, an old architecture document describes another, and a newer ADR introduces a third. Giving the agent all three does not resolve the contradiction. The agent still needs a way to determine which one governs the current change.
Context Engineering Is About Selection
This is why context engineering for software development should not mean simply filling a large context window.
The better question is:
What information does the agent need to make the decisions required by this task?
For a production change, relevant context might include:
- requirements and acceptance criteria
- affected source files
- architecture decisions
- API contracts
- schemas
- existing tests
- security constraints
- operational requirements
But more context is not automatically better.
Useful context should be evaluated along four dimensions:
Relevance: Does it affect the current decision?
Freshness: Is it still accurate?
Authority: Which source wins if information conflicts?
Scope: Does this rule apply to the component being changed?
That makes context engineering an information-selection problem, not a token-volume problem.
Different Development Stages Need Different Context
Another mistake is treating a software change as one large generation request. Planning, implementation, testing, and review answer different questions.
Planning
For an order-cancellation feature, planning might need business rules, acceptance criteria, service ownership, API contracts, and architectural boundaries.
The question is:
What should change, and where should that responsibility live?
Implementation
Once the plan is established, the agent needs narrower technical context: interfaces, implementations, schemas, nearby tests, utilities, and local conventions.
Now the question becomes:
How should this approved change be implemented?
Testing
Testing needs expected behavior and edge cases, not merely the implementation. If tests are derived only from generated code, they can reproduce the same misunderstanding.
Review
Review should compare the implementation against independent evidence: requirements, acceptance criteria, architectural constraints, existing tests, API compatibility, and the actual diff.
The question is no longer whether the code looks reasonable. It is whether the change is correct.
Passing Tests Can Validate the Wrong Assumption
Suppose the requirement says:
Customers may cancel an order before fulfillment starts.
The agent decides fulfillment begins when the order enters Processing.
It implements:
if order.status != Processing:
allow cancellation
It then generates tests based on that interpretation . All tests pass. But suppose the actual business rule defines fulfillment as starting when a warehouse reservation is created, which happens earlier. The implementation and tests are internally consistent. Both are wrong. This is why generated tests are useful evidence, but they are not independent proof that the requirement was understood correctly.
A More Reliable AI Development Model
A practical model is:
Intent → Context → Execution → Validation → Feedback
1. Intent
Define expected behavior, acceptance criteria, constraints, and explicit non-goals. Do not use prompting to hide unresolved requirements.
2. Context
Identify the decisions the agent will need to make, then identify the authoritative information for those decisions. Avoid attaching everything simply because it is available.
3. Execution
Bound what the agent may change.
For example:
- preserve the public API
- reuse the existing authorization policy
- modify only specified components
- report architectural conflicts before proceeding
4. Validation
Match verification to the risk. Regression tests can protect existing behavior. Contract tests can protect consumers. Architecture checks can detect dependency violations. Business acceptance criteria can validate domain behavior. High-risk changes may still require targeted human review.
5. Feedback
When an agent makes a bad decision, do not automatically conclude:
We need a better prompt.
Ask why the required information was unavailable or misunderstood.
Was an architecture rule undocumented?
Was an obsolete document retrieved?
Did two sources conflict?
Was a business rule known only by one engineer?
Fixing those problems improves future development instead of making every developer rediscover the same missing context.
Better AI Coding Requires Better Engineering Systems
Good AI coding prompts remain useful. Clear instructions reduce ambiguity and help coding agents understand scope and expected outcomes. But production reliability cannot depend primarily on how well individual developers write prompts.
The stronger approach is to build an environment where agents can obtain relevant context, distinguish authoritative information, surface uncertainty, operate within explicit boundaries, and have their output checked against independent evidence.
The question therefore changes from:
How do we write better prompts?
to:
How does our engineering system prevent missing context from becoming incorrect code?
As coding agents take on larger changes in your repositories, how are you deciding what context they should receive—and which sources they should trust?
As your teams give coding agents larger tasks, how are you deciding what information they should trust?
Top comments (1)
Where I keep getting burned is exactly your point that someone must first know which questions need answering. The retry-on-timeout example is a good one because those questions aren't discoverable from the repo — whether a timeout means the payment failed or only that the response was lost lives in the provider's docs and in someone's head.
The mitigation that's worked best for me is forcing an assumptions step: before the agent writes code, it writes down what it believes (this operation is safe to retry, the provider supports idempotency keys, cancellation belongs in this service), and the review target becomes that list instead of the diff. Diffing wrong assumptions takes seconds; diffing the business logic those assumptions produced takes an afternoon — and as your opening example shows, by then the tests have faithfully encoded the same wrong belief.
One thing I haven't solved: the "why" half. ADRs and wiki pages decay fast enough that an agent reading them six months later receives stale reasons with current confidence. The only place that's stayed reliable for me is comments at the decision point itself. Have you experimented with making the agent generate the question list itself before implementing? I can't tell yet whether that genuinely catches cross-service boundary cases like your cancellation example, or just produces plausible-but-wrong questions at a higher rate.