Skip to content

fix: add adjudication recovery - #109

Open
jack-lrx wants to merge 5 commits into
MageByte-Zero:mainfrom
jack-lrx:codex/fix-adjudication-recovery
Open

fix: add adjudication recovery#109
jack-lrx wants to merge 5 commits into
MageByte-Zero:mainfrom
jack-lrx:codex/fix-adjudication-recovery

Conversation

@jack-lrx

Copy link
Copy Markdown

Summary

  • add ssf execution adjudicate <change-dir> --wave <id> --decision allow-review --confirm --reason <text>
  • persist a plan-scoped human decision bound to the exact failed receipt and repair chain
  • authorize exactly one continuous review without synthesizing pass or releasing dependents
  • expose authorization state through execution show --json and document operator recovery

Root cause

The repair circuit breaker correctly moved a wave to adjudication-required, but recordReview then rejected every subsequent review and no CLI command could persist the human decision requested by the workflow. Creating a new execution-plan revision discarded the identity of the repair chain instead of adjudicating it.

Safety behavior

  • stale plans, unknown/non-blocked waves, malformed evidence, invalid decisions, and replay attempts fail closed
  • authorization is bound to plan hash/revision, failure count, previous head/report, and failed receipt hash
  • a failed authorized review appends evidence and returns to adjudication-required
  • only a real replacement pass receipt releases dependent waves

Verification

  • focused execution tests: 66 passed, 0 failed, 0 skipped
  • npm run build
  • full suite: 673 passed, 0 failed, 0 skipped
  • strict change validation, ssf doctor, and git diff --check

Fixes #108

@jack-lrx
jack-lrx marked this pull request as ready for review August 13, 2026 06:09

@MageByte-Zero MageByte-Zero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

该 PR 解决的裁决恢复断点有实际价值,但以下问题必须修复后才能合并到 main:

  1. 移除整个 changes/add-adjudication-recovery/。其中包含 .spec-superflow.yaml.superpowers/sdd/ 的计划、receipt、review 报告及此次运行的 planning artifacts。仓库明确规定插件仓库不提交 changes/<change>/.spec-superflow.yaml.superpowers/;请只保留生产代码、测试、skills 与公开文档。参见

    spec-superflow/README.md

    Lines 212 to 216 in f96ddc8

    ### 插件仓库与使用项目的边界
    本仓库发布的是 workflow、模板、脚本、测试和文档,不是某一次真实运行的工作目录。因此不会提交 `changes/<change>/``.spec-superflow.yaml``.superpowers/``ssf sync` 生成的根 `specs/`;它们默认由 `.gitignore` 排除。需要展示完整流程时,只维护脱敏、固定的 `docs/examples/` 示例。
    **使用此插件的项目**中,活动输入仍是 `changes/<change>/specs/`,根 `specs/` 仍是可选的发布基线。消费者可按自己的审计或发布要求决定是否将这些项目工件纳入版本控制;这不会改变活动工作流只读取 change 的规则。

  2. 修复已授权 pass 对连续修复范围的绕过。当前 validateRepairContinuity 允许 pass 复用最后一个失败 receipt 的完整旧范围;在 adjudication 后,这可以无需从 previousRepair.previous_head 开始审查修复就将 wave 标为 resolved 并放行依赖。allow-review 路径至少应拒绝该旧范围复用,并要求 base 等于 previousRepair.previous_head。请新增“拒绝旧范围 pass、接受连续范围 review”的回归测试。参见

    function validateRepairContinuity(previousReceipt, previousRepair, nextReceipt) {
    if (previousReceipt?.status !== 'fail') return;
    const previousHead = previousRepair?.previous_head ?? previousReceipt.head;
    if (!previousHead) throw new Error('Repair state is missing the previous review head');
    // A failed re-review must examine a repair that starts at the prior review
    // head. A pass may also certify the exact original range: this preserves the
    // established fail→pass receipt flow for a corrected review finding.
    const repeatsPreviousRange = nextReceipt.status === 'pass'
    && nextReceipt.base === previousReceipt.base
    && nextReceipt.head === previousReceipt.head;
    if (nextReceipt.base !== previousHead && !repeatsPreviousRange) {
    throw new Error('Repair review base must equal the previous review head so repair ranges are continuous');
    }

  3. 将确认事实持久化到 adjudication receipt。CLI 要求 --confirm,但写入 ledger 的 authorization 未记录该字段,未满足 #108 对 decision、reason、timestamp 和 confirmation 均可审计的要求。请写入并测试 confirmed: true。参见

    const authorization = {
    id: randomUUID(),
    status: 'authorized',
    decision: input.decision,
    reason: input.reason.trim(),
    failure_count: repair.failure_count,
    previous_head: repair.previous_head,
    previous_report: repair.previous_report,
    failed_receipt: adjudicationReceiptEvidence(receipt),
    authorized_at: new Date().toISOString(),
    };
    ledger.adjudications.push(authorization);
    writeAdjudicationLedger(changeDir, plan, waveId, ledger);

另外,#108 仍写“五次失败”,而当前 main 的既定阈值是三次。此 PR 保留三次是正确的,但合并会因 Fixes #108 自动关闭 issue;请先将 issue 的验收文字改为当前阈值(3)或配置化表述。

非阻塞:请在发布前同步 INSTALL.md 中的 execution-control 示例,补充 ssf execution adjudicate 与失败后重新裁决的语义。

完成以上修改并重新通过构建、测试和 CI 后,请请求重新审查。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SDD repair chain becomes unrecoverable because adjudication-required has no CLI resolution path

2 participants