project-tiny-context-harness 0.2.81 → 0.2.83

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.
Files changed (52) hide show
  1. package/README.md +11 -3
  2. package/assets/README.md +11 -3
  3. package/assets/README.zh-CN.md +9 -1
  4. package/assets/protected-harness-baseline.json +18 -0
  5. package/assets/skills/composite-long-task-workflow/SKILL.md +21 -1
  6. package/assets/skills/composite-long-task-workflow/assets/execution-binding.template.md +10 -0
  7. package/assets/skills/composite-long-task-workflow/assets/goal-objective.template.md +6 -15
  8. package/assets/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md +32 -15
  9. package/dist/commands/composite-long-task.js +45 -2
  10. package/dist/lib/superpowers-task-ac010.d.ts +6 -0
  11. package/dist/lib/superpowers-task-ac010.js +26 -0
  12. package/dist/lib/superpowers-task-assertion-normalizers.js +8 -1
  13. package/dist/lib/superpowers-task-assertions.js +35 -20
  14. package/dist/lib/superpowers-task-attempt.d.ts +4 -0
  15. package/dist/lib/superpowers-task-attempt.js +102 -0
  16. package/dist/lib/superpowers-task-command-specs.d.ts +3 -0
  17. package/dist/lib/superpowers-task-command-specs.js +52 -0
  18. package/dist/lib/superpowers-task-compile.d.ts +4 -1
  19. package/dist/lib/superpowers-task-compile.js +7 -1
  20. package/dist/lib/superpowers-task-contradictions.d.ts +6 -0
  21. package/dist/lib/superpowers-task-contradictions.js +126 -0
  22. package/dist/lib/superpowers-task-current-evidence.d.ts +3 -0
  23. package/dist/lib/superpowers-task-current-evidence.js +154 -0
  24. package/dist/lib/superpowers-task-delivery.js +30 -18
  25. package/dist/lib/superpowers-task-derive.d.ts +1 -0
  26. package/dist/lib/superpowers-task-derive.js +76 -1
  27. package/dist/lib/superpowers-task-evidence-kernel.d.ts +12 -0
  28. package/dist/lib/superpowers-task-evidence-kernel.js +351 -0
  29. package/dist/lib/superpowers-task-evidence-records.d.ts +2 -0
  30. package/dist/lib/superpowers-task-evidence-records.js +55 -0
  31. package/dist/lib/superpowers-task-evidence.d.ts +10 -0
  32. package/dist/lib/superpowers-task-evidence.js +141 -0
  33. package/dist/lib/superpowers-task-fields.d.ts +22 -0
  34. package/dist/lib/superpowers-task-fields.js +276 -0
  35. package/dist/lib/superpowers-task-gates.js +36 -24
  36. package/dist/lib/superpowers-task-harness-drift.d.ts +11 -0
  37. package/dist/lib/superpowers-task-harness-drift.js +86 -0
  38. package/dist/lib/superpowers-task-protected-baseline.d.ts +10 -0
  39. package/dist/lib/superpowers-task-protected-baseline.js +47 -0
  40. package/dist/lib/superpowers-task-source-compile.js +93 -95
  41. package/dist/lib/superpowers-task-source-parser.js +1 -3
  42. package/dist/lib/superpowers-task-state-schema.d.ts +158 -3
  43. package/dist/lib/superpowers-task-state-schema.js +23 -1
  44. package/dist/lib/superpowers-task-state-shape.d.ts +3 -0
  45. package/dist/lib/superpowers-task-state-shape.js +50 -0
  46. package/dist/lib/superpowers-task-state.js +19 -39
  47. package/dist/lib/superpowers-task-status.js +11 -1
  48. package/dist/lib/superpowers-task-under-specified.d.ts +7 -0
  49. package/dist/lib/superpowers-task-under-specified.js +61 -0
  50. package/dist/lib/superpowers-task-validator.js +11 -37
  51. package/package.json +69 -69
  52. package/source-mappings.yaml +3 -0
