fix: resolve hook and directive commands through the launch seam - #1384
leandrodamascena merged 3 commits into
Conversation
Directive strings handed to the conductor hardcoded a
`bun <harness>/tools/aidlc-<tool>.ts` prefix. harnessDir() resolved WHICH
tree the tool lives in, but nothing resolved HOW to launch it: a native
install ships no `.ts` under the harness tree and requires no bun on
PATH, so every one of these commands was unrunnable there. The Stop hook
is the worst case - it blocks turn-end, so the conductor was told to
proceed and handed a command that cannot run.
Route all 14 sites through aidlcInvocation()/aidlcToolInvocation(), which
already resolve `aidlc engine <route>` on a compiled install and
`bun <harness>/tools/aidlc-<tool>.ts` on a copy install:
- core/hooks/aidlc-continue-workflow.ts - the Stop hook's next, continue,
park and report guidance
- core/tools/aidlc-orchestrate.ts - steering continue, claim/release,
knowledge, unpark, stale-cursor report, unit resume (4 sites), recompose
- core/tools/aidlc-state.ts - blocking-sensor override log and report
- core/tools/aidlc-utility.ts - plugin sync (2 sites), graph compile
t153 gains the matching guard. It accepted `bun ${harnessDir()}/tools/`
as "the seam", which is why this survived: the existing scan only rejects
a hardcoded harness-directory literal. The new guard reads the same
directive from the other side - any tree spelling, no bun launcher - and
covers the split-literal form (`run \`bun " + hd + "/tools/...`) that hid
from a line-oriented scan, with a negative control pinning both shapes.
t249 pinned the copy-channel spelling (`orchestrate.ts next`) of a command the hook now resolves per channel. The assertions read the same intent either way once they match the verb rather than the launcher: exactly one `next` steer, and no `continue` steer, whether the reason says `bun <harness>/tools/aidlc-orchestrate.ts next` or `aidlc engine orchestrate next`.
a05acb3 to
1ba9a3d
Compare
Use the dispatcher invocation helper for recompose and plugin sync so the commands emitted to the conductor retain their required engine namespace. Execute the emitted recomposition and doctor recovery commands in both copy and native installations. Exercise Stop recovery and steering through the compiled release binary without Bun on PATH for all seven harnesses, and register the added hook coverage.
leandrodamascena
left a comment
There was a problem hiding this comment.
Thanks, Taiki, for moving these commands onto the existing invocation helpers.
I reviewed the current head 9f1a1a1 against main 147a3cc. This restores the documented native-install contract without Bun and matches our agreed bug-fix scope.
I fixed the missing engine namespace in recomposition and both doctor plugin-sync remedies, and pushed 9f1a1a1. Regression tests execute the emitted commands in copy and native installations and cover native Stop recovery across all seven harnesses.
Required CI, security scans, Markdownlint, 52 native build gates, 60 Copilot tests, packaging determinism, typecheck, lint and coverage checks passed. No blocking findings remain. Validation used Linux; macOS/Windows and live-model journeys were not run. Automated AI review was skipped.
Proposed event: APPROVE.
Problem
Directive strings handed to the conductor hardcoded a
bun <harness>/tools/aidlc-<tool>.tsprefix.harnessDir()resolved WHICH tree the tool lives in, but nothing resolved HOW to launch it.A native install ships no
.tsunder the harness tree and requires no bun on PATH, so every one of these commands was unrunnable there. The Stop hook is the worst case: it blocks turn-end, so the conductor was told to proceed and handed a command that cannot run — a dead end.This also contradicts the framework's own onboarding text: "Framework hooks run through the self-contained aidlc binary. No separate script runtime or executable bits are required."
It was masked in development because a source checkout has both the
.tsprojection under.claude/tools/and bun on PATH.Fix
Route all 14 sites through
aidlcInvocation()/aidlcToolInvocation(), which already resolveaidlc engine <route>on a compiled install andbun <harness>/tools/aidlc-<tool>.tson a copy install. The surrounding code already used this seam — these sites simply did not go through it.core/hooks/aidlc-continue-workflow.tsnext,continue,park,reportguidance (5)core/tools/aidlc-orchestrate.tscontinue,claim/release,knowledge,unpark, stale-cursorreport,unit resume(×4),recompose(10)core/tools/aidlc-state.tslog decision/log answer,report(3)core/tools/aidlc-utility.tsplugin sync(×2),graph compile(3)Substitution is verified in both projections:
dist/claude→bun .claude/tools/aidlc.ts→bun .claude/tools/aidlc-orchestrate.ts nextdist-release/claude→aidlc→aidlc engine orchestrate nextWhy this survived
tests/unit/t153-engine-directive-harness-seam.test.tsinspects exactly this shape, but its regex only rejects a hardcoded harness-directory literal — its comment explicitly callsbun ${harnessDir()}/tools/"the seam", i.e. the correct form. Thebunlauncher was never in scope.t153 now guards both halves. The new check reads the same directive from the other side — any tree spelling, no bun launcher — and covers the split-literal form (
run \bun " + hd + "/tools/...`) that a line-oriented scan cannot see, with a negative control pinning both shapes so the scan cannot pass by matching nothing.t249pinned the copy-channel spelling of a command that is now channel-dependent; its assertions were changed to match the verb (exactly onenextsteer, nocontinuesteer) rather than the launcher.Verification
bun scripts/package.ts --check(determinism),bun run typecheck,bun run lint— clean--parallel 4t121-stop-hook-enforce(142 pass / 0 fail),t248-steering-content-delivery,t249-copilot-adapter(58 pass),t230-dispatcher-routes,t153(new guard)Remaining failures on the test machine were each reproduced on
mainat the same or worse rate, so none are attributable to this change:t37andt-e2e-isolated-runnerfail identically onmain;t326andt78are budget timeouts that are worse onmain(t326: 7 failing cases onmainvs 3 here;t78: 22 vs 3);t-tui-tmux-compatneedstmux, which is not installed.Reported by a user who hit the Stop hook dead end on a native install; the
loadDelegate/TOOLShalf of that report is already fixed by #1115.Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.