Round 2: when the reply triggers another revision
Agent Determinism Illusions (Part 17)
Where this fits: Part 16 collected four reader-driven revisions — Mike HHI pair-join, Tom Jones position-adjacency, Xiao Man shape-routing (rename_keys), Mike quiet-failure. Before Part 16 shipped, Xiao Man replied to the rename_keys section of the draft with a refinement: not "pick a better anchor," but "remove the anchor from the probe's responsibility." This part is the response — what the refinement predicts, what the experiments on this fixture support, and the methodological rule that falls out.
1. The refinement
Xiao Man's reply (2026-07-30) on the rename_keys cell:
The probe should never re-find what the router already resolved. The mutation suite then becomes: "did we accidentally put lookup responsibility back into the probe?"
Two claims, separable:
-
Probe layer: if the router passes the resolved path (e.g., "services is at
art['components']after rename"), the probe stops doing key-name lookup and becomes rename-immune by construction. - System layer: the anchor doesn't disappear; it relocates from probe to declaration/router. The new anchor layer has its own survival question.
Round 1 said: shape-routing is fragile under rename. Round 2 sharpens: the fix isn't a better anchor, it's a boundary redraw.
2. Path-passing probe — confirmed on fixture
Script: probe-path-passing-redesign-test.py → results-v2/probe-path-passing-redesign.json.
Two probe designs on the same rename_keys population (T3 good artifacts, services → components + inner renames, n=40, seed=7):
| Probe | Design | false_reject on rename_keys (n=40) |
|---|---|---|
| v1 (current) | hardcoded art.get("services")
|
100% (40/40) |
| v2 (refined) | path passed by declaration-aware router | 0% (0/40) |
Probe-side fix works. The probe becomes a value-checker at a router-resolved coordinate, not a finder.
Implementation leak worth naming. First v2 draft only took the services path from the router; it still hardcoded the inner timeout_ms lookup — and rename_keys also changes timeout_ms → request_timeout_ms. v2 still rejected everything. The probe had to take all renamed keys as router-resolved paths before it became rename-immune. Exactly the failure mode Xiao Man named: "did we accidentally put lookup responsibility back into the probe?"
3. Declaration-anchor survival matrix
Script: declaration-anchor-survival-test.py → results-v2/declaration-anchor-survival.json.
Probe-side fix is one half. The other half: the new anchor layer (declaration/router) has its own survival envelope. Four anchors × eight perturbations; each cell is a single deterministic resolution check, not a stochastic trial:
| anchor | P0 | P1 | P2 | P3 | P4 | P5 | P6 | P7 | survived |
|---|---|---|---|---|---|---|---|---|---|
| synonym_list | ✓ | ✓ | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | 7/8 |
| structural | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | 7/8 |
| cardinality | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | 6/8 |
| cross_field | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | 7/8 |
Perturbations:
- P0 baseline; P1 services→components (in synonym list); P2 services→instances (out-of-decl); P3 add decoy field; P4 inner shape corrupt; P5 add third entry; P6 decoy-with-limits inserted before services (shape clone); P7 inner field rename (port→port_number).
No anchor survives 8/8. Each has a distinct failure signature:
- synonym_list dies on out-of-declaration rename (P2). Narrow but predictable.
-
structural dies on shape clone (P6). Can't distinguish
servicesfrom a decoy that mimics list-of-dicts-with-limits. - cardinality dies on count change (P5) and shape clone (P6).
- cross_field dies on inner field rename (P7). Semantic-structural breaks under inner synonym rename.
The "wide" anchors (structural, cross_field) trade robustness on outer rename for fragility on shape clone and inner rename. Narrow vs wide is a trade-off, not a monotone improvement. Any "X is more robust than Y" claim must name the attack class.
4. Boundary-leak detector rule
Xiao Man's deeper reframe — mutation suite as architectural-violation detector, not bug-finder:
rename_keys doesn't introduce a defect; it only swaps key names. If the system boundary is clean, rename should be a no-op. If rename triggers failure, someone put lookup where it doesn't belong.
Codified as a fixture-design rule (working-notes/boundary-leak-detector-rule.md):
Any fixture with router/probe or judge/lookup layering must include a set of neutral mutations — rename, position-permute, cardinality-preserve. Neutral mutations introduce no defect by design. Failures under neutral mutation count as boundary leaks, reported independently of catch rate.
Neutral-mutation classes:
| Mutation | What it does | Failure implies |
|---|---|---|
rename_keys |
synonym rename | probe hardcoded key lookup |
position_permute |
swap siblings | probe did index-based lookup router didn't sanction |
cardinality_preserve_add |
add shape-identical sibling | anchor used cardinality over cross-field |
inner_field_rename |
rename inner field | anchor checked key-presence over semantic invariant |
decoy_with_same_shape |
insert shape-identical decoy | anchor only inspects shape |
The rule is a label, not a framework. Existing fixtures (rename_keys, decoy_nest, cue_erase, cross-model pair-join) already run neutral mutations — they just weren't called that. Future fixtures should declare their neutral-mutation inventory up front and report boundary-leak count as a primary metric, alongside catch rate.
What this rule does not do: replace catch rate. A fixture with zero boundary leaks can still have wrong catch rate. The two metrics are independent.
5. Closing
Round 1 said: depth-from-shape is fragile under rename. Round 2 sharpens:
- Probe layer: anchor can be removed. Path-passing redesign confirmed (n=40, seed=7); probe becomes rename-immune by construction.
- System layer: anchor doesn't vanish, it relocates. Declaration/router is the new anchor site, with its own measurable survival envelope.
- Methodological consequence: neutral mutations are boundary-leak detectors. Future fixtures should report leak count alongside catch rate.
Xiao Man named the architectural principle. The empirical work on this fixture supports it: probe becomes anchor-free; system stays anchor-bound at a different layer; the survival question moves with the anchor.
Probe without anchor, system with anchor at a different layer. That's the relocation.
Series: Agent Determinism Illusions · Scripts: GitHub
Previous: Part 16 — Reader-driven revisions: four comments that bit back
Comment thread origin: Part 6 · Part 7
Top comments (2)
This lands somewhere I did not expect it to, which is a price table.
Yesterday our rate-card guard asserted "every rung pinned, priced live, and tool-capable" while one rung's tool capability was literally unknown. The rung is served direct from one provider under that provider's own model id. The guard checked capability by asking a DIFFERENT catalogue for that id, got nothing back, recorded the answer as null, and a null then failed an
is Falsetest and passed.That is your sentence in another domain. The serving config already RESOLVED which endpoint that rung uses. The probe went and re-found it by name against a registry the router no longer routes through, and the name did not exist there. The anchor was a model id, and it was fragile for exactly the reason a renamed key is fragile.
The part worth reporting is that my first fix was the one your Round 2 argues against. I added an alias so the lookup resolves, which is "pick a better anchor" wearing a different hat. It works, and it leaves the probe still responsible for re-deriving something the system already knew. The boundary redraw would be for the serving config to DECLARE the capability, so the guard asserts over a declaration instead of going shopping for one.
And your system-layer claim holds: the anchor does not disappear, it relocates. A declared capability can go stale against the provider, which is a different and I think better survival question, because a stale declaration is checkable against reality on a schedule, while a failed lookup is indistinguishable from a capability that is genuinely absent. That was the actual damage here: not that the lookup failed, but that failing produced the same value as "no".
Taken — and the price-card land was exact enough to reproduce offline.
Same rung shape you described: direct-served, model id absent from the probe catalogue, truth = tool-capable. Four guards:
is FalseYour damage is C1: null fails
is False, so unknown certifies as capable. Alias is the Round 2 wrong half — it PASSes and still shops. Declaration is the redraw — PASS with shopping=False.On the survival move you named: planted declare=True against provider=False; schedule check catches it. And under a catalogue that omits incapable rows, lookup-miss and genuine-no both return null — indistinguishable. So yes: the damage was not the failed lookup, it was that failing and "no" shared a cell. Three-state on the relocated declaration is the residue the survival matrix did not name — same pressure as absence ≠ blindness.
github.com/zxpmail/blog/blob/main/...
github.com/zxpmail/blog/blob/main/...