project-tiny-context-harness 0.2.81 → 0.2.82

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
@@ -100,6 +100,8 @@ The three inputs also carry capability-first delivery boundaries. Product / Arch
100
100
 
101
101
  `ty-context composite-long-task compile` uses a strict heading-based grammar for that packet. Product / Architecture Source is one document-level object with fixed fields. Technical Realization Plan items are definitions only when written as Markdown headings such as `## PI-001: ...`; Acceptance Checklist items are definitions only when written as headings such as `## AC-001: ...`. Fields inside those sections must use fixed `key: value`, indented-list or `key: |` syntax. Plain prose, tables, mapping previews and ordinary lists that mention `PI-001` or `AC-001` are references, not definitions; old list-style definitions such as `- PI-001: ...` followed by delivery fields now fail at compile time with file and line guidance.
102
102
 
103
+ Strict V2 packets also require canonical Product / PI / AC field groups. Product Source carries Scope Fit and owner-boundary fields such as `scope_fit_decision`, `selected_scope_fit_slice`, `owner_boundary`, `primary_capability_path`, `non_completing_outcomes` and `assertion_policy`; PI items carry owner, trigger, state-transition, observable-result and assertion-support fields; ACs carry `assertion_command`, `assertion_artifacts`, `positive_assertions`, `negative_assertions`, `machine_blocking`, `invalid_completion_signals` and `assertion_result_required`. Unknown, duplicate, table or missing canonical fields fail compile. 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`; aliases such as `runtime`, `browser`, `api`, `data` and `security` compile to the canonical names, and `code` cannot complete a machine-backed AC by itself. The generated evidence index is available as both `derived/evidence-index.md` and `derived/evidence-index.json`.
104
+
103
105
  For non-trivial Superpowers-backed slices, the workflow protocol requires a structured `slice-delta.json`. The executor applies it with `ty-context composite-long-task apply-slice-delta <workdir> <slice-delta.json>`, then runs `ty-context composite-long-task derive` and `ty-context composite-long-task slice-gate`. Each delta records touched plan items/ACs, code changes, closed and remaining proof layers, blockers, cleanup assertions, `progress_value` and canonical evidence records with `proves`, `does_not_prove`, freshness, redaction, reviewability, command exit code when applicable, assertion result and negative evidence scan. Default slice guidance is to group 2-4 strongly related missing layers that share an AC, runtime scenario, proof environment or verification path, while single-gap slices are reserved for blockers, contradictions or small metadata cleanup. The protocol also asks executors to classify missing layers, reuse DB/API/Browser environments only with unique proof prefixes and cleanup assertions, and run a stale/overclaim scan after deriving artifacts.
104
106
 
105
107
  The generated Superpowers prompt uses Slice Gate / Epoch Gate / Final Gate cadence instead of running a full final gate after every slice. Progress Accounting tracks AC acceptance completion, engineering implementation progress, runtime/proof progress, system capability progress, representative sample progress, real object coverage, full population operation progress, artifact budget, proof-layer milestone status and workflow overhead in state and generated `derived/progress-ledger.*`. Workflow overhead backpressure asks executors to batch shared provider/browser/runtime/security epoch proof environments, prune stale artifacts and choose the Next 3-5 high-value clusters that close the most blocking AC/proof-layer gaps.
@@ -163,7 +165,7 @@ npm ci
163
165
  npm run smoke:quickstart
164
166
  npm run preview:pack
165
167
  cd /path/to/your/test-repo
166
- npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.81.tgz
168
+ npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.82.tgz
167
169
  npx --no-install ty-context init --adopt
168
170
  make validate-context
169
171
  ```
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.81.tgz
97
+ npm install -D /path/to/project-tiny-context-harness/tmp/ty-context/source-preview/package/project-tiny-context-harness-0.2.82.tgz
98
98
  npx --no-install ty-context init --adopt
99
99
  make validate-context
100
100
  ```
@@ -144,6 +144,8 @@ The three inputs also carry capability-first delivery boundaries. Product / Arch
144
144
 
145
145
  `ty-context composite-long-task compile` uses a strict heading-based grammar for that packet. Product / Architecture Source is one document-level object with fixed fields. Technical Realization Plan items are definitions only when written as Markdown headings such as `## PI-001: ...`; Acceptance Checklist items are definitions only when written as headings such as `## AC-001: ...`. Fields inside those sections must use fixed `key: value`, indented-list or `key: |` syntax. Plain prose, tables, mapping previews and ordinary lists that mention `PI-001` or `AC-001` are references, not definitions; old list-style definitions such as `- PI-001: ...` followed by delivery fields now fail at compile time with file and line guidance.
146
146
 
