project-tiny-context-harness 0.2.84 → 0.2.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,11 +94,11 @@ For ordinary target-mode preparation, a two-document upstream input remains enou
94
94
 
95
95
  The ordinary long-task path uses `/normal-long-task`. It is the non-Superpowers acceptance pass: it can generate or reuse the full acceptance checklist and can produce a generic target-mode prompt.
96
96
 
97
- The Composite Long-Task Workflow path uses `/composite-long-task-workflow` when three inputs already exist: `Product / Architecture Source`, `Technical Realization Plan` and `Acceptance Checklist`. The product/architecture source preserves original intent and scope; the technical realization plan is the execution blueprint and plan-conformance source; the checklist is the acceptance authority. The Skill does not perform complexity routing: invocation means Superpowers-backed composite execution was already selected. Two-document compatibility is allowed only when the first document clearly contains both product/architecture source and technical realization plan sections. If only a product/architecture source and checklist exist, the Skill stops with a Missing Fields Report for a missing `Technical Realization Plan` instead of generating one. The technical realization plan must already satisfy the required Superpowers-ready Markdown implementation plan fields. When it does, the Skill freezes the package-managed workflow into `workflow-protocol.md`, writes task-local `execution-binding.md`, and renders `goal-objective.txt` as a thin Codex Goal objective instead of packing the full workflow into goal text. This is intentional: the Goal objective stays small enough to preserve the persistent completion contract, while the complete executable workflow lives in the protocol snapshot and the task-specific binding. The expected runtime effect is explicit fusion rather than agent improvisation: Tiny Context Workflow Contract first, then three-input authority, state compilation, Superpowers implementation slices, canonical evidence/state updates, generated views, slice/epoch gates and final-gate completion. The workflow is Tiny Context's composite adapter layer, aligned to the official Superpowers skills while remaining a Tiny Context-owned adapter rather than an upstream-owned schema; it is not the Tiny Context Workflow Contract itself, not a business fact source, not a generic prompt generator and not a Superpowers fork. It may wrap Superpowers with Tiny Context authority, conformance and acceptance gates, but it must not redefine or fork Superpowers execution mechanics. It requires parent-level `Product Context Delta` and `Technical Context Delta` checks before implementation and uses a canonical state kernel under `tmp/ty-context/plan-acceptance/<plan-slug>/`: `task-state.json` is the only execution state source, `events.ndjson` is append-only and `derived/**` contains generated local audit, plan-conformance matrix, final acceptance verdict, progress ledger, evidence index, context alignment, final summary and final card views. Complete acceptance rows are externally reviewable evidence claims derived from `task-state.evidence[]`: the checklist supplies the proof chain, fresh reviewable evidence must satisfy every required layer, and machine-verifiable layers such as UI/browser/runtime/API/data/integration/test require passed assertion results, zero command/assertion exit codes, target AC/layer coverage, passed positive and negative assertions and no negative evidence contradiction. Screenshot-only proof, component screenshots, viewmodels, diagnostic pages, API-only proof for a UI Path AC, final cards, matrix/verdict rows, validator passes and prose summaries are invalid as completion proof for those layers. Material drift, missing layers, failed/stale assertion reports, failed negative evidence scans or unapproved sibling substitution prevent `complete`. Goal-mode wording separates `audit_task_complete`, `acceptance_target_status`, computed `product_goal_complete` and resolver-owned `completion_output_status`: implementation / execution goals complete only when `ty-context composite-long-task final-gate` computes `product_goal_complete=true` and `completion_output_status=accept`; read-only audit goals may end at `audit_task_complete`, but a non-accepted verdict says `Audit workflow completed; acceptance target not complete.` and does not use unqualified `Goal achieved` or `update_goal(status="complete")` as acceptance of the user target.
97
+ The Composite Long-Task Workflow path uses `/composite-long-task-workflow` when three inputs already exist: `Product / Architecture Source`, `Technical Realization Plan` and `Acceptance Checklist`. The product/architecture source preserves original intent and scope; the technical realization plan is the execution blueprint and plan-conformance source; the checklist is the acceptance authority. The Skill does not perform complexity routing: invocation means Superpowers-backed composite execution was already selected. Two-document compatibility is allowed only when the first document clearly contains both product/architecture source and technical realization plan sections. If only a product/architecture source and checklist exist, the Skill stops with a Missing Fields Report for a missing `Technical Realization Plan` instead of generating one. The technical realization plan must already satisfy the required Superpowers-ready Markdown implementation plan fields. When it does, the Skill freezes the package-managed workflow into `workflow-protocol.md`, writes task-local `execution-binding.md`, and renders `goal-objective.txt` as a thin Codex Goal objective instead of packing the full workflow into goal text. This is intentional: the Goal objective stays small enough to preserve the persistent completion contract, while the complete executable workflow lives in the protocol snapshot and the task-specific binding. The expected runtime effect is explicit fusion rather than agent improvisation: Tiny Context Workflow Contract first, then three-input authority, state compilation, Superpowers implementation slices, canonical evidence/state updates, generated views, slice/epoch gates and final-gate completion. The workflow is Tiny Context's composite adapter layer, aligned to the official Superpowers skills while remaining a Tiny Context-owned adapter rather than an upstream-owned schema; it is not the Tiny Context Workflow Contract itself, not a business fact source, not a generic prompt generator and not a Superpowers fork. It may wrap Superpowers with Tiny Context authority, conformance and acceptance gates, but it must not redefine or fork Superpowers execution mechanics. It requires parent-level `Product Context Delta` and `Technical Context Delta` checks before implementation and uses a canonical state kernel under `tmp/ty-context/plan-acceptance/<plan-slug>/`: `task-state.json` is the only execution state source, `events.ndjson` is append-only and `derived/**` contains generated local audit, plan-conformance matrix, final acceptance verdict, progress ledger, evidence index, context alignment, final summary and final card views. Complete acceptance rows are externally reviewable evidence claims derived from `task-state.evidence[]`: the checklist supplies the proof chain, fresh reviewable evidence must satisfy every required layer, and machine-verifiable layers such as UI/browser/runtime/API/data/integration/test require passed assertion results, zero command/assertion exit codes, target AC/layer coverage, passed positive and negative assertions and no negative evidence contradiction. Screenshot-only proof, component screenshots, viewmodels, diagnostic pages, API-only proof for a UI Path AC, final cards, matrix/verdict rows, validator passes and prose summaries are invalid as completion proof for those layers. Material drift, missing layers, failed/stale assertion reports, failed negative evidence scans or unapproved sibling substitution prevent `complete`. Goal-mode wording separates `audit_task_complete`, `acceptance_target_status`, computed `product_goal_complete` and resolver-owned `completion_output_status`: implementation / execution goals complete only when `ty-context composite-long-task final-gate` computes `product_goal_complete=true` and `completion_output_status=accept`; read-only audit goals may end at `audit_task_complete`, but a non-accepted verdict says `Audit workflow completed; acceptance target not complete.` and does not use unqualified `Goal achieved` or `update_goal(status="complete")` as acceptance of the user target. Non-accepting final-gate output also carries `blocker_triage` category and next action; transient bookkeeping or regenerable generated-output mismatch can self-recover once, while real evidence, environment, contract and harness-drift blockers remain explicit.
98
98
 
99
99
  Strict completion is current-attempt-only and runs through one Trusted Evidence Kernel shared by final gate, `validate-superpowers-state`, state-backed `validate-plan-acceptance` and derived completion views, then through one completion-output resolver. `compile` derives required command specs from each machine-blocking AC's `assertion_command`, `assertion_artifacts`, proof layers, required tests, positive/negative assertions, invalid completion signals and expected final evidence; `start-attempt --mode product_task|harness_task` records the current execution identity; `run-assertion` records assertion command runs; `record-evidence` registers artifacts as canonical EvidenceRecordV2; and `final-gate` recomputes from current records. EvidenceRecordV2 must carry attempt/source/product/plan/checklist hashes, git head, worktree fingerprint, command spec/run ids, command line and exit code, artifact path/SHA/mtime, target AC ids, target PI ids, target proof layers, assertion status/exit code, positive assertions, negative assertions, invalid completion signals, negative evidence scan and required test ids. Legacy v1 evidence, historical `events.ndjson` complete events, stale `derived/**` views, matrix/verdict/evidence-index/final-summary rows, validator passes, final cards, auditor prose, AC summary-only proof, unregistered temporary JSON and hand-written status files cannot complete machine-blocking ACs or authorize generated final-answer `accept`. Newer failed command runs, Playwright/JUnit/test result failures, owner DOM forbidden states, source/worktree drift, task-state false/partial status and derived/state mismatches invalidate older passed evidence for the same AC/layer.
100
100
 
101
- The final-gate order is fixed inside the kernel and output resolver: load the three inputs, recompute source hashes, load task state, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, scan contradictions, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, resolve `completion_output_status`, regenerate `derived/**` and append an event. A machine-blocking AC with missing assertion command/artifacts/assertions/invalid signals, UI proof without browser/e2e/smoke/trace evidence, generated-only final evidence, manual-only test cases or no possible `assertion_result` is `under_specified`; its PI is blocked and `product_goal_complete=false`. AC-010/final-gate summary evidence cannot bootstrap other ACs: if a summary AC passes while another required AC is missing, failed or stale, the summary AC is invalidated with `final_gate_cannot_bootstrap_from_summary_only`.
101
+ The final-gate order is fixed inside the kernel and output resolver: load the three inputs, recompute source hashes, load task state, snapshot previous final/gates/meta transient bookkeeping as audit-only, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, scan contradictions, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, build current candidate state, resolve candidate `completion_output_status`, regenerate current `derived/**`, scan generated output in current-candidate mode, classify `blocker_triage`, self-recover once when allowed and append an event. A machine-blocking AC with missing assertion command/artifacts/assertions/invalid signals, UI proof without browser/e2e/smoke/trace evidence, generated-only final evidence, manual-only test cases or no possible `assertion_result` is `under_specified`; its PI is blocked and `product_goal_complete=false`. AC-010/final-gate summary evidence cannot bootstrap other ACs: if a summary AC passes while another required AC is missing, failed or stale, the summary AC is invalidated with `final_gate_cannot_bootstrap_from_summary_only`.
102
102
 
103
103
  Harness Drift Lock separates product proof from harness proof. A `product_task` that changes Playwright specs, tests, assertion generators, AC010 helpers, evidence writers, final-gate, validator, derive, task-state reducer, composite workflow Skill/protocol or related Makefile/package test targets is blocked with `harness_drift_detected`, `acceptance_target_status=blocked`, `product_goal_complete=false` and the message "本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。" A `harness_task` may change harness files only with adversarial fixtures whose expected final-gate outcomes include stale evidence, historical complete, derived contradiction, AC010 summary-only, target mismatch, API-only-for-UI, negative evidence after pass, source hash mismatch, dirty worktree mismatch, missing assertion_result, test weakening, scope leakage, missing UI/browser owner-surface proof, missing negative semantic proof and a happy path; it proves the harness, not product completion. `protected-harness-baseline.json` protects the final gate, validator, derive, evidence registration, assertion schema, fixture expectations, workflow protocol, Skill markdown and test runner scripts; product tasks changing that baseline are blocked, and harness tasks need a baseline reason plus fixture verification. HFC-003 is the durable false-completion regression suite: 35 committed mini workdirs plus one runner cover the Trusted Evidence Kernel, completion-output resolver, generated-output scanner, selected CLI smoke paths and one happy path, and are package release blockers for harness changes.
104
104
 
@@ -171,7 +171,7 @@ npm ci
171
171
  npm run smoke:quickstart
172
172
  npm run preview:pack
173
173
  cd /path/to/your/test-repo
174
- npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.84.tgz
174
+ npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.85.tgz
175
175
  npx --no-install ty-context init --adopt
176
176
  make validate-context
177
177
  ```
package/assets/README.md CHANGED
@@ -94,7 +94,7 @@ That smoke packs the local workspace, installs it into a disposable repo, runs `
94
94
  ```sh
95
95
  npm run preview:pack
96
96
  cd /path/to/your/test-repo
97
- npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.84.tgz
97
+ npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.85.tgz
98
98
  npx --no-install ty-context init --adopt
99
99
  make validate-context
100
100
  ```