@@ -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,59 @@ 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
+ schema_version: evidence.schema_version ?? "",
173
+ task_attempt_id: evidence.task_attempt_id ?? "",
174
+ source_bundle_hash: evidence.source_bundle_hash ?? "",
175
+ product_source_hash: evidence.product_source_hash ?? "",
176
+ technical_plan_hash: evidence.technical_plan_hash ?? "",
177
+ acceptance_checklist_hash: evidence.acceptance_checklist_hash ?? "",
178
+ type: evidence.type,
179
+ command_spec_id: evidence.command_spec_id ?? "",
180
+ command_run_id: evidence.command_run_id ?? "",
181
+ command: evidence.command ?? "",
182
+ command_exit_code: evidence.command_exit_code,
183
+ artifact_path: evidence.artifact_path ?? "",
184
+ artifact_sha256: evidence.artifact_sha256 ?? "",
185
+ artifact_mtime: evidence.artifact_mtime ?? "",
186
+ artifact_paths: evidence.artifact_paths,
187
+ target_ac_ids: evidence.target_ac_ids ?? evidence.assertion_result?.target_ac_ids ?? [],
188
+ target_pi_ids: evidence.target_pi_ids ?? evidence.assertion_result?.target_pi_ids ?? [],
189
+ target_proof_layers: evidence.target_proof_layers ?? evidence.assertion_result?.target_proof_layers ?? [],
190
+ proves: evidence.proves,
191
+ does_not_prove: evidence.does_not_prove,
192
+ assertion_result: evidence.assertion_result ?? null,
193
+ negative_evidence_scan: evidence.negative_evidence_scan ?? null,
194
+ freshness: evidence.freshness,
195
+ reviewability: evidence.reviewability,
196
+ redaction: evidence.redaction
197
+ }
198
+ ]));
199
+ const proofLayers = Object.fromEntries(Object.entries(state.graph.proof_layers ?? {}).map(([layerId, layer]) => {
200
+ const evaluation = evaluateProofLayerAssertions(state, layerId);
201
+ return [
202
+ layerId,
203
+ {
204
+ layer_id: layerId,
205
+ status: layer.status,
206
+ required: layer.required,
207
+ evidence_ids: layer.evidence_ids,
208
+ assertion_status: evaluation.assertion_status,
209
+ blocking_assertion_failures: evaluation.blocking_assertion_failures,
210
+ negative_evidence_findings: evaluation.negative_evidence_findings,
211
+ evidence: layer.evidence_ids.map((evidenceId) => evidenceById[evidenceId]).filter(Boolean)
212
+ }
213
+ ];
214
+ }));
215
+ return { proof_layers: proofLayers, evidence: evidenceById };
216
+ }
149
217
  async function assertDerivedJson(workdir, basename, expected, errors) {
150
218
  const file = path.join(workdir, "derived", `${basename}.json`);
151
219
  if (!(await pathExists(file))) {
@@ -238,9 +306,16 @@ ${stableJson(progress)}
238
306
  `;
239
307
  }
240
308
  function evidenceMarkdown(state) {
309
+ const index = deriveEvidenceIndex(state);
310
+ const layers = Object.values(index.proof_layers);
241
311
  return [
242
312
  "# Evidence Index",
243
313
  "",
314
+ ...layers.map((item) => {
315
+ const evidenceIds = item.evidence_ids ?? [];
316
+ return `- ${item.layer_id}: ${item.assertion_status}; evidence ${evidenceIds.join(", ") || "(none)"}`;
317
+ }),
318
+ "",
244
319
  ...state.evidence.map((item) => `- ${item.evidence_id}: proves ${item.proves.join(", ")}; does_not_prove ${item.does_not_prove.join(", ")}`)
245
320
  ].join("\n");
246
321
  }
@@ -0,0 +1,12 @@
1
+ import { type SuperpowersTaskState } from "./superpowers-task-state-schema.js";
2
+ export interface TrustedEvidenceKernelResult {
3
+ product_goal_complete: boolean;
4
+ acceptance_target_status: "complete" | "partial" | "blocked" | "invalidated" | "under_specified";
5
+ errors: string[];
6
+ ac_statuses: Record<string, string>;
7
+ pi_statuses: Record<string, string>;
8
+ stale_evidence_ids: string[];
9
+ harness_task_final_verdict?: "passed" | "failed";
10
+ }
11
+ export declare function evaluateTrustedEvidenceKernel(workdir: string, providedState?: SuperpowersTaskState): Promise<TrustedEvidenceKernelResult>;
12
+ export declare function applyTrustedEvidenceKernelResult(state: SuperpowersTaskState, result: TrustedEvidenceKernelResult): void;
@@ -0,0 +1,351 @@
1
+ import { deriveRequiredCommandSpecs, requiredCommandSpecsHash } from "./superpowers-task-command-specs.js";
2
+ import { evaluateAc010Bootstrap } from "./superpowers-task-ac010.js";
3
+ import { evaluateCurrentAttemptArtifact } from "./superpowers-task-current-evidence.js";
4
+ import { scanSuperpowersContradictions } from "./superpowers-task-contradictions.js";
5
+ import { detectHarnessDrift } from "./superpowers-task-harness-drift.js";
6
+ import { evaluateProtectedBaseline } from "./superpowers-task-protected-baseline.js";
7
+ import { evaluateProofLayerAssertions, isMachineVerifiableLayer } from "./superpowers-task-assertions.js";
8
+ import { findUnderSpecifiedAcs } from "./superpowers-task-under-specified.js";
9
+ import { loadSuperpowersState, sourceRecords } from "./superpowers-task-state.js";
10
+ export async function evaluateTrustedEvidenceKernel(workdir, providedState) {
11
+ const state = providedState ?? (await loadSuperpowersState(workdir));
12
+ const errors = [];
13
+ const acStatuses = {};
14
+ const staleEvidenceIds = new Set();
15
+ const attempt = currentAttempt(state);
16
+ const currentSources = await sourceRecords(workdir);
17
+ if (!attempt) {
18
+ errors.push("missing current attempt: final-gate requires current_attempt_id with ExecutionAttempt");
19
+ }
20
+ else {
21
+ validateAttemptAgainstSources(state, attempt, currentSources, errors);
22
+ }
23
+ const expectedSpecs = deriveRequiredCommandSpecs(state);
24
+ validateRequiredSpecs(state, attempt, expectedSpecs, errors);
25
+ const underSpecified = new Map(findUnderSpecifiedAcs(state).map((item) => [item.ac_id, item.reasons]));
26
+ for (const reasons of underSpecified.values()) {
27
+ errors.push(...reasons);
28
+ }
29
+ const contradictionScan = await scanSuperpowersContradictions(workdir, state);
30
+ errors.push(...contradictionScan.errors);
31
+ const drift = detectHarnessDrift(state);
32
+ errors.push(...drift.errors);
33
+ const baseline = evaluateProtectedBaseline(state);
34
+ errors.push(...baseline.errors);
35
+ const evidenceById = new Map((state.evidence ?? []).map((evidence) => [evidence.evidence_id, evidence]));
36
+ for (const [acId, ac] of Object.entries(state.graph?.acceptance_criteria ?? {})) {
37
+ const acErrors = [];
38
+ if (underSpecified.has(acId)) {
39
+ acStatuses[acId] = "under_specified";
40
+ continue;
41
+ }
42
+ const requiredLayers = ac.required_proof_layers ?? [];
43
+ const spec = specForAc(state, expectedSpecs, acId);
44
+ if ((ac.machine_blocking === true || ac.assertion_result_required === true) && !spec) {
45
+ acErrors.push(`${acId} missing required_command_spec`);
46
+ }
47
+ if (spec) {
48
+ acErrors.push(...validateCommandRunsForSpec(state, attempt, spec));
49
+ }
50
+ for (const layerName of requiredLayers) {
51
+ const layerId = `${acId}.${layerName}`;
52
+ const layer = state.graph.proof_layers?.[layerId];
53
+ if (!layer || layer.status !== "satisfied") {
54
+ acErrors.push(`${layerId} missing current satisfied proof layer`);
55
+ continue;
56
+ }
57
+ if (isMachineVerifiableLayer(layerId)) {
58
+ const evaluation = evaluateProofLayerAssertions(state, layerId);
59
+ acErrors.push(...evaluation.blocking_assertion_failures, ...evaluation.negative_evidence_findings);
60
+ for (const evidenceId of layer.evidence_ids ?? []) {
61
+ const evidence = evidenceById.get(evidenceId);
62
+ if (!evidence) {
63
+ acErrors.push(`${layerId} references unregistered evidence ${evidenceId}`);
64
+ continue;
65
+ }
66
+ acErrors.push(...validateEvidenceAgainstSpec(state, evidence, spec, layerId));
67
+ acErrors.push(...(await evaluateCurrentAttemptArtifact(workdir, evidence, layerId)));
68
+ if (isStaleEvidenceError(acErrors)) {
69
+ staleEvidenceIds.add(evidence.evidence_id);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ errors.push(...acErrors);
75
+ acStatuses[acId] = statusForAcErrors(acErrors, requiredLayers.length);
76
+ }
77
+ const ac010 = evaluateAc010Bootstrap(state, acStatuses);
78
+ for (const acId of ac010.invalidated_ac_ids) {
79
+ acStatuses[acId] = "invalidated";
80
+ }
81
+ errors.push(...ac010.errors);
82
+ const piStatuses = recomputePlanStatuses(state, acStatuses);
83
+ const allAcsComplete = Object.keys(state.graph?.acceptance_criteria ?? {}).length > 0 &&
84
+ Object.values(acStatuses).every((status) => status === "complete" || status === "out_of_scope_NA");
85
+ const allPisComplete = Object.keys(state.graph?.plan_items ?? {}).length > 0 &&
86
+ Object.values(piStatuses).every((status) => status === "complete" || status === "out_of_scope_NA");
87
+ const uniqueErrors = unique(errors);
88
+ const productComplete = uniqueErrors.length === 0 && allAcsComplete && allPisComplete && drift.product_goal_complete !== false && baseline.product_goal_complete !== false;
89
+ return {
90
+ product_goal_complete: productComplete,
91
+ acceptance_target_status: productComplete ? "complete" : statusForGlobalErrors(uniqueErrors, acStatuses),
92
+ errors: uniqueErrors,
93
+ ac_statuses: acStatuses,
94
+ pi_statuses: piStatuses,
95
+ stale_evidence_ids: [...staleEvidenceIds],
96
+ harness_task_final_verdict: drift.harness_task_final_verdict
97
+ };
98
+ }
99
+ export function applyTrustedEvidenceKernelResult(state, result) {
100
+ for (const [acId, status] of Object.entries(result.ac_statuses)) {
101
+ const ac = state.graph.acceptance_criteria[acId];
102
+ if (ac) {
103
+ ac.status = status;
104
+ }
105
+ }
106
+ for (const [piId, status] of Object.entries(result.pi_statuses)) {
107
+ const pi = state.graph.plan_items[piId];
108
+ if (pi) {
109
+ pi.status = status;
110
+ }
111
+ }
112
+ state.final.product_goal_complete = result.product_goal_complete;
113
+ state.meta.product_goal_complete = result.product_goal_complete;
114
+ state.final.acceptance_target_status = result.acceptance_target_status;
115
+ state.meta.acceptance_target_status = result.acceptance_target_status;
116
+ state.final.audit_task_complete = true;
117
+ state.meta.audit_task_complete = true;
118
+ state.final.completion_basis = result.product_goal_complete
119
+ ? ["trusted_evidence_kernel", "current_attempt_evidence", "negative_evidence_scan_passed", "harness_drift_lock_passed"]
120
+ : [];
121
+ state.final.next_required_actions = result.product_goal_complete ? [] : result.errors.slice(0, 12);
122
+ state.gates.final_gate = {
123
+ status: result.product_goal_complete ? "pass" : result.acceptance_target_status,
124
+ kernel: "trusted_evidence_kernel",
125
+ order: [
126
+ "load_three_inputs",
127
+ "recompute_source_hashes",
128
+ "load_task_state",
129
+ "load_current_attempt",
130
+ "load_command_run_records",
131
+ "load_registered_evidence_records",
132
+ "discard_stale_evidence",
133
+ "contradiction_scan",
134
+ "recompute_every_ac",
135
+ "recompute_every_pi",
136
+ "recompute_acceptance_target_status",
137
+ "recompute_product_goal_complete",
138
+ "regenerate_derived",
139
+ "append_event"
140
+ ],
141
+ errors: result.errors,
142
+ stale_evidence_ids: result.stale_evidence_ids,
143
+ harness_task_final_verdict: result.harness_task_final_verdict,
144
+ next_required_actions: state.final.next_required_actions
145
+ };
146
+ }
147
+ function validateAttemptAgainstSources(state, attempt, currentSources, errors) {
148
+ const productHash = currentSources.product_architecture_source?.sha256 ?? "";
149
+ const planHash = currentSources.technical_realization_plan?.sha256 ?? "";
150
+ const checklistHash = currentSources.acceptance_checklist?.sha256 ?? "";
151
+ for (const [key, source] of Object.entries(currentSources)) {
152
+ const expected = state.sources[key]?.sha256;
153
+ if (expected && source.sha256 !== expected) {
154
+ errors.push(`source hash mismatch for ${key}: expected ${expected}, actual ${source.sha256}; recompile graph before final-gate`);
155
+ }
156
+ }
157
+ if (attempt.product_source_hash !== productHash) {
158
+ errors.push("source hash mismatch: current attempt product_source_hash does not match product-architecture-source.md");
159
+ }
160
+ if (attempt.technical_plan_hash !== planHash) {
161
+ errors.push("source hash mismatch: current attempt technical_plan_hash does not match technical-realization-plan.md");
162
+ }
163
+ if (attempt.acceptance_checklist_hash !== checklistHash) {
164
+ errors.push("source hash mismatch: current attempt acceptance_checklist_hash does not match acceptance-checklist.md");
165
+ }
166
+ for (const field of [
167
+ "task_attempt_id",
168
+ "source_bundle_hash",
169
+ "product_source_hash",
170
+ "technical_plan_hash",
171
+ "acceptance_checklist_hash",
172
+ "git_head",
173
+ "git_status_short",
174
+ "tracked_diff_hash",
175
+ "relevant_untracked_hash",
176
+ "worktree_fingerprint",
177
+ "started_at",
178
+ "required_command_specs_hash",
179
+ "mode"
180
+ ]) {
181
+ if (!attempt[field]) {
182
+ errors.push(`current attempt missing required field ${field}`);
183
+ }
184
+ }
185
+ }
186
+ function validateRequiredSpecs(state, attempt, expectedSpecs, errors) {
187
+ const expectedByAc = new Map(expectedSpecs.map((spec) => [spec.ac_id, spec]));
188
+ for (const [acId, ac] of Object.entries(state.graph?.acceptance_criteria ?? {})) {
189
+ if (ac.machine_blocking !== true && ac.assertion_result_required !== true) {
190
+ continue;
191
+ }
192
+ const expected = expectedByAc.get(acId);
193
+ const actual = (state.required_command_specs ?? []).find((spec) => spec.ac_id === acId);
194
+ if (!expected || !actual) {
195
+ errors.push(`${acId} missing required_command_spec`);
196
+ continue;
197
+ }
198
+ if (actual.command_spec_id !== expected.command_spec_id) {
199
+ errors.push(`${acId} command_spec_id mismatch; required command specs must be recompiled from Acceptance Checklist`);
200
+ }
201
+ }
202
+ if (attempt) {
203
+ const specsHash = requiredCommandSpecsHash(state.required_command_specs ?? []);
204
+ if (attempt.required_command_specs_hash !== specsHash) {
205
+ errors.push("required_command_specs_hash mismatch for current attempt");
206
+ }
207
+ }
208
+ }
209
+ function validateCommandRunsForSpec(state, attempt, spec) {
210
+ const errors = [];
211
+ for (const proofLayer of spec.proof_layers.filter((layer) => isMachineVerifiableLayer(`${spec.ac_id}.${layer}`))) {
212
+ const run = (state.command_runs ?? []).find((item) => item.task_attempt_id === state.current_attempt_id &&
213
+ item.command_spec_id === spec.command_spec_id &&
214
+ item.ac_id === spec.ac_id &&
215
+ item.proof_layer === proofLayer);
216
+ if (!run) {
217
+ errors.push(`${spec.ac_id}.${proofLayer} missing current attempt command-run record for command_spec_id ${spec.command_spec_id}`);
218
+ continue;
219
+ }
220
+ errors.push(...validateCommandRun(run, attempt));
221
+ }
222
+ return errors;
223
+ }
224
+ function validateCommandRun(run, attempt) {
225
+ const errors = [];
226
+ if (attempt && run.task_attempt_id !== attempt.task_attempt_id) {
227
+ errors.push(`${run.command_run_id} stale command run from ${run.task_attempt_id}; expected ${attempt.task_attempt_id}`);
228
+ }
229
+ if (run.exit_code !== 0) {
230
+ errors.push(`${run.command_run_id} command_exit_code=${run.exit_code}; expected 0`);
231
+ }
232
+ if (!run.command_line.trim()) {
233
+ errors.push(`${run.command_run_id} missing command_line`);
234
+ }
235
+ return errors;
236
+ }
237
+ function validateEvidenceAgainstSpec(state, evidence, spec, layerId) {
238
+ if (!spec) {
239
+ return [];
240
+ }
241
+ const errors = [];
242
+ const assertion = evidence.assertion_result;
243
+ const label = `proof layer ${layerId} evidence ${evidence.evidence_id}`;
244
+ const expectedPiIds = state.graph.acceptance_criteria[spec.ac_id]?.related_plan_items ?? [];
245
+ const targetPiIds = evidence.target_pi_ids ?? assertion?.target_pi_ids ?? [];
246
+ for (const piId of expectedPiIds) {
247
+ if (!targetPiIds.includes(piId)) {
248
+ errors.push(`${label} target_pi_ids ${targetPiIds.join(", ") || "(none)"} do not include ${piId}`);
249
+ }
250
+ }
251
+ if (assertion) {
252
+ const assertionIds = new Set(assertion.positive_assertions.map((item) => item.id));
253
+ for (const id of spec.positive_assertions ?? []) {
254
+ if (!assertionIds.has(id)) {
255
+ errors.push(`${label} missing positive assertion ${id}`);
256
+ }
257
+ }
258
+ const negativeIds = new Set(assertion.negative_assertions.map((item) => item.id));
259
+ for (const id of spec.negative_assertions ?? []) {
260
+ if (!negativeIds.has(id)) {
261
+ errors.push(`${label} missing negative assertion ${id}`);
262
+ }
263
+ }
264
+ const requiredTests = new Set(assertion.required_test_ids ?? []);
265
+ for (const testId of spec.required_test_ids ?? []) {
266
+ if (!requiredTests.has(testId)) {
267
+ errors.push(`${label} assertion_result.required_test_ids missing ${testId}`);
268
+ }
269
+ }
270
+ const invalidChecks = [
271
+ ...((assertion.invalid_completion_signals ?? []).map((item) => `${item.id} ${item.forbidden_text ?? ""}`)),
272
+ ...((assertion.negative_evidence_scan?.invalid_completion_signals_checked ?? []).map((item) => String(item)))
273
+ ].join("\n");
274
+ for (const signal of spec.invalid_completion_signals ?? []) {
275
+ if (!invalidChecks.includes(signal)) {
276
+ errors.push(`${label} invalid_completion_signals did not check ${signal}`);
277
+ }
278
+ }
279
+ }
280
+ return errors;
281
+ }
282
+ function specForAc(state, expectedSpecs, acId) {
283
+ const actual = (state.required_command_specs ?? []).find((spec) => spec.ac_id === acId);
284
+ if (actual) {
285
+ return actual;
286
+ }
287
+ return expectedSpecs.find((spec) => spec.ac_id === acId);
288
+ }
289
+ function statusForAcErrors(errors, requiredLayerCount) {
290
+ if (requiredLayerCount === 0) {
291
+ return "not_run";
292
+ }
293
+ const text = errors.join("\n");
294
+ if (!text) {
295
+ return "complete";
296
+ }
297
+ if (/under_specified/i.test(text)) {
298
+ return "under_specified";
299
+ }
300
+ if (/stale|failed|invalid|contradiction|negative evidence|forbidden|bootstrap/i.test(text)) {
301
+ return "invalidated";
302
+ }
303
+ if (/blocked|harness_drift|protected_baseline|source hash mismatch/i.test(text)) {
304
+ return "blocked";
305
+ }
306
+ return "partial";
307
+ }
308
+ function recomputePlanStatuses(state, acStatuses) {
309
+ const statuses = {};
310
+ for (const [planId, item] of Object.entries(state.graph?.plan_items ?? {})) {
311
+ const relatedStatuses = (item.related_acs ?? []).map((acId) => acStatuses[acId] ?? state.graph.acceptance_criteria[acId]?.status ?? "not_run");
312
+ if (relatedStatuses.length > 0 && relatedStatuses.every((status) => status === "complete" || status === "out_of_scope_NA")) {
313
+ statuses[planId] = "complete";
314
+ }
315
+ else if (relatedStatuses.some((status) => status === "under_specified" || status === "blocked")) {
316
+ statuses[planId] = "blocked";
317
+ }
318
+ else if (relatedStatuses.some((status) => status === "invalidated")) {
319
+ statuses[planId] = "invalidated";
320
+ }
321
+ else if (relatedStatuses.some((status) => status === "partial")) {
322
+ statuses[planId] = "partial";
323
+ }
324
+ else {
325
+ statuses[planId] = "not_started";
326
+ }
327
+ }
328
+ return statuses;
329
+ }
330
+ function statusForGlobalErrors(errors, acStatuses) {
331
+ const text = errors.join("\n");
332
+ if (Object.values(acStatuses).includes("under_specified") || /under_specified/i.test(text)) {
333
+ return "under_specified";
334
+ }
335
+ if (/harness_drift|protected_baseline|source hash mismatch|missing current attempt|required_command_specs_hash|harness_task_missing/i.test(text)) {
336
+ return "blocked";
337
+ }
338
+ if (/stale|failed|invalid|contradiction|negative evidence|forbidden|bootstrap/i.test(text)) {
339
+ return "invalidated";
340
+ }
341
+ return "partial";
342
+ }
343
+ function currentAttempt(state) {
344
+ return (state.attempts ?? []).find((item) => item.task_attempt_id === state.current_attempt_id) ?? (state.attempts ?? []).at(-1);
345
+ }
346
+ function isStaleEvidenceError(errors) {
347
+ return errors.some((error) => /stale evidence|source_bundle_hash mismatch|artifact_sha256 mismatch|artifact_mtime/i.test(error));
348
+ }
349
+ function unique(values) {
350
+ return [...new Set(values.filter(Boolean))];
351
+ }
@@ -0,0 +1,2 @@
1
+ import { type SuperpowersEvidenceRecord } from "./superpowers-task-state-schema.js";
2
+ export declare function readEvidenceRecords(value: unknown): SuperpowersEvidenceRecord[];
@@ -0,0 +1,55 @@
1
+ import { normalizeAssertionResult, normalizeNegativeEvidenceScan } from "./superpowers-task-assertion-normalizers.js";
2
+ import { normalizeProofLayerId } from "./superpowers-task-fields.js";
3
+ import { asStringArray, isRecord } from "./superpowers-task-state-schema.js";
4
+ export function readEvidenceRecords(value) {
5
+ if (!Array.isArray(value)) {
6
+ return [];
7
+ }
8
+ return value.filter(isRecord).map((item) => ({
9
+ evidence_id: String(item.evidence_id ?? item.evidenceId ?? ""),
10
+ schema_version: item.schema_version === undefined ? undefined : String(item.schema_version),
11
+ task_attempt_id: item.task_attempt_id === undefined ? undefined : String(item.task_attempt_id),
12
+ source_bundle_hash: item.source_bundle_hash === undefined ? undefined : String(item.source_bundle_hash),
13
+ product_source_hash: item.product_source_hash === undefined ? undefined : String(item.product_source_hash),
14
+ technical_plan_hash: item.technical_plan_hash === undefined ? undefined : String(item.technical_plan_hash),
15
+ acceptance_checklist_hash: item.acceptance_checklist_hash === undefined ? undefined : String(item.acceptance_checklist_hash),
16
+ git_head: item.git_head === undefined ? undefined : String(item.git_head),
17
+ worktree_fingerprint: item.worktree_fingerprint === undefined ? undefined : String(item.worktree_fingerprint),
18
+ command_spec_id: item.command_spec_id === undefined ? undefined : String(item.command_spec_id),
19
+ command_run_id: item.command_run_id === undefined ? undefined : String(item.command_run_id),
20
+ command_line: item.command_line === undefined ? undefined : String(item.command_line),
21
+ artifact_path: item.artifact_path === undefined ? undefined : String(item.artifact_path),
22
+ artifact_sha256: item.artifact_sha256 === undefined ? undefined : String(item.artifact_sha256),
23
+ artifact_mtime: item.artifact_mtime === undefined ? undefined : String(item.artifact_mtime),
24
+ target_ac_ids: asStringArray(item.target_ac_ids),
25
+ target_pi_ids: asStringArray(item.target_pi_ids),
26
+ target_proof_layers: asStringArray(item.target_proof_layers).map(normalizeProofLayerId),
27
+ slice_id: String(item.slice_id ?? item.sliceId ?? ""),
28
+ type: String(item.type ?? ""),
29
+ freshness: isRecord(item.freshness)
30
+ ? {
31
+ created_at: String(item.freshness.created_at ?? ""),
32
+ valid_for: String(item.freshness.valid_for ?? ""),
33
+ stale_after: item.freshness.stale_after === null ? null : item.freshness.stale_after === undefined ? null : String(item.freshness.stale_after)
34
+ }
35
+ : { created_at: "", valid_for: "", stale_after: null },
36
+ command: item.command === undefined ? undefined : String(item.command),
37
+ command_exit_code: item.command_exit_code === undefined ? undefined : Number(item.command_exit_code),
38
+ artifact_paths: asStringArray(item.artifact_paths),
39
+ proves: asStringArray(item.proves).map(normalizeProofLayerId),
40
+ does_not_prove: asStringArray(item.does_not_prove).map((claim) => (claim.includes(".") ? normalizeProofLayerId(claim) : claim)),
41
+ redaction: isRecord(item.redaction)
42
+ ? { checked: item.redaction.checked === true, contains_secret: item.redaction.contains_secret === true }
43
+ : { checked: false, contains_secret: false },
44
+ reviewability: isRecord(item.reviewability)
45
+ ? {
46
+ external_reviewer_can_reproduce: item.reviewability.external_reviewer_can_reproduce === true,
47
+ reproduction_steps: String(item.reviewability.reproduction_steps ?? "")
48
+ }
49
+ : { external_reviewer_can_reproduce: false, reproduction_steps: "" },
50
+ assertion_result: normalizeAssertionResult(item.assertion_result),
51
+ negative_evidence_scan: normalizeNegativeEvidenceScan(item.negative_evidence_scan),
52
+ sibling_substitution_used: item.sibling_substitution_used === true,
53
+ sibling_substitution_approval_source: item.sibling_substitution_approval_source === undefined ? undefined : String(item.sibling_substitution_approval_source)
54
+ }));
55
+ }
@@ -0,0 +1,10 @@
1
+ import { type CommandRunRecord, type SuperpowersEvidenceRecord } from "./superpowers-task-state-schema.js";
2
+ export declare function runSuperpowersAssertion(workdir: string, options: {
3
+ acId: string;
4
+ proofLayer: string;
5
+ commandArgs: string[];
6
+ }): Promise<CommandRunRecord>;
7
+ export declare function recordSuperpowersEvidence(workdir: string, options: {
8
+ artifactPath: string;
9
+ commandRunId: string;
10
+ }): Promise<SuperpowersEvidenceRecord>;