A slot cannot be paraphrased away
Summarisation loses specifics because it is language compression, and language compression rounds. The fix is not a better summariser. It is to keep the things that must not be lost outside the prose entirely, as named fields.
{
"task": "Resolve a duplicate charge on order ORD-88213",
"entities": {"order_id": "ORD-88213", "amount": "4,180 INR",
"customer_id": "c_9912"},
"constraints": ["refund to original payment method",
"customer wants confirmation by email"],
"decisions": [{"what": "issue partial refund", "turn": 7}],
"rejected": [{"what": "store credit", "why": "customer declined", "turn": 5}],
"open": ["whether the second charge was captured or only authorised"]
}Rendered into the window in a fixed place, in a fixed order, on every turn. Perhaps 150 tokens. An order id in a JSON field survives any amount of compaction, because nothing summarises it: it is copied.
Update rules that do not lose history
The temptation is to overwrite fields as new information arrives. Resist it in two specific places.
Never silently overwrite a value the user stated. If the amount changes from 4,180 to 4,050, that is either a correction or a different charge, and the difference matters. Record the new value with its turn and keep the old one marked superseded. A field that changes with no trace turns a real disagreement into a mystery.
Keep provenance. Which turn set this, and was it stated by the user or inferred by the model? Those two have very different reliability, and a downstream decision (issue a refund of this amount) should be able to tell them apart.
state.set("amount", "4,050 INR", turn=11, source="user", supersedes="4,180 INR")Extraction is a model call, so it has an error rate
Something has to populate the fields, and unless the user filled a form, that something is a model. Which means the state can be wrong, and unlike a wrong answer, a wrong state persists and shapes every subsequent turn.
Three defences.
Extract with a schema and validate. A date field that must parse, an amount that must match a currency pattern, an order id that must match your format and exist. Reject rather than store what fails.
Prefer explicit signals. A value the user typed is more reliable than one inferred from a paraphrase. Where the interface can capture something directly (a selected order, an attached file, a chosen option) take it from the interface rather than from the text.
Show the state to the user. This is the strongest defence and it is a product decision as much as an engineering one. A visible panel saying “Order ORD-88213 · refund to original method · 4,050 INR” lets a human catch the error the extractor made, in one glance, before it does any damage. Make it editable and you have turned an unreliable inference into a confirmed fact.
Where it goes in the window
At a fixed position, immediately before the recent turns and after the compacted middle. Fixed matters for two reasons: the model learns where to look within the request, and a stable position means the diff between two turns is small, which is friendlier to caching than a block that moves.
Label it plainly and say what it is:
<state>
Established facts for this conversation. These override anything in the
summary below if they conflict.
...
</state>That conflict rule earns its tokens. Compaction will eventually produce a summary that contradicts a field, and stating the precedence resolves it deterministically instead of leaving it to the model.
Keep it small
State is not a database. If the block grows past a few hundred tokens it has stopped being a set of load-bearing facts and become a second transcript, with the same growth problem and none of the readability. Cap the number of entries per field, drop resolved open questions, and archive superseded values to storage rather than carrying them in the window.
A useful discipline: if you cannot read the whole state block in ten seconds, it is too big, and something in it is not load-bearing.
The pattern generalises
This is the same idea as the manifest in the selection module and the handover note later in this one: keep the load-bearing facts in a structure your code controls, and let the prose be prose.
Anything you would be unhappy to see paraphrased belongs in a field. Everything else can be summarised, dropped, or left to the transcript. Once you have drawn that line, compaction stops being frightening: the worst it can do is lose texture, and the facts are somewhere it cannot reach.
Every lesson here is open. Your progress is recorded once you pass the Data, SQL and Getting to the Answer exam.
Check your understanding
Why does storing an order id in a structured state field survive compaction when the same id inside a summary paragraph often does not?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Sayali, your AI tutor
