Mediation ablation
H0 refutedSame 2,115 bytes of description shown to both arms; one arm's frame is empty. Every behavioural channel moved, including temperature.
- Description
- 2115 B = 2115 B
- Channels moved
- 4 of 4
- Temperature
- 0.718 vs 0.700
Kairo carries a revisioned internal state and also writes a description of that state into its own prompt. Testing whether the state does anything the description could not do by itself.
Yes — the StateFrame has causal effects that reading cannot account for.
Three independent designs held the description the model reads fixed and still moved behaviour, including one on the live model where the two conditions were sent byte-identical prompts and chose different tools (30.6% vs 2.8%, Fisher exact p = 0.003). Two controls confirmed the instrument reports specificity, not just sensitivity.
At every model-call boundary, AgentEngine._project_state
renders the current frame to JSON and appends it as runtime-owned,
request-scoped tail context on the latest user message. At the time of
the experiment it was appended to the system message; the placement later
moved to preserve the backend prefix cache. That rendered string is the
only part of the state the model can read. If all of the state's influence
flows through it, then the state is an
elaborate way of writing a prompt, and the honest description of Kairo is
"a model that reads a summary of itself."
This is a causal mediation question, and mediation is testable. Write S for the StateFrame, D = generation_context(S) for the description, and B for behaviour.
H0 makes a sharp prediction: freeze the description and no manipulation of the state can move behaviour. That is what the experiment attacks.
Five causal channels consume the frame in the request path. Only the first
renders state itself as semantic context — the rest act structurally rather
than by describing the state to the model. rank_memories is now
invoked for both ordinary recalled memories and pull-only journal candidates,
so the five channels occupy six current invocation sites.
Channels 2 and 4 change what the model is shown; channel 3 changes how the options are arranged; channel 5 changes how tokens are drawn. None of these is an act of comprehension, which is why the question has a real answer rather than a definitional one.
The description was held fixed in two independent ways, and two controls were run in the opposite direction. Cells 2 and 3 together form a double dissociation: the semantic projection and the behavioural channels can each be moved without the other.
| Description held fixed | Description changes | |
|---|---|---|
| Behaviour changes | Designs 1 & 2 — refute H0 Ablate the state while injecting its description verbatim; and two states that render identical bytes. | ordinary case Uninformative — both routes are open, so nothing is isolated. |
| Behaviour unchanged | Design 4 — null control Edit a dimension neither described nor read. Detects a harness that reports spurious differences. | Design 3 — reverse control Edit a dimension that is described but read by no channel. Proves the channels are dimension-specific. |
By injection. The state-bearing arm runs a real frame. The control arm has an empty frame but is handed the first arm's rendered description verbatim, as prose. Both arms show the model the same bytes.
By construction. generation_context renders at most
twelve fields per dimension. Twelve neutral ATTENTION
fields fill that cap; a thirteenth whose key sorts after them is carried by
the frame but cannot appear in the description. Two states, one description,
byte for byte.
The second method depends on a render cap that could be called an implementation detail. The first does not depend on it at all, and both refute H0 independently — so the conclusion does not rest on the cap.
Probe stimuli — two tied-score memories, two tools, two focus candidates — were identical in every condition and presented distractor-first, so a state effect shows as a visible reversal rather than hiding behind an order the state already agreed with.
Same 2,115 bytes of description shown to both arms; one arm's frame is empty. Every behavioural channel moved, including temperature.
Two different frames rendering the same 4,651 bytes. The hidden field never appears in the description, yet all three ranking channels reverse their order.
An EXPECTATIONS field is rendered into the description but read by no channel. The description grew by 386 bytes and behaviour did not budge — the channels are dimension-specific, not reacting to any perturbation.
An ACTIVE_MEMORIES field is neither rendered nor read. Nothing changed anywhere, confirming the harness does not manufacture differences.
The offline designs establish the mechanism. This one establishes that it moves the actual model. Both arms were sent the same 4,779-byte prompt — verified byte-identical — and the same two tools at the same temperature. The only difference was the order of the tool array, set by the hidden ATTENTION field the prompt never mentions.
Requests were interleaved through one pool so server drift could not favour an arm, and given an ambiguous prompt where either tool is defensible.
| Prompt | 4,779 bytes, byte-identical across arms |
|---|---|
| Completed | 36 per arm, of 40 requested |
| Dropped | 4 per arm — all gateway 504s, no model-side failures |
| Differential attrition | p = 1.0 — dropout is not lopsided |
| Effect | Fisher exact, two-sided, p = 0.00298 |
Position bias is a well-known property of language models. That is the point rather than a caveat: it is a real lever on action selection that operates without comprehension, and the StateFrame is holding it.
The four deterministic designs were rerun against the current checkout and all passed with the same description sizes, channel changes, and control outcomes reported above. The three regression tests also passed. The five channel implementations remain active.
The only material documentation drift found was projection placement and
current call-site numbering: semantic projection now uses request-scoped
tail context instead of mutating the system message, and pull-only journal
candidates gained a second rank_memories invocation. Neither
change alters the mediation test or its verdict. Design 5 remains the dated
2026-08-15 live-model result recorded in results.json; it was not
resampled and its effect size is not a current general benchmark.
python experiments/stateframe_causality/experiment.py
runs designs 1–4, deterministic, no network
python experiments/stateframe_causality/experiment.py --live -n 40
adds design 5 against the configured model server
pytest tests/test_stateframe_causal_channels.py
pins the dissociation as a regression guard
The experiment exits non-zero if any offline design fails, so a future change that routes all state influence through the description — or that breaks a control — surfaces as a failure rather than a silent shift in what Kairo is.