⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
packages/loopover-engine/src/governor/chokepoint.ts's denyResult (lines 113-138, decision ternary at line 133) computes decision as input.stage === "kill_switch" ? "paused" : "deny" -- it keys off the stage label, not the ledger eventType. When the budget cap's termination ceiling fires (evaluateGovernorChokepoint's budget-cap stage, ~238-249), it passes stage: "budget_cap" with eventType: "kill_switch" (per budget-cap.ts:87-92's own comment: "termination... is the most severe (kill_switch)"). Because stage isn't literally "kill_switch", the ledger row gets decision: "deny" instead of "paused" -- the same eventType that the top-level kill-switch path correctly maps to "paused". The existing termination-ceiling test in test/chokepoint.test.ts only asserts eventType, never decision.
Requirements
Key the ternary in denyResult off eventType === "kill_switch" rather than stage === "kill_switch", so the ledger's decision field correctly reflects "paused" whenever the underlying event type is a kill-switch event, regardless of which stage triggered it.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
packages/loopover-engine/** -- 99%+ patch coverage, branch-counted, on the corrected ternary.
Expected Outcome
Any chokepoint stage whose event type is kill_switch records decision: "paused" in the governor ledger, consistent regardless of which specific gate triggered it.
Links & Resources
packages/loopover-engine/src/governor/chokepoint.ts:113-138,238-249
packages/loopover-engine/src/governor/budget-cap.ts:87-92
test/chokepoint.test.ts
Context
packages/loopover-engine/src/governor/chokepoint.ts'sdenyResult(lines 113-138, decision ternary at line 133) computesdecisionasinput.stage === "kill_switch" ? "paused" : "deny"-- it keys off the stage label, not the ledgereventType. When the budget cap's termination ceiling fires (evaluateGovernorChokepoint's budget-cap stage, ~238-249), it passesstage: "budget_cap"witheventType: "kill_switch"(perbudget-cap.ts:87-92's own comment: "termination... is the most severe (kill_switch)"). Because stage isn't literally"kill_switch", the ledger row getsdecision: "deny"instead of"paused"-- the sameeventTypethat the top-level kill-switch path correctly maps to"paused". The existing termination-ceiling test intest/chokepoint.test.tsonly assertseventType, neverdecision.Requirements
Key the ternary in
denyResultoffeventType === "kill_switch"rather thanstage === "kill_switch", so the ledger'sdecisionfield correctly reflects"paused"whenever the underlying event type is a kill-switch event, regardless of which stage triggered it.Deliverables
denyResult's decision ternary checkseventType, notstageledgerEvent.decision === "paused", not"deny"All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
packages/loopover-engine/**-- 99%+ patch coverage, branch-counted, on the corrected ternary.Expected Outcome
Any chokepoint stage whose event type is
kill_switchrecordsdecision: "paused"in the governor ledger, consistent regardless of which specific gate triggered it.Links & Resources
packages/loopover-engine/src/governor/chokepoint.ts:113-138,238-249packages/loopover-engine/src/governor/budget-cap.ts:87-92test/chokepoint.test.ts