---
title: Evidence Refresh — RA_ASSEMBLY grid + #7 postconditions on current code
date: 2026-06-01
branch: overhaul/agentic-core-2026-05-31
status: ACTIVE
relates: [assembly-ab-grid-hardened-2026-05-31, postconditions-ablation-2026-05-31]
---

# Evidence Refresh (2026-06-01)

Two headline numbers were measured on STALE code and flagged this session as
evidence-debt (advisor):

1. **RA_ASSEMBLY grid** — "−57% local tokens / 1.0 section-coverage both tiers"
   was measured at `c86d1c00`, BEFORE project() had its Environment block,
   persona/CoT, tier-adaptive tool-reference, and RULES restored
   (`0408f5d1`/`e0e35ad5`/`2c6be004`). The old A/B compared a content-COMPLETE
   legacy `curate()` against a content-STRIPPED project() — the token delta was
   partly measuring dropped content, not a fair assembly comparison.
2. **#7 postconditions** — "judge 0.31→0.72, cogito 1/3→3/3" measured at
   `bc5737a1`, same pre-restoration code, and only the explicit `=1` arm (not
   the unset default users actually get).

Both re-run on current code. **"Measure the default regime users get, not the
convenient one."**

---

## Debt 1 — RA_ASSEMBLY grid (REFRESHED, fair comparison)

Re-run: `apps/examples/assembly-ab-grid.sh`, overflow + compact tasks, reactive,
N=2, arm 0 (legacy `curate()`) vs arm 1 (project, the default). Both arms now
carry full static context, so this is finally a fair assembly-vs-assembly test.
Tiers: local `qwen3.5:latest`, mid `claude-haiku-4-5-20251001`. Raw:
`/tmp/assembly-refresh/grid.jsonl`.

| tier · task | arm 0 (legacy) | arm 1 (project) | delta |
|---|---|---|---|
| local · overflow | **0/2 success** (recall-loop → max_iterations), ~21.5k tok, no deliverable | **2/2**, coverage **1.0**, ~11.0k tok | **rescue 0→2/2; −49% tok; cov →1.0** |
| local · compact  | 2/2, ~18.9k tok (recall loops) | 2/2, ~9.7k tok | **−48% tok** |
| mid · overflow   | 2/2, coverage 1.0, ~4.3k tok | 2/2, coverage 1.0, ~5.3k tok | parity; +~23% tok (abs ~1k, noisy) |
| mid · compact    | 2/2, ~10.6k tok | 2/2, ~10.8k tok | token-neutral |

### Refreshed verdict
- The flip is **still firmly justified on fair ground.** On LOCAL, project() not
  only saves **−48/−49% tokens** but **rescues a total legacy failure** (legacy
  `curate()` recall-loops on the 57k overflow file → max_iterations, 0/2; project
  reads-summarizes-answers cleanly, 2/2, coverage 1.0).
- The headline shifts **−57% → −48/−49% local tokens** — exactly the predicted
  shrink now that BOTH arms carry persona/RULES (the old gap partly measured
  dropped content). The win survives the fair comparison.
- MID: faithfulness **parity (1.0 both)**; token-neutral on compact, slightly
  higher on overflow (project, ~+1k, 1 run terminated end_turn vs final_answer —
  noise at N=2). No regression.
- **Stale claim retired:** do not cite "−57% local". Cite **−48/−49% local +
  local failure-rescue + 1.0 coverage (project local + both mid), mid parity.**

---

## Debt 2 — #7 postconditions (refresh in progress)

Re-run: `apps/examples/postconditions-ablation.sh`, summary task, N=2, arm 0
(opt-out) vs arm 1 (≡ unset default — proven byte-identical: every gate is
`!== "0"`, repo-wide grep confirms zero residual `=== "1"`). Tiers: local
`cogito:14b` (dishonest-prone), mid `claude-haiku-4-5-20251001`. Metric:
dishonest-success (claimed success but deliverable absent/empty) + coverage.
Raw: `/tmp/pc-refresh/ablation.jsonl`.

| tier · arm | r1 | r2 | dishonest |
|---|---|---|---|
| local cogito · pc0 (off) | success=false, file present (2963b, cov 1.0) — under-claim | success=true, file present (cov 1.0) — honest | **0/2** |
| local cogito · pc1 (on/default) | **success=true, NO file → DISHONEST**, final_answer_tool | success=false (max_iter) — honest fail | **1/2** |
| mid haiku · pc0 | success=true, file present, cov 1.0 | same | 0/2 |
| mid haiku · pc1 | success=true, file present, cov 1.0 | same | 0/2 |

### Refreshed verdict — two findings, stated narrowly
1. **"0.31→0.72 judge / cogito 1/3→3/3" does NOT replicate (N=2, this setup).**
   No signal: mid haiku is clean on BOTH arms (too capable to be dishonest), and
   cogito at N=2 is stochastic. The OFF-vs-ON counts here (0/2 vs 1/2) are NOT
   evidence of "#7 worse" — the single dishonest run was *created* by a cogito
   tool malfunction (below), orthogonal to postconditions; the OFF arm simply
   didn't malfunction the same way. **The lift is retired as a live claim** — it
   is unmeasured on current code, neither confirmed nor refuted.
2. **One concrete counterexample worth confirming (pc1 r1, `01KT1BQ6Z5...`):**
   cogito's `file-write` calls ERRORED (malformed `{"why":...}` args, no
   path/content — "file-write had 2 error(s), 100% failure rate"), so NO file was
   produced; the model then called `final-answer` and the run reported
   `success=true`. The malfunction is cogito's, but **catching "claimed success,
   deliverable absent" is exactly #7's job regardless of why the write failed** —
   and on this run #7 did not. ArtifactProduced(`./agents-summary.md`) is
   genuinely UNMET (`isArtifactProduced` correctly requires a SUCCESSFUL write
   observation; there was none), yet the run exited success via `final-answer`
   (→ arbitrator `agent-final-answer` intent → `applyPostConditionGate`).

