HELD: delegation-context split failed its recorded evaluation - #369
Brian Krabach (bkrabach) wants to merge 2 commits into
Conversation
…g any file Committed on its own, ahead of the implementation commit, so the frozen decision rule provably predates the numbers. Rule: SHIP only if success LB >= -5pp AND delegation count within +/-30% of main. Both conditions; the delegation gate is two-sided on purpose (moving depth out of the root prompt can fail by suppressing legitimate delegation OR by removing the wave discipline that told the root to batch). Design: S3-class scenarios, foundation root, arms main vs branch, n>=3 valid runs per arm per provider, both providers (anthropic opus-5 root; openai gpt-5.6-terra root), DTUs. Also records, before spending, that the design cannot be bought at the $10 authority: 12 valid runs / 0.67 observed validity = 18 launches; 9 x $3.53 (opus-5 S3) + 9 x $4.63 (terra) = $73.44. Even at 100% validity, $48.96. $10 buys ~2 valid runs = n=1/arm on one provider, which cannot produce a success lower bound and so has a 0% chance of satisfying the rule. The authority that WOULD close it is $73.44. Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…plus agent-body depth, and repair the estimator that hid the problem HELD: this is the treatment half of model_performance-8rug (B). Its pre-registered eval (07d51b9) is NOT-POSSIBLE at the $10 authority, so the primary metric is UNMEASURED and this PR must not be marked ready. See docs/lanes/.../B-measurements.md. behaviors/agents.yaml and behaviors/tasks.yaml each context.include'd delegation-instructions.md + multi-agent-patterns.md -- 6,276 tokens (len//4) / 5,402 (o200k_base) measured on disk -- into the root system prompt of every foundation-root session. THE VALIDATOR REPORTED 1000 AND CALLED IT A WARNING. Rule 4 of behavior-hygiene resolved an include only two ways: a leading "@" was charged a flat 500, anything else was tried as a relative path. `foundation:context/agents/...` matches NEITHER -- no leading "@", and neither behaviors/foundation:context/... nor <repo>/foundation:context/... exists -- so it took the 500-token default. Two includes x 500 = exactly 1000, against a `> 1000` ERROR gate: 6,276 real tokens graded WARNING, one token under the ERROR that was true. A 6.28x understatement landing precisely on its own boundary. MAIN a0decc6 OLD estimator 1000 -> WARNING | NEW estimator 6276 -> ERROR THIS BRANCH OLD estimator 500 -> ok | NEW estimator 487 -> ok The estimator fix (validate-bundle-repo v3.14.0) strips an optional "@" and also tries the path half of a `<namespace>:<path>` ref against the behavior dir and the repo root. An include it still cannot resolve keeps the 500 fallback but is now recorded in context_unresolved_includes with context_tokens_is_estimate -- a guess folded silently into a number that reads as measured is the defect, not the fallback. The split: - context/agents/delegation-core.md (NEW, 487 tokens len//4 / 464 o200k): the imperative, the immediate triggers, basic delegate usage, the two context parameters. The root session IS the delegator and needs these. - context/agents/delegation-depth.md (renamed from delegation-instructions.md, awareness removed): session resumption, wave discipline, reading a structured return, scrutinising an agent's "N/A", large session files, the context-sink pattern itself -- exactly what that pattern says to defer. - multi-agent-patterns.md: unchanged content, no longer behavior-loaded. Depth is @-mentioned from the two agents that can act on it, and only those: foundation-expert (the ONLY agent declaring tool-delegate -- the behavior sets exclude_tools: [tool-delegate], so no other spawned agent can delegate at all) and session-analyst (the ONLY agent that resumes sessions by session_id). A test pins that "only one" claim, so a future agent gaining tool-delegate fails rather than silently losing the routing. tasks.yaml references the SAME core file, not the full list: tool-task is a delegation-shaped tool, so the imperative applies, and one shared file makes drift between the two behaviors impossible. It gets no depth -- tool-task exposes neither context_depth/context_scope nor session resumption. Real foundation-root session, project-scope source override (~/.amplifier/cache untouched): raw.system 130,055 -> 106,655 chars (-23,400); provider-reported input 52,741 -> 47,014 tokens (-5,727). Wave Discipline / Context Sink Pattern / Reading a Structured Agent Return / Multi-Agent Patterns all ABSENT from the root prompt, core PRESENT, and every depth @mention resolves from both agent bodies. That -5,727 is the SECONDARY metric. The primary one -- task success and delegation-count sanity -- is unmeasured, and the split could plausibly suppress legitimate delegation OR cause over-delegation. Hence held. BREAKING for external references: context/agents/delegation-instructions.md no longer exists. All in-repo references updated. Tests: 33 new in tests/test_behavior_context_budget.py (12 fail on main). Suite 2,064 passed, 3 skipped; the 2 failures are pre-existing and reproduce on a0decc6 (test_sources.py::test_resolve_existing_file, test_grpc_adapter_main.py::test_non_isinstance_object_with_mount_passes). Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…at the $10 authority Terminal outcome: RESOLVED AT THE CAP (goal branch B). A and C are DONE and ship in this PR. B's code half is DONE and measured on #369; B's eval is NOT-POSSIBLE at $10 -- 12 valid runs / 0.67 observed validity = 18 launches x blended $4.08 = $73.44, priced before spending, $0 spent on it, design not shrunk and relabelled. Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…ystem instruction (A) + pin the tool-skills double-mount semantics (C) (#368) * fix(bundle): foundation's ROOT body was 499 chars of documentation prose, sent as system instruction (A) Everything below a bundle's frontmatter is the system instruction whenever that bundle is composed as the ROOT (docs/BUNDLE_GUIDE.md: "Everything below the frontmatter is sent to the model as system instruction. It is not documentation, and it is not free."). Root bundle.md carried a "# Foundation Bundle v2.0" title, a feature table and an MCP config sample below the frontmatter -- so every foundation-root session opened its system prompt with product documentation rather than with common-system-base. This is the same defect class as the notify-README body fixed by app-cli #315/#316. Measured with the validator FIXED in aaa5c47 (whose extractor previously returned an empty string that satisfied every check): main a0decc6 : verdict FLAG, prose_chars 499 "This bundle provides the standard Amplifier foundation with the enhanced delegate tool for agent orchestration.\n| Feature | ..." this branch : verdict OK, prose_chars 0 "body carries no prose (mentions/scaffolding only)" repo-wide : 1 prose_below_frontmatter WARNING -> 0, over 32 files checked Real session, foundation as ROOT (project-scope source override; ~/.amplifier/cache untouched), raw.system[0].text head: before (5dfe9c07, 130,055 chars): "# Foundation Bundle v2.0\n\nThis bundle provides the standard Amplifier foundation... | Feature | Description |..." after (268a6e56, 129,178 chars): "@foundation:context/shared/common-system-base.md \n\n---\n\n<context_file ...># Primary Core Instructions\n\nYou are Amplifier..." The prose is not deleted -- it moves into the frontmatter `description:`, which is manifest metadata and is never sent to the model. The body is now the single @mention it should always have been. (C) tool-skills is mounted twice -- behaviors/agents.yaml (foundation's own skills dir) and bundle.md:33 via amplifier-bundle-skills' skills.yaml. Measured first, per the goal: NOTHING IS DROPPED. merge_module_lists collapses the two declarations by module id and deep_merge concatenates list-typed config, so both skills sources survive in both compose orders; a real foundation-root session lists all three foundation skills alongside the curated collection. That is a finding, not a bug -- so no code changed. But it is safe only because of the list-concat rule added in 70d521f (#120), which is invisible at both declaration sites and fails SILENTLY if it regresses. tests/test_tool_skills_double_mount.py pins it: disabling list-concat fails 2 of its 7 tests; restored, 7 pass. Suite: 2038 passed, 3 skipped, 2 failed -- both failures reproduce unchanged on a0decc6 with these changes stashed (test_sources.py::test_resolve_existing_file, test_grpc_adapter_main.py::test_non_isinstance_object_with_mount_passes). Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * docs(8rug): lane DONE-NOTE -- A and C shipped, B's eval NOT-POSSIBLE at the $10 authority Terminal outcome: RESOLVED AT THE CAP (goal branch B). A and C are DONE and ship in this PR. B's code half is DONE and measured on #369; B's eval is NOT-POSSIBLE at $10 -- 12 valid runs / 0.67 observed validity = 18 launches x blended $4.08 = $73.44, priced before spending, $0 spent on it, design not shrunk and relabelled. Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --------- Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Manager verification — NO-SHIP confirmed. This PR stays draft. The root-prompt split is not shipping.Gates re-run by me against head The rule, applied verbatim
NO-SHIP follows mechanically. 14 launches, 14 valid (100%). The caveat matters as much as the verdict, and the lane leads with itCondition 1 fails on interval width, not on a measured regression — the point estimate is 0.0 pp, and the condition is arithmetically unsatisfiable below n What it actually found — the mechanism, which is the deliverable
Delegation happens on turn 1 only, on the anthropic cell, in every run of both arms; turns 2-5 delegate zero times in both. Arm A spawns two explorers in parallel sharing one Gates I verified independently
Two harness defects it found that are worth more than this PR
Both live in the evals repo, which this lane does not own. Reported, not fixed. Filed for follow-up. Two things reported against interestThe lane flagged a goal-authoring ambiguity I introduced: its $20.62 driving session is not netted against the $80 authority, because the authority's arithmetic is And it names the blocker for merging this PR as-is even if the eval had passed: it deletes DispositionDraft, unmerged. The split is real work with a measured -23,365-char root-prompt win, and it does not ship, because the gate it was pre-registered against says so. Priced next steps, unbought: condition 1 needs n>=73/arm ( |
…nded exactly on its own ERROR boundary (v3.14.0) (#371) * fix(recipes): the context-token estimator understated by 6.28x and landed exactly on its own ERROR boundary (v3.14.0) Extracted from the HELD #369 (lane 8rug, delegation-context split). That PR is NO-SHIP -- its pre-registered eval failed (delegation ratio 0.667 on the anthropic cell, outside +/-30%) -- but its branch carried this independent, separable win. This PR is ONLY the estimator. `git diff --name-only` is quoted in the PR body so the exclusion is visible rather than asserted. THE DEFECT. `validate-bundle-repo`'s behavior-hygiene Rule 4 resolved a `context.include` only two ways: a leading "@" was charged a flat 500 tokens, anything else was tried as a relative path. A `<namespace>:<path>` include -- `foundation:context/agents/delegation-instructions.md`, the form this repo's own behaviors use -- matches NEITHER: no leading "@", and neither `behaviors/foundation:context/...` nor `<repo>/foundation:context/...` exists. It fell through to the flat 500-token default. behaviors/agents.yaml carries two such includes. 2 x 500 = EXACTLY 1000, against a `> 1000` ERROR gate. So 6,276 real on-disk tokens were reported as 1000 and graded WARNING -- one token under the ERROR that was true. A 6.28x understatement landing precisely on its own boundary, in the instrument that was supposed to catch it. THE FIX (v3.14.0). Strip an optional "@" and, for a `<namespace>:<path>` ref, also try the path half against the behavior directory and the repo root. When the file is in THIS repo, read it. When it genuinely is not, keep the 500 fallback -- but record the include in `context_unresolved_includes` and set `context_tokens_is_estimate`. A guess folded silently into a number that reads as measured is the defect; the fallback itself is not. THE RULER, NAMED. The unit stays `len(content) // 4` (chars/4) so the recipe stays dependency-free. Calibrated against tiktoken 0.12.0 and footnoted in the recipe: on this repo's context markdown (n=31 files >=1500 bytes) chars/4 / o200k_base has median 1.128, range 0.940-1.312 -- it runs HIGH on prose, the conservative direction for a budget gate (fires early, never late). On the two files that motivated this: chars/4 6,276 vs o200k_base 5,402 (+16.2%), cl100k_base 5,466. FAIL-BEFORE / PASS-AFTER, on a real repo file as the known-token fixture (`context/agents/session-storage-knowledge.md`, 9,961 bytes; chars/4 2,490 vs o200k_base 2,648 = -6.0%, inside +/-10%; the flat 500 is -81.1% on the same file): tests/test_context_include_estimator.py is 6 failed / 2 passed against the v3.13.0 recipe and 8 passed against v3.14.0. The tests EXECUTE the recipe's own step body rather than re-implementing it -- a re-implementation agrees with itself while the recipe drifts, which is the failure mode under investigation. RECIPE RE-RUN on foundation main, $0.00 (deterministic step body, no LLM): BEFORE v3.13.0 agents ~1000 WARNING | tasks ~1000 WARNING | 0 errors AFTER v3.14.0 agents ~6276 ERROR | tasks ~6276 ERROR | 2 errors plus a third, previously invisible finding: foundation-expert ~566 (was a silent flat 500). Those two ERRORs are the defect being surfaced, not introduced -- the 6,276 tokens were already in every foundation-root system prompt. The fix that clears them is the split held in #369. Checked, not assumed: `grep -rn "validate-bundle-repo" .github/ Makefile*` returns nothing, so this does not red CI. Suite: 2,046 passed, 3 skipped, 2 failed. Both failures are pre-existing and were re-confirmed on a detached worktree at origin/main on this host (test_sources.py::test_resolve_existing_file, test_grpc_adapter_main.py::test_non_isinstance_object_with_mount_passes). ruff check + format clean. No runtime code touched -- recipe YAML and tests only, so there is no system-prompt byte-identity surface to compare. Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * docs(j05m): lane DONE-NOTE and evidence index for the estimator extraction Records the $0.00 spend against a $0.00 authority, the hunk-level extraction method and its mechanical exclusion check, the chars/4 <-> o200k_base calibration with its honest repo-wide spread, the fail-before/pass-after counts, the three consequences of the recipe re-run, and the `gh pr edit` projects-classic trap that silently no-ops on this repo. Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * docs(j05m): commit the publication readback for the lane marker Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --------- Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Decisive run complete — NO-SHIP. This PR stays draft.
The deciding number is the opus delegation ratio, 0.4737. The split is not worse — it is better on quality and cost, and it still does not shipCOND1 fails on interval width, not on a measured regression: the point estimate is +12.25 pp in the split's favour. What kills it is COND2, and specifically what happens on Anthropic. Mechanism (pre-registered secondary, never gating): opus arm A spawns 1.9 per delegating turn, arm B 1.125, and bursts are identical to per-turn — every Anthropic pair is dispatched in ONE parallel tool-call batch, and the split collapses that pair to a single spawn. Terra delegates sequentially, which is exactly why the two providers move in opposite directions. The pre-registration is what makes this verdict binding
Had that choice been made after seeing the data, either answer would have looked defensible. That is the whole reason it was frozen first. I recomputed the deciding number independentlyFrom Two findings worth more than this PRn=73 WAS NEVER SUFFICIENT. An arm-dependent instrument defect, found and fixed mid-run. The session writer flushes a turn's Scope limit, declared before any runArm A is the merge-base $227.29 of authority deliberately unspent, per a stop-decision committed before the runs it stops: going from n=51 to n=68 moves COND1's LB from about −13 pp to −12 pp against a −5 pp floor. It buys nothing for the gate. |
Current disposition
The evaluation was funded and completed; the delegation-context split failed its recorded acceptance gates. This PR remains draft and must not be described as awaiting evaluation funding. The independent estimator correction already merged in #371; the eight-file evidence report is #370. The user decision on closing this rejected experiment versus retaining it for further research is pending. No rejected behavior has shipped through this PR.
The original proposal and preregistration context below are retained as historical evidence.
Original body (written when the eval was unfunded) — kept verbatim
The defect
behaviors/agents.yamlandbehaviors/tasks.yamleachcontext.includeddelegation-instructions.md+multi-agent-patterns.md— 6,276 tokens (len//4) / 5,402 (o200k_base), measured on disk — into the root system prompt of every foundation-root session.The validator reported 1,000 and graded it a WARNING.
recipes/validate-bundle-repo.yamlbehavior-hygiene Rule 4 resolved acontext.includetwo ways: a leading@was charged a flat 500 tokens; anything else was tried as a relative path.foundation:context/agents/delegation-instructions.mdmatches neither — no leading@, and neitherbehaviors/foundation:context/...nor<repo>/foundation:context/...exists — so it fell through to the 500-token default.Two includes × 500 = exactly 1000, against a
> 1000ERROR gate. 6,276 real tokens reported as 1000 and graded WARNING — one token below the ERROR that was true. A 6.28× understatement that landed precisely on its own boundary.Fail-before / pass-after
The honest fail-before requires the fixed estimator — same shape as
aaa5c47, which made (A)'s fail-before trustworthy.The estimator repair (
validate-bundle-repov3.14.0)Strips an optional
@and, for a<namespace>:<path>ref, also tries the path half against the behavior directory and the repo root. When the file is in this repo, read it. When it genuinely is not, keep the 500 fallback — but record the include incontext_unresolved_includesand setcontext_tokens_is_estimate. An unknown folded silently into a number that reads as measured is the defect; the fallback itself is fine as long as it is visible.The split
len//4context/agents/delegation-core.md(new)context/agents/delegation-depth.md(renamed)context/agents/multi-agent-patterns.mdCore = the delegation imperative, the immediate triggers, basic
delegateusage, the two context parameters — the root session is the delegator and needs these. Depth = session resumption, wave discipline, reading a structured return, scrutinising an agent's "N/A", large session-file handling, and the context-sink pattern itself — which is precisely the material that pattern says to defer.Which agents get depth, and why
foundation-experttool-delegate. The behavior setsexclude_tools: [tool-delegate], so no other spawned agent can delegate at all — it is the only sub-agent that ever fans out. Getsdelegation-depth.mdandmulti-agent-patterns.md.session-analystsession_idand reads large session files — the two depth sections written for exactly that. Getsdelegation-depth.md.test_the_only_agent_declaring_tool_delegate_is_the_one_we_routed_depth_topins the "only one" claim, so a future agent gainingtool-delegatefails a test rather than silently losing the routing.tasks.yaml— references the same core, does not drop contexttool-taskis a delegation-shaped tool (it spawns sub-agents), so the imperative and the triggers apply to it; and pointing both behaviors at one file makes drift between them impossible. It gets no depth:tool-taskexposes neithercontext_depth/context_scopenor session resumption.Real-session effect — foundation as ROOT
Project-scope
.amplifier/settings.yamlsource override.~/.amplifier/cachewas not edited.Depth stays reachable:
Why this is HELD — the eval could not be bought
Pre-registered before any file was edited, in its own commit
07d51b9:Design: S3-class scenarios, foundation root, arms
mainvs branch, n≥3 valid runs per arm per provider, both providers (anthropic opus-5 root; openai gpt-5.6-terra root), in DTUs. Primary = task success + delegation-count sanity; secondary = root-prompt tokens and $/task.Priced against the $10 authority using this program's own observed rates and its 67 % observed validity rate:
The arithmetic does not close, by 4×–7×. At the cheapest observed rate ($2.62/run) $10 buys 3 launches ⇒ ~2 valid runs — n=1 per arm on one provider. n=1 cannot produce a lower bound on success, so it cannot evaluate the rule's first condition, and one delegation count per arm cannot support a ±30 % comparison: a 0 % chance of satisfying the pre-registered rule. Spending it would be the exact failure mode the goal names against lane
1ru.$0 was spent on the eval. The authority that would close it is $73.44 ($48.96 at perfect validity).
−5,727 root-prompt tokens is the SECONDARY metric. The primary one is unmeasured, and the split could plausibly fail in either direction — suppressing legitimate delegation, or removing the wave discipline that told the root to batch. That is why the gate is two-sided, and why this stays a draft.
Recorded in advance so it cannot read as an excuse later:
otr's pre-registered gate came back UNEVALUABLE because delegation counts at its cell were[0,0,1,0,0]. If arm-A S3 runs here median 0 delegations, the ±30 % condition is likewise unevaluable, and the honest report is "unevaluable" — not a substitute gate invented after the fact.⚠ Breaking for external references
context/agents/delegation-instructions.mdno longer exists — it isdelegation-depth.md. Any bundle outside this repo that@-mentions the old path will stop resolving. All in-repo references were updated.Tests
tests/test_behavior_context_budget.py— 33 tests, 12 of which fail onmain. They measure the real files from disk, so the budget cannot be satisfied by an estimator's blind spot.Both failures are pre-existing and reproduce on
a0decc6:tests/test_sources.py::TestFileSourceHandler::test_resolve_existing_filetests/test_grpc_adapter_main.py::TestVerifyModuleType::test_non_isinstance_object_with_mount_passesSpend
$0 on the eval (not bought — see above). $0.20 total on three
amplifier run "hi"haikusessions for the real-session measurements. No DTUs created; 0 ledger rows opened.Generated with Amplifier
Co-Authored-By: Amplifier 240397093+microsoft-amplifier@users.noreply.github.com