1032 lines
37 KiB
Markdown
1032 lines
37 KiB
Markdown
# 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 <path>` 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 <path>` 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-<planIdSafe>-<dispatchRunIdSafe>.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-<planIdSafe>-<dispatchRunIdSafe>.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=<status>
|
||
verdict=<verdict>
|
||
reason=<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-<planId>-<dispatchRunId>.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
|