26 KiB
Auto-Next Obligation Gate Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Enforce that an approved plan may not stop at a task boundary when the current task is complete and the next task is already known, unless the closure is explicitly waiting_user, blocked, pending_verification, or a separately-declared high-risk stop point; otherwise the flow must auto-dispatch the next task and any stop is a continuity failure.
Architecture: Extend the current approved-plan continuity gate from a passive “missing dispatch receipt” detector into an obligation gate that evaluates task-boundary stops as first-class failures. Keep the design minimal: preserve the current receipt-based truth model, add explicit stop-intent / high-risk-stop metadata, fail first in tests, then wire the hook path so dry-run planner intent is no longer enough when the next task is deterministically known. Design the slices so the same evaluator can later be extracted into the continuity plugin MVP without changing the behavior contract.
Tech Stack: Node.js ESM scripts, TypeScript hook integration, JSON input/output envelopes, file-backed dispatch receipts, script-level tests, continuity plugin MVP compatibility layer
Context Baseline
The current repo already has a partial continuity hard gate:
scripts/approved_plan_continuity_gate.mjs- fails only when
taskState=complete+ next action known + no validdispatchReceipt+ closure not in legal terminal states
- fails only when
scripts/approved_plan_dispatch_binding.mjs- writes receipt files once a dispatch is actually bound
hooks/force-recall/handler.ts- builds continuity input from wrapper/planner state and injects the continuity block
scripts/test_approved_plan_continuity_gate.mjs- already covers missing receipt, fake receipt, valid receipt, and legal terminal states
docs/plans/2026-04-24-continuity-plugin-mvp.md- already assumes this continuity behavior will later be extracted into a plugin
The remaining gap is narrower and more specific:
- The current gate says “don’t close if a known next action exists but no real receipt exists.”
- But it does not yet model the stronger obligation: if the next task in the same approved plan is already known and not blocked by an allowed stop condition, the system must auto-next dispatch instead of pausing at the boundary.
- This means the failure is not only “missing receipt,” but also “stopped at a task boundary when auto-next was obligatory.”
- We need a minimal extension that preserves existing receipt truth, avoids speculative dispatch, and remains compatible with continuity-plugin extraction.
Target Behavior Contract
When all of the following are true:
- current workflow is inside the same approved plan
- current task is complete
- the next task is known / derivable as a concrete next task
- closure state is not
waiting_user,blocked, orpending_verification - no explicit high-risk stop point is active
Then:
- the system must not stop at the task boundary
- the execution layer must auto-dispatch the next task
- a real dispatch receipt must exist for the next task handoff
- otherwise the reply/hook path must produce a continuity failure
When any of the following are true, auto-next is not obligatory:
- closure state is
waiting_user - closure state is
blocked - closure state is
pending_verification - an explicit high-risk stop point is active
- no next task is known
- current task is not complete
- plan scope is absent or ambiguous
Required New Concepts
To keep the design minimal, introduce only the following new concepts:
nextTaskKnown: boolean or derivable fact that the next task in the same approved plan is knownsameApprovedPlan: boolean proving the next task belongs to the same approved plan, not merely a generic next actiontaskBoundaryStop: boolean indicating the system is trying to end the current reply at a completed-task boundary instead of dispatching onwardhighRiskStop: boolean indicating an allowed explicit stop point outside the normal legal closure statesautoNextObligatory: derived evaluator result when auto-next must happen nowreason=missing_auto_next_dispatch(or equivalent canonical reason) for the new failure mode
Do not widen this into a generalized workflow engine or arbitrary planner ontology in this slice.
Current Gap
- current continuity gate checks a known next action, but it does not specifically require that the next task is the next task in the same approved plan
- current hook can surface planner-derived action from dry-run planning, but planner intent is not a real dispatch and does not prove continuity actually happened
- current dispatch binding writes receipts once dispatch is actually bound, but the gate does not yet express "must auto-dispatch now" as its own obligation at the task boundary
- current legal terminal states are hard-coded and do not include explicit
highRiskStopmetadata
Non-goals
- generalized multi-plan scheduling
- speculative dispatch when the next task is ambiguous
- removing current receipt validation
- implementing continuity-plugin extraction in this slice
Canonical Task-Boundary Stop Scenario
This is the scenario the implementation must lock down:
- Approved plan has ordered tasks, e.g. Task 8 -> Task 9.
- Task 8 just completed.
- Task 9 is already known from the same approved plan.
- The agent emits a normal closeout / handoff / “next I can continue with Task 9” style response.
- No real auto-dispatch receipt exists for Task 9.
- Closure is not
waiting_user,blocked,pending_verification. - No high-risk stop point is active.
Expected outcome:
- continuity gate fails
- hook output explicitly forbids stopping at this task boundary
- system must route to auto-next dispatch path or continuity failure path
- dry-run planner intent alone does not satisfy the obligation
Task 1: Capture the auto-next obligation contract in docs first
Files:
- Create:
docs/runbooks/auto-next-obligation-gate.md - Read:
docs/runbooks/approved-plan-continuity.md - Read:
docs/plans/2026-04-24-approved-plan-continuity-hard-gate.md - Read:
docs/plans/2026-04-24-continuity-plugin-mvp.md
Step 1: Write the behavior contract only Document, in exact terms:
- when auto-next is obligatory
- legal non-auto-next closures:
waiting_userblockedpending_verification
- allowed non-closure exception:
- explicit
highRiskStop
- explicit
- forbidden behavior:
- completed task + known next task + same approved plan + normal closeout without dispatch
Step 2: Add a single canonical failure table Include rows for:
- complete + next task known + no receipt + completed closure => FAIL
- complete + next task known + valid receipt => PASS
- complete + next task known + waiting_user => PASS
- complete + next task known + blocked => PASS
- complete + next task known + pending_verification => PASS
- complete + next task known + highRiskStop => PASS
Step 3: Verify the file exists and key phrases are present Run:
grep -n "auto-next\|highRiskStop\|waiting_user\|pending_verification\|same approved plan" docs/runbooks/auto-next-obligation-gate.md
Expected: matching lines found
Step 4: Commit
git add docs/runbooks/auto-next-obligation-gate.md
git commit -m "docs: define auto-next obligation gate contract"
Task 2: Record the exact continuity / hook / dispatch gap before code changes
Files:
- Modify:
docs/plans/2026-04-24-auto-next-obligation-gate.md - Read:
scripts/approved_plan_continuity_gate.mjs - Read:
scripts/approved_plan_dispatch_binding.mjs - Read:
hooks/force-recall/handler.ts - Read:
scripts/test_approved_plan_continuity_gate.mjs
Step 1: Add a “Current Gap” section with exact bullets Capture these facts:
- current continuity gate checks known next action, not specifically same-plan next task
- current hook can surface planner-derived action but dry-run planner intent is not real dispatch
- current dispatch binding writes receipts, but the gate does not yet express “must auto-dispatch now” as its own obligation
- current legal terminal states are hard-coded and do not include high-risk stop metadata
Step 2: Add a “Non-goals” section Explicitly exclude:
- generalized multi-plan scheduling
- speculative dispatch when next task is ambiguous
- removing current receipt validation
- implementing plugin extraction in this slice
Step 3: Verify plan text now contains both sections Run:
grep -n "Current Gap\|Non-goals" docs/plans/2026-04-24-auto-next-obligation-gate.md
Expected: matching lines found
Step 4: Commit
git add docs/plans/2026-04-24-auto-next-obligation-gate.md
git commit -m "docs: capture current auto-next continuity gap"
Task 3: Add fail-first test for the core task-boundary stop scenario
Files:
- Modify:
scripts/test_approved_plan_continuity_gate.mjs - Test:
scripts/approved_plan_continuity_gate.mjs
Step 1: Write one failing test case for the exact forbidden stop Add a case with input shaped like:
{
"planId": "plan-auto-next-core",
"currentTask": "task-8",
"taskState": "complete",
"nextTaskKnown": true,
"sameApprovedPlan": true,
"taskBoundaryStop": true,
"nextDerivedAction": {
"type": "message_subagent",
"task": "continue with task-9"
},
"replyClosureState": "completed",
"highRiskStop": false,
"dispatchReceipt": null
}
Expected assertion:
ok === falseverdict === 'continuity_failure'reason === 'missing_auto_next_dispatch'(or the canonical reason you choose for this feature)
Step 2: Run the test suite to verify failure Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: FAIL because the new failure mode does not exist yet
Step 3: Commit the failing test only
git add scripts/test_approved_plan_continuity_gate.mjs
git commit -m "test: fail when approved plan stops at task boundary without auto-next dispatch"
Task 4: Add fail-first test proving dry-run planner intent is still not enough
Files:
- Modify:
scripts/test_approved_plan_continuity_gate.mjs - Read:
hooks/force-recall/handler.ts
Step 1: Add a second failing test Case:
taskState='complete'nextTaskKnown=truesameApprovedPlan=truetaskBoundaryStop=truederivedActionexistsdispatchReceipt=nullreplyClosureState='completed'highRiskStop=false
Expected:
- still FAIL
- still same continuity failure reason
This locks the rule that planner-derived next intent is not itself a pass.
Step 2: Run tests to verify failure Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: FAIL
Step 3: Commit
git add scripts/test_approved_plan_continuity_gate.mjs
git commit -m "test: fail auto-next obligation when only dry-run derived action exists"
Task 5: Add pass-path test for explicit high-risk stop
Files:
- Modify:
scripts/test_approved_plan_continuity_gate.mjs - Test:
scripts/approved_plan_continuity_gate.mjs
Step 1: Add a pass test Case:
- task complete
- next task known
- same approved plan
- task boundary stop true
- no dispatch receipt
- closure state
completed highRiskStop=true
Expected:
ok === trueverdict === 'pass'
Step 2: Run tests to verify it fails before implementation Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: FAIL until evaluator understands highRiskStop
Step 3: Commit
git add scripts/test_approved_plan_continuity_gate.mjs
git commit -m "test: allow explicit high-risk stop to bypass auto-next obligation"
Task 6: Add neutral-path tests so the gate stays minimal
Files:
- Modify:
scripts/test_approved_plan_continuity_gate.mjs
Step 1: Add a pass test for ambiguous next task Case:
taskState='complete'nextTaskKnown=falsesameApprovedPlan=truetaskBoundaryStop=true- no dispatch receipt
- closure state
completed
Expected:
- PASS, because auto-next is not obligatory when the next task is not known
Step 2: Add a pass test for different-plan / unknown-plan next action Case:
- next action exists
sameApprovedPlan=false- no receipt
- closure state
completed
Expected:
- PASS or falls back to old behavior only if no same-plan next-task obligation is active
Step 3: Run tests to verify current behavior does not satisfy them yet Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: FAIL or mixed results; note exact mismatch in implementation comments if needed
Step 4: Commit
git add scripts/test_approved_plan_continuity_gate.mjs
git commit -m "test: add neutral auto-next obligation coverage for unknown or out-of-plan next task"
Task 7: Extend the continuity gate with minimal obligation logic
Files:
- Modify:
scripts/approved_plan_continuity_gate.mjs - Modify:
scripts/test_approved_plan_continuity_gate.mjs
Step 1: Add the smallest possible derived booleans Implement helpers like:
const taskComplete = payload?.taskState === 'complete';
const nextAction = payload?.nextDerivedAction ?? payload?.derivedAction ?? null;
const nextTaskKnown = payload?.nextTaskKnown === true;
const sameApprovedPlan = payload?.sameApprovedPlan === true;
const taskBoundaryStop = payload?.taskBoundaryStop === true;
const highRiskStop = payload?.highRiskStop === true;
const hasDispatchReceipt = hasValidDispatchReceipt(payload?.dispatchReceipt ?? null);
const closureState = payload?.replyClosureState ?? null;
const isLegalTerminalState = LEGAL_TERMINAL_STATES.has(closureState);
const autoNextObligatory = taskComplete && nextTaskKnown && sameApprovedPlan && taskBoundaryStop && !isLegalTerminalState && !highRiskStop;
Step 2: Add the new failure rule before the generic pass path Minimal rule:
- if
autoNextObligatoryand no valid dispatch receipt exists => fail with:ok: falsestatus: 'continuity_failure'verdict: 'continuity_failure'reason: 'missing_auto_next_dispatch'
Keep the existing generic receipt failure behavior for legacy cases that are not strict same-plan task-boundary obligation cases, unless tests prove it should collapse into the new reason.
Step 3: Run the continuity gate tests Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: PASS for all old and new cases
Step 4: Commit
git add scripts/approved_plan_continuity_gate.mjs scripts/test_approved_plan_continuity_gate.mjs
git commit -m "feat: enforce auto-next obligation at approved plan task boundaries"
Task 8: Add dispatch-binding test that the next task receipt is mandatory proof
Files:
- Modify:
scripts/test_approved_plan_continuity_gate.mjs - Modify:
scripts/test_force_recall_long_task_preflight.mjs - Read:
scripts/approved_plan_dispatch_binding.mjs
Step 1: Add a test that a receipt with wrong task linkage does not satisfy auto-next Case:
- current task is
task-8 - next task known is
task-9 - receipt exists but links to stale or mismatched action/task context
Expected:
- FAIL
- reason remains an auto-next continuity failure
If current receipt schema lacks enough linkage to assert this exactly, capture that as an explicit schema gap in comments and lock at least plan/task equality on currently available fields.
Step 2: Add a preflight hook assertion Expected hook output should still fail when planner says the next task is known but no real bound receipt for that next dispatch exists.
Step 3: Run both suites Run:
node scripts/test_approved_plan_continuity_gate.mjs
node scripts/test_force_recall_long_task_preflight.mjs
Expected: FAIL before hook/input wiring lands, or PASS only for the script-level side if hook has not been updated yet
Step 4: Commit
git add scripts/test_approved_plan_continuity_gate.mjs scripts/test_force_recall_long_task_preflight.mjs
git commit -m "test: require real next-task dispatch proof for auto-next obligation"
Task 9: Add explicit hook input fields for task-boundary obligation
Files:
- Modify:
hooks/force-recall/handler.ts - Read:
scripts/plan_long_task_auto_chain.mjs - Read:
scripts/approved_plan_continuity_gate.mjs
Step 1: Add a focused builder for auto-next obligation fields
Extend buildApprovedPlanContinuityInput(...) or equivalent with fields shaped like:
{
nextTaskKnown,
sameApprovedPlan,
taskBoundaryStop,
highRiskStop
}
Derive them conservatively:
nextTaskKnown=trueonly when the next task is explicit from the approved-plan/auto-chain resultsameApprovedPlan=trueonly when the next task belongs to the same approved plan, not merely a generic follow-uptaskBoundaryStop=trueonly when the current reply is closing out at a completed-task boundary rather than continuing in-flighthighRiskStop=trueonly when some upstream gate explicitly marks the stop as high-risk / owner-confirm-required
Do not infer these loosely from free-form text.
Step 2: Preserve current legal closure fallback behavior Keep:
waiting_userfor button-path handoffcompletedas normal fallback
But ensure those defaults do not accidentally mask auto-next obligation cases.
Step 3: Syntax-check the hook file Run:
node --check hooks/force-recall/handler.ts
Expected: PASS
Step 4: Commit
git add hooks/force-recall/handler.ts
git commit -m "feat: feed auto-next obligation metadata into continuity hook input"
Task 10: Upgrade hook messaging so the failure is explicit
Files:
- Modify:
hooks/force-recall/handler.ts - Modify:
scripts/test_force_recall_long_task_preflight.mjs
Step 1: Add fail-first assertion for the new reason in hook output Expect the injected block to include something equivalent to:
reason=missing_auto_next_dispatch- “Do not stop at this completed-task boundary.”
- “Auto-dispatch the next task in the same approved plan, unless waiting_user / blocked / pending_verification / high-risk stop applies.”
Step 2: Implement the smallest wording update In the continuity block builder, add a branch for the new reason so the prompt block distinguishes:
- generic missing dispatch receipt
- auto-next obligation failure at a task boundary
Step 3: Run hook smoke tests Run:
node scripts/test_force_recall_long_task_preflight.mjs
Expected: PASS
Step 4: Commit
git add hooks/force-recall/handler.ts scripts/test_force_recall_long_task_preflight.mjs
git commit -m "feat: surface explicit auto-next obligation failure in force-recall hook"
Task 11: Add minimal receipt-linkage hardening only if required by tests
Files:
- Modify:
scripts/approved_plan_dispatch_binding.mjs - Modify:
scripts/test_approved_plan_continuity_gate.mjs - Modify:
docs/runbooks/approved-plan-continuity.md - Modify:
docs/runbooks/auto-next-obligation-gate.md
Step 1: Only if needed, add one additional linkage field If the new tests cannot reliably distinguish “some dispatch happened” from “the required next task was dispatched,” add only one minimal extra receipt field such as:
nextTaskIdornextTaskKey
Do not redesign the whole receipt schema.
Step 2: Add fail-first + pass-path tests for that field
- stale/missing linkage => FAIL
- correct linkage => PASS
Step 3: Re-run targeted tests Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: PASS
Step 4: Commit
git add scripts/approved_plan_dispatch_binding.mjs scripts/test_approved_plan_continuity_gate.mjs docs/runbooks/approved-plan-continuity.md docs/runbooks/auto-next-obligation-gate.md
git commit -m "feat: harden dispatch receipt linkage for auto-next obligation"
Task 12: Add continuity-plugin MVP compatibility notes before extraction
Files:
- Modify:
docs/plans/2026-04-24-auto-next-obligation-gate.md - Modify:
docs/plans/2026-04-24-continuity-plugin-mvp.md - Read:
plugins/continuity/if present, otherwise keep as future note only
Step 1: Add an explicit “Plugin MVP Compatibility” section Document these compatibility constraints:
- auto-next obligation must remain a pure evaluator rule, not hook-only string logic
- high-risk stop must become a config/input flag, not a prompt convention
- same-plan next-task proof must be representable in plugin evaluator input
- receipt validation and receipt storage remain separable from evaluator logic
- legacy script envelopes must remain bridgeable during extraction
Step 2: Add the expected plugin module seams List future homes:
- evaluator rule ->
plugins/continuity/src/continuity/evaluator.mjs - receipt linkage validation ->
plugins/continuity/src/continuity/receipt-validator.mjs - hook wording ->
plugins/continuity/src/adapters/force-recall.mjs
Step 3: Verify both plan docs mention highRiskStop and auto-next
Run:
grep -n "highRiskStop\|auto-next" docs/plans/2026-04-24-auto-next-obligation-gate.md docs/plans/2026-04-24-continuity-plugin-mvp.md
Expected: matching lines found
Step 4: Commit
git add docs/plans/2026-04-24-auto-next-obligation-gate.md docs/plans/2026-04-24-continuity-plugin-mvp.md
git commit -m "docs: capture continuity plugin compatibility for auto-next obligation"
Task 13: Run the focused verification bundle
Files:
- Verify:
scripts/approved_plan_continuity_gate.mjs - Verify:
scripts/test_approved_plan_continuity_gate.mjs - Verify:
scripts/test_force_recall_long_task_preflight.mjs - Verify:
hooks/force-recall/handler.ts
Step 1: Run continuity gate suite Run:
node scripts/test_approved_plan_continuity_gate.mjs
Expected: PASS
Step 2: Run hook smoke suite Run:
node scripts/test_force_recall_long_task_preflight.mjs
Expected: PASS
Step 3: Run syntax check Run:
node --check hooks/force-recall/handler.ts
node --check scripts/approved_plan_continuity_gate.mjs
node --check scripts/approved_plan_dispatch_binding.mjs
Expected: PASS
Step 4: Record exact verification output in the plan tail Include:
- exact commands
- PASS summary
- any deliberately deferred cases
Step 5: Commit
git add docs/plans/2026-04-24-auto-next-obligation-gate.md
git commit -m "chore: verify auto-next obligation gate slice"
Task 14: Final acceptance checklist and handoff state
Files:
- Modify:
docs/plans/2026-04-24-auto-next-obligation-gate.md
Step 1: Add the acceptance checklist Mark the plan acceptable only when all items are true:
- completed-task boundary stop without auto-next now fails
- dry-run planner intent alone does not satisfy continuity
- legal closure states still pass
- explicit high-risk stop passes
- same-plan next-task obligation is distinguished from generic next-action wording
- hook output surfaces the new failure clearly
- plugin extraction compatibility is documented
- tests pass
Step 2: Add explicit remaining risks Include at least:
- current hook may still need better upstream proof for
sameApprovedPlan - high-risk stop source of truth may not yet exist and may need one future metadata slice
- receipt schema may need exactly one extra linkage field if stale receipts can spoof pass conditions
- non-
force-recallentry points remain out of scope for this slice
Step 3: Leave status as pending verification Do not mark implementation complete in the plan; leave it as a verified-ready handoff target.
Step 4: Commit
git add docs/plans/2026-04-24-auto-next-obligation-gate.md
git commit -m "docs: finalize auto-next obligation gate implementation plan"
Minimal Enforcement Design Summary
The enforcement should stay intentionally small:
-
Keep receipt truth model
- a real dispatch receipt remains the pass proof
- planner intent alone is not proof
-
Add one stronger evaluator branch
- when the next task in the same approved plan is known and the current reply is stopping at a completed-task boundary, auto-next becomes obligatory
- missing receipt in this branch is a dedicated continuity failure
-
Allow only narrow exemptions
waiting_userblockedpending_verificationhighRiskStop=true
-
Keep hook integration thin
- hook computes structured booleans
- evaluator makes the decision
- hook renders the reason-specific block
-
Preserve plugin extraction path
- no hook-only business logic
- no receipt-store / evaluator coupling
- no prompt-only policy with no machine-checkable input
Acceptance Criteria
- A completed task in the same approved plan cannot stop at a boundary when the next task is known unless an allowed exemption applies.
- The continuity evaluator emits a dedicated failure for missing required auto-next dispatch.
- A real dispatch receipt is still required; dry-run planner output alone cannot pass.
- Legal closure states
waiting_user,blocked,pending_verificationstill pass unchanged. - Explicit
highRiskStopbypass is supported and test-covered. - Hook output clearly explains the auto-next obligation failure.
- Script-level continuity tests pass.
- Hook smoke tests pass.
- The plan documents how this behavior migrates cleanly into the continuity plugin MVP.
Risks / Open Questions
- The current hook may not yet expose a strong enough source of truth for
sameApprovedPlan; if so, one narrow upstream metadata field may be needed. highRiskStopmay not currently exist in structured input, so the first implementation may need a conservative default offalseuntil an upstream gate can set it explicitly.- If current receipt shape cannot prove the required next-task linkage, one minimal receipt field should be added instead of broad schema redesign.
- This slice deliberately does not solve non-hook entry points or general workflow orchestration.
Plan complete and saved to docs/plans/2026-04-24-auto-next-obligation-gate.md. Two execution options:
1. Subagent-Driven (this session) - I dispatch fresh subagent per task, review between tasks, fast iteration
2. Parallel Session (separate) - Open new session with executing-plans, batch execution with checkpoints
Which approach?
If Subagent-Driven chosen:
- REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- Stay in this session
- Fresh subagent per task + code review
If Parallel Session chosen:
- Guide them to open new session in worktree
- REQUIRED SUB-SKILL: New session uses superpowers:executing-plans