147
+ Strict V2 packets also require canonical Product / PI / AC field groups. Product Source carries Scope Fit and owner-boundary fields such as `scope_fit_decision`, `selected_scope_fit_slice`, `owner_boundary`, `primary_capability_path`, `non_completing_outcomes` and `assertion_policy`; PI items carry owner, trigger, state-transition, observable-result and assertion-support fields; ACs carry `assertion_command`, `assertion_artifacts`, `positive_assertions`, `negative_assertions`, `machine_blocking`, `invalid_completion_signals` and `assertion_result_required`. Unknown, duplicate, table or missing canonical fields fail compile. 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`; aliases such as `runtime`, `browser`, `api`, `data` and `security` compile to the canonical names, and `code` cannot complete a machine-backed AC by itself. The generated evidence index is available as both `derived/evidence-index.md` and `derived/evidence-index.json`.
148
+
147
149
  For non-trivial Superpowers-backed slices, the workflow protocol requires a structured `slice-delta.json`. The executor applies it with `ty-context composite-long-task apply-slice-delta <workdir> <slice-delta.json>`, then runs `ty-context composite-long-task derive` and `ty-context composite-long-task slice-gate`. Each delta records touched plan items/ACs, code changes, closed and remaining proof layers, blockers, cleanup assertions, `progress_value` and canonical evidence records with `proves`, `does_not_prove`, freshness, redaction, reviewability, command exit code when applicable, assertion result and negative evidence scan. Default slice guidance is to group 2-4 strongly related missing layers that share an AC, runtime scenario, proof environment or verification path, while single-gap slices are reserved for blockers, contradictions or small metadata cleanup. The protocol also asks executors to classify missing layers, reuse DB/API/Browser environments only with unique proof prefixes and cleanup assertions, and run a stale/overclaim scan after deriving artifacts.
148
150
 
149
151
  The generated Superpowers prompt uses Slice Gate / Epoch Gate / Final Gate cadence instead of running a full final gate after every slice. Progress Accounting tracks AC acceptance completion, engineering implementation progress, runtime/proof progress, system capability progress, representative sample progress, real object coverage, full population operation progress, artifact budget, proof-layer milestone status and workflow overhead in state and generated `derived/progress-ledger.*`. Workflow overhead backpressure asks executors to batch shared provider/browser/runtime/security epoch proof environments, prune stale artifacts and choose the Next 3-5 high-value clusters that close the most blocking AC/proof-layer gaps.
@@ -62,6 +62,8 @@ Machine-verifiable proof layer(如 UI/browser、runtime、API/schema、data ar
62
62
 
63
63
  `ty-context composite-long-task compile` 对这三份输入使用严格的 heading-based grammar。Product / Architecture Source 是一个文档级对象,只读固定字段。Technical Realization Plan 里的 PI 只有写成 `## PI-001: ...` 这类 Markdown heading 才是正式定义;Acceptance Checklist 里的 AC 也只有 `## AC-001: ...` 这类 heading 才是正式定义。heading section 内字段必须使用固定 `key: value`、缩进列表或 `key: |` 多行块。正文、表格、mapping preview、`related_acs` / `related_plan_items` 和普通列表里出现的 `PI-001` / `AC-001` 都只是引用;旧式 `- PI-001: ...` 或 `- AC-001: ...` 后面跟字段的写法会在 compile 阶段带文件和行号报错。
64
64
 
65
+ Strict V2 输入还要求 canonical Product / PI / AC 字段组。Product Source 必须包含 `scope_fit_decision`、`selected_scope_fit_slice`、`owner_boundary`、`primary_capability_path`、`non_completing_outcomes`、`assertion_policy` 等 Scope Fit / owner 字段;PI 必须包含 owner、trigger、state transition、observable result 和 assertion support 字段;AC 必须包含 `assertion_command`、`assertion_artifacts`、`positive_assertions`、`negative_assertions`、`machine_blocking`、`invalid_completion_signals` 和 `assertion_result_required`。未知字段、重复字段、表格字段和缺失 canonical 字段都会 compile fail。Canonical proof layers 是 `code`、`api_schema`、`worker_runtime`、`data_artifact`、`integration`、`ui_browser`、`security_redaction`、`all_provider_all_runner`、`cleanup_stale_scan` 和 `test`;`runtime` / `browser` / `api` / `data` / `security` 只是 legacy alias,会编译到 canonical 名称,且 `code` 不能单独完成 machine-backed AC。Evidence index 同时生成 `derived/evidence-index.md` 和 `derived/evidence-index.json`。
66
+
65
67
  对于非平凡 slice,生成的 composite workflow prompt 要求使用结构化 `slice-delta.json`。executor 通过 `ty-context composite-long-task apply-slice-delta <workdir> <slice-delta.json>` 应用 delta,然后运行 `ty-context composite-long-task derive` 和 `ty-context composite-long-task slice-gate`。每个 delta 记录 touched plan items / ACs、code changes、closed / remaining proof layers、blockers、cleanup assertions、`progress_value`,以及带有 `proves`、`does_not_prove`、freshness、redaction 和 reviewability 的 canonical evidence records。默认 slice 策略是把同一 AC、runtime 场景、proof 环境或验证路径下的 2-4 个强相关 missing layers 合并处理;单 gap slice 只留给 blocker、contradiction 或小型 metadata cleanup。prompt 还会要求先分类 missing layer、复用 DB/API/Browser 环境时使用唯一 proof prefix 和 cleanup assertion,并在生成 derived artifacts 后做 stale/overclaim scan。
66
68
 
67
69
  当 slice 声称关闭 machine-verifiable layer 时,`slice-delta.json` 的 evidence record 还应包含 `command_exit_code`、`assertion_result`,UI/browser 等需要时还应包含 `negative_evidence_scan`;derived matrix/verdict 只展示 assertion status 和 blocker,不能替代 assertion 执行。
@@ -86,6 +86,8 @@ Strict input grammar:
86
86
  - Plain prose, lists, tables, mapping previews and `related_*` fields that mention PI/AC IDs are references, not definitions.
87
87
  - Legacy list-style definitions such as `- PI-001: ...` or `- AC-001: ...` followed by delivery fields are invalid.
88
88
 
