eval: compare st2-managed and harness-native delegation across 12 matched cells - #76
Draft
schickling wants to merge 1 commit into
Draft
eval: compare st2-managed and harness-native delegation across 12 matched cells#76schickling wants to merge 1 commit into
schickling wants to merge 1 commit into
Conversation
Add the twelve matched `delegation-*` cells: three delegation tasks (broad multi-file search, independent review of a green-suite patch, one scoped implementation) across four arms (`claude-st2`, `claude-native`, `codex-st2`, `codex-native`). Each native arm has a same-harness managed counterpart, so the delegation mechanism is not confounded with the model family. Within a task the arms are byte-identical in task, held-out graders, frozen product repository, deliverable contract, and timeout; only the seats and the coordinator persona vary. Deliverables are attributed per delegate in a shared `findings/` directory, so one arm-blind oracle reads a bus delegation and a native fan-out identically; `grade.sh` learns the arm only for the delegation-evidence judge. `bin/check-delegation-parity.sh` proves the matching, the grader discrimination in both bus shapes against nineteen planted failures, and the tasks' premises without starting a model. A non-gating `observations` signal judge records bus latency and round-trips, because `st2 eval` keeps no metrics and a single-seat folder eval always consumes its whole timeout. `evidence/delegation-parity-design-20260812.md` preregisters the question, metrics, n = 3 replication, rerun policy, falsification rule, and the two honest boundaries: native arms necessarily run unmanaged, and native fan-out is self-attested with only a negative mechanical guarantee. No arm has been run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The question
Are st2-managed sub-agents worse than harness-native sub-agents on real delegation work? This is a regression
check on an existing fleet capability, not a feature demo: if handing a scoped slice to a peer seat over the bus
produces fewer correct outcomes — or the same outcomes far more slowly — than letting a harness fan out to its own
sub-agents, that is a defect in the managed path and we want it measured rather than argued.
Four arms, and why four rather than three
cells/delegation-{sweep,review,implement}-{claude-st2,claude-native,codex-st2,codex-native}/— 4 arms × 3 tasks= 12 cells.
A three-arm shape (one managed arm plus two native arms, or one managed plus one native) confounds the delegation
mechanism with the model family. If
claude-st2underperformscodex-native, that difference is unattributable.So every native arm has a same-harness managed counterpart, and every comparison the pass criterion makes is
within a harness:
claude-st2vsclaude-native,codex-st2vscodex-native. The mechanism is the only thingthat varies inside a comparison.
Within a task the four arms are byte-identical except for the seat declarations and the coordinator persona. The
managed arms declare worker seats and a coordinator whose persona names its delegates over the bus; the native arms
declare a single seat whose persona fans out to harness sub-agents. Task text, graders, fixture repository, frozen
baseline manifest, deliverable contract, kickoff target, and timeout are all shared bytes, and
bin/check-delegation-parity.shproves it.Three tasks
sweeplegacyTitle(), delivered as two attributed slices plus a summaryreviewimplementEach task ships one mechanical grader used by all four arms. The
delegationjudge takes an arm-kind argument(
st2/native) so a single grader reads a bus delegation and a harness fan-out identically — the outcome gradersnever learn which arm produced the deliverable.
Metrics and pass criterion
Gating judges produce a PASS/FAIL per run. A non-gating
signaljudge (judges/observe.sh) records descriptiveper-run metrics into a durable metric sink: kickoff timestamp, confirmation timestamp, derived bus latency, bus
message count, bus seat count, delegate labels, and the deliverable list.
Managed delegation is "worse" only if, in ≥2 of 3 tasks, the managed arm has strictly fewer PASS runs than its
same-harness native arm — or outcomes tie and its median bus latency exceeds 2× native.
Anything else is a null result. The criterion is preregistered in
evidence/delegation-parity-design-20260812.mdso the thresholdcannot be chosen after the numbers land.
Cost
n=3 per cell → 36 runs. The one real run cost $3.36, so the full tournament is ~$120.
One real run — VOID, not failed
delegation-sweep-claude-st2was run once for real. The result is void: the coordinator could not have used thebus at all, because
st2 message sendhard-fails in that catalog.The two "delegation" messages present in the run were hand-written files — named
s1sendands2send, whereasa real send gets a random suffix like
ffxvrm. The agents, finding the bus broken, wrote inbox files by hand. Sothe
delegationjudge graded a filesystem workaround, not st2 bus delivery. The run cannot speak to thequestion the eval asks, in either direction.
Root cause chain
package.jsoncontains{"type":"module"}.typekey as an Agent Spec, so that file becomes a phantomagent (Discovery admits any JSON with a top-level
typekey as an Agent Spec, so an ordinary{"type":"module"}package.json becomes a phantom agent st2#247).discovered.specsis therefore non-empty.state (The catalog-less flat-bus fallback is gated on unrelated catalog state: one stray
package.json(or an empty.st2) un-addresses every seat in a compact-team eval st2#248).dingandsendresolve nothing; delegated messages sit unread.max-timeout.Self-amplifying
st2 ls,st2 agents,st2 validate, andst2 doctoreach create.st2, which permanently breakssend.The agents ran exactly those commands to diagnose the broken bus — so the act of investigating the failure made it
unrecoverable.
Verified isolation breach
A stray send wrote
repo/resources/inbox/inside the audited fixture, which theisolationjudge grades asbyte-identical to the frozen baseline. That judge can pass while the fixture is mutated. This is verified, not
theoretical, and it is the most serious finding here: an isolation judge that passes on a mutated fixture is not an
isolation judge.
What the run did prove works
Fixture copy, team boot, kickoff delivery, bus addressing, judge execution, the isolation judge's mechanics, the
signal judge's metric sink, and
SPEC_DIRresolution. The coordinator persona worked: it delegated real scopedslices to the right peers without doing the work itself, which is the behaviour the managed arms depend on.
The cell design is largely vindicated; the runner underneath it is not.
Disclosed defects
Three known problems, stated rather than hidden:
delegate_labelsmetric is poisoned.judges/observe.shglobsfindings/*.md, which includesCONTRACT.md. The contract documents the attribution format with a placeholder(
delegate: <the identity of the delegate that wrote this file>), so the metric reads the literal string<thein every arm. Gating is unaffected —grade.shreads onlyslice-*.md— but the metric is unusableas shipped.
st2 eval's wall clock isuseless because cells always burn their
max-timeout. That is wrong: the runner does exit early on asup→requester confirmation post-dating a worker report. Once DING works, runner duration becomes a usable
measure alongside bus latency.
ST_AGENTbreakage (Corpus migration: 40 cells declareenv { ST_AGENT "<team>.<seat>" }, which st2 now rejects at boot (the runner owns ST_AGENT) #75). The tournament copiedthe established seat pattern, which declares
env { ST_AGENT "<team>.<seat>" }; st2 now ownsST_AGENTandrejects that at boot. This is an intentional upstream ownership change, not a bug, but it broke 40 of 59 cells
corpus-wide (94 seat declarations) and these 12 cells inherit it. It should be fixed as one corpus-wide
migration, not patched per-cell here — a partial fix would reintroduce exactly the harness confound the 4-arm
design exists to remove.
Note also that
bin/check-delegation-parity.shprints12 delegation-parity cells match within each task, but itsmatching check deliberately does not compare the
team { }seat blocks across arms, since those differ by design.An asymmetric seat-env divergence between
claude-st2andcodex-st2would pass the gate. Read that PASS line as"tasks, graders, fixtures, personas, timeout, and kickoff match", not "the cells are identical".
Structural limitation — what this eval cannot conclude
The native arms cannot run managed. A folder eval launches
exec claude/exec codexdirectly, soAGENT_LAUNCH_HOSTEDis unset and the managed refusal never fires.So this tournament compares managed delegation against UNMANAGED native delegation. It is not a clean
managed-vs-native contrast holding hosting constant, and it cannot answer whether the managed wrapper is what
costs anything. It bounds the claim to: does delegating over the st2 bus produce worse outcomes or materially worse
latency than a harness delegating to its own sub-agents, when the native side runs unmanaged.
What's in this branch
cells/delegation-*/bin/check-delegation-parity.sh— a free, model-free gate proving arm matching, task premises, and graderdiscrimination against 20 planted failures plus tolerance positives
evidence/delegation-parity-design-20260812.md— the preregistered designdocs/vrs/spec.mdparagraph, regeneratedCATALOG.md, and a.gitattributesruleso the reviewed proposal patch's blank context lines don't trip the corpus whitespace gate
Gate output
Review asks
preregistered precisely so it can't be moved later.
isolationjudge in this PR, or is it purely an st2 fix?ST_AGENTmigration land first as one corpus-wide change, with this branch rebasing onto it?