Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ npx spec-superflow list # 或通过 npx 使用
| `ssf execution show <dir> [--json]` | 查看并校验当前执行计划、wave 与 receipt |
| `ssf execution revise <dir> ...` | 将已有计划保留/升级为 SDD,并生成新 revision;不允许降级 |
| `ssf execution review <dir> ...` | 为一个计划 wave 记录 review receipt |
| `ssf execution adjudicate <dir> ...` | 为 `adjudication-required` wave 授权一次 review |
| `ssf install-cursor` | 部署到 Cursor `.cursor/` 目录 |
| `ssf install-workbuddy` | 部署到 WorkBuddy marketplace 插件(含 skills/rules/runtime) |
| `ssf install-codebuddy` | 部署到 `~/.codebuddy/`(CodeBuddy Code CLI) |
Expand Down Expand Up @@ -245,6 +246,8 @@ ssf execution revise changes/my-change --mode sdd --confirm --reason "need paral
# 每个 wave 都先写入非空 review report,再记录 receipt。
ssf execution review changes/my-change --wave foundation --base <sha> --head <sha> \
--report .superpowers/sdd/reviews/foundation.md --verdict pass
ssf execution adjudicate changes/my-change --wave foundation --decision allow-review \
--confirm --reason "reviewed the unresolved findings and authorizes one focused review"
```

`--report` 相对于 `<change>` 解析,且必须位于
Expand All @@ -256,6 +259,8 @@ report 本身必须为普通、非空、非符号链接文件。
每个 wave 的 review receipt 必须是当前 revision 的 `pass`,依赖 wave 和 closing
才会放行;修订计划会使旧 receipt 失效。恢复、切换和手动保存是 control-plane
overlay,不会增加第九个状态;其 CLI 与 CodeBuddy/WorkBuddy Markdown adapter 保持相同 guard。
裁决不会生成 `pass` 或放行依赖;授权 review 若仍失败,wave 会再次进入
`adjudication-required` 并需要新的人工裁决。

---

Expand Down
48 changes: 48 additions & 0 deletions changes/add-adjudication-recovery/.spec-superflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# .spec-superflow.yaml — lightweight state machine
# Derived data. Always rebuildable from artifacts. Lost/corrupt → fall back to content-level detection.

# === Core state ===
state: executing
workflow: full
revision: 3

# === Hashes (fast staleness detection) ===
artifacts_hash: sha256:6de60171eab018a140f6d391b6a9d51771ea4af870c52982a7094016e3193d80
contract_hash: sha256:e096bbe1ab2911c969a3da9db7d121d231287c323e8742ac6546690349ccf2c1

# === Execution progress ===
execution_mode: sdd
execution_plan_hash: sha256:113acf81372a51ce75371fa5865b041e9a42bc03e99c8b881ba1ef34984b8234
execution_plan_revision: 3
batches_completed: 0
test_result: null
spec_merged: false
spec_publication_receipt: null

# === Metadata ===
change_name: add-adjudication-recovery
last_transition: 2026-08-12T15:42:46.151Z
last_transition_from: approved-for-build
last_transition_to: executing

# === Decision points ===
dp_0_decisions: change_name=add-adjudication-recovery; intent=add an auditable human adjudication recovery path for SDD waves after five failed reviews; constraints=preserve all failure evidence, never synthesize PASS, authorize exactly one continuous review, keep dependents blocked until PASS, no unrelated release changes; related_optimizations=stay focused; communication=draft artifacts for review; artifact_language=English; workflow_path=full, aligned with recommendation
dp_0_result: confirmed
dp_0_confirmed: true
dp_0_timestamp: 2026-08-12T15:15:00Z
dp_1_result: confirmed: root cause reproduced in v1.0.1; adjudication-required has no recovery command
dp_1_timestamp: 2026-08-12T15:35:00Z
dp_2_result: approved by explicit user request to fix Issue #108 and submit a PR: one-shot audited adjudication recovery, no synthesized pass or threshold change; blind-reader check passed
dp_2_timestamp: 2026-08-12T15:36:00Z
dp_3_result: approved by explicit user request to implement Issue #108 and submit a PR: three serial waves, TDD, one-shot current-plan authorization, no scope expansion
dp_3_timestamp: 2026-08-12T15:42:00Z
dp_4_result: sdd: plan revision 3; user-confirmed-revision; Refresh the one-wave plan after synchronizing its approved execution contract; behavior and scope are unchanged
dp_4_timestamp: 2026-08-12T15:42:46.353Z
dp_5_result: null
dp_5_timestamp: null
dp_5_decisions: null
dp_5_confirmed: null
dp_6_result: null
dp_6_timestamp: null
dp_7_result: null
dp_7_timestamp: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"mode": "sdd",
"source": "user-confirmed-revision",
"rationale": "Refresh the one-wave plan after synchronizing its approved execution contract; behavior and scope are unchanged",
"waves": [
{
"id": "adjudication-recovery",
"strategy": "serial",
"tasks": [
"1.1",
"2.1",
"2.2",
"3.1"
],
"depends_on": []
}
],
"artifacts_hash": "sha256:6de60171eab018a140f6d391b6a9d51771ea4af870c52982a7094016e3193d80",
"contract_hash": "sha256:e096bbe1ab2911c969a3da9db7d121d231287c323e8742ac6546690349ccf2c1",
"workflow": "full",
"revision": 3,
"recommendation": {
"available_modes": [
"inline",
"batch-inline",
"sdd"
],
"recommendation": {
"mode": "sdd",
"reasons": [
"The 4 tasks exceed the configured inline threshold of 3."
]
},
"facts": {
"workflow": "full",
"documented_task_count": 4,
"planned_task_count": 4,
"planned_wave_count": 1,
"has_parallel_wave": false,
"inline_threshold": 3
}
},
"recommendation_receipt": {
"recommendation": {
"available_modes": [
"inline",
"batch-inline",
"sdd"
],
"recommendation": {
"mode": "sdd",
"reasons": [
"The 4 tasks exceed the configured inline threshold of 3."
]
},
"facts": {
"workflow": "full",
"documented_task_count": 4,
"planned_task_count": 4,
"planned_wave_count": 1,
"has_parallel_wave": false,
"inline_threshold": 3
}
},
"waves": [
{
"id": "adjudication-recovery",
"strategy": "serial",
"tasks": [
"1.1",
"2.1",
"2.2",
"3.1"
],
"depends_on": []
}
],
"artifacts_hash": "sha256:6de60171eab018a140f6d391b6a9d51771ea4af870c52982a7094016e3193d80",
"contract_hash": "sha256:e096bbe1ab2911c969a3da9db7d121d231287c323e8742ac6546690349ccf2c1",
"workflow": "full",
"execution_plan_revision_at_recommendation": 2,
"created_at": "2026-08-12T15:42:46.257Z",
"hash": "sha256:181bf090274abf8e4873bc3f6562ddbb7dfa64c8fe0ea57d1431804338a848c8"
},
"selection": {
"confirmed": true,
"followed_recommendation": true,
"acknowledged_non_recommendation": false
},
"hash": "sha256:113acf81372a51ce75371fa5865b041e9a42bc03e99c8b881ba1ef34984b8234"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"recommendation": {
"available_modes": [
"inline",
"batch-inline",
"sdd"
],
"recommendation": {
"mode": "sdd",
"reasons": [
"The 4 tasks exceed the configured inline threshold of 3."
]
},
"facts": {
"workflow": "full",
"documented_task_count": 4,
"planned_task_count": 4,
"planned_wave_count": 1,
"has_parallel_wave": false,
"inline_threshold": 3
}
},
"waves": [
{
"id": "adjudication-recovery",
"strategy": "serial",
"tasks": [
"1.1",
"2.1",
"2.2",
"3.1"
],
"depends_on": []
}
],
"artifacts_hash": "sha256:6de60171eab018a140f6d391b6a9d51771ea4af870c52982a7094016e3193d80",
"contract_hash": "sha256:e096bbe1ab2911c969a3da9db7d121d231287c323e8742ac6546690349ccf2c1",
"workflow": "full",
"execution_plan_revision_at_recommendation": 2,
"created_at": "2026-08-12T15:42:46.257Z",
"hash": "sha256:181bf090274abf8e4873bc3f6562ddbb7dfa64c8fe0ea57d1431804338a848c8"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"status": "pass",
"base": "d3955fe891aa8d40de1e5721b7f79e9f9760659c",
"head": "ddd8b9f18ba50d4f98ac098fb44e95003c59869a",
"report": ".superpowers/sdd/reviews/adjudication-recovery.md",
"report_sha256": "sha256:ddd10a6910de5c30c03a750b017f779b062831518bf4252e7239ac9fb63253ba",
"plan_hash": "sha256:113acf81372a51ce75371fa5865b041e9a42bc03e99c8b881ba1ef34984b8234",
"plan_revision": 3,
"recorded_at": "2026-08-12T15:45:27.379Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"status": "pass",
"base": "d3955fe891aa8d40de1e5721b7f79e9f9760659c",
"head": "ddd8b9f18ba50d4f98ac098fb44e95003c59869a",
"report": ".superpowers/sdd/reviews/adjudication-recovery.md",
"report_sha256": "sha256:ddd10a6910de5c30c03a750b017f779b062831518bf4252e7239ac9fb63253ba",
"plan_hash": "sha256:113acf81372a51ce75371fa5865b041e9a42bc03e99c8b881ba1ef34984b8234",
"plan_revision": 3,
"recorded_at": "2026-08-12T15:45:27.379Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Adjudication recovery review

Verdict: PASS

Scope reviewed: `d3955fe891aa8d40de1e5721b7f79e9f9760659c..ddd8b9f` against the approved delta and execution contract.

Evidence:

- `node --test tests/lib/execution-plan.test.mjs tests/lib/cmd-execution.test.mjs`: 66 passed, 0 failed, 0 skipped.
- `npm run build`: passed.
- `npm_config_cache=/private/tmp/spec-superflow-npm-cache npm test`: 673 passed, 0 failed, 0 skipped.
- Strict change validation, doctor, and `git diff --check`: passed.
- The authorization is plan-scoped, bound to the exact failed receipt and repair identity, fail-closed on malformed evidence, and consumed after one review.
- A decision never synthesizes pass or releases dependents; failed authorized review requires a new adjudication.

Findings: no Critical, Important, or Minor findings.

Review constraint: this side conversation prohibits subagents, so the required independent reviewer could not be dispatched. The review was performed as a separate controller pass after implementation and full verification.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"schema_version": 2,
"available_modes": [
"full",
"hotfix",
"tweak",
"quick",
"lightweight"
],
"facts": {
"task_count": 4,
"file_count": 8,
"config_doc_only": "no",
"schema_api_change": "yes",
"new_module": "no",
"behavioral_constraint_change": "yes",
"cross_module_change": "yes",
"uncertainty": "low",
"request_kind": "standard",
"affected_paths": [
"scripts/lib/execution-plan.mjs",
"scripts/lib/cmd-execution.mjs",
"scripts/spec-superflow.mjs",
"tests/lib/execution-plan.test.mjs",
"tests/lib/cmd-execution.test.mjs"
],
"exclusion_checks": {
"production_behavior": "yes",
"public_boundary": "yes",
"installer": "no",
"state_machine": "yes",
"external_side_effect": "no",
"data_permission_config_semantics": "no",
"expected_behavior_clear": "yes",
"verification_reproducible": "yes",
"impact_paths_complete": "yes"
}
},
"missing_facts": [],
"status": "ready",
"recommendation": {
"mode": "full",
"reasons": [
"Risk signals require the user to choose Quick or Full."
],
"risk_reasons": [
"behavioral constraint changed (PRD, spec, design, data, or permission)",
"schema or API changes",
"cross-module change"
]
},
"created_at": "2026-08-12T15:11:46.829Z",
"selection": {
"mode": "full",
"reason": "User requested fixing Issue #108 and submitting a PR; state-machine and public CLI changes match the Full recommendation.",
"followed_recommendation": true,
"acknowledged_non_recommendation": false,
"accepted_automatically": false,
"risk_override": false,
"verification_strategy": null,
"scope_confirmation": null,
"verification_result": null,
"escalation_reason": null,
"confirmed_at": "2026-08-12T15:12:26.871Z",
"selected_at": "2026-08-12T15:12:26.871Z"
},
"hash": "sha256:2a4212e4804e56829877e2002d4bcc20ec6248bbef03cd218624ee574d63842c"
}
43 changes: 43 additions & 0 deletions changes/add-adjudication-recovery/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Adjudication recovery design

## Facts and Constraints

- `recordReview` currently refuses every review once plan-scoped repair state is `adjudication-required`, while no CLI command can persist the requested human decision.
- Review receipts, repair state, and execution work are isolated by plan hash and revision; adjudication evidence must preserve the same boundary.
- Existing continuity validation requires a repair review base to equal the previous review head, except for the established corrected-pass range behavior.
- The fix must preserve all failures, never synthesize `pass`, and add no runtime dependency.

## Goals and Non-goals

- **Goals**: provide an auditable explicit decision, authorize one review only, reject stale/replayed decisions, expose recovery status, and retain dependent-wave blocking until pass.
- **Non-goals**: alter the failure threshold, automatically decide for a human, reset failure counts, publish specs, or introduce a new core workflow state.

## Decisions

### Decision: Store a plan-scoped adjudication receipt

- **Choice**: add `plans/<plan-identity>/adjudications/<wave>.json`, bound to the current repair chain by plan identity, failure count, previous head, and previous report.
- **Rationale**: a separate immutable decision record preserves repair evidence and avoids making hand-edited repair state authoritative.
- **Alternatives**: mutate repair status to `repairing` or create a new plan revision. The former erases why the circuit opened; the latter discards the identity of the chain being adjudicated.
- **Consequences**: `execution show` gains an `adjudication` object and storage gains one plan-scoped directory.

### Decision: Make authorization self-invalidating when review state changes

- **Choice**: an authorization is active only while its bound failure count, previous head, previous report, and latest fail receipt still match. `recordReview` consumes it after writing the authorized result; even an interruption after the review write changes the repair identity and prevents replay.
- **Rationale**: binding authorization to immutable evidence supplies one-shot behavior without weakening review continuity.
- **Alternatives**: a free-standing boolean or manual repair-state edit. Both can be replayed or detached from the evidence that was adjudicated.
- **Consequences**: a failed authorized review returns to `adjudication-required` and requires a fresh decision.

### Decision: Keep dependents blocked until pass

- **Choice**: an active authorization makes only the adjudicated wave eligible/retryable; dependency checks continue to require a current pass receipt.
- **Rationale**: adjudication permits evidence gathering, not completion.
- **Alternatives**: treat adjudication as pass. This would violate the existing review gate.
- **Consequences**: `execution show --json` clearly distinguishes authorization from resolution.

## Risks and Verification

- **Stale or forged authorization** → validate current plan and exact repair identity → tests mutate plan/repair inputs and assert rejection.
- **Authorization replay** → consume after review and bind to failure identity → tests attempt a second review without a new adjudication.
- **Accidental dependent release** → preserve pass-only dependency logic → tests inspect dependent eligibility before and after pass.
- **CLI ambiguity** → require one `--wave`, `--decision allow-review`, `--confirm`, and safe `--reason` → command tests cover missing and invalid inputs.
Loading
Loading