89
+ Strict V2 canonical fields are code-owned by `superpowers-task-fields.ts` and must be present in the three sources. Product Source includes Scope Fit fields such as `scope_fit_decision`, `selected_scope_fit_slice`, `owner_boundary`, `primary_capability_path`, `non_completing_outcomes` and `assertion_policy`. PI items include owner/trigger/state/observable/assertion fields such as `owner_boundary`, `primary_capability_path`, `trigger_contract`, `state_transition_contract`, `observable_result_contract`, `assertion_support`, `required_assertion_commands` and `invalid_implementation_shortcuts`. ACs include assertion-gate fields such as `assertion_command`, `assertion_artifacts`, `positive_assertions`, `negative_assertions`, `machine_blocking`, `invalid_completion_signals` and `assertion_result_required`. Unknown fields, duplicate fields, table fields and missing canonical fields fail compile; this Skill must not infer, repair or backfill them.
90
+
89
91
  ## Authority Model
90
92
 
91
93
  - Product / Architecture Source owns intent, scope and boundaries.
@@ -171,7 +173,7 @@ Superpowers review and verification remain useful execution checks, but they can
171
173
 
172
174
  Agents must not hand-set `product_goal_complete`. Implementation / execution goals complete only when final gate computes `product_goal_complete=true`.
173
175
 
174
- For UI/browser/API/runtime/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/layer coverage, passed positive and negative assertions and no failed/stale `negative_evidence_scan`.
176
+ 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/layer coverage, passed positive and negative assertions, reviewable artifacts and no failed/stale `negative_evidence_scan` with matching target proof layers and checked invalid completion signals.
175
177
 
176
178
  If `audit_task_complete` is true but `acceptance_target_status` is not complete, report:
177
179
 
