← Back to research
Research

The Context Stack under agents

What happens to curated context once it has to survive a handoff between agents, evidenced against Signal & Flow's live architecture, not hypothesised for this page.

4 ways curated context broke at an agent-to-agent handoff, all found in one live system

The Context Stack set out seven layers of business context a model needs to reason well: Facts, History, Rules, Precedence, Exceptions, Boundaries, and Verdict shape. That piece was written against a single call: one model, one curated brief, one output. Most of what goes wrong there is visible in the room: you can read the brief, read the output, see the gap.

Agents change what "context" has to survive. It isn't handed to one model once. It's produced by one agent, discarded as a live object, and handed on as text, to be re-read and re-interpreted by another agent that never saw what the first one saw. The seven layers don't disappear at that seam. They just stop being guaranteed.

The architecture is not a pipeline

It's tempting to picture a multi-agent system as an assembly line: agent one finishes, hands a clean structured object to agent two, which hands it to agent three. That's not what's actually running in Signal & Flow, my own multi-agent platform, and I'd guess it's not what's running in most production agent systems either.

Signal & Flow runs seven agents, each a separate model call. Some run in parallel: the audit agent (ux_audit.py) and the persona-simulation agent (visitor_mind.py) both read the same raw page signals independently and produce independent output. A synthesis agent (synthesis.py) is the real cross-agent step, but it doesn't sit server-side waiting for the other two to finish and hand it structured state. It's called from its own endpoint (/api/synthesis), which the browser hits only after it already has both the audit text and the persona text back in hand. The handoff, in practice, is two raw prose blobs shipped from the browser back to the server, not one agent passing a data structure to the next.

That matters because it means synthesis never sees what the audit or persona agents saw. It only sees what they said. Every one of the failures below follows from that one fact: the thing carrying context across the seam is prose, not state, and prose is a much weaker contract than it looks like from the outside.

(See the context drift demo for the same shape of failure, dramatised across a fictional three-stage claims pipeline. What follows is the real version.)

Four ways context breaks at the seam

1. The fragile contract

The clearest failure, and the one with the cleanest evidence trail, is a scoring pipeline that broke twice for two different reasons, three weeks apart, with the same symptom both times: every dimension score in every report silently pinned to 95.

The scoring logic works by parsing structured meaning, a numeric score per dimension, out of unstructured text. An agent writes findings as markdown bullets; a regex (_BULLET_RE) pulls the bullets out; a scoring function counts and weights them. That's a contract: the model has to keep producing bullets in a format the regex recognises, or the parser sees nothing, and a parser that sees nothing returns its ceiling value rather than failing loudly. Ninety-five, for every dimension, with no exception thrown and no error logged. A confident-looking report, built on a scoring pass that never actually ran.

The first break came from a formatting collision: a bullet marker (* text) collided with the same character used to open italic formatting elsewhere in the same cleanup step (strip_markdown), and the italic-stripping logic quietly ate the bullet marker along with the asterisk. The fix was a one-line normalisation, added upstream of the italic regex, and rolled out across every file that shared the cleanup function.

Every file except one. A second file (competitor_compare.py) called the raw model output directly, without ever routing it through strip_markdown at all. The blanket fix (commit dcfd860) reached five files and missed a sixth simply because that sixth file wasn't plugged into the thing being fixed, caught and patched the same day, in a one-line follow-up (1384624). Same failure, same day, caught almost immediately, but it's the most honest illustration in this whole piece of what "shared context" actually requires: not just a correct fix, but every consumer of that context actually wired into it.

The third break, five days later (commit a9efdc1), was a different root cause producing the identical symptom. A prompt instruction told the model findings "must begin with exactly one of these two prefixes." The model complied literally, dropping the leading bullet character the parser needed, because nothing in the instruction said to keep it. The contract itself had been too narrow: _BULLET_RE only recognised a hyphen, asterisk, or numbered marker, not the bracketed tags ([ON-PAGE], [PAGE-SIGNALS], [DECISION]) the model had started using instead. The fix widened the regex to recognise both forms, and rewrote the prompt to state, explicitly, that the hyphen always comes first, turning an assumption into a stated rule.

