Files
reporting-governance-plugin/docs/plans/2026-04-24-auto-next-obligation-gate.md

26 KiB
Raw Blame History

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 valid dispatchReceipt + closure not in legal terminal states
  • 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:

  1. The current gate says “dont close if a known next action exists but no real receipt exists.”
  2. 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.
  3. This means the failure is not only “missing receipt,” but also “stopped at a task boundary when auto-next was obligatory.”
  4. 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, or pending_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 known
  • sameApprovedPlan: boolean proving the next task belongs to the same approved plan, not merely a generic next action
  • taskBoundaryStop: boolean indicating the system is trying to end the current reply at a completed-task boundary instead of dispatching onward
  • highRiskStop: boolean indicating an allowed explicit stop point outside the normal legal closure states
  • autoNextObligatory: derived evaluator result when auto-next must happen now
  • reason=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 highRiskStop metadata

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:

  1. Approved plan has ordered tasks, e.g. Task 8 -> Task 9.
  2. Task 8 just completed.
  3. Task 9 is already known from the same approved plan.
  4. The agent emits a normal closeout / handoff / “next I can continue with Task 9” style response.
  5. No real auto-dispatch receipt exists for Task 9.
  6. Closure is not waiting_user, blocked, pending_verification.
  7. 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_user
    • blocked
    • pending_verification
  • allowed non-closure exception:
    • explicit highRiskStop
  • 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 === false
  • verdict === '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=true
  • sameApprovedPlan=true
  • taskBoundaryStop=true
  • derivedAction exists
  • dispatchReceipt=null
  • replyClosureState='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 === true
  • verdict === '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=false
  • sameApprovedPlan=true
  • taskBoundaryStop=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 autoNextObligatory and no valid dispatch receipt exists => fail with:
    • ok: false
    • status: '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=true only when the next task is explicit from the approved-plan/auto-chain result
  • sameApprovedPlan=true only when the next task belongs to the same approved plan, not merely a generic follow-up
  • taskBoundaryStop=true only when the current reply is closing out at a completed-task boundary rather than continuing in-flight
  • highRiskStop=true only 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_user for button-path handoff
  • completed as 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:

  • nextTaskId or
  • nextTaskKey

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-recall entry 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:

  1. Keep receipt truth model

    • a real dispatch receipt remains the pass proof
    • planner intent alone is not proof
  2. 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
  3. Allow only narrow exemptions

    • waiting_user
    • blocked
    • pending_verification
    • highRiskStop=true
  4. Keep hook integration thin

    • hook computes structured booleans
    • evaluator makes the decision
    • hook renders the reason-specific block
  5. 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_verification still pass unchanged.
  • Explicit highRiskStop bypass 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

  1. 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.
  2. highRiskStop may not currently exist in structured input, so the first implementation may need a conservative default of false until an upstream gate can set it explicitly.
  3. If current receipt shape cannot prove the required next-task linkage, one minimal receipt field should be added instead of broad schema redesign.
  4. 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