@@ -9,14 +9,14 @@ First read and obey:
9
9
  - task-state.json and generated derived/** views
10
10
 
11
11
  Persistent contract:
12
- Product / Architecture Source owns intent, scope and boundaries. Technical Realization Plan owns PI implementation and plan conformance. Acceptance Checklist owns AC completion semantics and proof layers. task-state.json is the only execution state source; events.ndjson is append-only; derived/** is generated and must not be hand-edited as authority.
12
+ Product / Architecture Source owns intent, scope, Scope Fit, owner boundaries and assertion policy. Technical Realization Plan owns PI implementation, plan conformance, trigger/state/observable contracts and required assertion commands. Acceptance Checklist owns AC completion semantics, proof layers, assertion_command/artifacts, positive/negative assertions, machine_blocking, invalid_completion_signals and assertion_result_required. task-state.json is the only execution state source; events.ndjson is append-only; derived/** is generated and must not be hand-edited as authority.
13
13
 
14
14
  Use workflow-protocol.md to combine Tiny Context gates with official Superpowers execution. It is not business Context and must not be registered in project_context/context.toml. Do not redefine, duplicate or fork Superpowers mechanics. Prefer superpowers:subagent-driven-development when subagents are available, otherwise use superpowers:executing-plans. Use TDD for behavior gaps and superpowers:verification-before-completion before completion claims.
15
15
 
16
16
  Work in slices. Each slice must update state through slice-delta.json, canonical evidence records, derive, and slice-gate. Run epoch-gate for shared provider/browser/runtime/security proof environments. Preserve Context Delta, plan conformance, acceptance proof layers, redaction, reviewability and sample/full-population boundaries.
17
17
 
18
18
  Forbidden shortcuts:
19
- Do not mark UI/runtime/API/data/integration/test ACs complete from screenshots, final cards, validator passes, matrix/verdict rows or prose. Required machine-verifiable layers need 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.
19
+ Do not mark UI/worker/API/data/integration/test ACs complete from screenshots, final cards, validator passes, matrix/verdict rows or prose. Canonical layers are code, api_schema, worker_runtime, data_artifact, integration, ui_browser, security_redaction, all_provider_all_runner, cleanup_stale_scan and test; code cannot complete a machine-backed AC alone. Required machine-verifiable layers need 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.
20
20
  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. Manual edits under derived/** are not authority. 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.
21
21
 
22
22
  Completion:
@@ -37,11 +37,13 @@ Implementation advances through coherent slices. Each slice selects related PI /
37
37
 
38
38
  Evidence is canonical state, not prose. Every proof record enters `task-state.evidence[]` with evidence id, slice id, type, command or artifact paths, command exit code when applicable, `proves`, `does_not_prove`, freshness, redaction, reviewability / reproduction data and, for machine-verifiable layers, an `assertion_result`. Evidence must be fresh, reviewable and free of secrets, raw credentials, tokens, cookies and long raw payloads.
39
39
 
40
- Machine-verifiable layers such as `ui_browser`, `api_schema`, `runtime`, `worker_runtime`, `data_artifact`, `integration`, `security_redaction`, `test`, `all_provider_all_runner` and `cleanup_stale_scan` are not complete from descriptions, screenshots, final cards, validator passes, matrix rows or verdict rows. They require `assertion_result.schema_version=assertion-result-v1`, `assertion_result.status=passed`, assertion exit code `0`, command exit code `0` when present, target AC/layer coverage, passed positive and negative assertions and reviewable artifacts. UI/browser layers also require owner surface, route/path, user action, browser/playwright/UI assertion evidence and a passed `negative_evidence_scan`.
40
+ 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 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. Machine-verifiable layers are not complete from descriptions, screenshots, final cards, validator passes, matrix rows or verdict rows. They require `assertion_result.schema_version=assertion-result-v1`, `assertion_result.status=passed`, assertion exit code `0`, command exit code `0` when present, target AC/layer coverage, passed positive and negative assertions and reviewable artifacts. UI/browser layers also require owner surface, route/path, user action, browser/playwright/UI assertion evidence and a passed `negative_evidence_scan` with matching target proof layers and checked invalid completion signals.
41
+
42
+ Strict V2 source fields are canonical. Product Source must carry Scope Fit, owner, primary capability and assertion policy fields. PI items must carry owner boundary, primary capability path, trigger/state/observable contracts, assertion support, required assertion commands and invalid implementation shortcuts. ACs must carry assertion command, artifacts, positive/negative assertions, machine-blocking flag, invalid completion signals and assertion-result requirement. Unknown, duplicate, table or missing canonical fields block compile; the workflow must not generate, infer, rewrite or repair the Technical Realization Plan or Acceptance Checklist.
41
43
 
42
44
  ## Derived Views
43
45
 
44
- `derived/**` contains generated reading views only: local audit, plan-conformance matrix, final acceptance verdict, progress ledger, evidence index, context alignment and final summary. Matrix and verdict views may summarize `assertion_status`, blocking assertion failures and negative evidence findings, but they never replace assertion execution and never rewrite Product / Architecture Source, Technical Realization Plan, Acceptance Checklist or `task-state.json`.
46
+ `derived/**` contains generated reading views only: local audit, plan-conformance matrix, final acceptance verdict, progress ledger, evidence index (`md` and `json`), context alignment and final summary. Matrix, verdict and evidence-index views may summarize `assertion_status`, blocking assertion failures and negative evidence findings, but they never replace assertion execution and never rewrite Product / Architecture Source, Technical Realization Plan, Acceptance Checklist or `task-state.json`.
45
47
 
46
48
  ## Gates
47
49
 
@@ -306,6 +308,8 @@ does_not_prove
306
308
  freshness
307
309
  redaction
308
310
  reviewability / reproduction_steps
311
+ assertion_result for machine-verifiable layers
312
+ negative_evidence_scan with target_proof_layers where invalid completion signals must be ruled out
309
313
  ```
310
314
 
311
315
  `proves` and `does_not_prove` are both required because evidence must say what it proves and what it does not prove. This prevents samples, passing tests, screenshots, mocks or local audit text from being reused as full acceptance.
@@ -331,6 +335,7 @@ derived/local-audit.md
331
335
  derived/plan-conformance-matrix.md
332
336
  derived/final-acceptance-verdict.md
333
337
  derived/progress-ledger.md
338
+ derived/evidence-index.json
334
339
  derived/evidence-index.md
335
340
  derived/context-alignment.md
336
341
  derived/final-summary.md
@@ -1,3 +1,4 @@
1
+ import { normalizeProofLayerId } from "./superpowers-task-fields.js";
1
2
  import { isRecord } from "./superpowers-task-state-schema.js";
2
3
  export function normalizeAssertionResult(value) {
3
4
  if (!isRecord(value)) {
@@ -9,7 +10,7 @@ export function normalizeAssertionResult(value) {
9
10
  runner: String(value.runner ?? ""),
10
11
  exit_code: numberValue(value.exit_code),
11
12
  target_ac_ids: stringArray(value.target_ac_ids),
12
- target_proof_layers: stringArray(value.target_proof_layers),
13
+ target_proof_layers: stringArray(value.target_proof_layers).map(normalizeProofLayerId),
13
14
  owner_surface: value.owner_surface === undefined ? undefined : String(value.owner_surface),
14
15
  route: value.route === undefined ? undefined : String(value.route),
15
16
  action: value.action === undefined ? undefined : String(value.action),
@@ -26,6 +27,8 @@ export function normalizeNegativeEvidenceScan(value) {
26
27
  schema_version: String(value.schema_version ?? ""),
27
28
  status: String(value.status ?? ""),
28
29
  target_ac_ids: stringArray(value.target_ac_ids),
30
+ target_proof_layers: stringArray(value.target_proof_layers).map(normalizeProofLayerId),
31
+ invalid_completion_signals_checked: stringArray(value.invalid_completion_signals_checked),
29
32
  owner_surface: value.owner_surface === undefined ? undefined : String(value.owner_surface),
30
33
  route: value.route === undefined ? undefined : String(value.route),
31
34
  forbidden_findings: findingArray(value.forbidden_findings),
@@ -1,16 +1,6 @@
1
+ import { MACHINE_VERIFIABLE_LAYER_NAMES, normalizeProofLayerId, normalizeProofLayerName } from "./superpowers-task-fields.js";
1
2
  export { normalizeAssertionResult, normalizeNegativeEvidenceScan } from "./superpowers-task-assertion-normalizers.js";
2
- export const MACHINE_VERIFIABLE_PROOF_LAYERS = new Set([
3
- "ui_browser",
4
- "api_schema",
5
- "runtime",
6
- "worker_runtime",
7
- "data_artifact",
8
- "integration",
9
- "security_redaction",
10
- "test",
11
- "all_provider_all_runner",
12
- "cleanup_stale_scan"
13
- ]);
3
+ export const MACHINE_VERIFIABLE_PROOF_LAYERS = new Set(MACHINE_VERIFIABLE_LAYER_NAMES);
14
4
  export const UI_BROWSER_ASSERTION_TYPES = new Set(["browser_assertion", "playwright_assertion", "ui_browser_assertion"]);
15
5
  const DEFAULT_UI_FORBIDDEN_FINAL_STATES = ["未验证", "不可用", "暂不可用", "页面无明显变化"];
16
6
  const GENERIC_INVALID_EVIDENCE_TYPE_PATTERNS = [
@@ -33,7 +23,8 @@ const GENERIC_INVALID_EVIDENCE_TYPE_PATTERNS = [
33
23
  /\bsample[-_ ]?for[-_ ]?full[-_ ]?population\b/i
34
24
  ];
35
25
  export function proofLayerName(layerId) {
36
- return layerId.includes(".") ? layerId.slice(layerId.lastIndexOf(".") + 1) : layerId;
26
+ const raw = layerId.includes(".") ? layerId.slice(layerId.lastIndexOf(".") + 1) : layerId;
27
+ return normalizeProofLayerName(raw);
37
28
  }
38
29
  export function proofLayerAcId(layerId) {
39
30
  return layerId.includes(".") ? layerId.slice(0, layerId.lastIndexOf(".")) : "";
@@ -139,7 +130,9 @@ export function evaluateAssertionEvidence(evidence, layerId) {
139
130
  if (!assertion.target_ac_ids.includes(acId)) {
140
131
  failures.push(`${label} assertion target ACs ${assertion.target_ac_ids.join(", ") || "(none)"} do not include ${acId}`);
141
132
  }
142
- if (!assertion.target_proof_layers.includes(layerId) && !assertion.target_proof_layers.includes(layerName)) {
133
+ const assertionTargetLayers = assertion.target_proof_layers.map(normalizeProofLayerId);
134
+ const normalizedLayerId = normalizeProofLayerId(layerId);
135
+ if (!assertionTargetLayers.includes(normalizedLayerId) && !assertionTargetLayers.includes(layerName)) {
143
136
  failures.push(`${label} assertion target_proof_layers ${assertion.target_proof_layers.join(", ") || "(none)"} do not include ${layerId} or ${layerName}`);
144
137
  }
145
138
  failures.push(...checkAssertions(`${label} positive assertion`, assertion.positive_assertions));
@@ -205,6 +198,14 @@ export function evaluateNegativeEvidence(evidence, layerId) {
205
198
  if (!scan.target_ac_ids.includes(acId)) {
206
199
  findings.push(`${label} negative evidence scan target ACs ${scan.target_ac_ids.join(", ") || "(none)"} do not include ${acId}`);
207
200
  }
201
+ const targetLayers = (scan.target_proof_layers ?? []).map(normalizeProofLayerId);
202
+ const normalizedLayerId = normalizeProofLayerId(layerId);
203
+ if (targetLayers.length === 0) {
204
+ findings.push(`${label} negative evidence scan target proof layers are missing; expected ${normalizedLayerId}`);
205
+ }
206
+ else if (!targetLayers.includes(normalizedLayerId) && !targetLayers.includes(proofLayerName(layerId))) {
207
+ findings.push(`${label} negative evidence scan target proof layers ${targetLayers.join(", ") || "(none)"} do not include ${normalizedLayerId}`);
208
+ }
208
209
  for (const finding of scan.forbidden_findings ?? []) {
209
210
  if (finding.status === "found") {
210
211
  findings.push(`${label} negative evidence found forbidden text ${finding.forbidden_text ?? finding.id}: ${finding.actual ?? ""}`.trim());
@@ -226,7 +227,7 @@ function invalidEvidenceReason(evidence, layerName) {
226
227
  if (genericShortcut) {
227
228
  return `matches invalid completion evidence ${genericShortcut}`;
228
229
  }
229
- if ((layerName === "runtime" || layerName === "worker_runtime" || layerName === "integration" || layerName === "ui_browser") && /\b(unit|mock|viewmodel)\b/i.test(evidence.type)) {
230
+ if ((layerName === "worker_runtime" || layerName === "integration" || layerName === "ui_browser") && /\b(unit|mock|viewmodel)\b/i.test(evidence.type)) {
230
231
  return "unit, mock or viewmodel evidence is auxiliary only for runtime, worker, integration and UI layers";
231
232
  }
232
233
  if (layerName === "ui_browser" && /\b(api|schema)\b/i.test(evidence.type)) {
@@ -235,7 +236,7 @@ function invalidEvidenceReason(evidence, layerName) {
235
236
  if (layerName === "ui_browser" && /^screenshot$/i.test(evidence.type)) {
236
237
  return "screenshot-only evidence cannot satisfy UI Path AC";
237
238
  }
238
- if ((layerName === "runtime" || layerName === "worker_runtime" || layerName === "data_artifact" || layerName === "security_redaction") && /\b(ui|browser|playwright|screenshot)\b/i.test(evidence.type)) {
239
+ if ((layerName === "worker_runtime" || layerName === "data_artifact" || layerName === "security_redaction") && /\b(ui|browser|playwright|screenshot)\b/i.test(evidence.type)) {
239
240
  return "UI-only evidence cannot satisfy runtime, data or security proof layers";
240
241
  }
241
242
  return undefined;
@@ -1,23 +1,6 @@
1
1
  import { computeScopeConflicts } from "./superpowers-task-compile.js";
2
+ import { ACCEPTANCE_SCOPES, isSelectedScopeFitSlice, PLAN_DELIVERY_SCOPES, PRODUCT_DELIVERY_SCOPES, SCOPE_FIT_DECISIONS } from "./superpowers-task-fields.js";
2
3
  import { isRecord } from "./superpowers-task-state-schema.js";
3
- const PRODUCT_DELIVERY_SCOPES = new Set([
4
- "system_capability_build",
5
- "representative_sample_validation",
6
- "full_population_operation",
7
- "mixed_scope_requires_boundary"
8
- ]);
9
- const PLAN_DELIVERY_SCOPES = new Set([
10
- "system_capability_build",
11
- "representative_sample_validation",
12
- "full_population_operation",
13
- "out_of_scope_backlog"
14
- ]);
15
- const ACCEPTANCE_SCOPES = new Set([
16
- "system_capability_build",
17
- "representative_sample_validation",
18
- "full_population_operation",
19
- "full_population_not_required"
20
- ]);
21
4
  export function validateDeliveryContract(state, errors) {
22
5
  const product = state.delivery?.product_architecture_scope;
23
6
  if (!isRecord(product)) {
@@ -29,6 +12,17 @@ export function validateDeliveryContract(state, errors) {
29
12
  requireArray(errors, "Product / Architecture Source representative_samples_validate", product.representative_samples_validate);
30
13
  requireArray(errors, "Product / Architecture Source representative_samples_do_not_validate", product.representative_samples_do_not_validate);
31
14
  requireArray(errors, "Product / Architecture Source out_of_scope_backlog", product.out_of_scope_backlog);
15
+ requireEnum(errors, "Product / Architecture Source scope_fit_decision", product.scope_fit_decision, SCOPE_FIT_DECISIONS);
16
+ requireText(errors, "Product / Architecture Source selected_scope_fit_slice", product.selected_scope_fit_slice);
17
+ if (typeof product.selected_scope_fit_slice === "string" && product.selected_scope_fit_slice && !isSelectedScopeFitSlice(product.selected_scope_fit_slice)) {
18
+ errors.push(`Product / Architecture Source selected_scope_fit_slice must be none or SFC-###: ${product.selected_scope_fit_slice}`);
19
+ }
20
+ requireText(errors, "Product / Architecture Source owner_boundary", product.owner_boundary);
21
+ requireText(errors, "Product / Architecture Source primary_capability_path", product.primary_capability_path);
22
+ requireArray(errors, "Product / Architecture Source non_completing_outcomes", product.non_completing_outcomes);
23
+ requireText(errors, "Product / Architecture Source assertion_policy", product.assertion_policy);
24
+ requireText(errors, "Product / Architecture Source source_authority", product.source_authority);
25
+ requireText(errors, "Product / Architecture Source product_goal", product.product_goal);
32
26
  }
33
27
  for (const [planId, item] of Object.entries(state.graph?.plan_items ?? {})) {
34
28
  requireEnum(errors, `${planId} delivery_scope`, item.delivery_scope, PLAN_DELIVERY_SCOPES);
@@ -36,6 +30,15 @@ export function validateDeliveryContract(state, errors) {
36
30
  requireArray(errors, `${planId} representative_samples`, item.representative_samples);
37
31
  requireText(errors, `${planId} full_population_boundary`, item.full_population_boundary);
38
32
  requireArray(errors, `${planId} non_required_population`, item.non_required_population);
33
+ requireText(errors, `${planId} owner_boundary`, item.owner_boundary);
34
+ requireText(errors, `${planId} primary_capability_path`, item.primary_capability_path);
35
+ requireText(errors, `${planId} trigger_contract`, item.trigger_contract);
36
+ requireText(errors, `${planId} state_transition_contract`, item.state_transition_contract);
37
+ requireText(errors, `${planId} observable_result_contract`, item.observable_result_contract);
38
+ requireText(errors, `${planId} assertion_support`, item.assertion_support);
39
+ requireArray(errors, `${planId} required_assertion_commands`, item.required_assertion_commands);
40
+ requireArray(errors, `${planId} invalid_implementation_shortcuts`, item.invalid_implementation_shortcuts);
41
+ requireArray(errors, `${planId} implementation_paths`, item.implementation_paths);
39
42
  }
40
43
  for (const [acId, ac] of Object.entries(state.graph?.acceptance_criteria ?? {})) {
41
44
  requireEnum(errors, `${acId} acceptance_scope`, ac.acceptance_scope, ACCEPTANCE_SCOPES);
@@ -43,6 +46,15 @@ export function validateDeliveryContract(state, errors) {
43
46
  requireArray(errors, `${acId} ac_does_not_validate`, ac.ac_does_not_validate);
44
47
  requireText(errors, `${acId} sample_boundary`, ac.sample_boundary);
45
48
  requireBoolean(errors, `${acId} full_population_required`, ac.full_population_required);
49
+ requireArray(errors, `${acId} related_plan_items`, ac.related_plan_items);
50
+ requireArray(errors, `${acId} required_proof_layers`, ac.required_proof_layers);
51
+ requireText(errors, `${acId} assertion_command`, ac.assertion_command);
52
+ requireArray(errors, `${acId} assertion_artifacts`, ac.assertion_artifacts);
53
+ requireArray(errors, `${acId} positive_assertions`, ac.positive_assertions);
54
+ requireArray(errors, `${acId} negative_assertions`, ac.negative_assertions);
55
+ requireBoolean(errors, `${acId} machine_blocking`, ac.machine_blocking);
56
+ requireArray(errors, `${acId} invalid_completion_signals`, ac.invalid_completion_signals);
57
+ requireBoolean(errors, `${acId} assertion_result_required`, ac.assertion_result_required);
46
58
  }
47
59
  }
48
60
  export function validateScopeConflicts(state, errors) {
@@ -11,3 +11,4 @@ export declare function deriveObjects(state: SuperpowersTaskState): {
11
11
  progress: Record<string, unknown>;
12
12
  };
13
13
  export declare function derivedMatchesState(workdir: string, state: SuperpowersTaskState): Promise<string[]>;
14
+ export declare function deriveEvidenceIndex(state: SuperpowersTaskState): Record<string, unknown>;
@@ -11,6 +11,7 @@ export async function deriveSuperpowersArtifacts(workdir) {
11
11
  await writeDerived(files, path.join(derivedDir, "plan-conformance-matrix.json"), stableJson(derived.matrix));
12
12
  await writeDerived(files, path.join(derivedDir, "final-acceptance-verdict.json"), stableJson(derived.verdict));
13
13
  await writeDerived(files, path.join(derivedDir, "progress-ledger.json"), stableJson(derived.progress));
14
+ await writeDerived(files, path.join(derivedDir, "evidence-index.json"), stableJson(deriveEvidenceIndex(state)));
14
15
  await writeDerived(files, path.join(derivedDir, "plan-conformance-matrix.md"), matrixMarkdown(derived.matrix));
15
16
  await writeDerived(files, path.join(derivedDir, "final-acceptance-verdict.md"), verdictMarkdown(derived.verdict));
16
17
  await writeDerived(files, path.join(derivedDir, "local-audit.md"), localAuditMarkdown(state));
@@ -38,6 +39,15 @@ export function deriveObjects(state) {
38
39
  representative_samples: item.representative_samples,
39
40
  full_population_boundary: item.full_population_boundary,
40
41
  non_required_population: item.non_required_population,
42
+ owner_boundary: item.owner_boundary,
43
+ primary_capability_path: item.primary_capability_path,
44
+ trigger_contract: item.trigger_contract,
45
+ state_transition_contract: item.state_transition_contract,
46
+ observable_result_contract: item.observable_result_contract,
47
+ assertion_support: item.assertion_support,
48
+ required_assertion_commands: item.required_assertion_commands,
49
+ invalid_implementation_shortcuts: item.invalid_implementation_shortcuts,
50
+ blockers: item.blockers ?? [],
41
51
  conformance_type: item.owner_surfaces.length > 0 ? "product_surface" : "implementation",
42
52
  owner_surface: item.owner_surfaces[0] ?? "",
43
53
  forbidden_primary_surfaces: item.forbidden_surfaces,
@@ -82,6 +92,13 @@ export function deriveObjects(state) {
82
92
  sample_boundary: ac.sample_boundary,
83
93
  full_population_required: ac.full_population_required,
84
94
  full_population_status: ac.full_population_required === true || ac.acceptance_scope === "full_population_operation" ? status : "not_in_scope",
95
+ assertion_command: ac.assertion_command ?? "",
96
+ assertion_artifacts: ac.assertion_artifacts ?? [],
97
+ positive_assertions: ac.positive_assertions ?? [],
98
+ negative_assertions: ac.negative_assertions ?? [],
99
+ machine_blocking: ac.machine_blocking ?? false,
100
+ invalid_completion_signals: ac.invalid_completion_signals ?? [],
101
+ assertion_result_required: ac.assertion_result_required ?? false,
85
102
  required_evidence: requiredLayers,
86
103
  required_proof_chain: requiredLayers,
87
104
  fresh_evidence: evidenceText(state, evidenceIds),
@@ -90,7 +107,7 @@ export function deriveObjects(state) {
90
107
  assertion_status: assertionSummary.assertion_status,
91
108
  blocking_assertion_failures: assertionSummary.blocking_assertion_failures,
92
109
  negative_evidence_findings: assertionSummary.negative_evidence_findings,
93
- invalid_completion_signals: invalidCompletionSignals,
110
+ invalid_evidence_findings: invalidCompletionSignals,
94
111
  required_next_evidence: requiredNextEvidence(missingLayers, assertionSummary),
95
112
  contradictions: [],
96
113
  context_fact_refs: [],
@@ -144,8 +161,45 @@ export async function derivedMatchesState(workdir, state) {
144
161
  const expected = deriveObjects(state);
145
162
  await assertDerivedJson(workdir, "plan-conformance-matrix", expected.matrix, errors);
146
163
  await assertDerivedJson(workdir, "final-acceptance-verdict", expected.verdict, errors);
164
+ await assertDerivedJson(workdir, "evidence-index", deriveEvidenceIndex(state), errors);
147
165
  return errors;
148
166
  }
167
+ export function deriveEvidenceIndex(state) {
168
+ const evidenceById = Object.fromEntries((state.evidence ?? []).map((evidence) => [
169
+ evidence.evidence_id,
170
+ {
171
+ evidence_id: evidence.evidence_id,
172
+ type: evidence.type,
173
+ command: evidence.command ?? "",
174
+ command_exit_code: evidence.command_exit_code,
175
+ artifact_paths: evidence.artifact_paths,
176
+ proves: evidence.proves,
177
+ does_not_prove: evidence.does_not_prove,
178
+ assertion_result: evidence.assertion_result ?? null,
179
+ negative_evidence_scan: evidence.negative_evidence_scan ?? null,
180
+ freshness: evidence.freshness,
181
+ reviewability: evidence.reviewability,
182
+ redaction: evidence.redaction
183
+ }
184
+ ]));
185
+ const proofLayers = Object.fromEntries(Object.entries(state.graph.proof_layers ?? {}).map(([layerId, layer]) => {
186
+ const evaluation = evaluateProofLayerAssertions(state, layerId);
187
+ return [
188
+ layerId,
189
+ {
190
+ layer_id: layerId,
191
+ status: layer.status,
192
+ required: layer.required,
193
+ evidence_ids: layer.evidence_ids,
194
+ assertion_status: evaluation.assertion_status,
195
+ blocking_assertion_failures: evaluation.blocking_assertion_failures,
196
+ negative_evidence_findings: evaluation.negative_evidence_findings,
197
+ evidence: layer.evidence_ids.map((evidenceId) => evidenceById[evidenceId]).filter(Boolean)
198
+ }
199
+ ];
200
+ }));
201
+ return { proof_layers: proofLayers, evidence: evidenceById };
202
+ }
149
203
  async function assertDerivedJson(workdir, basename, expected, errors) {
150
204
  const file = path.join(workdir, "derived", `${basename}.json`);
151
205
  if (!(await pathExists(file))) {
@@ -238,9 +292,16 @@ ${stableJson(progress)}
238
292
  `;
239
293
  }
240
294
  function evidenceMarkdown(state) {
295
+ const index = deriveEvidenceIndex(state);
296
+ const layers = Object.values(index.proof_layers);
241
297
  return [
242
298
  "# Evidence Index",
243
299
  "",
300
+ ...layers.map((item) => {
301
+ const evidenceIds = item.evidence_ids ?? [];
302
+ return `- ${item.layer_id}: ${item.assertion_status}; evidence ${evidenceIds.join(", ") || "(none)"}`;
303
+ }),
304
+ "",
244
305
  ...state.evidence.map((item) => `- ${item.evidence_id}: proves ${item.proves.join(", ")}; does_not_prove ${item.does_not_prove.join(", ")}`)
245
306
  ].join("\n");
246
307
  }
@@ -0,0 +1,22 @@
1
+ export declare const PRODUCT_FIELDS: readonly ["delivery_scope", "full_population_required", "representative_samples_validate", "representative_samples_do_not_validate", "out_of_scope_backlog", "scope_fit_decision", "selected_scope_fit_slice", "owner_boundary", "primary_capability_path", "non_completing_outcomes", "assertion_policy", "source_authority", "product_goal", "surface_ia_lock", "decision_lock", "context_delta", "source_to_context_coverage", "acceptance_semantics", "impact"];
2
+ export declare const PLAN_FIELDS: readonly ["delivery_scope", "capability_target", "representative_samples", "full_population_boundary", "non_required_population", "owner_surfaces", "forbidden_surfaces", "owner_boundary", "primary_capability_path", "trigger_contract", "state_transition_contract", "observable_result_contract", "assertion_support", "required_assertion_commands", "invalid_implementation_shortcuts", "implementation_paths", "required_tests", "related_acs", "requirement_ref", "decision_id", "proof_layer_ids", "api_schema_changes", "state_machine", "data_flow", "worker_runtime_behavior", "ui_ia_changes", "migration_plan", "evidence_artifacts", "explicit_no_test_scope", "non_completing_shortcuts", "substitution_policy", "drift_severity", "partial_conditions", "blockers", "context_fact_refs"];
3
+ export declare const ACCEPTANCE_FIELDS: readonly ["acceptance_scope", "ac_validates", "ac_does_not_validate", "sample_boundary", "full_population_required", "related_plan_items", "required_proof_layers", "assertion_command", "assertion_artifacts", "positive_assertions", "negative_assertions", "machine_blocking", "invalid_completion_signals", "assertion_result_required", "ac_type", "proof_chain", "verification_method", "fail_conditions", "invalid_evidence", "substitution_policy", "missing_layer_downgrade", "auditor_expectation", "out_of_scope_na_approval_source", "required_test_ids", "explicit_no_test_scope", "hard_blockers", "validates_explanation", "does_not_validate_explanation", "final_evidence_expected", "test_cases"];
4
+ export declare const PRODUCT_REQUIRED_FIELDS: readonly ["delivery_scope", "full_population_required", "representative_samples_validate", "representative_samples_do_not_validate", "out_of_scope_backlog", "scope_fit_decision", "selected_scope_fit_slice", "owner_boundary", "primary_capability_path", "non_completing_outcomes", "assertion_policy", "source_authority", "product_goal"];
5
+ export declare const PLAN_REQUIRED_FIELDS: readonly ["delivery_scope", "capability_target", "representative_samples", "full_population_boundary", "non_required_population", "owner_boundary", "primary_capability_path", "trigger_contract", "state_transition_contract", "observable_result_contract", "assertion_support", "required_assertion_commands", "invalid_implementation_shortcuts", "implementation_paths"];
6
+ export declare const ACCEPTANCE_REQUIRED_FIELDS: readonly ["acceptance_scope", "ac_validates", "ac_does_not_validate", "sample_boundary", "full_population_required", "related_plan_items", "required_proof_layers", "assertion_command", "assertion_artifacts", "positive_assertions", "negative_assertions", "machine_blocking", "invalid_completion_signals", "assertion_result_required"];
7
+ type FieldType = "array" | "boolean" | "enum" | "text";
8
+ export declare const PRODUCT_FIELD_TYPES: Record<(typeof PRODUCT_FIELDS)[number], FieldType>;
9
+ export declare const PLAN_FIELD_TYPES: Record<(typeof PLAN_FIELDS)[number], FieldType>;
10
+ export declare const ACCEPTANCE_FIELD_TYPES: Record<(typeof ACCEPTANCE_FIELDS)[number], FieldType>;
11
+ export declare const PRODUCT_DELIVERY_SCOPES: Set<string>;
12
+ export declare const PLAN_DELIVERY_SCOPES: Set<string>;
13
+ export declare const ACCEPTANCE_SCOPES: Set<string>;
14
+ export declare const SCOPE_FIT_DECISIONS: Set<string>;
15
+ export declare const CANONICAL_PROOF_LAYERS: readonly ["code", "api_schema", "worker_runtime", "data_artifact", "integration", "ui_browser", "security_redaction", "all_provider_all_runner", "cleanup_stale_scan", "test"];
16
+ export declare const LEGACY_PROOF_LAYER_ALIASES: Record<string, string>;
17
+ export declare const MACHINE_VERIFIABLE_LAYER_NAMES: Set<string>;
18
+ export declare function fieldSet(fields: readonly string[]): Set<string>;
19
+ export declare function normalizeProofLayerName(layer: string): string;
20
+ export declare function normalizeProofLayerId(layerId: string): string;
21
+ export declare function isSelectedScopeFitSlice(value: string): boolean;
22
+ export {};