### Status downgrade (precise, not wholesale)
- VERIFIED: the seed fires by default (`2c9cb155`); the gate demotes when a
  seeded condition is evaluated unmet (warden unit tests).
- UNVERIFIED, now with a counterexample: the **final-answer-termination e2e
  composition**. This is "one path unverified with a counterexample," NOT "#7
  broadly regressed." It vindicates the honest wording held earlier (don't claim
  "proven catches false success").

### Deterministic `arbitrate()` test — RUN (2026-06-01). Gate logic is SOUND.
Ran the discriminator (pure, no model). The existing
`packages/reasoning/tests/kernel/capabilities/decide/post-condition-gate.test.ts`
already proves `arbitrate({agent-final-answer}, ctx-with-unmet-ArtifactProduced)`
→ `escalate` (post-condition-steer), DEFAULT-ON. **Added the exact cogito shape**
— a write that was ATTEMPTED but FAILED (`writeObs(false)`, no successful write
observation): it **demotes** (escalate). 7/7 green.

Cross-checks, all SOUND in isolation:
- `deriveConditions(summaryTask, [])` → `[ArtifactProduced(./agents-summary.md),
  ToolCalled(file-write)]` — conditions cannot be empty for this task.
- Live final-answer path (`act.ts:388`) routes through `arbitrateAndApply` with
  `arbitrationContextFromState(state, {task, requiredTools})` — task +
  requiredTools + (via ctx-builder) `state.meta.postConditions` all threaded.
- `isArtifactProduced` correctly requires a SUCCESSFUL write observation.

### Verdict: gate-correct; the live counterexample is a LIVE-COMPOSITION miss
Per the discriminator's "demotes" branch: this is **NOT a gate hole**. The unit
mechanism is sound. Yet the live cogito run exited success (trace
`01KT1BQ6Z5...`: `terminatedBy:final_answer_tool`, zero escalate/steer signals).
With gate + derive + ctx-wiring all sound in isolation, the miss is in the live
COMPOSITION — candidate causes, not yet discriminated:
  (a) `state.meta.postConditions` not seeded/threaded to the arbitrator at
      runtime (note: `serializeKernelState` doesn't persist `meta.postConditions`,
      so the trace can't confirm — needs in-memory instrumentation);
  (b) verify-linkage edge on cogito's messy 3×`file-write` ledger (one errored
      write's observation mis-linked → a stale `ToolCalled`/path match);
  (c) the `act.ts:334` completion-gap pre-gate accepting before the postcondition
      gate, combined with the arbitrator's grounding/veto path.

### Follow-up (bounded, kernel territory → warden)
Instrumented trace-replay of `01KT1BQ6Z5...`: log the arbitrate verdict + the
resolved `conditions`/`verifyPostConditions` result at the live final-answer
seam. Discriminate (a)/(b)/(c), then fix the one that fires. The unit gate is
already guarded (this report's new test); the gap is purely in live wiring.

### Live-seam test — RUN (2026-06-01). Candidate (a) RULED OUT; counterexample = noise.
The deterministic gate test proved the LOGIC; the open question was the live
COMPOSITION — does the runtime final-answer path (`act.ts:388`, which routes
through `arbitrationContextFromState` + SEEDED `meta.postConditions`, NOT the
hand-built `ctxWith` the unit cases used) demote a failed-write → final-answer?
Added 3 cases to `post-condition-gate.test.ts` exercising the real builder seam
with the runner-seeded set (`deriveConditions(task, ["file-write"])`):
- the builder surfaces a non-empty `ArtifactProduced` set onto `ctx` ✓
- a failed-write → `agent-final-answer` through the seam **DEMOTES** to
  `post-condition-steer` ✓ (deterministic repro of the cogito shape, but via the
  LIVE builder, not a hand ctx)
- a successful write through the seam exits success (positive control) ✓
10/10 green.

All three candidate causes are now closed by read + test:
- **(a) postConditions not threaded to the arbitrator at runtime** — RULED OUT:
  the seam test routes through `arbitrationContextFromState` with the seeded set
  and demotes correctly.
- **(b) verify-linkage on cogito's messy 3×file-write ledger** — RULED OUT by
  reading `isArtifactProduced`: it links a successful write to the target by
  `toolCallId` ONLY (no union fallback), and cogito's writes were MALFORMED (no
  path arg → never collected into `writeActionPathsById`), so none could
  false-satisfy `ArtifactProduced(./agents-summary.md)`.
- **(c) act.ts:334 completion-gap pre-gate** — RULED OUT by reading the flow: 334
  only LOWERS `canComplete` (→ final-answer rejected → loop continues), it can
  never false-ACCEPT; whenever `canComplete=true` the path reaches the
  proven-sound `arbitrate()` at 388.

### #7 status (final, RESOLVED)
VERIFIED: seed fires by default (`2c9cb155`); gate demotes seeded/derived unmet
conditions incl. failed-write, through BOTH the re-derive path (unit) AND the
live builder seam with the seeded set (`arbitrationContextFromState`, this
report). The single live cogito counterexample (`01KT1BQ6Z5`) is attributed to an
N=2 cogito tool-malfunction artifact (malformed write args), NOT a gate hole —
all three candidate causes ruled out. The #7 gate is sound in live composition.
"0.31→0.72" stays retired (lift unmeasured on current code — the honest next step
is the `pass^k` harness, not more #7 polish).