@@ -331,9 +331,9 @@ Technical architecture support is a Minimal Context capability: use restrained `
331
331
 
332
332
  For long-running plans, RFCs or implementation proposals, invoke `/normal-long-task` to turn a plan plus relevant Context into a falsifiable acceptance checklist and an optional generic paste-ready goal/target-mode prompt. It also supports a two-document upstream input from Web GPT or another external planner: `Development Plan` for execution direction and `Acceptance and Tests` for target-mode acceptance input. If the plan already contains an explicit concrete acceptance checklist, the Skill copies that checklist verbatim into a separate full-checklist file instead of generating a competing checklist. The two-document packet path is strict mode: when required fields cannot be fully parsed from both documents, the Skill preserves the inputs, reports the missing fields, and stops without generating a checklist or goal/target-mode prompt. This is one pre-execution acceptance pass, not a task planner or workflow engine: it stores temporary inputs under `tmp/ty-context/plan-acceptance/**`, asks for confirmation when durable assumptions are unclear, and leaves execution evidence to the future executor, tests, CI, review or human acceptance. The generated prompt may require a local audit under the same temporary directory so future sessions can recover acceptance progress; that audit is not Context, not a quality proof and not a replacement for the project's Tiny Context workflow contract. The full checklist is the acceptance authority, while any compact prompt summary exists for navigation, priority and recovery after context compaction.
333
333
 
334
- When the next step explicitly needs Superpowers-backed long-task execution, invoke `/composite-long-task-workflow` on the Product / Architecture Source, Technical Realization Plan and Acceptance Checklist. It emits `workflow-protocol.md`, `execution-binding.md` and `goal-objective.txt` so the future executor sees which inputs feed Context Delta assessment, `superpowers:subagent-driven-development`, `superpowers:executing-plans`, TDD, `superpowers:verification-before-completion`, canonical `task-state.json`, append-only `events.ndjson`, generated `derived/**` views, proof-chain evidence and optional auditor review. This is Tiny Context's composite adapter layer for Superpowers-backed workflows, aligned to the official Superpowers skills while remaining a Tiny Context-owned adapter rather than an upstream-owned schema. It may wrap Superpowers with authority, conformance and acceptance gates, but it must not redefine, duplicate or fork Superpowers execution mechanics; if a future Tiny Context-added step would conflict with, duplicate or override a Superpowers responsibility, stop and surface the boundary conflict instead of silently merging workflows. It cannot replace `/normal-long-task` for ordinary checklist preparation, does not route complexity, and does not derive a technical plan from a product plan; the Technical Realization Plan must already be a Superpowers-ready Markdown implementation plan or the Skill stops before rendering entry artifacts. A two-document packet is accepted only when the first document explicitly contains both product/architecture source and technical realization plan sections. Product / Architecture Source, Technical Realization Plan and Acceptance Checklist remain the upstream authorities, while state/derived views/validator/auditor artifacts cannot rewrite them. Capability-first delivery scope stays inside those same three inputs: source, plan items and ACs must explicitly distinguish reusable system capability build, representative sample validation, full population operation and out-of-scope backlog; `scope_conflict_requires_decision` blocks completion, and sample/framework evidence cannot prove full population unless the AC says so. The generated Goal objective also disambiguates `audit_task_complete`, `acceptance_target_status`, computed `product_goal_complete` and resolver-owned `completion_output_status`; implementation / execution goals finish only when `product_goal_complete=true` and `completion_output_status=accept`, while a read-only audit goal can end at `audit_task_complete` only with a non-accepted verdict reported as `Audit workflow completed; acceptance target not complete.`, not as `Goal achieved`.
334
+ When the next step explicitly needs Superpowers-backed long-task execution, invoke `/composite-long-task-workflow` on the Product / Architecture Source, Technical Realization Plan and Acceptance Checklist. It emits `workflow-protocol.md`, `execution-binding.md` and `goal-objective.txt` so the future executor sees which inputs feed Context Delta assessment, `superpowers:subagent-driven-development`, `superpowers:executing-plans`, TDD, `superpowers:verification-before-completion`, canonical `task-state.json`, append-only `events.ndjson`, generated `derived/**` views, proof-chain evidence and optional auditor review. This is Tiny Context's composite adapter layer for Superpowers-backed workflows, aligned to the official Superpowers skills while remaining a Tiny Context-owned adapter rather than an upstream-owned schema. It may wrap Superpowers with authority, conformance and acceptance gates, but it must not redefine, duplicate or fork Superpowers execution mechanics; if a future Tiny Context-added step would conflict with, duplicate or override a Superpowers responsibility, stop and surface the boundary conflict instead of silently merging workflows. It cannot replace `/normal-long-task` for ordinary checklist preparation, does not route complexity, and does not derive a technical plan from a product plan; the Technical Realization Plan must already be a Superpowers-ready Markdown implementation plan or the Skill stops before rendering entry artifacts. A two-document packet is accepted only when the first document explicitly contains both product/architecture source and technical realization plan sections. Product / Architecture Source, Technical Realization Plan and Acceptance Checklist remain the upstream authorities, while state/derived views/validator/auditor artifacts cannot rewrite them. Capability-first delivery scope stays inside those same three inputs: source, plan items and ACs must explicitly distinguish reusable system capability build, representative sample validation, full population operation and out-of-scope backlog; `scope_conflict_requires_decision` blocks completion, and sample/framework evidence cannot prove full population unless the AC says so. The generated Goal objective also disambiguates `audit_task_complete`, `acceptance_target_status`, computed `product_goal_complete` and resolver-owned `completion_output_status`; implementation / execution goals finish only when `product_goal_complete=true` and `completion_output_status=accept`, while a read-only audit goal can end at `audit_task_complete` only with a non-accepted verdict reported as `Audit workflow completed; acceptance target not complete.`, not as `Goal achieved`. When final-gate does not accept, generated output includes `blocker_triage` category and next action; self-recoverable transient bookkeeping or generated-output mismatch can be regenerated once, but missing evidence, environment, contract and harness-drift blockers remain explicit.
335
335
 
336
- Important usage note: Minimal Context intentionally keeps Context read order, Context/code priority and drift checks as agent-level soft constraints rather than machine-enforced gates. That tradeoff works well for short tasks, but long tasks with large context windows, multiple handoffs or many verification loops are expected to drift unless product intent, technical implementation target and acceptance target are externalized. Superpowers alone can still drift under this pressure: it strengthens execution discipline, but it does not by itself preserve source authority, prevent scope shrinkage, prove full conformance to the Technical Realization Plan or enforce AC-by-AC evidence against the Acceptance Checklist. Use `/normal-long-task` before long-running execution when ordinary checklist preparation is needed; use `/composite-long-task-workflow` when the three upstream inputs already exist and Superpowers-backed execution is desired. Treat `task-state.json` as the only execution state source, `events.ndjson` as append-only, `derived/**` as generated reading views and `task-state.evidence[]` as the canonical evidence ledger. `validate-superpowers-state` and state-backed `validate-plan-acceptance` are still artifact/state-consistency validators, not product-quality proof; they now also reject missing/failed assertion-backed evidence for machine-verifiable layers, negative evidence contradictions, generated-output mismatch and false-completion wording under non-accept resolver status. A subagent auditor is an extra gap-finding pass on top of executor self-evidence and validator checks, not a replacement for either. Passing Superpowers review or verification does not bypass incomplete state rows, weak evidence, missing proof layers, failed assertion gates or blocking auditor findings.
336
+ Important usage note: Minimal Context intentionally keeps Context read order, Context/code priority and drift checks as agent-level soft constraints rather than machine-enforced gates. That tradeoff works well for short tasks, but long tasks with large context windows, multiple handoffs or many verification loops are expected to drift unless product intent, technical implementation target and acceptance target are externalized. Superpowers alone can still drift under this pressure: it strengthens execution discipline, but it does not by itself preserve source authority, prevent scope shrinkage, prove full conformance to the Technical Realization Plan or enforce AC-by-AC evidence against the Acceptance Checklist. Use `/normal-long-task` before long-running execution when ordinary checklist preparation is needed; use `/composite-long-task-workflow` when the three upstream inputs already exist and Superpowers-backed execution is desired. Treat `task-state.json` as the only execution state source, `events.ndjson` as append-only, `derived/**` as generated reading views and `task-state.evidence[]` as the canonical evidence ledger. `validate-superpowers-state` and state-backed `validate-plan-acceptance` are still artifact/state-consistency validators, not product-quality proof; they now also reject missing/failed assertion-backed evidence for machine-verifiable layers, negative evidence contradictions, generated-output mismatch and false-completion wording under non-accept resolver status, and they surface state-backed blocker triage when final-gate has written it. A subagent auditor is an extra gap-finding pass on top of executor self-evidence and validator checks, not a replacement for either. Passing Superpowers review or verification does not bypass incomplete state rows, weak evidence, missing proof layers, failed assertion gates or blocking auditor findings.
337
337
 
338
338
  Hallucination guard: do not register `workflow-protocol.md` in `project_context/context.toml`, treat it as business Context, let `derived/**` rewrite Product / Plan / Checklist, use local audit or Superpowers review as quality proof, use screenshots/final cards/matrix/verdict/validator pass/prose as machine-verifiable proof, use sample evidence as full-population proof, claim full alignment while Source-to-Context Coverage or Context-to-Implementation Binding has unresolved required gaps, handwrite `product_goal_complete` or `completion_output_status`, or complete an implementation Goal before final-gate passes and resolver status is `accept`.
339
339
 
@@ -54,7 +54,7 @@ Tiny Context 有两个核心层。Minimal Context 是长期事实源层:说明
54
54
 
55
55
  对于长程任务,Harness 提供两个显式调用的长程任务 Skill。普通长程任务用 `/normal-long-task`:它把方案和验收输入临时放到 `tmp/ty-context/plan-acceptance/**`,生成或复用完整验收清单,并可输出普通目标模式文本。如果外部规划模型参与,推荐仍然只给两份产物:`《开发方案》` 作为执行方向和 plan traceability source,`《验收清单和测试用例》` 作为 Codex target-mode acceptance input packet。第一份应包含可逐项追踪的 plan item、预期落点 surface、full scope 与 sampled/optional 边界;第二份应包含 AC、required evidence、测试命令、真实产品路径 / core path、证据分层、无效证据、状态机、local audit 和 blocker。Source Pack 只是临时上传材料,不是 durable Context。如果方案里已经有明确、具体的“验收清单”,`/normal-long-task` 会直接复用那份清单并单独写入完整验收清单文件;两份输入包走 strict mode,如果两份内容无法完整解析出 required fields,或第二份缺少 required evidence、verification method、fail condition、状态机、无效证据规则等必要字段,Skill 会停止并列出缺失项,不生成完整验收清单或目标模式文本。
56
56
 
57
- Composite Long-Task Workflow Skill 用 `/composite-long-task-workflow`。如果下一步明确要 Superpowers-backed 目标模式执行,推荐在三份输入都存在后调用:`Product / Architecture Source`(产品/架构原始意图源)、`Technical Realization Plan`(具体技术实现方案)和 `Acceptance Checklist`(验收清单)。它不做复杂度分流;调用它表示上游已经决定使用 composite long-task execution。它不要求先跑 `/normal-long-task`,但也不会把产品方案现场翻译成技术方案;如果只有产品/架构方案和验收清单,Skill 会用 Missing Fields Report 停止并报告缺少 `Technical Realization Plan`。两份输入兼容只限第一份明确包含产品/架构源和技术实现方案两个章节。`Technical Realization Plan` 必须已经满足 Superpowers-ready Markdown implementation plan 的必填字段;满足时它跳过方案生成,直接绑定 Superpowers 执行,不满足时直接中断并报告缺失字段,不生成 prompt。它输出 `workflow-protocol.md`、`execution-binding.md` 和可直接用于 Codex Goal mode 的薄 `goal-objective.txt`,不是把完整 workflow 塞进 4000 字 Goal:Goal 只保留持续完成契约,完整可执行流程放在 protocol snapshot 和 task-specific binding。预期运行效果是显式融合而不是让 agent 自行发挥:先 Tiny Context 流程契约,再三份输入权威,再编译 task-state,再进入 Superpowers implementation slice,每个 slice 更新 canonical state/evidence,derive 出阅读视图,经过 slice/epoch gate,最后 final-gate 计算完成。这个 workflow 是面向 Superpowers execution 的 Tiny Context 适配层,对齐官方 Superpowers skills,但不是上游维护的 schema;它不是 Tiny Context 流程契约本身、不是业务事实源、不是普通 prompt generator、也不是 Superpowers fork。它可以在 Superpowers 外层增加 Tiny Context 的权威、对图纸和验收门禁,但不能重新定义、重复或分叉 Superpowers 执行机制。如果未来改动让 Tiny Context 新增步骤和官方 Superpowers 职责冲突、重复或覆盖,应停止修改并提示边界冲突,不要静默合并两套流程。它不生成技术方案或验收清单、不执行计划、不证明完成,也不会把临时 state、derived views 或 verdict 注册成 `project_context/**`。三输入是上游权威,state / derived views / validator / auditor 不能改写它们。`task-state.json` 是唯一执行状态源,`events.ndjson` 追加记录状态变更,`derived/**` 只生成 local audit、plan-conformance matrix、final acceptance verdict、progress ledger、evidence index、context alignment、final summary 和 final card 等阅读视图。完整验收行按外部审计证据处理:proof chain 来自验收清单,fresh evidence 必须通过 `task-state.evidence[]` 满足每个 required layer,存在 material drift、缺 required layer 或未批准 sibling substitution 时不能标 `complete`。Goal mode 表述必须区分 `audit_task_complete`、`acceptance_target_status`、computed `product_goal_complete` 和 resolver-owned `completion_output_status`:实现/执行目标只在 `ty-context composite-long-task final-gate` 计算出 `product_goal_complete=true` 且 `completion_output_status=accept` 时完成;只读审计目标可在 `audit_task_complete` 时结束,但 verdict 不是 accepted/complete 时,回复写 `Audit workflow completed; acceptance target not complete.`,不能用未限定的 `Goal achieved` 或 `update_goal(status="complete")` 表示用户验收目标已完成。
57
+ Composite Long-Task Workflow Skill 用 `/composite-long-task-workflow`。如果下一步明确要 Superpowers-backed 目标模式执行,推荐在三份输入都存在后调用:`Product / Architecture Source`(产品/架构原始意图源)、`Technical Realization Plan`(具体技术实现方案)和 `Acceptance Checklist`(验收清单)。它不做复杂度分流;调用它表示上游已经决定使用 composite long-task execution。它不要求先跑 `/normal-long-task`,但也不会把产品方案现场翻译成技术方案;如果只有产品/架构方案和验收清单,Skill 会用 Missing Fields Report 停止并报告缺少 `Technical Realization Plan`。两份输入兼容只限第一份明确包含产品/架构源和技术实现方案两个章节。`Technical Realization Plan` 必须已经满足 Superpowers-ready Markdown implementation plan 的必填字段;满足时它跳过方案生成,直接绑定 Superpowers 执行,不满足时直接中断并报告缺失字段,不生成 prompt。它输出 `workflow-protocol.md`、`execution-binding.md` 和可直接用于 Codex Goal mode 的薄 `goal-objective.txt`,不是把完整 workflow 塞进 4000 字 Goal:Goal 只保留持续完成契约,完整可执行流程放在 protocol snapshot 和 task-specific binding。预期运行效果是显式融合而不是让 agent 自行发挥:先 Tiny Context 流程契约,再三份输入权威,再编译 task-state,再进入 Superpowers implementation slice,每个 slice 更新 canonical state/evidence,derive 出阅读视图,经过 slice/epoch gate,最后 final-gate 计算完成。这个 workflow 是面向 Superpowers execution 的 Tiny Context 适配层,对齐官方 Superpowers skills,但不是上游维护的 schema;它不是 Tiny Context 流程契约本身、不是业务事实源、不是普通 prompt generator、也不是 Superpowers fork。它可以在 Superpowers 外层增加 Tiny Context 的权威、对图纸和验收门禁,但不能重新定义、重复或分叉 Superpowers 执行机制。如果未来改动让 Tiny Context 新增步骤和官方 Superpowers 职责冲突、重复或覆盖,应停止修改并提示边界冲突,不要静默合并两套流程。它不生成技术方案或验收清单、不执行计划、不证明完成,也不会把临时 state、derived views 或 verdict 注册成 `project_context/**`。三输入是上游权威,state / derived views / validator / auditor 不能改写它们。`task-state.json` 是唯一执行状态源,`events.ndjson` 追加记录状态变更,`derived/**` 只生成 local audit、plan-conformance matrix、final acceptance verdict、progress ledger、evidence index、context alignment、final summary 和 final card 等阅读视图。完整验收行按外部审计证据处理:proof chain 来自验收清单,fresh evidence 必须通过 `task-state.evidence[]` 满足每个 required layer,存在 material drift、缺 required layer 或未批准 sibling substitution 时不能标 `complete`。Goal mode 表述必须区分 `audit_task_complete`、`acceptance_target_status`、computed `product_goal_complete` 和 resolver-owned `completion_output_status`:实现/执行目标只在 `ty-context composite-long-task final-gate` 计算出 `product_goal_complete=true` 且 `completion_output_status=accept` 时完成;只读审计目标可在 `audit_task_complete` 时结束,但 verdict 不是 accepted/complete 时,回复写 `Audit workflow completed; acceptance target not complete.`,不能用未限定的 `Goal achieved` 或 `update_goal(status="complete")` 表示用户验收目标已完成。final-gate 未 accept 时,输出必须带 `blocker_triage` category 和 next action;旧 transient bookkeeping 或可重新生成的 generated-output mismatch 最多自愈重跑一次,真实证据、环境、契约和 harness drift blocker 仍保持 blocked/reject。
58
58
 
59
59
  Machine-verifiable proof layer(如 UI/browser、runtime、API/schema、data artifact、integration、test)不能靠截图、final card、validator pass、matrix/verdict 行或 prose evidence 完成;必须有 `assertion_result.status=passed`、命令和 assertion exit code 为 0、target AC/layer 匹配、positive/negative assertions 通过、reviewable artifacts,且没有 failed/stale `negative_evidence_scan`。UI Path AC 不能用 component screenshot、storybook、viewmodel、mock/unit、diagnostic page 或 API-only evidence 替代 owner page/browser 主路径;`未验证`、`不可用`、`暂不可用`、`页面无明显变化` 等 owner-surface forbidden state 会使 AC/layer 失效。
60
60
 
@@ -70,9 +70,9 @@ Strict V2 输入还要求 canonical Product / PI / AC 字段组。Product Source
70
70
 
71
71
  严格完成判定只看 current attempt,并且统一经过 Trusted Evidence Kernel,再经过 completion-output resolver;final-gate、`validate-superpowers-state`、state-backed `validate-plan-acceptance` 和 derived completion views 使用同一个 kernel result。`compile` 从每个 machine-blocking AC 的 `assertion_command`、`assertion_artifacts`、proof layers、required tests、positive/negative assertions、invalid completion signals 和 final evidence expectation 生成 required command specs;`start-attempt --mode product_task|harness_task` 创建当前执行身份;`run-assertion` 记录 assertion command run;`record-evidence` 把 artifact 注册成 canonical EvidenceRecordV2;`final-gate` 只从当前记录重算。EvidenceRecordV2 必须包含 attempt/source/product/plan/checklist hash、git head、worktree fingerprint、command spec/run id、command line / exit code、artifact path/SHA/mtime、target AC ids、target PI ids、target proof layers、assertion status / exit code、positive assertions、negative assertions、invalid completion signals、negative evidence scan 和 required test ids。legacy v1 evidence、历史 `events.ndjson` complete 事件、旧 `derived/**` complete 视图、matrix/verdict/evidence-index/final-summary 行、validator pass、final card、auditor prose、AC summary-only proof、未注册临时 JSON 和手写 status 文件都不能完成 machine-blocking AC,也不能把 generated final answer 升级为 `accept`;更新的 failed command、Playwright/JUnit/test result 失败、owner DOM forbidden state、source/worktree drift、当前 task-state false/partial 或 derived/state mismatch 会让同 AC/layer 的旧 passed evidence 失效。
72
72
 
73
- final-gate 在 kernel 和 output resolver 内部固定执行:load 三输入、重算 source hashes、load task-state、resolve current attempt、load required command specs、load command-run records、load registered EvidenceRecords、discard stale evidence、scan unregistered assertion JSON、contradiction scan、AC-010 bootstrap prevention、under-specified AC checks、Harness Drift Lock、protected baseline guard、validate scope conflicts、重算每个 AC、重算每个 PI、重算 `acceptance_target_status`、重算 `product_goal_complete`、resolve `completion_output_status`、regenerate `derived/**`、append event。machine-blocking AC 缺 assertion command/artifacts/assertions/invalid signals,UI proof 缺 browser/e2e/smoke/trace,final evidence 只指向 generated view,test cases 只有人工查看,或无法产出 `assertion_result` 时,AC 是 `under_specified`,PI blocked,`product_goal_complete=false`。AC-010 / final-gate summary 不能反向证明其它 AC:如果 summary AC passed 但其它 required AC missing / failed / stale,则 summary AC invalidated,reason 是 `final_gate_cannot_bootstrap_from_summary_only`。
73
+ final-gate 在 kernel、output resolver triage 内部固定执行:load 三输入、重算 source hashes、load task-state、把旧 final/gates/meta transient bookkeeping snapshot 成 audit-only、resolve current attempt、load required command specs、load command-run records、load registered EvidenceRecords、discard stale evidence、scan unregistered assertion JSON、contradiction scan、AC-010 bootstrap prevention、under-specified AC checks、Harness Drift Lock、protected baseline guard、validate scope conflicts、重算每个 AC、重算每个 PI、重算 `acceptance_target_status`、重算 `product_goal_complete`、build current candidate state、resolve candidate `completion_output_status`、regenerate current `derived/**`、按 current candidate mode 扫 generated output、分类 `blocker_triage`、允许 transient/generated-output 自愈一次、append event。旧 `completion_output_status=blocked` 或旧 `generated_output_mismatch=true` 不能把 current kernel accept 拖回 blocked;当前 user-visible false completion claim 仍会 blocked。machine-blocking AC 缺 assertion command/artifacts/assertions/invalid signals,UI proof 缺 browser/e2e/smoke/trace,final evidence 只指向 generated view,test cases 只有人工查看,或无法产出 `assertion_result` 时,AC 是 `under_specified`,PI blocked,`product_goal_complete=false`。AC-010 / final-gate summary 不能反向证明其它 AC:如果 summary AC passed 但其它 required AC missing / failed / stale,则 summary AC invalidated,reason 是 `final_gate_cannot_bootstrap_from_summary_only`。
74
74
 
75
- Harness Drift Lock 把产品证明和验收工具链证明拆开。`product_task` 修改 Playwright spec、测试、assertion generator、AC010 helper、evidence writer、final-gate、validator、derive、task-state reducer、composite workflow Skill/protocol 或相关 Makefile/package test target 时,直接输出 `harness_drift_detected`、`acceptance_target_status=blocked`、`product_goal_complete=false`,并使用文案“本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。”`harness_task` 可以修改 harness,但必须有 stale evidence、historical complete、derived contradiction、AC010 summary-only、target mismatch、API-only-for-UI、negative evidence after pass、source hash mismatch、dirty worktree mismatch、missing assertion_result、test weakening、scope leakage、missing UI/browser owner-surface proof、missing negative semantic proof 和 happy path fixtures;它只证明 harness 修对,不证明产品任务完成。`protected-harness-baseline.json` 保护 final-gate、validator、derive、evidence registration、assertion schema、fixture expected outcomes、workflow protocol、Skill markdown 和 test runner scripts;product task 改 baseline blocked,harness task 改 baseline 必须写 reason 并跑 fixtures。HFC-003 是持久 false-completion regression suite:35 个提交的 mini workdir 加一个 runner 覆盖 Trusted Evidence Kernel、completion-output resolvergenerated-output scanner、选定 CLI smoke path happy path,并作为 harness 改动的 package release blocker。
75
+ Harness Drift Lock 把产品证明和验收工具链证明拆开。`product_task` 修改 Playwright spec、测试、assertion generator、AC010 helper、evidence writer、final-gate、validator、derive、task-state reducer、composite workflow Skill/protocol 或相关 Makefile/package test target 时,直接输出 `harness_drift_detected`、`acceptance_target_status=blocked`、`product_goal_complete=false`,并使用文案“本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。”`harness_task` 可以修改 harness,但必须有 stale evidence、historical complete、derived contradiction、AC010 summary-only、target mismatch、API-only-for-UI、negative evidence after pass、source hash mismatch、dirty worktree mismatch、missing assertion_result、test weakening、scope leakage、missing UI/browser owner-surface proof、missing negative semantic proof 和 happy path fixtures;它只证明 harness 修对,不证明产品任务完成。`protected-harness-baseline.json` 保护 final-gate、validator、derive、evidence registration、assertion schema、fixture expected outcomes、workflow protocol、Skill markdown 和 test runner scripts;product task 改 baseline blocked,harness task 改 baseline 必须写 reason 并跑 fixtures。HFC-003 是持久 false-completion regression suite;HFC-004 是持久 final-gate blocker triage suite,覆盖旧 transient 自锁、candidate-driven scannerblocker category/next actionone-pass self-recovery,并作为 harness 改动的 package release blocker。
76
76
 
77
77
  生成的 composite workflow prompt 使用 Slice Gate / Epoch Gate / Final Gate 分层节奏,而不是每个 slice 后都跑完整 final gate。Progress Accounting 在 state 和 generated `derived/progress-ledger.*` 中记录 AC acceptance completion、engineering implementation progress、runtime/proof progress、system capability progress、representative sample progress、real object coverage、full population operation progress、artifact budget 和 workflow overhead。每个 slice 需要声明 artifact budget、proof-layer milestone 状态和 cleanup expectation。workflow overhead backpressure 要求 executor 批处理共享的 provider/browser/runtime/security epoch proof environment,清理 stale artifact,并选择 Next 3-5 high-value clusters 来优先关闭最多阻塞 AC / proof-layer gap。
78
78
 
@@ -3,14 +3,14 @@
3
3
  "purpose": "Protect composite-long-task final completion mechanics from product-task self-validation drift.",
4
4
  "baseline_reason": "Trusted Evidence Kernel and Harness Drift Lock define the canonical completion proof surface.",
5
5
  "protected_categories": {
6
- "final_gate_implementation": ["packages/ty-context/src/lib/superpowers-task-gates.ts", "packages/ty-context/src/lib/superpowers-task-evidence-kernel.ts", "packages/ty-context/src/lib/superpowers-task-command-run-correlation.ts", "packages/ty-context/src/lib/superpowers-task-unregistered-evidence.ts", "packages/ty-context/src/lib/superpowers-task-ac010.ts"],
6
+ "final_gate_implementation": ["packages/ty-context/src/commands/composite-long-task.ts", "packages/ty-context/src/lib/superpowers-task-gates.ts", "packages/ty-context/src/lib/superpowers-task-evidence-kernel.ts", "packages/ty-context/src/lib/superpowers-task-command-run-correlation.ts", "packages/ty-context/src/lib/superpowers-task-unregistered-evidence.ts", "packages/ty-context/src/lib/superpowers-task-ac010.ts"],
7
7
  "completion_output_implementation": ["packages/ty-context/src/lib/superpowers-task-completion-output.ts", "packages/ty-context/src/lib/superpowers-task-final-card.ts"],
8
- "validator_implementation": ["packages/ty-context/src/lib/superpowers-task-validator.ts"],
8
+ "validator_implementation": ["packages/ty-context/src/lib/superpowers-task-validator.ts", "packages/ty-context/src/lib/plan-acceptance-validator.ts"],
9
9
  "derive_implementation": ["packages/ty-context/src/lib/superpowers-task-derive.ts"],
10
10
  "evidence_registration_implementation": ["packages/ty-context/src/lib/superpowers-task-evidence.ts", "packages/ty-context/src/lib/superpowers-task-current-evidence.ts"],
11
11
  "harness_protection_implementation": ["packages/ty-context/src/lib/superpowers-task-harness-drift.ts", "packages/ty-context/src/lib/superpowers-task-protected-baseline.ts"],
12
12
  "assertion_result_schema": ["packages/ty-context/src/lib/superpowers-task-state-schema.ts", "packages/ty-context/src/lib/superpowers-task-assertion-normalizers.ts"],
13
- "fixture_expected_outcomes": ["tests/ty-context/superpowers-task-evidence-kernel.test.mjs", "tests/ty-context/composite-long-task-assertion-gate.test.mjs", "tests/ty-context/composite-long-task-expanded-assertion-gate.test.mjs", "tests/ty-context/composite-long-task-trusted-evidence-kernel.test.mjs", "tests/ty-context/composite-long-task-completion-output-gate.test.mjs", "tests/ty-context/fixtures/composite-long-task/completion-output-gate/expected-outcomes.json", "tests/ty-context/composite-long-task-false-completion-regression.test.mjs", "tests/ty-context/fixtures/composite-long-task/false-completion-regression/manifest.json"],
13
+ "fixture_expected_outcomes": ["tests/ty-context/superpowers-task-evidence-kernel.test.mjs", "tests/ty-context/composite-long-task-assertion-gate.test.mjs", "tests/ty-context/composite-long-task-expanded-assertion-gate.test.mjs", "tests/ty-context/composite-long-task-trusted-evidence-kernel.test.mjs", "tests/ty-context/composite-long-task-completion-output-gate.test.mjs", "tests/ty-context/fixtures/composite-long-task/completion-output-gate/expected-outcomes.json", "tests/ty-context/composite-long-task-false-completion-regression.test.mjs", "tests/ty-context/fixtures/composite-long-task/false-completion-regression/manifest.json", "tests/ty-context/composite-long-task-final-gate-triage.test.mjs", "tests/ty-context/fixtures/composite-long-task/final-gate-triage/manifest.json"],
14
14
  "workflow_protocol": [".codex/ty-context-managed/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md", ".codex/ty-context-managed/skills/composite-long-task-workflow/assets/goal-objective.template.md", ".codex/ty-context-managed/skills/composite-long-task-workflow/assets/execution-binding.template.md"],
15
15
  "skill_markdown": [".codex/ty-context-managed/skills/composite-long-task-workflow/SKILL.md"],
16
16
  "test_runner_scripts": ["packages/ty-context/package.json", "package.json", "Makefile"]
@@ -176,6 +176,7 @@ Superpowers review and verification remain useful execution checks, but they can
176
176
  - `execution-binding.md` as task binding.
177
177
  - `product_goal_complete` only by final gate.
178
178
  - `completion_output_status` only by final-gate completion-output resolver.
179
+ - `blocker_triage` category and next action when final gate fails.
179
180
  - `audit_task_complete` not equal to product acceptance.
180
181
  - assertion-backed machine-verifiable proof layers and negative evidence scan.
181
182
  - forbidden shortcuts.
@@ -187,13 +188,13 @@ Agents must not hand-set `product_goal_complete` or `completion_output_status`.
187
188
 
188
189
  Final completion is current-attempt-only and owned by the Trusted Evidence Kernel shared by final gate, `validate-superpowers-state`, state-backed `validate-plan-acceptance` and derived completion views. Legacy v1 evidence, old attempt evidence, stale passed assertion JSON, historical `events.ndjson` completion events, stale `derived/**` views, matrix/verdict/evidence-index/final-summary rows, validator passes, final cards, auditor prose, AC summary-only proof, unregistered temporary JSON and hand-written status files are audit material only. They cannot complete machine-blocking ACs. Current failed command runs, Playwright/JUnit/test-result artifacts, owner DOM forbidden states, source/worktree drift, task-state false/partial status or derived/state mismatch invalidate older positive proof for the same AC/layer.
189
190
 
190
- The final gate recomputes in this order: load the three inputs, recompute source hashes, load task state, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, run contradiction scan, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, resolve `completion_output_status`, regenerate `derived/**` and append an event.
191
+ The final gate recomputes in this order: load the three inputs, recompute source hashes, load task state, snapshot previous final/gates/meta transient bookkeeping as audit-only, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, run contradiction scan, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, build the current candidate state, resolve candidate `completion_output_status`, regenerate current `derived/**`, scan generated output in the current candidate mode, classify blockers with `blocker_triage`, perform at most one self-recovery pass for transient bookkeeping or regenerable generated-output mismatch, then write current final state and append an event.
191
192
 
192
193
  Canonical proof layers are `code`, `api_schema`, `worker_runtime`, `data_artifact`, `integration`, `ui_browser`, `security_redaction`, `all_provider_all_runner`, `cleanup_stale_scan` and `test`; legacy source aliases map `runtime -> worker_runtime`, `browser -> ui_browser`, `api -> api_schema`, `data -> data_artifact` and `security -> security_redaction`. `code` cannot complete a machine-backed AC by itself. For UI/browser/API/worker/data/integration/security/test/all-provider/cleanup proof layers, do not mark ACs complete from screenshots, final cards, validator passes, matrix/verdict rows or prose evidence. Required machine-verifiable layers need passed `assertion_result`, zero command/assertion exit codes, target AC/PI/layer coverage, passed positive and negative assertions, no invalid completion signal, reviewable artifacts and passed `negative_evidence_scan` with matching target proof layers. Machine-blocking ACs with missing assertion command/artifacts/assertions/invalid signals, manual-only tests, generated-only final evidence, impossible assertion results or UI proof without browser/e2e/smoke/trace evidence are `under_specified`, block the related PI and force `product_goal_complete=false`.
193
194
 
194
195
  AC-010 / final-gate summary ACs can only summarize fresh EvidenceRecordV2 proof for the other ACs. If AC-010 passes while another required AC is missing, failed, stale or under-specified, invalidate AC-010 with `final_gate_cannot_bootstrap_from_summary_only`.
195
196
 
196
- Harness Drift Lock: `product_task` cannot complete if it changed Playwright specs, tests, assertion generators, AC010 helpers, evidence writers, final-gate, validator, derive, task-state reducer, this workflow Skill/protocol or related Makefile/package test targets. Report `harness_drift_detected`, `acceptance_target_status=blocked`, `product_goal_complete=false` and exactly: `本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。` A `harness_task` must have adversarial fixtures with expected final-gate outcomes and a happy-path fixture; it proves harness behavior only and must not declare product completion. HFC-003 is the durable false-completion regression suite: 35 committed mini workdirs plus one runner cover the Trusted Evidence Kernel, completion-output resolver, generated-output scanner, selected CLI smoke paths and one happy path. `protected-harness-baseline.json` protects final-gate, validator, derive, evidence registration, assertion schema, fixture expected outcomes, workflow protocol, Skill markdown and test runner scripts; product task baseline changes are blocked, harness task baseline changes require a reason and fixture verification.
197
+ Harness Drift Lock: `product_task` cannot complete if it changed Playwright specs, tests, assertion generators, AC010 helpers, evidence writers, final-gate, validator, derive, task-state reducer, this workflow Skill/protocol or related Makefile/package test targets. Report `harness_drift_detected`, `acceptance_target_status=blocked`, `product_goal_complete=false` and exactly: `本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。` A `harness_task` must have adversarial fixtures with expected final-gate outcomes and a happy-path fixture; it proves harness behavior only and must not declare product completion. HFC-003 is the durable false-completion regression suite, and HFC-004 is the durable final-gate blocker-triage suite covering old transient self-lock, candidate-driven scanner mode, blocker categories, next actions and one-pass self-recovery. `protected-harness-baseline.json` protects final-gate, validator, derive, evidence registration, assertion schema, fixture expected outcomes, workflow protocol, Skill markdown and test runner scripts; product task baseline changes are blocked, harness task baseline changes require a reason and fixture verification.
197
198
 
198
199
  If `audit_task_complete` is true but `acceptance_target_status` is not complete, report:
199
200
 
@@ -203,7 +204,7 @@ Audit workflow completed; acceptance target not complete.
203
204
 
204
205
  Do not use unqualified `Goal achieved` or `update_goal(status="complete")` as product acceptance in that case.
205
206
 
206
- If final-gate has not run, the required final answer is `blocked`. If final-gate runs but `product_goal_complete=false` or `acceptance_target_status` is not accepted, the required final answer is `reject` or `blocked`. Validator pass, matrix/verdict row completion, final cards, local audit or stale generated text must never promote the final answer to `accept`.
207
+ If final-gate has not run, the required final answer is `blocked`. If final-gate runs but `product_goal_complete=false` or `acceptance_target_status` is not accepted, the required final answer is `reject` or `blocked` and must include blocker triage category plus next action. Validator pass, matrix/verdict row completion, final cards, local audit or stale generated text must never promote the final answer to `accept`.
207
208
 
208
209
  ## Forbidden Behaviors
209
210
 
@@ -44,6 +44,11 @@ completion_gate:
44
44
  matrix_verdict_final_card_never_authorizes_accept: true
45
45
  audit_task_complete_never_authorizes_accept: true
46
46
  generated_output_mismatch_blocks_accept: true
47
+ final_gate_uses_current_candidate_before_scanner: true
48
+ old_transient_bookkeeping_is_audit_only: true
49
+ blocker_triage_category_required_on_failure: true
50
+ blocker_triage_next_action_required_on_failure: true
51
+ self_recoverable_generated_output_mismatch_retries_once: true
47
52
  cannot_hand_set_product_goal_complete: true
48
53
  cannot_hand_set_completion_output_status: true
49
54
  includes_ac_evidence_assertion_gate: true
@@ -11,7 +11,7 @@ Forbidden shortcuts:
11
11
  Do not mark UI/worker/API/data/integration/test ACs complete from screenshots, final cards, validator passes, derived rows, historical complete events, auditor prose, AC summary proof, unregistered JSON or stale attempts. Required machine proof needs current-attempt EvidenceRecordV2, assertion_result.status=passed, zero command/assertion exit codes, target AC/layer coverage, passed positive and negative assertions, reviewable artifacts and no failed/stale negative_evidence_scan with matching target proof layers. Tests alone do not prove plan conformance. Superpowers review does not override Tiny Context gates. Sample evidence does not prove full population unless AC allows. Local audit cannot mark final completion. Do not claim full implementation while Context Delta is required but Context is not updated, or while Source-to-Context Coverage / Context-to-Implementation Binding has unresolved required gaps.
12
12
 
13
13
  Completion:
14
- Do not hand-set product_goal_complete or completion_output_status. Only final-gate computes product_goal_complete through the Trusted Evidence Kernel; resolver writes completion_output_status as accept, reject or blocked. Machine-blocking ACs missing assertion command/artifacts/assertions/invalid signals, manual-only proof, generated-only final evidence, impossible assertion_result or UI proof without browser/e2e/smoke/trace are under_specified and block completion. AC-010 cannot bootstrap missing, failed or stale ACs. product_task changing tests/harness/final-gate/validator/assertion generators/workflow protocol is harness_drift_detected and must split to harness_task; harness_task proves harness behavior only. Run AC Evidence Assertion Gate, Negative Evidence Scan Gate, validators, then final-gate. Require final-gate compute product_goal_complete=true and completion_output_status=accept before treating implementation as complete. If completion_output_status is reject or blocked, or final-gate has not run, the final answer must be reject or blocked and must not say Goal achieved, completed, accepted, done or call update_goal(status="complete"). If audit_task_complete is true but acceptance_target_status is not complete, report "Audit workflow completed; acceptance target not complete." If historical complete conflicts with current recompute, report "Historical stale completion event detected and ignored." and "Current recomputed product_goal_complete=false."
14
+ Do not hand-set product_goal_complete or completion_output_status. Only final-gate computes product_goal_complete through the Trusted Evidence Kernel; resolver writes completion_output_status as accept, reject or blocked. Machine-blocking ACs missing assertion command/artifacts/assertions/invalid signals, manual-only proof, generated-only final evidence, impossible assertion_result or UI proof without browser/e2e/smoke/trace are under_specified and block completion. AC-010 cannot bootstrap missing, failed or stale ACs. product_task changing tests/harness/final-gate/validator/assertion generators/workflow protocol is harness_drift_detected and must split to harness_task; harness_task proves harness behavior only. Run AC Evidence Assertion Gate, Negative Evidence Scan Gate, validators, then final-gate. Require final-gate compute product_goal_complete=true and completion_output_status=accept before treating implementation as complete. If final-gate fails, use blocker_triage category/next_action; self-recoverable transient/generated-output mismatch may recover once, then rerun. Reject/blocked answers must not say Goal achieved, completed, accepted, done or call update_goal(status="complete"). If audit_task_complete is true but acceptance_target_status is not complete, report "Audit workflow completed; acceptance target not complete."
15
15
 
16
16
  Blocked:
17
- Use repo tools, local app/browser sessions, CLI auth and authorized elevation. Stop only for MFA, missing permission, external approval or unavailable credentials, then return the minimal user action list plus next agent step.
17
+ Use repo tools, local app/browser sessions, CLI auth and authorized elevation. Stop only for MFA, missing permission, external approval or unavailable credentials, then return minimal user action plus next agent step.
@@ -18,7 +18,7 @@ Tiny Context Workflow Contract
18
18
  -> each slice updates canonical state and evidence
19
19
  -> derive local audit / matrix / verdict / progress / evidence views
20
20
  -> run gates
21
- -> final-gate computes product_goal_complete
21
+ -> final-gate computes product_goal_complete and blocker triage
22
22
  ```
23
23
 
24
24
  ## Workflow Identity
@@ -65,11 +65,11 @@ Superpowers remains the execution layer: prefer `superpowers:subagent-driven-dev
65
65
 
66
66
  ## Final Gate Protocol
67
67
 
68
- Final completion always runs through the Trusted Evidence Kernel, then through the completion-output resolver. Final gate, `validate-superpowers-state`, state-backed `validate-plan-acceptance` and derived completion views use the same kernel and resolver result. Superpowers verification, validators, auditor checks and generated views are useful execution checks, but they are not proof authority or completion-output authority. The AC Evidence Assertion Gate and Negative Evidence Scan Gate are enforced inside the kernel, not by trusting generated matrix or verdict text. The final gate itself runs in fixed order: load the three inputs, recompute source hashes, load task state, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, run contradiction scan, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, resolve `completion_output_status`, regenerate `derived/**` and append an event.
68
+ Final completion always runs through the Trusted Evidence Kernel, then through the completion-output resolver and blocker triage. Final gate, `validate-superpowers-state`, state-backed `validate-plan-acceptance` and derived completion views use the same kernel and resolver result. Superpowers verification, validators, auditor checks and generated views are useful execution checks, but they are not proof authority or completion-output authority. The AC Evidence Assertion Gate and Negative Evidence Scan Gate are enforced inside the kernel, not by trusting generated matrix or verdict text. The final gate itself runs in fixed order: load the three inputs, recompute source hashes, load task state, snapshot previous final/gates/meta transient bookkeeping as audit-only, resolve the current attempt, load required command specs, load command-run records, load registered EvidenceRecords, discard stale evidence, scan unregistered assertion JSON, run contradiction scan, run AC-010 bootstrap prevention, run under-specified AC checks, run Harness Drift Lock, run protected baseline guard, validate scope conflicts, recompute every AC, recompute every PI, recompute `acceptance_target_status`, recompute `product_goal_complete`, build the current candidate state, resolve candidate `completion_output_status`, regenerate current `derived/**`, scan generated output in the current candidate mode, classify blockers with `blocker_triage`, perform at most one self-recovery pass for transient bookkeeping or regenerable generated-output mismatch, write current final state and append an event.
69
69
 
70
- The final gate recomputes from current source hashes, current attempt, required command specs/runs, registered EvidenceRecordV2 records, contradiction scan, Harness Drift Lock and protected baseline state. It ignores stale passed artifacts, historical complete events, stale derived complete views, matrix/verdict/evidence-index/final-summary rows, validator passes, final cards, auditor prose, AC summary-only proof, unregistered temporary JSON and hand-written status files as proof. The completion-output resolver ignores those same surfaces as authority and emits only `accept`, `reject` or `blocked`. Newer failed commands, Playwright `.last-run.json`, `test-results/**/error-context.md`, JUnit/JSON reporter failures, negative evidence artifacts, owner DOM forbidden states, task-state false/partial values and derived/state mismatch block completion for the affected AC/layer. If historical completion conflicts with current recompute, report `Historical stale completion event detected and ignored.` and `Current recomputed product_goal_complete=false.`
70
+ The final gate recomputes from current source hashes, current attempt, required command specs/runs, registered EvidenceRecordV2 records, contradiction scan, Harness Drift Lock and protected baseline state. It ignores stale passed artifacts, historical complete events, stale derived complete views, old final/gates/meta transient findings, matrix/verdict/evidence-index/final-summary rows, validator passes, final cards, auditor prose, AC summary-only proof, unregistered temporary JSON and hand-written status files as proof. The completion-output resolver ignores those same surfaces as authority and emits only `accept`, `reject` or `blocked`. Generated-output scanning is current-candidate-driven: old `completion_output_status=blocked` or old `generated_output_mismatch=true` cannot drag a current kernel accept back to blocked, but current user-visible false completion claims still block. Newer failed commands, Playwright `.last-run.json`, `test-results/**/error-context.md`, JUnit/JSON reporter failures, negative evidence artifacts, owner DOM forbidden states, task-state false/partial values and derived/state mismatch block completion for the affected AC/layer. If historical completion conflicts with current recompute, report `Historical stale completion event detected and ignored.` and `Current recomputed product_goal_complete=false.`
71
71
 
72
- Harness Drift Lock: `product_task` is blocked when the current attempt changed Playwright specs, tests, assertion generators, AC010 helpers, evidence writers, final-gate, validator, derive, task-state reducer, this workflow Skill/protocol or related Makefile/package test targets. The output must include `harness_drift_detected`, `acceptance_target_status=blocked`, `product_goal_complete=false` and `本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。` A `harness_task` must include adversarial fixtures with expected final-gate outcomes for stale evidence, historical complete, derived contradiction, AC010 summary-only, target mismatch, API-only-for-UI, negative evidence after pass, source hash mismatch, dirty worktree mismatch, missing assertion_result, test weakening, scope leakage, missing UI/browser owner-surface proof, missing negative semantic proof and one happy path; it never proves product completion. HFC-003 is the durable false-completion regression suite: 35 committed mini workdirs plus one runner cover the Trusted Evidence Kernel, completion-output resolver, generated-output scanner, selected CLI smoke paths and one happy path. `protected-harness-baseline.json` blocks product-task changes to protected harness surfaces and requires a baseline reason plus fixtures for harness-task changes.
72
+ Harness Drift Lock: `product_task` is blocked when the current attempt changed Playwright specs, tests, assertion generators, AC010 helpers, evidence writers, final-gate, validator, derive, task-state reducer, this workflow Skill/protocol or related Makefile/package test targets. The output must include `harness_drift_detected`, `acceptance_target_status=blocked`, `product_goal_complete=false` and `本轮修改了验收工具链或测试本身,不能用被修改后的验收证明同一轮产品完成。请拆成独立 harness_task。` A `harness_task` must include adversarial fixtures with expected final-gate outcomes for stale evidence, historical complete, derived contradiction, AC010 summary-only, target mismatch, API-only-for-UI, negative evidence after pass, source hash mismatch, dirty worktree mismatch, missing assertion_result, test weakening, scope leakage, missing UI/browser owner-surface proof, missing negative semantic proof and one happy path; it never proves product completion. HFC-003 is the durable false-completion regression suite; HFC-004 is the durable final-gate blocker-triage suite for old transient self-lock, candidate-driven scanner mode, blocker categories, next actions and one-pass self-recovery. `protected-harness-baseline.json` blocks product-task changes to protected harness surfaces and requires a baseline reason plus fixtures for harness-task changes.
73
73
 
74
74
  ## Completion State Machine
75
75
 
@@ -510,24 +510,28 @@ Before final completion, the kernel order is fixed:
510
510
  1. load product-architecture-source.md, technical-realization-plan.md, acceptance-checklist.md
511
511
  2. recompute source hashes
512
512
  3. load task-state.json
513
- 4. resolve current_attempt
514
- 5. load required command specs
515
- 6. load command-run records
516
- 7. load registered EvidenceRecordV2 records
517
- 8. discard stale evidence
518
- 9. scan unregistered assertion JSON
519
- 10. contradiction scan
520
- 11. run AC-010 bootstrap prevention
521
- 12. run under-specified AC checks
522
- 13. run Harness Drift Lock
523
- 14. run protected baseline guard
524
- 15. recompute every AC
525
- 16. recompute every PI
526
- 17. recompute acceptance_target_status
527
- 18. recompute product_goal_complete
528
- 19. resolve completion_output_status
529
- 20. regenerate derived/**
530
- 21. append event
513
+ 4. snapshot previous final/gates/meta transient bookkeeping as audit-only
514
+ 5. resolve current_attempt
515
+ 6. load required command specs
516
+ 7. load command-run records
517
+ 8. load registered EvidenceRecordV2 records
518
+ 9. discard stale evidence
519
+ 10. scan unregistered assertion JSON
520
+ 11. contradiction scan
521
+ 12. run AC-010 bootstrap prevention
522
+ 13. run under-specified AC checks
523
+ 14. run Harness Drift Lock
524
+ 15. run protected baseline guard
525
+ 16. recompute every AC
526
+ 17. recompute every PI
527
+ 18. recompute acceptance_target_status
528
+ 19. recompute product_goal_complete
529
+ 20. build current candidate state
530
+ 21. resolve candidate completion_output_status
531
+ 22. regenerate current derived/**
532
+ 23. scan generated output in current candidate mode
533
+ 24. classify blocker_triage and self-recover once when allowed
534
+ 25. append event
531
535
  ```