Three fixes. One symptom, recurring. Nothing in any of the three incidents was the model reasoning badly; every one was a format contract failing invisibly at the boundary between what one agent produced and what the next process assumed it would receive.

2. The partial handoff

A second, quieter failure: the synthesis agent was built to explain why different visitor personas reacted differently to the same page. To do that well, it needs the full shape of each persona: age, device, emotional state, tech confidence, shopper type, together. For a period, it was only receiving some of those attributes.

There's no error here, no wrong output in an obvious sense. The synthesis still ran, still produced prose, still read as complete. It just explained less than it should have: conclusions without the context that had actually produced them, because part of that context never made the handoff. This is the failure type hardest to catch precisely because nothing about the output looks broken. It looks confidently thinner than it should.

3. Isolated reasoning

The audit agent flagged a UK business's navigation as a visitor-confusion risk, because the nav listed "Madrid" alongside a run of UK towns. That's a defensible read from a flat, crawler's-eye view of the page text. It's the wrong read of what a human visitor actually sees, because the page elsewhere made clear why Madrid was there.

What makes this a context failure rather than a one-off model mistake is what happened next: after the framing was corrected once, a later isolated pass flagged the same nav element again, in the same way, because that pass had no memory of the whole-page context the earlier fix had already established. Fixing the local mistake didn't fix the underlying cause, which was an agent reasoning from a narrow slice of the page and asserting that slice as ground truth. The same gap reopened the moment a fresh pass ran without inheriting what an earlier pass had already resolved.

4. Role bleed

The generation-stage agent, the one meant to surface raw observations for synthesis to later triangulate, was, for a period, given an expert persona in its instructions: something close to "you are a senior UX strategist." That framing measurably suppressed how many findings the agent surfaced and pushed it to jump straight to prescriptive fixes instead of neutral observations.

That's a subtler kind of context corruption: not missing information, but the wrong register of information arriving at a stage that needed something more raw. Synthesis was built to triangulate across observations; feed it conclusions instead, dressed up as observations, and it has less to actually work with, even though the input looks more authoritative on its face.

The fix was to strip expert framing from the generation stage entirely and reserve it for synthesis, where a confident, expert voice is actually the right register. A runtime check was added alongside the fix: a heuristic that flags when a meaningful share of findings look like commands rather than observations, so a recurrence surfaces as a warning rather than a silent shift in report quality. Worth noting as the one guardrail in this piece that isn't just a fix, but a way of catching the same failure earlier next time.

What all four have in common

None of these four are a model reasoning badly. Every one is context that existed, was correct, and then failed to survive a format change, a routing gap, or a register mismatch on its way from one agent to the next. The seven layers from the original framework are all still there in principle: the failures above are really about what happens to those layers once they have to travel through prose, get re-parsed, and arrive somewhere that never saw the original signal.

That's the actual argument for calling this "context design" and not "prompt engineering," extended one level further: for a single call, the discipline is curating what a model gets. For a system of agents, the discipline is verifying what actually survives between them, because nothing in the architecture guarantees it will, and when it doesn't, the failure is silent by default.

(See also: Testing the Patterns on Real Material, which applies the same standard, real internal codebase, not a hypothetical, to a different question.)

Frontmatter: content/research/context-stack-under-agents.md

title: The Context Stack under agents
slug: context-stack-under-agents
order: 6
summary: What happens to curated context once it has to survive a handoff between
  agents, evidenced against Signal & Flow's live architecture, not hypothesised for
  this page.
stat: '4'
stat_label: ways curated context broke at an agent-to-agent handoff, all found in
  one live system

If this way of thinking is relevant to a problem you're facing, I'd be glad to talk it through.

Start a conversation