Where You Put Things in the Context Changes the Answer
Same instructions, same documents, different results — because the constraint sat in the middle of a long array. Two ordering rules, one of which also decides whether your prompt cache ever hits.
Two agents, identical instructions, identical retrieved documents, identical tools. One reliably follows a constraint; the other drops it around turn fifteen. The difference is ordering — where in the assembled array each piece sits, and whether its position is stable across turns.
Context assembly gets treated as plumbing: gather the pieces, concatenate, send. It's a design surface with rules, and two of them account for most of the difference.
Rule 1: position within the array is not neutral
Material at the very start and the very end of a long context gets used more reliably than material in the middle. This is a well-observed property of long-context models, and however much it improves, planning around it costs nothing.
The practical layout:
- Start: identity, standing constraints, output requirements. Things that must hold for every turn.
- Middle: bulk material — retrieved documents, accumulated history, long tool results. The stuff that's referenced when relevant and ignored otherwise.
- End: the current task, the immediate question, and any constraint that is easy to violate right now.
→ The move that fixes the most cases: restate the critical constraint at the end, immediately before the model acts. A rule stated once at turn one and never again is competing with everything since. The same rule, re-injected each turn just before the request, holds.
This is not repetition for emphasis. It's placing the constraint where it can't be buried by the growing middle.
Rule 2: stability is worth more than compactness
Prompt caching keys on a prefix. Everything up to the first byte that changes can be reused; everything after is reprocessed. So a context whose early portion is byte-identical across turns is dramatically cheaper and faster than one that shuffles.
The mistakes that break it are small and easy to make:
- ❌ A timestamp in the system prompt — changes every call, invalidates everything.
- ❌ Tool lists assembled from an unordered set — same tools, different order, no cache hit.
- ❌ Retrieved documents inserted before the standing instructions — new documents each turn push the invalidation point to the top.
- ❌ Re-summarizing history each turn, rewriting the middle every time.
✅ The layout that caches well: fixed system prompt → fixed tool definitions → stable retrieved material → append-only history → the volatile current turn last. Volatility increases monotonically toward the end.
This ordering serves both rules at once, which is convenient: constraints at the front are also the most stable content, and the volatile task at the end is also the most attended-to position. ⚠️ The one real tension: a constraint restated at the end is volatile by construction. It's a small suffix, and it's worth the cache cost — but keep it small and keep it last, so it invalidates nothing but itself.
Structured state beats narrated state
For anything the run must track — items completed, decisions made, constraints accumulated — put it in a compact structured block the loop regenerates, rather than leaving it distributed across conversational turns.
## Run state
Task: reconcile 12 invoices against ledger
Completed: 7 (INV-201..207)
Outstanding: INV-208..212
Constraints: read-only on ledger; escalate any variance over 500
Decisions: treat FX rounding under 0.01 as immaterial (turn 4)
Three advantages over hoping the model remembers: it's compact; it's checkable, so a bug in the state is visible rather than inferred; and it survives compaction, because the loop regenerates it from durable state rather than depending on any surviving message.
🔍 Diagnosing an ordering problem
The symptom is a constraint or fact that's followed early and dropped later.
- Dump the raw array on a failing turn.
- Locate the constraint. Note its position — how many tokens from the start, and how many from the end.
- If it's buried in the middle of a long context, that's your answer.
- Test by re-injecting it at the end each turn. If the behavior fixes, it was position; if not, look elsewhere.
This takes minutes and rules out the most common cause before you start rewriting prompts.
The takeaway
The array is a document, and where things sit in a document affects what gets used. Put standing constraints at the front, bulk in the middle, the live task and the easily-violated rule at the end. Keep the prefix byte-stable so caching works, and hold run state as a structured block the loop owns rather than as a story the model is expected to remember. Most "the model ignored my instruction" bugs are one of these two rules being broken.