diff --git a/docs/plans/2026-04-24-continuity-plugin-mvp.md b/docs/plans/2026-04-24-continuity-plugin-mvp.md new file mode 100644 index 0000000..384f791 --- /dev/null +++ b/docs/plans/2026-04-24-continuity-plugin-mvp.md @@ -0,0 +1,1031 @@ +# Continuity Plugin MVP Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Extract the current approved-plan continuity hard-gate into an installable, configurable, testable OpenClaw plugin MVP with bilingual README guidance, example config, and smoke-test flow. + +**Architecture:** Keep the MVP small and adapter-first. Move continuity logic out of the current hard-coded scripts into a plugin package with four clear seams: config schema, continuity evaluator, receipt validator/storage helper, and hook adapter. Preserve current behavior first, then wrap it in plugin packaging, plugin docs, and plugin-level tests so the same continuity gate can be installed and configured without patching core workflow logic. + +**Tech Stack:** Node.js, ESM (`.mjs`/TypeScript where already present), file-backed JSON receipts, OpenClaw hook/plugin conventions, bilingual Markdown docs, script-level test runners. + +--- + +## Implementation Notes for the Engineer + +- Current behavior already exists in these files and should be treated as the extraction source of truth for MVP parity: + - `scripts/approved_plan_continuity_gate.mjs` + - `scripts/approved_plan_dispatch_binding.mjs` + - `scripts/test_approved_plan_continuity_gate.mjs` + - `hooks/force-recall/handler.ts` + - `docs/runbooks/approved-plan-continuity.md` + - `state/approved-plan-continuity/README.md` +- The workspace currently has an empty top-level `plugins/` directory, so the plan assumes creating a dedicated plugin package there instead of mixing plugin code back into `scripts/`. +- Do not widen scope into a generalized workflow engine. MVP means: preserve today’s continuity decision model, make it pluggable/configurable, document installation, and prove it with tests and a smoke path. +- Prefer pure functions for evaluator/validator pieces so they can be tested without spawning hooks. +- Treat current hard-gate scripts as compatibility fixtures during migration. Only remove or thin them after plugin parity is verified. + +## Proposed MVP Package Layout + +```text +plugins/continuity/ + README.md + README.zh-TW.md + package.json + HOOK.md + examples/ + openclaw.continuity.example.json + approved-plan-receipt.example.json + src/ + index.mjs + config/ + schema.mjs + defaults.mjs + continuity/ + evaluator.mjs + receipt-validator.mjs + receipt-store.mjs + types.md + adapters/ + force-recall.mjs + script-bridge.mjs + test/ + continuity.evaluator.test.mjs + continuity.receipt-validator.test.mjs + continuity.plugin.test.mjs + continuity.smoke.test.mjs +``` + +If the repo’s actual plugin loader requires a different manifest filename or entrypoint shape, adapt the filenames but keep the same responsibilities and test coverage. + +## Acceptance Target + +The MVP is acceptable only when all of the following are true: + +1. Continuity rules are configurable through a plugin config schema instead of only hard-coded constants. +2. The evaluator can be imported and tested as a standalone module. +3. Receipt validation is separated from gate decision logic. +4. A hook adapter can call the plugin and inject the same kind of hard-gate behavior now implemented in `hooks/force-recall/handler.ts`. +5. The plugin ships with bilingual install/apply documentation. +6. The repo contains example config and at least one repeatable smoke test command. +7. Existing current-script behavior is either preserved through bridge wrappers or explicitly mapped in the README migration section. + +--- + +### Task 1: Capture current continuity behavior as extraction baseline + +**Files:** +- Review: `scripts/approved_plan_continuity_gate.mjs` +- Review: `scripts/approved_plan_dispatch_binding.mjs` +- Review: `scripts/test_approved_plan_continuity_gate.mjs` +- Review: `hooks/force-recall/handler.ts` +- Review: `docs/runbooks/approved-plan-continuity.md` + +**Step 1: Create a baseline notes section in the plan worklog** +- Write down the exact current responsibilities: + - legal terminal states + - minimum dispatch receipt fields + - receipt filename convention + - how `force-recall` currently invokes continuity + - which behaviors are already covered by tests + +**Step 2: Verify nothing was guessed** +Run: +```bash +rg -n "waiting_user|blocked|pending_verification|dispatchReceipt|nextDerivedAction|approved_plan_continuity" \ + scripts/approved_plan_continuity_gate.mjs \ + scripts/approved_plan_dispatch_binding.mjs \ + scripts/test_approved_plan_continuity_gate.mjs \ + hooks/force-recall/handler.ts \ + docs/runbooks/approved-plan-continuity.md +``` +Expected: matching lines confirm all baseline rules come from checked-in files + +**Step 3: Commit baseline notes** +```bash +git add docs/plans/2026-04-24-continuity-plugin-mvp.md +git commit -m "docs: capture continuity plugin extraction baseline" +``` + +### Task 1 Baseline Worklog (captured 2026-04-24) + +#### Reviewed source-of-truth files +- `scripts/approved_plan_continuity_gate.mjs` +- `scripts/approved_plan_dispatch_binding.mjs` +- `scripts/test_approved_plan_continuity_gate.mjs` +- `scripts/test_force_recall_long_task_preflight.mjs` +- `hooks/force-recall/handler.ts` +- `docs/runbooks/approved-plan-continuity.md` + +#### Current responsibilities baseline +- `scripts/approved_plan_continuity_gate.mjs` + - Reads JSON input from `--input ` and emits one JSON envelope to stdout. + - Evaluates approved-plan continuity only when: + - `taskState === 'complete'` + - a next action is known via `nextDerivedAction ?? derivedAction` + - no valid `dispatchReceipt` is present + - `replyClosureState` is not one of the legal terminal states. + - Hard-coded legal terminal states today are exactly: + - `waiting_user` + - `blocked` + - `pending_verification` + - Current failure output is: + - `ok: false` + - `status: 'continuity_failure'` + - `verdict: 'continuity_failure'` + - `reason: 'missing_dispatch_receipt'` + - Current pass output is: + - `ok: true` + - `status: 'pass'` + - `verdict: 'pass'` + - Always stamps `gate: 'approved_plan_continuity'` in the response envelope. + - Current receipt validation inside the gate is intentionally narrow: it only requires `planId`, `currentTask`, object-shaped `nextDerivedAction`, and `dispatchedAt` to treat `dispatchReceipt` as valid. + +- `scripts/approved_plan_dispatch_binding.mjs` + - Reads JSON input from `--input ` and optional `--receipt-dir` override. + - Default receipt dir is `state/approved-plan-continuity` resolved from `process.cwd()`. + - Builds a receipt from: + - `planId` + - `currentTask` + - `nextDerivedAction ?? derivedAction` + - `dispatchedAt` + - `dispatchRunId` + - `childSessionKey` + - `replyClosureState` + - Validates presence of all seven fields above before writing. + - Adds filesystem-safety checks by slugifying `planId` and `dispatchRunId`; missing/unsafe values are reported as `planId_filesystem_safe` / `dispatchRunId_filesystem_safe`. + - On success writes `receipt--.json` under the receipt dir and returns: + - `ok: true` + - `status: 'receipt_written'` + - `binding: 'approved_plan_dispatch'` + - `receiptPath` + - `receipt` + - On validation failure returns: + - `ok: false` + - `status: 'missing_required_receipt_fields'` + - `binding: 'approved_plan_dispatch'` + - `missing: string[]` + - `receiptPath: null` + +- `hooks/force-recall/handler.ts` + - Runs continuity as a hook-time adapter, not a pure module yet. + - Continuity input is assembled by `buildApprovedPlanContinuityInput(wrapperResult, autoChainPlanResult)`. + - Hook mapping behavior today: + - source next action = `wrapperResult.nextDerivedAction ?? wrapperResult.derivedAction ?? plannerDerivedAction` + - `plannerDerivedAction` is synthesized from auto-chain planner output when `derivedAction !== 'none'` + - if no next action exists, continuity gate is skipped (`null`) + - `replyClosureState` defaults to: + - `wrapperResult.replyClosureState`, else + - `'waiting_user'` when `wrapperResult.handoff?.mode === 'button_path'`, else + - `'completed'` + - `dispatchReceipt` is passed through from `wrapperResult.dispatchReceipt ?? null` + - `taskState` defaults to `wrapperResult.taskState ?? (plannerDerivedAction ? 'complete' : null)` + - The hook executes `scripts/approved_plan_continuity_gate.mjs` via JSON-script indirection, then renders a prompt block. + +#### Minimal receipt contract baseline +- Receipt fields documented/runbook + dispatch binding currently agree on the following MVP minimum shape: + - `planId` + - `currentTask` + - `nextDerivedAction` + - `dispatchedAt` + - `dispatchRunId` + - `childSessionKey` + - `replyClosureState` +- Important parity note: the gate currently enforces only a smaller subset for pass/fail (`planId`, `currentTask`, object `nextDerivedAction`, `dispatchedAt`), while dispatch binding enforces the full seven-field receipt contract before persisting. +- Extraction must preserve this mismatch unless explicitly changed in a later task. + +#### Receipt filename / storage convention baseline +- Receipt directory default: `state/approved-plan-continuity` +- Receipt filename pattern: `receipt--.json` +- Safe segments are produced by lowercasing, trimming, replacing non `[a-z0-9._-]` runs with `-`, trimming edge dashes, and collapsing repeated dashes. + +#### Hook block shape baseline +- The continuity block currently injected by `hooks/force-recall/handler.ts` is: + +```text +[APPROVED_PLAN_CONTINUITY_GATE] +status= +verdict= +reason= +- HARD_GATE: Do not close out this reply as normal completion. +- HARD_GATE: Route back to continuity failure until a real next dispatch receipt exists, unless closure state is waiting_user, blocked, or pending_verification. +[/APPROVED_PLAN_CONTINUITY_GATE] +``` + +- `reason=` is only included when present. +- The two `HARD_GATE` lines are only added when `result.ok === false`. +- The block is omitted entirely when no continuity input can be constructed. + +#### Current input / output envelopes +- Continuity gate script envelope: + - input: JSON file path via `--input`; optional `--compact` + - output keys: `ok`, `status`, `verdict`, `reason?`, `gate`, `compact`, `inputPath`, `input` +- Dispatch binding script envelope: + - input: JSON file path via `--input`; optional `--receipt-dir`; optional `--compact` + - output keys on success: `ok`, `status`, `binding`, `compact`, `inputPath`, `receipt`, `receiptPath`, `input` + - output keys on failure: same envelope plus `missing`, with `receiptPath: null` + +#### Test coverage baseline already present +- `scripts/test_approved_plan_continuity_gate.mjs` covers: + - JSON envelope skeleton / gate label + - fail when `taskState=complete` + known next action + no valid dispatch receipt + non-legal closure + - fail when planner uses `derivedAction` without bound receipt + - fail when `dispatchReceipt` is fake non-null object without minimum fields + - pass when valid dispatch receipt exists + - pass when `derivedAction` has bound dispatch receipt + - pass for legal closure states `waiting_user`, `blocked`, `pending_verification` +- `scripts/test_force_recall_long_task_preflight.mjs` covers continuity integration in hook preflight: + - continuity block is emitted in pass-path plumbing + - dry-run auto-chain dispatch alone still yields `status=continuity_failure` + - hook block must surface `verdict=continuity_failure` and `reason=missing_dispatch_receipt` + - hook guidance must route back to continuity failure until a real receipt exists + +#### Known limitations / extraction constraints +- Continuity rules are hard-coded in scripts and hook glue; there is no plugin config surface yet. +- Hook integration shells out through script execution instead of importing a shared evaluator. +- Receipt validation logic is split: + - gate pass/fail uses a smaller inline validator + - receipt persistence uses a fuller required-field validator +- Current gate treats any object-shaped `nextDerivedAction` as sufficient inside a receipt; action schema is not validated further. +- Current gate does not read receipts from disk by convention; it only validates the in-memory `dispatchReceipt` payload passed into it. +- Hook-generated `plannerDerivedAction` is dry-run planner intent, not proof of real dispatch; continuity intentionally still fails until a real receipt is attached. + +### Task 2: Create plugin package skeleton + +**Files:** +- Create: `plugins/continuity/package.json` +- Create: `plugins/continuity/README.md` +- Create: `plugins/continuity/README.zh-TW.md` +- Create: `plugins/continuity/HOOK.md` +- Create: `plugins/continuity/src/index.mjs` + +**Step 1: Create the directory tree only** +Run: +```bash +mkdir -p plugins/continuity/src plugins/continuity/src/config plugins/continuity/src/continuity plugins/continuity/src/adapters plugins/continuity/examples plugins/continuity/test +``` +Expected: directories exist + +**Step 2: Add minimal package metadata and placeholder entrypoint** +- `package.json` should declare the plugin name, version, ESM type, and test script. +- `src/index.mjs` should export placeholders for: + - config schema/defaults + - evaluator + - receipt validator + - hook adapter factory + +**Step 3: Verify files exist** +Run: +```bash +test -f plugins/continuity/package.json \ + && test -f plugins/continuity/src/index.mjs \ + && test -f plugins/continuity/README.md \ + && test -f plugins/continuity/README.zh-TW.md \ + && echo OK +``` +Expected: `OK` + +**Step 4: Commit** +```bash +git add plugins/continuity +git commit -m "chore: add continuity plugin package skeleton" +``` + +### Task 3: Define plugin config schema contract + +**Files:** +- Create: `plugins/continuity/src/config/schema.mjs` +- Create: `plugins/continuity/src/config/defaults.mjs` +- Create: `plugins/continuity/examples/openclaw.continuity.example.json` +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` + +**Step 1: Write the config keys before implementation code** +Define exact keys for MVP, for example: +- `enabled` +- `planMatchers` +- `legalTerminalStates` +- `receiptDir` +- `requireRealDispatchReceipt` +- `allowReplyClosureWithoutDispatch` +- `debug` +- `adapter.forceRecall.enabled` +- `adapter.forceRecall.injectBlockLabel` + +**Step 2: Add schema/default exports** +- `schema.mjs` should export the allowed key list, required types, and validation helper contract. +- `defaults.mjs` should export a concrete defaults object aligned with today’s behavior. + +**Step 3: Add example config** +- Put a fully populated example JSON under `plugins/continuity/examples/openclaw.continuity.example.json`. + +**Step 4: Verify example config matches schema keys** +Run: +```bash +node -e "import('./plugins/continuity/src/config/defaults.mjs').then(m=>console.log(Object.keys(m.defaultConfig||m.defaults||{})))" +``` +Expected: prints the default key list without runtime error + +**Step 5: Commit** +```bash +git add plugins/continuity/src/config plugins/continuity/examples/openclaw.continuity.example.json plugins/continuity/README.md plugins/continuity/README.zh-TW.md +git commit -m "feat: define continuity plugin config schema and defaults" +``` + +### Task 4: Write failing tests for config validation + +**Files:** +- Create: `plugins/continuity/test/continuity.config.test.mjs` +- Test: `plugins/continuity/src/config/schema.mjs` + +**Step 1: Write fail-first tests for valid config** +Cover: +- accepts default config +- accepts custom receipt directory +- accepts custom legal terminal states list + +**Step 2: Write fail-first tests for invalid config** +Cover: +- rejects non-array `legalTerminalStates` +- rejects empty `receiptDir` +- rejects unknown terminal state type entries +- rejects disabled adapter object shape if malformed + +**Step 3: Run tests to verify failure** +Run: +```bash +node plugins/continuity/test/continuity.config.test.mjs +``` +Expected: FAIL because validator behavior is not fully implemented yet + +**Step 4: Commit** +```bash +git add plugins/continuity/test/continuity.config.test.mjs +git commit -m "test: add fail-first continuity plugin config validation tests" +``` + +### Task 5: Implement minimal config validator + +**Files:** +- Modify: `plugins/continuity/src/config/schema.mjs` +- Modify: `plugins/continuity/src/config/defaults.mjs` +- Modify: `plugins/continuity/test/continuity.config.test.mjs` + +**Step 1: Implement the smallest validator that passes the tests** +- Normalize missing fields from defaults. +- Reject malformed fields with explicit error codes/messages. +- Preserve current terminal states: `waiting_user`, `blocked`, `pending_verification`. + +**Step 2: Run tests** +Run: +```bash +node plugins/continuity/test/continuity.config.test.mjs +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add plugins/continuity/src/config/schema.mjs plugins/continuity/src/config/defaults.mjs plugins/continuity/test/continuity.config.test.mjs +git commit -m "feat: validate continuity plugin config" +``` + +### Task 6: Extract receipt validator contract + +**Files:** +- Create: `plugins/continuity/src/continuity/receipt-validator.mjs` +- Create: `plugins/continuity/src/continuity/types.md` +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` + +**Step 1: Document the receipt shape in one place** +Define these fields as the MVP minimum: +- `planId` +- `currentTask` +- `nextDerivedAction` +- `dispatchedAt` +- `dispatchRunId` +- `childSessionKey` +- `replyClosureState` + +**Step 2: Export validator API shape** +- `validateReceipt(receipt)` returns `{ ok, errors, normalizedReceipt }` +- `isValidReceipt(receipt)` returns boolean + +**Step 3: Verify file exists and exports load** +Run: +```bash +node -e "import('./plugins/continuity/src/continuity/receipt-validator.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))" +``` +Expected: export list includes validator functions + +**Step 4: Commit** +```bash +git add plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/src/continuity/types.md plugins/continuity/README.md plugins/continuity/README.zh-TW.md +git commit -m "chore: define continuity receipt validator contract" +``` + +### Task 7: Write failing tests for receipt validator + +**Files:** +- Create: `plugins/continuity/test/continuity.receipt-validator.test.mjs` +- Test: `plugins/continuity/src/continuity/receipt-validator.mjs` + +**Step 1: Write success-path tests** +Cover: +- valid receipt with all minimum fields passes +- filesystem-safe IDs are accepted + +**Step 2: Write failure-path tests** +Cover: +- missing `planId` +- missing `dispatchRunId` +- non-object `nextDerivedAction` +- empty `childSessionKey` +- fake non-null receipt object fails + +**Step 3: Run tests to verify failure** +Run: +```bash +node plugins/continuity/test/continuity.receipt-validator.test.mjs +``` +Expected: FAIL + +**Step 4: Commit** +```bash +git add plugins/continuity/test/continuity.receipt-validator.test.mjs +git commit -m "test: add fail-first continuity receipt validator tests" +``` + +### Task 8: Implement receipt validator + +**Files:** +- Modify: `plugins/continuity/src/continuity/receipt-validator.mjs` +- Modify: `plugins/continuity/test/continuity.receipt-validator.test.mjs` + +**Step 1: Implement field validation and normalization** +- Reuse current minimum field expectations from `scripts/approved_plan_dispatch_binding.mjs` and `scripts/approved_plan_continuity_gate.mjs`. +- Keep validation separate from file I/O. + +**Step 2: Run tests** +Run: +```bash +node plugins/continuity/test/continuity.receipt-validator.test.mjs +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/test/continuity.receipt-validator.test.mjs +git commit -m "feat: implement continuity receipt validator" +``` + +### Task 9: Extract receipt store helper + +**Files:** +- Create: `plugins/continuity/src/continuity/receipt-store.mjs` +- Modify: `plugins/continuity/examples/approved-plan-receipt.example.json` +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` + +**Step 1: Create the example receipt JSON** +- Add a real-looking valid receipt example matching the documented minimum shape. + +**Step 2: Implement file naming helpers only** +Export small functions for: +- slugifying `planId` +- slugifying `dispatchRunId` +- building `receipt--.json` +- resolving the receipt path from config + +**Step 3: Verify helper exports load** +Run: +```bash +node -e "import('./plugins/continuity/src/continuity/receipt-store.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))" +``` +Expected: helper export names print successfully + +**Step 4: Commit** +```bash +git add plugins/continuity/src/continuity/receipt-store.mjs plugins/continuity/examples/approved-plan-receipt.example.json plugins/continuity/README.md plugins/continuity/README.zh-TW.md +git commit -m "chore: add continuity receipt store helpers and examples" +``` + +### Task 10: Write failing tests for receipt store behavior + +**Files:** +- Create: `plugins/continuity/test/continuity.receipt-store.test.mjs` +- Test: `plugins/continuity/src/continuity/receipt-store.mjs` + +**Step 1: Write tests for path generation** +Cover: +- builds correct filename from safe IDs +- normalizes unsafe characters +- resolves receipt path inside configured receipt dir + +**Step 2: Write tests for write/read round-trip** +Cover: +- writes validated receipt JSON +- reads back same logical payload +- rejects invalid receipt before write + +**Step 3: Run tests to verify failure** +Run: +```bash +node plugins/continuity/test/continuity.receipt-store.test.mjs +``` +Expected: FAIL until read/write helpers exist + +**Step 4: Commit** +```bash +git add plugins/continuity/test/continuity.receipt-store.test.mjs +git commit -m "test: add fail-first continuity receipt store tests" +``` + +### Task 11: Implement receipt store helpers + +**Files:** +- Modify: `plugins/continuity/src/continuity/receipt-store.mjs` +- Modify: `plugins/continuity/test/continuity.receipt-store.test.mjs` + +**Step 1: Implement the minimum store API** +Export functions for: +- `buildReceiptFilename` +- `resolveReceiptPath` +- `writeReceipt` +- `readReceipt` + +**Step 2: Run tests** +Run: +```bash +node plugins/continuity/test/continuity.receipt-store.test.mjs +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add plugins/continuity/src/continuity/receipt-store.mjs plugins/continuity/test/continuity.receipt-store.test.mjs +git commit -m "feat: implement continuity receipt store helpers" +``` + +### Task 12: Extract continuity evaluator contract + +**Files:** +- Create: `plugins/continuity/src/continuity/evaluator.mjs` +- Modify: `plugins/continuity/src/index.mjs` +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` + +**Step 1: Define evaluator input/output shape** +Input should support: +- `taskState` +- `nextDerivedAction` +- `derivedAction` +- `replyClosureState` +- `dispatchReceipt` +- config override for legal terminal states + +Output should support: +- `ok` +- `status` +- `verdict` +- `reason` +- `gate` + +**Step 2: Stub the evaluator exports** +- `evaluateContinuity(payload, config)` +- `buildContinuityGateBlock(result, config)` + +**Step 3: Verify exports load** +Run: +```bash +node -e "import('./plugins/continuity/src/continuity/evaluator.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))" +``` +Expected: export list prints successfully + +**Step 4: Commit** +```bash +git add plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/src/index.mjs plugins/continuity/README.md plugins/continuity/README.zh-TW.md +git commit -m "chore: define continuity evaluator contract" +``` + +### Task 13: Write failing tests for continuity evaluator parity + +**Files:** +- Create: `plugins/continuity/test/continuity.evaluator.test.mjs` +- Test: `plugins/continuity/src/continuity/evaluator.mjs` +- Reference: `scripts/test_approved_plan_continuity_gate.mjs` + +**Step 1: Port the current continuity gate cases into plugin tests** +Cover at least: +- fail when task complete + next action known + no dispatch receipt + closure not legal +- fail when planner returns `derivedAction` without bound dispatch receipt +- fail when fake non-null receipt object is supplied +- pass when valid dispatch receipt exists +- pass when closure is `waiting_user` +- pass when closure is `blocked` +- pass when closure is `pending_verification` + +**Step 2: Add one plugin-specific config override case** +- custom legal terminal states list works + +**Step 3: Run tests to verify failure** +Run: +```bash +node plugins/continuity/test/continuity.evaluator.test.mjs +``` +Expected: FAIL + +**Step 4: Commit** +```bash +git add plugins/continuity/test/continuity.evaluator.test.mjs +git commit -m "test: add fail-first continuity evaluator parity tests" +``` + +### Task 14: Implement continuity evaluator + +**Files:** +- Modify: `plugins/continuity/src/continuity/evaluator.mjs` +- Modify: `plugins/continuity/src/continuity/receipt-validator.mjs` +- Modify: `plugins/continuity/test/continuity.evaluator.test.mjs` + +**Step 1: Implement the smallest evaluator that matches current behavior** +- Reuse receipt validator instead of inline checks. +- Preserve current failure reason: `missing_dispatch_receipt`. +- Preserve current legal closure state behavior. + +**Step 2: Run tests** +Run: +```bash +node plugins/continuity/test/continuity.evaluator.test.mjs +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/test/continuity.evaluator.test.mjs +git commit -m "feat: implement continuity evaluator" +``` + +### Task 15: Add script bridge for backward compatibility + +**Files:** +- Create: `plugins/continuity/src/adapters/script-bridge.mjs` +- Modify: `scripts/approved_plan_continuity_gate.mjs` +- Modify: `scripts/approved_plan_dispatch_binding.mjs` + +**Step 1: Write failing bridge tests first** +- The old scripts should still produce compatible JSON envelopes by delegating to plugin modules. + +**Step 2: Implement thin bridge wiring** +- Keep CLI parsing in scripts if easiest. +- Move decision logic to plugin modules. + +**Step 3: Run existing script tests** +Run: +```bash +node scripts/test_approved_plan_continuity_gate.mjs +``` +Expected: PASS with plugin-backed logic + +**Step 4: Commit** +```bash +git add plugins/continuity/src/adapters/script-bridge.mjs scripts/approved_plan_continuity_gate.mjs scripts/approved_plan_dispatch_binding.mjs +git commit -m "refactor: bridge legacy continuity scripts to plugin modules" +``` + +### Task 16: Extract hook adapter contract + +**Files:** +- Create: `plugins/continuity/src/adapters/force-recall.mjs` +- Modify: `plugins/continuity/HOOK.md` +- Modify: `plugins/continuity/src/index.mjs` + +**Step 1: Define hook adapter responsibilities** +The adapter should: +- accept hook context and plugin config +- build continuity input from hook state +- call the evaluator +- return a prompt block or structured gate result +- avoid duplicating evaluator rules + +**Step 2: Stub the factory export** +Export something like: +- `createForceRecallContinuityAdapter(config)` +- `runForceRecallContinuityAdapter(ctx, config)` + +**Step 3: Verify exports load** +Run: +```bash +node -e "import('./plugins/continuity/src/adapters/force-recall.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))" +``` +Expected: export names print successfully + +**Step 4: Commit** +```bash +git add plugins/continuity/src/adapters/force-recall.mjs plugins/continuity/HOOK.md plugins/continuity/src/index.mjs +git commit -m "chore: define force-recall continuity adapter contract" +``` + +### Task 17: Write failing tests for hook adapter + +**Files:** +- Create: `plugins/continuity/test/continuity.plugin.test.mjs` +- Test: `plugins/continuity/src/adapters/force-recall.mjs` +- Reference: `hooks/force-recall/handler.ts` + +**Step 1: Write success-path adapter tests** +Cover: +- returns no block when no approved-plan continuity context exists +- returns pass block when receipt is valid + +**Step 2: Write fail-path adapter tests** +Cover: +- returns hard-gate block when continuity fails +- includes expected gate label and reason +- honors config override for block label/debug mode + +**Step 3: Run tests to verify failure** +Run: +```bash +node plugins/continuity/test/continuity.plugin.test.mjs +``` +Expected: FAIL + +**Step 4: Commit** +```bash +git add plugins/continuity/test/continuity.plugin.test.mjs +git commit -m "test: add fail-first continuity hook adapter tests" +``` + +### Task 18: Implement hook adapter + +**Files:** +- Modify: `plugins/continuity/src/adapters/force-recall.mjs` +- Modify: `plugins/continuity/src/continuity/evaluator.mjs` +- Modify: `plugins/continuity/test/continuity.plugin.test.mjs` + +**Step 1: Implement adapter logic with minimal hook assumptions** +- Build gate input from hook payload. +- Delegate decisions to evaluator. +- Build the hard-gate block string in one place. + +**Step 2: Run tests** +Run: +```bash +node plugins/continuity/test/continuity.plugin.test.mjs +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add plugins/continuity/src/adapters/force-recall.mjs plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/test/continuity.plugin.test.mjs +git commit -m "feat: implement continuity force-recall adapter" +``` + +### Task 19: Wire `force-recall` hook to the plugin adapter + +**Files:** +- Modify: `hooks/force-recall/handler.ts` +- Test: `scripts/test_force_recall_long_task_preflight.mjs` +- Reference: `plugins/continuity/src/adapters/force-recall.mjs` + +**Step 1: Write the smallest integration change** +- Replace inline continuity-specific logic in `handler.ts` with plugin adapter invocation. +- Keep unrelated long-task governor behavior unchanged. + +**Step 2: Run targeted verification** +Run: +```bash +node scripts/test_approved_plan_continuity_gate.mjs +node scripts/test_force_recall_long_task_preflight.mjs +node --check hooks/force-recall/handler.ts +``` +Expected: PASS + +**Step 3: Commit** +```bash +git add hooks/force-recall/handler.ts +git commit -m "refactor: route force-recall continuity gate through plugin adapter" +``` + +### Task 20: Add plugin-level smoke test + +**Files:** +- Create: `plugins/continuity/test/continuity.smoke.test.mjs` +- Modify: `plugins/continuity/package.json` +- Modify: `plugins/continuity/examples/openclaw.continuity.example.json` + +**Step 1: Write a smoke test that exercises the public plugin path** +Smoke path should: +- load config +- validate config +- validate receipt +- evaluate a failing continuity payload +- evaluate a passing payload with valid receipt + +**Step 2: Run the smoke test** +Run: +```bash +node plugins/continuity/test/continuity.smoke.test.mjs +``` +Expected: PASS + +**Step 3: Expose a package script** +Add package script, for example: +```json +{ + "scripts": { + "test": "node test/continuity.config.test.mjs && node test/continuity.receipt-validator.test.mjs && node test/continuity.receipt-store.test.mjs && node test/continuity.evaluator.test.mjs && node test/continuity.plugin.test.mjs && node test/continuity.smoke.test.mjs" + } +} +``` + +**Step 4: Verify package test command** +Run: +```bash +cd plugins/continuity && npm test +``` +Expected: PASS + +**Step 5: Commit** +```bash +git add plugins/continuity/package.json plugins/continuity/test/continuity.smoke.test.mjs plugins/continuity/examples/openclaw.continuity.example.json +git commit -m "test: add continuity plugin smoke test and package test script" +``` + +### Task 21: Write bilingual README installation/apply instructions + +**Files:** +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` +- Reference: `plugins/continuity/HOOK.md` +- Reference: `plugins/continuity/examples/openclaw.continuity.example.json` + +**Step 1: Add English README sections** +Include: +- what problem the plugin solves +- MVP scope/non-goals +- install location and package layout +- config reference table/list +- example config snippet +- receipt format summary +- hook adapter usage +- smoke test command +- migration note from hard-coded scripts + +**Step 2: Add Traditional Chinese README sections with parity** +Include the same sections as the English README. + +**Step 3: Verify both READMEs mention the same critical commands** +Run: +```bash +rg -n "npm test|openclaw|receiptDir|waiting_user|pending_verification|blocked" plugins/continuity/README.md plugins/continuity/README.zh-TW.md +``` +Expected: both files contain the same core operational terms + +**Step 4: Commit** +```bash +git add plugins/continuity/README.md plugins/continuity/README.zh-TW.md plugins/continuity/HOOK.md +git commit -m "docs: add bilingual continuity plugin installation and usage guides" +``` + +### Task 22: Add example application note for root workspace config + +**Files:** +- Modify: `plugins/continuity/README.md` +- Modify: `plugins/continuity/README.zh-TW.md` +- Optional Create: `docs/runbooks/continuity-plugin-apply.md` + +**Step 1: Document how to apply the plugin in a real OpenClaw workspace** +Show a concrete example of: +- where the plugin folder lives +- how config points at `state/approved-plan-continuity` +- how `force-recall` should load/use the adapter + +**Step 2: Add a do-not-do list** +Explicitly warn against: +- changing core continuity rules during extraction +- using fake dispatch receipts for pass-through +- removing current scripts before parity tests pass + +**Step 3: Verify paths are exact** +Run: +```bash +test -d plugins/continuity && test -d state/approved-plan-continuity && test -f hooks/force-recall/handler.ts && echo OK +``` +Expected: `OK` + +**Step 4: Commit** +```bash +git add plugins/continuity/README.md plugins/continuity/README.zh-TW.md docs/runbooks/continuity-plugin-apply.md +git commit -m "docs: add continuity plugin apply guidance for workspace integration" +``` + +### Task 23: Run full verification suite + +**Files:** +- Test: `plugins/continuity/test/*.mjs` +- Test: `scripts/test_approved_plan_continuity_gate.mjs` +- Test: `scripts/test_force_recall_long_task_preflight.mjs` +- Check: `hooks/force-recall/handler.ts` + +**Step 1: Run plugin package tests** +Run: +```bash +cd plugins/continuity && npm test +``` +Expected: PASS + +**Step 2: Run compatibility tests from repo root** +Run: +```bash +node scripts/test_approved_plan_continuity_gate.mjs +node scripts/test_force_recall_long_task_preflight.mjs +node --check hooks/force-recall/handler.ts +``` +Expected: PASS + +**Step 3: Record exact verification results in the plan tail or PR notes** +- Copy exact commands +- Copy PASS summary counts +- Note any skipped tests + +**Step 4: Commit** +```bash +git add plugins/continuity hooks/force-recall/handler.ts scripts/approved_plan_continuity_gate.mjs scripts/approved_plan_dispatch_binding.mjs docs/plans/2026-04-24-continuity-plugin-mvp.md +git commit -m "chore: verify continuity plugin MVP end-to-end" +``` + +### Task 24: Final acceptance checklist and handoff + +**Files:** +- Modify: `docs/plans/2026-04-24-continuity-plugin-mvp.md` +- Review: `plugins/continuity/README.md` +- Review: `plugins/continuity/README.zh-TW.md` + +**Step 1: Add a checked acceptance checklist to the bottom of the plan** +Include: +- config schema implemented +- evaluator extracted +- receipt validator extracted +- hook adapter wired +- plugin-level tests passing +- bilingual README complete +- example config present +- smoke test present +- compatibility path preserved + +**Step 2: Mark remaining risks explicitly** +List at least: +- plugin loader assumptions may differ from current repo conventions +- current repo lacks an existing continuity plugin precedent +- future non-`force-recall` adapters are out of MVP scope + +**Step 3: Leave status as pending verification, not complete** +- Follow the workspace rule that implementation is not “done” until verified by the owner flow. + +**Step 4: Commit** +```bash +git add docs/plans/2026-04-24-continuity-plugin-mvp.md +git commit -m "docs: finalize continuity plugin MVP implementation plan" +``` + +--- + +## MVP Validation Checklist + +- [ ] `plugins/continuity/` package exists with entrypoint, docs, examples, and tests +- [ ] Config schema/defaults exist and are test-covered +- [ ] Receipt validator exists and is test-covered +- [ ] Receipt store helpers exist and are test-covered +- [ ] Continuity evaluator exists and matches current hard-gate behavior +- [ ] Legacy scripts bridge to plugin logic or are otherwise compatibility-covered +- [ ] `hooks/force-recall/handler.ts` consumes plugin adapter instead of continuity-specific inline logic +- [ ] English README explains install/config/test/migration +- [ ] Traditional Chinese README explains install/config/test/migration +- [ ] Example config and example receipt are checked in +- [ ] Smoke test passes +- [ ] Existing continuity and force-recall tests still pass + +## Risks / Open Questions + +1. The repo currently has an empty `plugins/` directory, so actual OpenClaw plugin manifest/loading conventions may need one discovery slice before implementation. +2. `hooks/force-recall/handler.ts` currently mixes several long-task concerns; extracting only continuity logic must avoid accidental behavior drift in unrelated gate-lock/auto-chain code. +3. Current script tests cover continuity decisions but not yet the full plugin install path, so smoke coverage is mandatory for MVP credibility. +4. The bilingual README must stay behaviorally aligned with actual example config and commands; drift here would make the plugin “documented” but not really adoptable. + +Plan complete and saved to `docs/plans/2026-04-24-continuity-plugin-mvp.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