Director prompt hygiene: impossible tool refs, triple-stated report contract, dead no-ship branch, persona coupling - #582
Merged
TheGreatAxios merged 2 commits intoAug 24, 2026
Conversation
…ract, drop dead no-ship branch, structured evidence gate
- Removed hand-written "Report: Summary, Findings, Blockers, Paths" duplicates
from worker system prompts (build, bruckheimer, explore, gaasbot, plan,
neckbeard, greybeard, intern, shakespeare, tester, testsmith, critique,
emil) — the shared sub-agent report contract and each package's
report.requiredSections already state it.
- Removed "Do not spawn agents"/"Never spawn" duplicates from prompts whose
packages already declare spawn.maySpawn: false (build, neckbeard,
brand-reviewer, draper) — spawn is enforced structurally by not mounting
the task tool.
- Removed impossible tool references: tester/testsmith telling the model not
to use write_file/edit_file or write notes under tmp/ when those tools are
never mounted (READ_TOOLS); critique's "if shell is allowed" hedge when
run_shell is always in its tool set; emil's and draper's write-tool denial
explanations; gaasbot's write-tool disclaimer; plan's ask_operator mention
(never mounted on workers).
- Removed the dead no-ship branch: evaluateSubAgentStop never returned
"no-ship" (only evaluateThrashStop and the never-edited/never-acted paths
fire), so the nudge director's stop === "no-ship" branch was unreachable.
Dropped it from SubAgentStopReason and the nudge director's switch.
ForcedStopReason (a separate type used by forcedStopReport/brief-dispatch
salvage classification) is untouched.
- Replaced persona-string coupling: shouldRequireEvidence keyed off
systemPromptRole.includes("CritiqueDirector"); now keys off a structured
directorId threaded from task-tool's already-resolved director id.
- Added a registry test that cross-checks every director's prompt text
against its mounted tool set for the known tool names, so a future prompt
can't reference a tool it cannot call.
Collaborator
Author
|
Reviewed clean — holding the merge until immediately after the 0.2.106 tag, then this lands first in 0.2.107. Reason is sequencing, not quality. This rewrites prompt text across 13 directors, which materially affects the inference loop. The new four-tier eval suite (#577) has no baseline yet — the 0.2.106 run establishes it. If this merges first, the baseline silently includes the prompt churn and we lose the ability to measure whether it helped or hurt. Landing it into 0.2.107 means it gets measured against a clean baseline, which is the whole point of resetting the suite. Nothing to do on your side; I will merge it as soon as the tag is cut. |
TheGreatAxios
enabled auto-merge
August 24, 2026 04:13
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.
Closes CL-6807.
This is a hygiene-only pass on director prompts: removes what is wrong or duplicated, never anything load-bearing-but-advisory. Does not touch the skywalker coordination prose (4-worker cap, lane disjointness, re-fix caps, anti-cascade block — that removal is CL-6953, explicitly last in the chain). Does not touch worker style/philosophy guidance (CL-6803, human-gated).
Diff is prompt text plus a small amount of structural plumbing to remove a persona-string check — please read the wording, not just the mechanics.
Defects and status
1. Impossible/stale tool references — all present, all fixed
tester/testsmithmountREAD_TOOLSonly (no write tools), but were told "Do not write_file/edit_file product code" / could write "optional notes under tmp/". Removed both — replaced with plain statements that no product-mutation tools exist.Do not write_file/edit_file product code.→ after:you have no product-mutation tools, so there is no way to patch source to make green.Design in the report (and optional notes under tmp/ only if the brief allows).→ after:Design in the report.critiquemountsREVIEW_TOOLSwhich always includesrun_shell, but hedgedif shell is allowed.Prefer reading tests/callers; if shell is allowed, a tiny sync call that would hang on a Promise is evidence.→ after:Prefer reading tests/callers; a tiny sync call via run_shell that would hang on a Promise is evidence.emil/draper/gaasbotexplained at length that write tools are denied, when the tool set already makes that true by omission.Verify — inspect code, run existing tests/linters when practical. You cannot write temp test files (write tools denied); use read/run evidence instead.→ after:Verify — inspect code, run existing tests/linters when practical; use read/run evidence, not temp test files.Never write/edit/delete product files. Never spawn. Never commit.→ after:Never commit.Load philosophy when judgment trade-offs matter. Stay advice-only — no write_file/edit_file/delete_file.→ after:Load philosophy when judgment trade-offs matter. Stay advice-only.Do not apply fixes. Do not write, edit, or delete product files. Do not spawn agents.→ after:Do not apply fixes.(spawn ban covered below)planmountsREVIEW_TOOLS(noask_operator, ever) but hedged the tool as "available" sometimes.Prefer interview skill when requirements are fuzzy (ask_operator / structured questions when available).→ after:When requirements are fuzzy, note the open questions under Blockers instead of guessing — you cannot ask the operator mid-run.src/agent/directors/registry.test.tstest"no director prompt references a tool its tool set does not mount"that scans every director's prompt text for known tool-name tokens and fails if a mentioned tool isn't in that director's mounted set (or the small always-mounted/spawn-conditional allowances). Skywalker is excluded — it's the primary session's role text, not a filtered sub-agent.2. Triple-stated report contract — present, fixed
Every leaf's hand-written trailing line
Report: Summary, Findings (...), Blockers, Paths.was a third restatement on top of (a)report.requiredSections(structural) and (b) the sharedbuildSubAgentReportContract()envelope appended to every sub-agent prompt. Removed the hand-written line from build, bruckheimer, explore, gaasbot, plan, neckbeard, greybeard, intern, shakespeare, tester, testsmith, critique, and emil — kept any domain-specific hint (e.g. "risk/sequencing advice") as a short standaloneFindings: ...sentence where it added real information.Also removed the redundant
Never spawn./Do not spawn agents./Do not spawn sub-agents.lines from build, neckbeard, brand-reviewer, and draper — each already declaresspawn: { maySpawn: false }, which structurally means thetasktool is never mounted, and the shared sub-agent appendix already states the no-recursion rule in prose.Never commit.is kept where present — it isn't structurally enforced (these leaves keeprun_shell), so it's a real instruction, not a duplicate.Directors with real per-field report guidance (draper, brand-reviewer, emil's original "# Report" section) were left alone — that's domain content, not a restatement of the headings.
3. Dead no-ship branch — present, fixed
SubAgentDirector.decideinsrc/subagent/nudge-director.tsbranched onstop === "no-ship", butevaluateSubAgentStop(src/subagent/stop-policy.ts) never returns that value — onlyevaluateThrashStop(which only returns"report-forced"ornull) and the explicitnever-acted/never-edited/incomplete-report/turn-budget/no-progresspaths run. The branch was unreachable. Removed"no-ship"fromSubAgentStopReasonand from the nudge director's switch/checkpoint mapping. LeftForcedStopReason(a separate type used byforcedStopReportandbrief-dispatch.ts's salvage classification, which genuinely does produce/consume"no-ship"reports) untouched — those tests still pass unchanged.4. Persona-string coupling — present, fixed
shouldRequireEvidenceinsrc/subagent/run.tsarmed the empty-readCounts gate viasystemPromptRole.includes("CritiqueDirector")— a rename of the persona or its identity-header text would silently change enforcement. Threaded the already-resolved closed-director id (resolvedDirectorIdintask-tool.ts) throughRunSubAgentParams.directorIdand switched the gate todirectorId === "critique".Tests updated
src/agent/directors/registry.test.ts— new tool-reference cross-check test.src/subagent/index.test.ts—shouldRequireEvidencetests rewritten to assert ondirectorIdinstead of constructing/matchingsystemPromptRoletext; added a case for "no directorId resolved".package.test.tsneeded changes — they already assert againstreport.requiredSectionsandtools.allow, not the removed prose.Gate
bun run check(prettier --check, eslint, tsc --noEmit, build, full test suite) is green: 0 lint errors (1319 pre-existing warnings, untouched by this diff), typecheck clean, build succeeds, 5331 tests pass across 383 files.