532
536
 
533
537
  Legacy/internal compatibility may exist as:
@@ -574,11 +578,14 @@ Rules:
574
578
  6. If completion_output_status is reject or blocked, do not say Goal achieved, completed, accepted or done.
575
579
  7. A read-only audit task may end, but must say:
576
580
  Audit workflow completed; acceptance target not complete.
577
- 8. Implementation / execution Goal mode can call update_goal complete only when product_goal_complete=true and completion_output_status=accept.
581
+ 8. Failed final-gate output includes blocker_triage category and next action.
582
+ 9. Implementation / execution Goal mode can call update_goal complete only when product_goal_complete=true and completion_output_status=accept.
578
583
  ```
579
584
 
580
585
  This must stay visible in Skill and Goal objective because Codex Goal mode can otherwise confuse "audit workflow ended" with "product target accepted."
581
586
 
587
+ When final-gate does not accept, output must include `blocker_triage.category`, `blocker_triage.next_action`, whether it was self-recoverable and whether recovery was attempted. Categories distinguish product evidence failure, missing current evidence, stale or contradictory evidence, generated-output mismatch, self-recoverable generated-output mismatch, transient state bookkeeping, environment blocked, contract blocked and harness drift blocked.
588
+
582
589
  ## 15. Blocker Strategy
583
590
 
584
591
  The executor maximizes autonomous progress:
@@ -98,6 +98,12 @@ export async function runCompositeLongTaskCommand(args, options) {
98
98
  console.log(`required_user_visible_status=${result.required_user_visible_status}`);
99
99
  console.log(`exit_code=${result.exit_code}`);
100
100
  console.log(`audit_task_complete=${result.audit_task_complete}`);
101
+ if (result.blocker_triage) {
102
+ console.log(`blocker_triage_category=${result.blocker_triage.category}`);
103
+ console.log(`blocker_triage_self_recoverable=${result.blocker_triage.self_recoverable}`);
104
+ console.log(`blocker_triage_recovery_attempted=${result.blocker_triage.recovery_attempted}`);
105
+ console.log(`blocker_triage_next_action=${result.blocker_triage.next_action}`);
106
+ }
101
107
  if (result.blocked_reasons.length > 0) {
102
108
  console.log(`blocked_reasons=${result.blocked_reasons.join("; ")}`);
103
109
  }
@@ -58,15 +58,25 @@ async function applyMapping(projectRoot, mapping) {
58
58
  if (typeof rendered === "string") {
59
59
  return (await writeTextIfChanged(target, rendered)) ? [mapping.target] : [];
60
60
  }
61
- await fs.rm(target, { recursive: true, force: true });
62
61
  await ensureDir(target);
63
62
  const changed = [];
63
+ const expectedRelatives = new Set(rendered.map((item) => item.relative));
64
64
  for (const item of rendered) {
65
65
  const targetFile = path.join(target, item.relative);
66
66
  if (await writeTextIfChanged(targetFile, item.content)) {
67
67
  changed.push(`${mapping.target}/${item.relative}`);
68
68
  }
69
69
  }
70
+ for (const targetFile of await listFiles(target)) {
71
+ if (path.basename(targetFile) === ".gitkeep") {
72
+ continue;
73
+ }
74
+ const relative = path.relative(target, targetFile);
75
+ if (!expectedRelatives.has(relative)) {
76
+ await fs.rm(targetFile, { force: true });
77
+ changed.push(`${mapping.target}/${relative}`);
78
+ }
79
+ }
70
80
  return changed;
71
81
  }
72
82
  async function renderMapping(projectRoot, mapping) {
@@ -13,6 +13,8 @@ export interface CompletionOutputContract {
13
13
  audit_task_complete: boolean;
14
14
  final_gate_ran: boolean;
15
15
  generated_output_mismatch: boolean;
16
+ blocker_triage?: FinalGateBlockerTriage;
17
+ candidate_state?: FinalGateCandidateState;
16
18
  }
17
19
  export interface CompletionOutputResolveInput {
18
20
  final_gate_ran?: boolean;
@@ -35,11 +37,42 @@ export interface CompletionOutputSurface {
35
37
  surface: string;
36
38
  text: string;
37
39
  }
40
+ export type CompletionOutputSurfaceType = "user_visible_final_summary" | "final_card" | "agent_final_answer" | "generated_summary" | "machine_readable_json_status" | "derived_diagnostic_json" | "matrix_diagnostic" | "verdict_diagnostic" | "workflow_protocol_text" | "execution_binding_text" | "rule_explanation_text" | "local_audit_diagnostic" | "unknown";
41
+ export type CompletionPhraseClassification = "true_false_completion_claim" | "allowed_protocol_reserved_word" | "allowed_machine_status_field" | "allowed_diagnostic_status" | "allowed_rule_explanation";
38
42
  export interface CompletionPhraseFinding {
39
43
  surface: string;
44
+ surface_type?: CompletionOutputSurfaceType;
45
+ classification?: CompletionPhraseClassification;
40
46
  phrase: string;
41
47
  line: number;
42
48
  text: string;
49
+ self_recoverable?: boolean;
50
+ }
51
+ export interface FinalGateCandidateState {
52
+ final_gate_ran: boolean;
53
+ product_goal_complete: boolean;
54
+ acceptance_target_status: string;
55
+ completion_output_status: CompletionOutputStatus;
56
+ generated_output_mismatch: boolean;
57
+ source: "trusted_evidence_kernel";
58
+ }
59
+ export type FinalGateBlockerCategory = "none" | "product_evidence_failed" | "missing_current_evidence" | "stale_or_contradictory_evidence" | "generated_output_mismatch" | "self_recoverable_generated_output_mismatch" | "transient_state_bookkeeping" | "environment_blocked" | "contract_blocked" | "harness_drift_blocked";
60
+ export interface FinalGateBlockerTriage {
61
+ category: FinalGateBlockerCategory;
62
+ self_recoverable: boolean;
63
+ recovery_attempted: boolean;
64
+ recovery_action: string;
65
+ next_action: string;
66
+ details: string[];
67
+ blocker_count: number;
68
+ }
69
+ export interface FinalGateBlockerTriageInput {
70
+ errors: string[];
71
+ output_findings: CompletionPhraseFinding[];
72
+ previous_transient_findings?: string[];
73
+ candidate_state?: FinalGateCandidateState;
74
+ recovery_attempted?: boolean;
75
+ recovery_action?: string;
43
76
  }
44
77
  export declare function resolveCompletionOutputStatus(input: CompletionOutputResolveInput): CompletionOutputContract;
45
78
  export declare function completionOutputContractFromState(state: SuperpowersTaskState): CompletionOutputContract;
@@ -48,5 +81,11 @@ export declare function scanFalseCompletionPhrases(input: {
48
81
  completion_output_status: CompletionOutputStatus;
49
82
  surfaces: CompletionOutputSurface[] | string;
50
83
  }): CompletionPhraseFinding[];
84
+ export declare function scanFalseCompletionPhrasesDetailed(input: {
85
+ completion_output_status: CompletionOutputStatus;
86
+ surfaces: CompletionOutputSurface[] | string;
87
+ }): CompletionPhraseFinding[];
51
88
  export declare function scanGeneratedCompletionOutputSurfaces(workdir: string, contract: CompletionOutputContract): Promise<CompletionPhraseFinding[]>;
89
+ export declare function scanGeneratedCompletionOutputSurfacesDetailed(workdir: string, contract: CompletionOutputContract): Promise<CompletionPhraseFinding[]>;
52
90
  export declare function completionPhraseFindingMessages(findings: CompletionPhraseFinding[]): string[];
91
+ export declare function triageFinalGateBlockers(input: FinalGateBlockerTriageInput): FinalGateBlockerTriage;
@@ -105,7 +105,7 @@ export function completionOutputContractFromState(state) {
105
105
  const finalRecord = state.final;
106
106
  const gate = isRecord(state.gates?.final_gate) ? state.gates.final_gate : {};
107
107
  const hasStoredOutput = typeof finalRecord.completion_output_status === "string" || typeof gate.completion_output_status === "string";
108
- return resolveCompletionOutputStatus({
108
+ const contract = resolveCompletionOutputStatus({
109
109
  final_gate_ran: hasStoredOutput || isRecord(state.gates?.final_gate),
110
110
  product_goal_complete: state.final.product_goal_complete,
111
111
  acceptance_target_status: state.final.acceptance_target_status,
@@ -114,6 +114,23 @@ export function completionOutputContractFromState(state) {
114
114
  rejection_reasons: asStringArray(finalRecord.rejection_reasons ?? gate.rejection_reasons),
115
115
  generated_output_mismatch: finalRecord.generated_output_mismatch === true || gate.generated_output_mismatch === true
116
116
  });
117
+ const triage = isRecord(finalRecord.blocker_triage)
118
+ ? finalRecord.blocker_triage
119
+ : isRecord(gate.blocker_triage)
120
+ ? gate.blocker_triage
121
+ : undefined;
122
+ const candidate = isRecord(finalRecord.candidate_state)
123
+ ? finalRecord.candidate_state
124
+ : isRecord(gate.candidate_state)
125
+ ? gate.candidate_state
126
+ : undefined;
127
+ if (triage) {
128
+ contract.blocker_triage = triage;
129
+ }
130
+ if (candidate) {
131
+ contract.candidate_state = candidate;
132
+ }
133
+ return contract;
117
134
  }
118
135
  export function applyCompletionOutputContract(state, contract) {
119
136
  const finalRecord = state.final;
@@ -132,9 +149,18 @@ export function applyCompletionOutputContract(state, contract) {
132
149
  finalRecord.blocked_reasons = contract.blocked_reasons;
133
150
  finalRecord.rejection_reasons = contract.rejection_reasons;
134
151
  finalRecord.generated_output_mismatch = contract.generated_output_mismatch;
152
+ if (contract.blocker_triage) {
153
+ finalRecord.blocker_triage = contract.blocker_triage;
154
+ }
155
+ if (contract.candidate_state) {
156
+ finalRecord.candidate_state = contract.candidate_state;
157
+ }
135
158
  metaRecord.completion_output_status = contract.completion_output_status;
136
159
  }
137
160
  export function scanFalseCompletionPhrases(input) {
161
+ return scanFalseCompletionPhrasesDetailed(input);
162
+ }
163
+ export function scanFalseCompletionPhrasesDetailed(input) {
138
164
  if (input.completion_output_status === "accept") {
139
165
  return [];
140
166
  }
@@ -143,12 +169,21 @@ export function scanFalseCompletionPhrases(input) {
143
169
  for (const surface of surfaces) {
144
170
  const lines = surface.text.split(/\r?\n/);
145
171
  for (const [index, line] of lines.entries()) {
146
- if (lineAllowedForNonAccept(line)) {
172
+ const allowed = classifyAllowedCompletionLine(surface.surface, line);
173
+ if (allowed) {
147
174
  continue;
148
175
  }
149
176
  for (const item of FORBIDDEN_PHRASES) {
150
177
  if (item.pattern.test(line)) {
151
- findings.push({ surface: surface.surface, phrase: item.phrase, line: index + 1, text: line.trim() });
178
+ findings.push({
179
+ surface: surface.surface,
180
+ surface_type: classifySurfaceLine(surface.surface, line),
181
+ classification: "true_false_completion_claim",
182
+ phrase: item.phrase,
183
+ line: index + 1,
184
+ text: line.trim(),
185
+ self_recoverable: isSelfRecoverableSurface(surface.surface)
186
+ });
152
187
  break;
153
188
  }
154
189
  }
@@ -157,6 +192,9 @@ export function scanFalseCompletionPhrases(input) {
157
192
  return findings;
158
193
  }
159
194
  export async function scanGeneratedCompletionOutputSurfaces(workdir, contract) {
195
+ return scanGeneratedCompletionOutputSurfacesDetailed(workdir, contract);
196
+ }
197
+ export async function scanGeneratedCompletionOutputSurfacesDetailed(workdir, contract) {
160
198
  const surfaces = [];
161
199
  for (const relative of GENERATED_COMPLETION_SURFACES) {
162
200
  const file = path.join(workdir, ...relative.split("/"));
@@ -164,10 +202,58 @@ export async function scanGeneratedCompletionOutputSurfaces(workdir, contract) {
164
202
  surfaces.push({ surface: relative, text: await readText(file) });
165
203
  }
166
204
  }
167
- return scanFalseCompletionPhrases({ completion_output_status: contract.completion_output_status, surfaces });
205
+ return scanFalseCompletionPhrasesDetailed({ completion_output_status: contract.completion_output_status, surfaces });
168
206
  }
169
207
  export function completionPhraseFindingMessages(findings) {
170
- return findings.map((finding) => `false completion phrase in ${finding.surface}:${finding.line}: ${finding.phrase}`);
208
+ return findings.map((finding) => {
209
+ const kind = finding.classification ? ` ${finding.classification}` : "";
210
+ return `false completion phrase${kind} in ${finding.surface}:${finding.line}: ${finding.phrase}`;
211
+ });
212
+ }
213
+ export function triageFinalGateBlockers(input) {
214
+ const errors = unique(input.errors);
215
+ const findings = input.output_findings ?? [];
216
+ const previous = unique(input.previous_transient_findings ?? []);
217
+ const details = unique([...errors, ...findings.map((finding) => `${finding.surface}:${finding.line}:${finding.phrase}`), ...previous]);
218
+ const recoveryAttempted = input.recovery_attempted === true;
219
+ const recoveryAction = input.recovery_action ?? "";
220
+ if (findings.length > 0) {
221
+ const selfRecoverable = findings.every((finding) => finding.self_recoverable === true);
222
+ return {
223
+ category: selfRecoverable ? "self_recoverable_generated_output_mismatch" : "generated_output_mismatch",
224
+ self_recoverable: selfRecoverable,
225
+ recovery_attempted: recoveryAttempted,
226
+ recovery_action: recoveryAction,
227
+ next_action: selfRecoverable
228
+ ? "regenerate derived generated-output surfaces and rerun final-gate once"
229
+ : "remove or regenerate the user-visible false completion wording before final-gate can accept",
230
+ details,
231
+ blocker_count: findings.length
232
+ };
233
+ }
234
+ const text = errors.join("\n");
235
+ if (/harness_drift|protected_baseline|product task modified|harness task missing/i.test(text)) {
236
+ return blocker("harness_drift_blocked", false, recoveryAttempted, recoveryAction, "split harness changes into a harness_task with adversarial fixtures before proving product completion", details);
237
+ }
238
+ if (/source file is missing|source_unreadable|scope_conflict_requires_decision|three[- ]input|Product \/ Plan \/ Checklist|Context Delta coverage is unresolved/i.test(text)) {
239
+ return blocker("contract_blocked", false, recoveryAttempted, recoveryAction, "clarify or restore the source contract before rerunning final-gate", details);
240
+ }
241
+ if (/required command not_run|command not_run|browser unavailable|playwright unavailable|dependency unavailable|environment_unknown|required_validator_unavailable|permission|MFA/i.test(text)) {
242
+ return blocker("environment_blocked", false, recoveryAttempted, recoveryAction, "restore the unavailable command, browser, dependency or permission and rerun final-gate", details);
243
+ }
244
+ if (/stale evidence|negative evidence|current contradiction|source hash mismatch|dirty worktree|failed_test_result_artifact|owner_dom_forbidden_state|playwright_last_run_failed/i.test(text)) {
245
+ return blocker("stale_or_contradictory_evidence", false, recoveryAttempted, recoveryAction, "replace stale or contradictory evidence with fresh current-attempt evidence", details);
246
+ }
247
+ if (/missing current|missing assertion result|not machine-backed|missing required proof layer|proof layer .*missing|requires all required plan items|incomplete|no evidence_ids|unknown evidence_id/i.test(text)) {
248
+ return blocker("missing_current_evidence", false, recoveryAttempted, recoveryAction, "add fresh current-attempt evidence for the missing AC, PI or proof layer", details);
249
+ }
250
+ if (previous.length > 0 && errors.length === 0) {
251
+ return blocker("transient_state_bookkeeping", true, recoveryAttempted, recoveryAction || "cleared previous transient bookkeeping before current candidate scan", "cleared previous transient bookkeeping; no user action required", details);
252
+ }
253
+ if (errors.length > 0) {
254
+ return blocker("product_evidence_failed", false, recoveryAttempted, recoveryAction, "fix the current product evidence failure and rerun final-gate", details);
255
+ }
256
+ return blocker("none", false, recoveryAttempted, recoveryAction, "no blocker remains", details);
171
257
  }
172
258
  function normalizeAcceptanceTargetStatus(value) {
173
259
  const normalized = String(value ?? "not_run").trim().toLowerCase();
@@ -182,46 +268,106 @@ function normalizeAcceptanceTargetStatus(value) {
182
268
  function isAcceptedStatus(value) {
183
269
  return value === "complete" || value === "accepted";
184
270
  }
185
- function lineAllowedForNonAccept(line) {
271
+ function classifyAllowedCompletionLine(surface, line) {
186
272
  const text = line.trim();
187
273
  if (!text) {
188
- return true;
274
+ return "allowed_rule_explanation";
189
275
  }
190
276
  if (/Audit workflow completed; acceptance target not complete\./i.test(text)) {
191
- return true;
277
+ return "allowed_rule_explanation";
192
278
  }
193
279
  if (/^Product goal complete:\s*false$/i.test(text)) {
194
- return true;
280
+ return "allowed_diagnostic_status";
195
281
  }
196
282
  if (/^(?:complete|partial|acceptance_required|missing_layer)_count:\s*\d+$/i.test(text)) {
197
- return true;
283
+ return "allowed_diagnostic_status";
198
284
  }
199
285
  if (/^-\s+[A-Z]+-\d+:\s*(?:complete|accepted|accept)\s*$/i.test(text)) {
200
- return true;
286
+ return "allowed_diagnostic_status";
201
287
  }
202
288
  const jsonField = /^"([^"]+)"\s*:\s*/.exec(text);
203
289
  if (jsonField && !/^(final_answer|final_conclusion|conclusion|summary|message|required_user_visible_status)$/i.test(jsonField[1])) {
204
- return true;
290
+ return "allowed_machine_status_field";
205
291
  }
206
292
  if (/\b(product_goal_complete|completion_output_status|acceptance_target_status|audit_task_complete)\b/i.test(text)) {
207
- return true;
293
+ return "allowed_diagnostic_status";
208
294
  }
209
- if (/["']?(overall_)?status["']?\s*:\s*["']?(complete|accepted|accept)["']?/i.test(text)) {
210
- return true;
295
+ if (isDiagnosticSurface(surface) && /["']?(overall_)?status["']?\s*:\s*["']?(complete|accepted|accept)["']?/i.test(text)) {
296
+ return "allowed_diagnostic_status";
211
297
  }
212
298
  if (/diagnostic|row-level|row status|not[_ -]?in[_ -]?scope/i.test(text)) {
213
- return true;
299
+ return "allowed_diagnostic_status";
214
300
  }
215
301
  if (/\b(do not|must not|cannot|never|unless|only when|forbid|forbidden|invalid|false[- ]completion|does not mean|cannot authorize|cannot imply)\b/i.test(text)) {
216
- return true;
302
+ return "allowed_rule_explanation";
217
303
  }
218
304
  if (/\bnot\s+(?:complete|completed|accepted|accept|done|successful)\b/i.test(text)) {
219
- return true;
305
+ return "allowed_rule_explanation";
220
306
  }
221
307
  if (/不得|不能|禁止|仅当|不是|不等于/.test(text)) {
222
- return true;
308
+ return "allowed_rule_explanation";
223
309
  }
224
- return false;
310
+ return undefined;
311
+ }
312
+ function classifySurfaceLine(surface, line) {
313
+ const normalized = surface.split(path.sep).join("/");
314
+ if (/^Final answer:|Goal achieved|ready to merge|implementation complete/i.test(line)) {
315
+ return "agent_final_answer";
316
+ }
317
+ if (normalized.endsWith("derived/final-summary.md")) {
318
+ return "user_visible_final_summary";
319
+ }
320
+ if (normalized.endsWith("derived/final-card.md")) {
321
+ return "final_card";
322
+ }
323
+ if (normalized.endsWith("goal-objective.txt")) {
324
+ return "agent_final_answer";
325
+ }
326
+ if (normalized.endsWith("execution-binding.md")) {
327
+ return "execution_binding_text";
328
+ }
329
+ if (normalized.endsWith("workflow-protocol.md")) {
330
+ return "workflow_protocol_text";
331
+ }
332
+ if (/final-acceptance-verdict\.json$/.test(normalized)) {
333
+ return "verdict_diagnostic";
334
+ }
335
+ if (/plan-conformance-matrix\.json$/.test(normalized)) {
336
+ return "matrix_diagnostic";
337
+ }
338
+ if (/\.json$/.test(normalized)) {
339
+ return "machine_readable_json_status";
340
+ }
341
+ if (/local-audit/.test(normalized)) {
342
+ return "local_audit_diagnostic";
343
+ }
344
+ if (/derived\//.test(normalized)) {
345
+ return "generated_summary";
346
+ }
347
+ return "unknown";
348
+ }
349
+ function isSelfRecoverableSurface(surface) {
350
+ const normalized = surface.split(path.sep).join("/");
351
+ return /^derived\/(?:final-summary|final-card|final-acceptance-verdict|plan-conformance-matrix|local-audit)\.(?:md|json)$/.test(normalized);
352
+ }
353
+ function isDiagnosticSurface(surface) {
354
+ const type = classifySurfaceLine(surface, "");
355
+ return (type === "machine_readable_json_status" ||
356
+ type === "derived_diagnostic_json" ||
357
+ type === "matrix_diagnostic" ||
358
+ type === "verdict_diagnostic" ||
359
+ type === "local_audit_diagnostic");
360
+ }
361
+ function blocker(category, selfRecoverable, recoveryAttempted, recoveryAction, nextAction, details) {
362
+ return {
363
+ category,
364
+ self_recoverable: selfRecoverable,
365
+ recovery_attempted: recoveryAttempted,
366
+ recovery_action: recoveryAction,
367
+ next_action: nextAction,
368
+ details,
369
+ blocker_count: category === "none" ? 0 : Math.max(1, details.length)
370
+ };
225
371
  }
226
372
  function unique(values) {
227
373
  return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
@@ -359,6 +359,16 @@ Technical Context Delta: ${state.context.technical_context_delta}
359
359
  function finalSummaryMarkdown(state, verdict, contract) {
360
360
  const reasons = contract.completion_output_status === "blocked" ? contract.blocked_reasons : contract.rejection_reasons;
361
361
  const reasonBlock = reasons.length > 0 ? reasons.map((reason) => `- ${reason}`).join("\n") : "- none";
362
+ const triage = contract.blocker_triage;
363
+ const triageBlock = triage
364
+ ? `blocker_triage_category: ${triage.category}
365
+ blocker_triage_self_recoverable: ${triage.self_recoverable}
366
+ blocker_triage_recovery_attempted: ${triage.recovery_attempted}
367
+ blocker_triage_next_action: ${triage.next_action}`
368
+ : `blocker_triage_category: none
369
+ blocker_triage_self_recoverable: false
370
+ blocker_triage_recovery_attempted: false
371
+ blocker_triage_next_action: no blocker remains`;
362
372
  const auditLine = contract.completion_output_status === "accept"
363
373
  ? "Final-gate accepted the current attempt."
364
374
  : "Audit workflow completed; acceptance target not complete.";
@@ -371,6 +381,7 @@ completion_output_status: ${contract.completion_output_status}
371
381
  final_answer_allowed: ${contract.final_answer_allowed}
372
382
  required_user_visible_status: ${contract.required_user_visible_status}
373
383
  exit_code: ${contract.exit_code}
384
+ ${triageBlock}
374
385
 
375
386
  Final answer: ${contract.final_answer}
376
387
 
@@ -1,6 +1,16 @@
1
1
  export function renderFinalCard(contract, state) {
2
2
  const reasons = contract.completion_output_status === "blocked" ? contract.blocked_reasons : contract.rejection_reasons;
3
3
  const reasonBlock = reasons.length > 0 ? reasons.map((reason) => `- ${reason}`).join("\n") : "- none";
4
+ const triage = contract.blocker_triage;
5
+ const triageBlock = triage
6
+ ? `blocker_triage_category: ${triage.category}
7
+ blocker_triage_self_recoverable: ${triage.self_recoverable}
8
+ blocker_triage_recovery_attempted: ${triage.recovery_attempted}
9
+ blocker_triage_next_action: ${triage.next_action}`
10
+ : `blocker_triage_category: none
11
+ blocker_triage_self_recoverable: false
12
+ blocker_triage_recovery_attempted: false
13
+ blocker_triage_next_action: no blocker remains`;
4
14
  const gate = contract.completion_output_status === "accept" ? "Final answer: accept" : `Final answer: ${contract.completion_output_status}`;
5
15
  const auditLine = contract.completion_output_status === "accept"
6
16
  ? "Final-gate accepted the current attempt."
@@ -15,6 +25,7 @@ exit_code: ${contract.exit_code}
15
25
  product_goal_complete: ${contract.product_goal_complete}
16
26
  acceptance_target_status: ${contract.acceptance_target_status}
17
27
  audit_task_complete: ${state.final.audit_task_complete}
28
+ ${triageBlock}
18
29
 
19
30
  ${auditLine}
20
31
 
@@ -2,7 +2,7 @@ import { appendSuperpowersEvent } from "./superpowers-task-events.js";
2
2
  import { deriveSuperpowersArtifacts } from "./superpowers-task-derive.js";
3
3
  import { validatePlanAcceptance } from "./plan-acceptance-validator.js";
4
4
  import { loadSuperpowersState, saveSuperpowersState } from "./superpowers-task-state.js";
5
- import { applyCompletionOutputContract, completionPhraseFindingMessages, resolveCompletionOutputStatus, scanGeneratedCompletionOutputSurfaces } from "./superpowers-task-completion-output.js";
5
+ import { applyCompletionOutputContract, completionPhraseFindingMessages, resolveCompletionOutputStatus, scanGeneratedCompletionOutputSurfacesDetailed, triageFinalGateBlockers } from "./superpowers-task-completion-output.js";
6
6
  import { applyTrustedEvidenceKernelResult, evaluateTrustedEvidenceKernel } from "./superpowers-task-evidence-kernel.js";
7
7
  import { isRecord } from "./superpowers-task-state-schema.js";
8
8
  import { validateSuperpowersState } from "./superpowers-task-validator.js";
@@ -26,10 +26,28 @@ export async function runEpochGate(workdir, epochId) {
26
26
  return { passed: true, messages: ["epoch derived artifacts refreshed"] };
27
27
  }
28
28
  export async function runFinalGate(workdir) {
29
+ return runFinalGateOnce(workdir, { recoveryAttempted: false, recoveryAction: "" });
30
+ }
31
+ async function runFinalGateOnce(workdir, options) {
29
32
  const state = await loadSuperpowersState(workdir);
33
+ const previousTransientFindings = previousTransientBookkeepingFindings(state);
30
34
  const kernel = await evaluateTrustedEvidenceKernel(workdir, state);
31
35
  applyTrustedEvidenceKernelResult(state, kernel);
32
36
  state.gates.validator = { status: "not_run", kernel: "trusted_evidence_kernel" };
37
+ const candidateContract = resolveCompletionOutputStatus({
38
+ final_gate_ran: true,
39
+ product_goal_complete: kernel.product_goal_complete && kernel.errors.length === 0,
40
+ acceptance_target_status: kernel.product_goal_complete && kernel.errors.length === 0 ? "complete" : kernel.acceptance_target_status,
41
+ audit_task_complete: true,
42
+ validator_errors: kernel.errors,
43
+ rejection_reasons: kernel.product_goal_complete ? [] : kernel.errors.slice(0, 12)
44
+ });
45
+ const candidateState = candidateStateFromContract(candidateContract);
46
+ candidateContract.candidate_state = candidateState;
47
+ applyCompletionOutputContract(state, candidateContract);
48
+ state.final.completion_basis = candidateContract.product_goal_complete
49
+ ? ["trusted_evidence_kernel", "current_attempt_evidence", "negative_evidence_scan_passed", "harness_drift_lock_passed"]
50
+ : [];
33
51
  await saveSuperpowersState(workdir, state);
34
52
  await deriveSuperpowersArtifacts(workdir);
35
53
  const report = await validateSuperpowersState(workdir, [workdir]);
@@ -48,6 +66,7 @@ export async function runFinalGate(workdir) {
48
66
  acceptance_validator_errors: acceptanceReport.errors,
49
67
  rejection_reasons: complete ? [] : nextRequiredActions
50
68
  });
69
+ contract.candidate_state = candidateState;
51
70
  applyCompletionOutputContract(latest, contract);
52
71
  latest.final.completion_basis = complete
53
72
  ? ["trusted_evidence_kernel", "current_attempt_evidence", "negative_evidence_scan_passed", "harness_drift_lock_passed"]
@@ -72,14 +91,36 @@ export async function runFinalGate(workdir) {
72
91
  exit_code: contract.exit_code,
73
92
  blocked_reasons: contract.blocked_reasons,
74
93
  rejection_reasons: contract.rejection_reasons,
75
- generated_output_mismatch: contract.generated_output_mismatch
94
+ generated_output_mismatch: contract.generated_output_mismatch,
95
+ candidate_state: candidateState,
96
+ previous_bookkeeping_snapshot: previousTransientFindings
76
97
  };
77
98
  await saveSuperpowersState(workdir, latest);
78
99
  await deriveSuperpowersArtifacts(workdir);
79
- const outputFindings = await scanGeneratedCompletionOutputSurfaces(workdir, contract);
100
+ const outputFindings = await scanGeneratedCompletionOutputSurfacesDetailed(workdir, contract);
101
+ let triage = triageFinalGateBlockers({
102
+ errors,
103
+ output_findings: outputFindings,
104
+ previous_transient_findings: previousTransientFindings,
105
+ candidate_state: candidateState,
106
+ recovery_attempted: options.recoveryAttempted || previousTransientFindings.length > 0,
107
+ recovery_action: options.recoveryAction || (previousTransientFindings.length > 0 ? "cleared previous transient bookkeeping" : "")
108
+ });
109
+ if (outputFindings.length > 0 && triage.self_recoverable && !options.recoveryAttempted) {
110
+ await deriveSuperpowersArtifacts(workdir);
111
+ return runFinalGateOnce(workdir, { recoveryAttempted: true, recoveryAction: "regenerated_derived_outputs" });
112
+ }
80
113
  if (outputFindings.length > 0) {
81
114
  errors = [...new Set([...errors, ...completionPhraseFindingMessages(outputFindings)])];
82
115
  complete = false;
116
+ triage = triageFinalGateBlockers({
117
+ errors,
118
+ output_findings: outputFindings,
119
+ previous_transient_findings: previousTransientFindings,
120
+ candidate_state: candidateState,
121
+ recovery_attempted: options.recoveryAttempted,
122
+ recovery_action: options.recoveryAction
123
+ });
83
124
  contract = resolveCompletionOutputStatus({
84
125
  final_gate_ran: true,
85
126
  product_goal_complete: false,
@@ -88,6 +129,8 @@ export async function runFinalGate(workdir) {
88
129
  validator_errors: errors,
89
130
  generated_output_mismatch: true
90
131
  });
132
+ contract.candidate_state = candidateState;
133
+ contract.blocker_triage = triage;
91
134
  const blockedLatest = await loadSuperpowersState(workdir);
92
135
  applyCompletionOutputContract(blockedLatest, contract);
93
136
  blockedLatest.final.completion_basis = [];
@@ -105,17 +148,54 @@ export async function runFinalGate(workdir) {
105
148
  blocked_reasons: contract.blocked_reasons,
106
149
  rejection_reasons: contract.rejection_reasons,
107
150
  generated_output_mismatch: contract.generated_output_mismatch,
108
- false_completion_phrase_findings: outputFindings
151
+ false_completion_phrase_findings: outputFindings,
152
+ candidate_state: candidateState,
153
+ blocker_triage: triage,
154
+ previous_bookkeeping_snapshot: previousTransientFindings
109
155
  };
110
156
  blockedLatest.final.false_completion_phrase_findings = outputFindings;
111
157
  await saveSuperpowersState(workdir, blockedLatest);
112
158
  await deriveSuperpowersArtifacts(workdir);
113
159
  }
160
+ else {
161
+ if (triage.category === "environment_blocked" || triage.category === "contract_blocked" || triage.category === "harness_drift_blocked") {
162
+ contract = resolveCompletionOutputStatus({
163
+ final_gate_ran: true,
164
+ product_goal_complete: false,
165
+ acceptance_target_status: "blocked",
166
+ audit_task_complete: true,
167
+ validator_errors: errors,
168
+ blocked_reasons: [triage.category],
169
+ rejection_reasons: []
170
+ });
171
+ contract.candidate_state = candidateState;
172
+ }
173
+ contract.blocker_triage = triage;
174
+ const triagedLatest = await loadSuperpowersState(workdir);
175
+ applyCompletionOutputContract(triagedLatest, contract);
176
+ triagedLatest.final.next_required_actions = contract.completion_output_status === "accept" ? [] : nextActionsForErrors(errors);
177
+ triagedLatest.gates.final_gate = {
178
+ ...(isRecord(triagedLatest.gates.final_gate) ? triagedLatest.gates.final_gate : {}),
179
+ completion_output_status: contract.completion_output_status,
180
+ final_answer_allowed: contract.final_answer_allowed,
181
+ required_user_visible_status: contract.required_user_visible_status,
182
+ exit_code: contract.exit_code,
183
+ blocked_reasons: contract.blocked_reasons,
184
+ rejection_reasons: contract.rejection_reasons,
185
+ generated_output_mismatch: contract.generated_output_mismatch,
186
+ candidate_state: candidateState,
187
+ blocker_triage: triage,
188
+ previous_bookkeeping_snapshot: previousTransientFindings
189
+ };
190
+ await saveSuperpowersState(workdir, triagedLatest);
191
+ await deriveSuperpowersArtifacts(workdir);
192
+ }
114
193
  await appendSuperpowersEvent(workdir, "final_gate", {
115
194
  product_goal_complete: contract.product_goal_complete,
116
- completion_output_status: contract.completion_output_status
195
+ completion_output_status: contract.completion_output_status,
196
+ blocker_triage: contract.blocker_triage
117
197
  });
118
- return { ...contract, errors };
198
+ return { ...contract, blocker_triage: contract.blocker_triage ?? triage, errors };
119
199
  }
120
200
  function acceptanceStatusForErrors(errors, kernel) {
121
201
  const text = errors.join("\n");
@@ -153,3 +233,35 @@ function nextActionsForErrors(errors) {
153
233
  return error;
154
234
  });
155
235
  }
236
+ function candidateStateFromContract(contract) {
237
+ return {
238
+ final_gate_ran: contract.final_gate_ran,
239
+ product_goal_complete: contract.product_goal_complete,
240
+ acceptance_target_status: contract.acceptance_target_status,
241
+ completion_output_status: contract.completion_output_status,
242
+ generated_output_mismatch: false,
243
+ source: "trusted_evidence_kernel"
244
+ };
245
+ }
246
+ function previousTransientBookkeepingFindings(state) {
247
+ const findings = [];
248
+ const finalRecord = state.final;
249
+ const metaRecord = state.meta;
250
+ const gate = isRecord(state.gates?.final_gate) ? state.gates.final_gate : {};
251
+ collectTransient(findings, "final", finalRecord);
252
+ collectTransient(findings, "meta", metaRecord);
253
+ collectTransient(findings, "gates.final_gate", gate);
254
+ return [...new Set(findings)];
255
+ }
256
+ function collectTransient(findings, label, record) {
257
+ const status = typeof record.completion_output_status === "string" ? record.completion_output_status : "";
258
+ if (status === "blocked" || status === "reject") {
259
+ findings.push(`${label}.completion_output_status=${status}`);
260
+ }
261
+ if (record.generated_output_mismatch === true) {
262
+ findings.push(`${label}.generated_output_mismatch=true`);
263
+ }
264
+ if (Array.isArray(record.false_completion_phrase_findings) && record.false_completion_phrase_findings.length > 0) {
265
+ findings.push(`${label}.false_completion_phrase_findings=${record.false_completion_phrase_findings.length}`);
266
+ }
267
+ }
@@ -77,6 +77,24 @@ export type SuperpowersPlanDeliveryScope = "system_capability_build" | "represen
77
77
  export type SuperpowersAcceptanceScope = "system_capability_build" | "representative_sample_validation" | "full_population_operation" | "full_population_not_required";
78
78
  export type SuperpowersScopeFitDecision = "fit_for_three_inputs" | "selected_from_split" | "blocked_for_decision" | "";
79
79
  export type CompletionOutputStatus = "accept" | "reject" | "blocked";
80
+ export type FinalGateBlockerCategory = "none" | "product_evidence_failed" | "missing_current_evidence" | "stale_or_contradictory_evidence" | "generated_output_mismatch" | "self_recoverable_generated_output_mismatch" | "transient_state_bookkeeping" | "environment_blocked" | "contract_blocked" | "harness_drift_blocked";
81
+ export interface FinalGateCandidateStateRecord {
82
+ final_gate_ran: boolean;
83
+ product_goal_complete: boolean;
84
+ acceptance_target_status: string;
85
+ completion_output_status: CompletionOutputStatus;
86
+ generated_output_mismatch: boolean;
87
+ source: string;
88
+ }
89
+ export interface FinalGateBlockerTriageRecord {
90
+ category: FinalGateBlockerCategory;
91
+ self_recoverable: boolean;
92
+ recovery_attempted: boolean;
93
+ recovery_action: string;
94
+ next_action: string;
95
+ details: string[];
96
+ blocker_count: number;
97
+ }
80
98
  export interface SuperpowersTaskState {
81
99
  meta: {
82
100
  task_id: string;
@@ -127,6 +145,8 @@ export interface SuperpowersTaskState {
127
145
  rejection_reasons?: string[];
128
146
  generated_output_mismatch?: boolean;
129
147
  false_completion_phrase_findings?: unknown[];
148
+ blocker_triage?: FinalGateBlockerTriageRecord;
149
+ candidate_state?: FinalGateCandidateStateRecord;
130
150
  completion_basis: string[];
131
151
  next_required_actions?: string[];
132
152
  };
@@ -48,14 +48,14 @@ export async function validateSuperpowersState(projectRoot, args = []) {
48
48
  validateAuditor(state, errors);
49
49
  validateFinalCompletion(state, errors);
50
50
  errors.push(...(await derivedMatchesState(targetDir, state)));
51
- await validateCompletionOutputConsistency(targetDir, state, errors);
51
+ await validateCompletionOutputConsistency(targetDir, state, errors, info);
52
52
  info.push(`checked superpowers task state ${repoRelative(projectRoot, targetDir)} plan_items=${Object.keys(state.graph?.plan_items ?? {}).length} acs=${Object.keys(state.graph?.acceptance_criteria ?? {}).length} evidence=${state.evidence?.length ?? 0}`);
53
53
  if (errors.length === 0) {
54
54
  info.push("Superpowers task state validation passed");
55
55
  }
56
56
  return { info, warnings, hygiene, errors };
57
57
  }
58
- async function validateCompletionOutputConsistency(workdir, state, errors) {
58
+ async function validateCompletionOutputConsistency(workdir, state, errors, info) {
59
59
  const contract = completionOutputContractFromState(state);
60
60
  const finalRecord = state.final;
61
61
  const gate = isRecord(state.gates?.final_gate) ? state.gates.final_gate : {};
@@ -75,6 +75,9 @@ async function validateCompletionOutputConsistency(workdir, state, errors) {
75
75
  if (finalRecord.exit_code !== undefined && finalRecord.exit_code !== contract.exit_code) {
76
76
  errors.push(`completion output exit_code mismatch: expected ${contract.exit_code}, found ${finalRecord.exit_code}`);
77
77
  }
78
+ if (contract.blocker_triage) {
79
+ info.push(`blocker_triage category=${contract.blocker_triage.category} self_recoverable=${contract.blocker_triage.self_recoverable} next_action=${contract.blocker_triage.next_action}`);
80
+ }
78
81
  errors.push(...completionPhraseFindingMessages(await scanGeneratedCompletionOutputSurfaces(workdir, contract)));
79
82
  await validateMarkdownCompletionStatus(workdir, contract.completion_output_status, errors);
80
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-tiny-context-harness",
3
- "version": "0.2.84",
3
+ "version": "0.2.85",
4
4
  "description": "Minimal project memory and validation harness for AI coding agents.",
5
5
  "license": "MIT",
6
6
  "author": "Seven128",