fix: route compiled gate-sensor dispatch through the engine namespace - #1166
Conversation
Native installs spawned `aidlc sensor fire ...`, which the dispatcher rejects (`unknown command 'sensor'`) because sensor is an engine-namespaced route. Blocking gate sensors therefore always failed closed; advisory failures were silently ignored. Spawn `aidlc engine sensor fire ...` like the sibling orchestrate dispatch does. Closes awslabs#1165 Signed-off-by: Vladimir Babin <vovababin@gmail.com>
wowzoo
left a comment
There was a problem hiding this comment.
Thank you for the fix and the regression test. The one-line routing change is what #1165 named, but the test is what keeps it fixed: it records the command the compiled dispatcher actually receives and asserts that gate sensors arrive as engine sensor fire, which is the thing that drifted silently.
Verified on this head
Base a0ee4415ec2b2d19f494b89348b6dfb2fdc77a49, head 6b52194399984602da22497dbf41175503f9bd7b.
- The defect is present on the current default branch (
09be7bddd35fd573f0bc7944af6bf6d8ea764198), not only on this pull request's base:core/tools/aidlc-state.ts:3040still spawns[executable, "sensor", ...args]. sensoris engine-namespaced —core/tools/aidlc.ts:708-716declares the route withnamespace: "engine"andvisibility: "hidden"— so the top-level form cannot resolve, and the message atcore/tools/aidlc.ts:1505is theerror: unknown command 'sensor'in the report. On a binary built from this head,aidlc sensor fire …prints exactly that, whileaidlc engine sensor fire …reaches the route and stops on the route's ownprojectRequirementrefusal — the namespace is the whole difference.- The prefix matches the convention already in the same file at
:2190and:2277, which spawn[executable, "engine", "orchestrate", ...subargs]. fireGateSensorsis the only dispatcher for gate sensors, and its three callers —gate-start, theapproverevision backstop, andrevise— all reach it, so the single line covers every path that fires them.
Control
Both arms on the current default branch, single-file runs, packager run before each:
| arm | result |
|---|---|
| your test applied, source unfixed | 14 pass / 1 fail — the only failure is the new case, at expect(result.status).toBe(0), because the blocking gate refuses |
| same tree with the one-line fix | 15 pass / 0 fail |
On the head tree: t311 10/10, t92 + t94 + t95 89/89, gen-coverage-registry 37/37, and bun run check (packager, --check, three tsc projects, biome) clean. Measured with bun 1.4.0 on macOS; CI runs ubuntu, so CI is what adjudicates the full suite.
Nothing to change
No other sensor-route dispatch is left behind, and every compiled dispatch in core/ that omits engine is correct to omit it. Taking all 17 compiledExecutable() call sites in core/ on this head: core/tools/aidlc-metrics.ts:403 passes the --internal-metrics-send flag, which the dispatcher handles at core/tools/aidlc.ts:2891; core/tools/aidlc-utility.ts:657 builds its args at :646-650 already starting with engine; core/tools/aidlc-utility.ts:1771 passes team-board, a public verb of the route at core/tools/aidlc.ts:213-232; the three in core/tools/aidlc-lifecycle.ts are package-manager detection rather than dispatch; and the rest already carry the prefix. No prose in core/, harness/, docs/ or the generated tree instructs aidlc sensor fire without the namespace.
Closes #1165 is accurate: that issue's Expected Behavior section asks for the aidlc engine sensor fire … invocation, and this delivers it. The advisory-severity ordering the report mentions in passing — the default_severity !== "blocking" check at core/tools/aidlc-state.ts:3052 running before result.error at :3061 and result.status at :3075 — is a separate behaviour this change does not alter, and not one to fold in here.
Status
CI is green on 6b521943 — all 21 checks pass, including the four unit shards, the integration and e2e suite, smoke, and the contract job (determinism, typecheck, lint). The pull request now reports clean. Approving.
* origin/main: fix: make compiled dispatch exhaustive over TOOLS so native review briefs route (#1070) (#1115) test: skip POSIX gate-sensor fixture on Windows (#1208) fix: make /aidlc compose scopes durable across an engine reinstall (#1159) fix: refuse orphaned positionals at intent-create instead of storing a truncated description (#1114) (#1195) fix: route compiled gate-sensor dispatch through the engine namespace (#1166) fix: name the accepted values in review-path refusals (#1082) (#1194) fix: discover stage-level summary questions when units are skipped (#1110) fix: keep a JSON-scalar gate reply instead of parsing it away (#1186) fix: resolve the zero-Unit code-generation location in the traceability sensor (#1179) fix(config): one quiet line for --show, and honest source options on a copy-channel refresh (#1185) test(t238): normalize walkFiles separators in the invocation-surface selector (#1184) fix(config): Kiro provides its own model access, so the provider section has nothing to ask (#1183) chore: prepare 2.9.0 release (#1181) feat!: classic scope v1 parity with scope-owned ceremony switches (#1151) fix: publish changed previews without a daily cap (#1178) fix: separate Bun copy and native installer runtimes (#1174) fix: publish next-patch previews nightly (#1169) fix: keep review bookkeeping out of the artifact, and out of the reviewer's findings (#1160) fix: measure the review budget against the engine's own ordinal, not the caller's (#1158)
Summary
Closes #1165. In native/compiled installs,
fireGateSensors()incore/tools/aidlc-state.tsspawnedaidlc sensor fire …, butsensoris an engine-namespaced route, so the dispatcher exits witherror: unknown command 'sensor'. Blocking gate sensors therefore always failed closed at the gate; advisory ones failed silently (the severity check happens beforeresult.error/result.statusare inspected).Changes
core/tools/aidlc-state.ts: the compiled branch now spawns[executable, "engine", "sensor", ...args], matching how the sibling orchestrate dispatch in the same file already spawns[executable, "engine", "orchestrate", ...]. Thebun(source) branch is unchanged.tests/integration/t311-gate-sensor-enforcement.test.ts: new case "compiled dispatch fires sensors through the engine namespace" — pointsAIDLC_COMPILED_EXECUTABLEat a stub that logs its argv and execs the real dispatcher, then asserts both fires arrive asengine sensor fire gate-probe …,SENSOR_FIREDis recorded twice, and the gate opens.User experience
Before: with a
fire_on: gate/default_severity: blockingsensor on a native 2.8.2 install,aidlc engine orchestrate report --result awaiting-approvalalways refuses the gate with a dispatcher error, and advisory gate sensors never actually run.After: gate sensors execute through
aidlc engine sensor fire …, record their verdict, and the gate proceeds or blocks according to that verdict.Checklist
Test plan
Run locally (bun 1.4.2, Linux):
bun scripts/package.ts && bun scripts/package.ts --check— deterministic across all harnesses.bun test tests/integration/t311-gate-sensor-enforcement.test.ts— 10 pass, 0 fail.dist/claudecopy, the new test fails (gateexits 1, dispatcher rejectssensor); with the fix restored it passes.bun test tests/unit/t94-sensor-fire-hook.test.ts tests/integration/t95-sensor-fire-hook-feature.test.ts— 40 pass.bun x biome check --error-on-warningson both touched files — clean;tsc --noEmit -p tsconfig.jsonand-p tsconfig.tests.json— clean.bun tests/run-tests.ts: 422 files, 10472 assertions, 1 failed assertion —t276-cursor-adaptercase 33 (expect(process.env.USER ?? process.env.LOGNAME).toBeTruthy()), which fails identically on a cleanmaincheckout in my shell because$USER/$LOGNAMEare unset there, and passes on this branch withUSERexported. Environment-only, outside this diff; 25 live-Claude files skipped as designed.No version / changelog changes per the release metadata policy.
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.