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.
- package/README.md +11 -3
- package/assets/README.md +11 -3
- package/assets/README.zh-CN.md +9 -1
- package/assets/protected-harness-baseline.json +18 -0
- package/assets/skills/composite-long-task-workflow/SKILL.md +21 -1
- package/assets/skills/composite-long-task-workflow/assets/execution-binding.template.md +10 -0
- package/assets/skills/composite-long-task-workflow/assets/goal-objective.template.md +6 -15
- package/assets/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md +32 -15
- package/dist/commands/composite-long-task.js +45 -2
- package/dist/lib/superpowers-task-ac010.d.ts +6 -0
- package/dist/lib/superpowers-task-ac010.js +26 -0
- package/dist/lib/superpowers-task-assertion-normalizers.js +8 -1
- package/dist/lib/superpowers-task-assertions.js +35 -20
- package/dist/lib/superpowers-task-attempt.d.ts +4 -0
- package/dist/lib/superpowers-task-attempt.js +102 -0
- package/dist/lib/superpowers-task-command-specs.d.ts +3 -0
- package/dist/lib/superpowers-task-command-specs.js +52 -0
- package/dist/lib/superpowers-task-compile.d.ts +4 -1
- package/dist/lib/superpowers-task-compile.js +7 -1
- package/dist/lib/superpowers-task-contradictions.d.ts +6 -0
- package/dist/lib/superpowers-task-contradictions.js +126 -0
- package/dist/lib/superpowers-task-current-evidence.d.ts +3 -0
- package/dist/lib/superpowers-task-current-evidence.js +154 -0
- package/dist/lib/superpowers-task-delivery.js +30 -18
- package/dist/lib/superpowers-task-derive.d.ts +1 -0
- package/dist/lib/superpowers-task-derive.js +76 -1
- package/dist/lib/superpowers-task-evidence-kernel.d.ts +12 -0
- package/dist/lib/superpowers-task-evidence-kernel.js +351 -0
- package/dist/lib/superpowers-task-evidence-records.d.ts +2 -0
- package/dist/lib/superpowers-task-evidence-records.js +55 -0
- package/dist/lib/superpowers-task-evidence.d.ts +10 -0
- package/dist/lib/superpowers-task-evidence.js +141 -0
- package/dist/lib/superpowers-task-fields.d.ts +22 -0
- package/dist/lib/superpowers-task-fields.js +276 -0
- package/dist/lib/superpowers-task-gates.js +36 -24
- package/dist/lib/superpowers-task-harness-drift.d.ts +11 -0
- package/dist/lib/superpowers-task-harness-drift.js +86 -0
- package/dist/lib/superpowers-task-protected-baseline.d.ts +10 -0
- package/dist/lib/superpowers-task-protected-baseline.js +47 -0
- package/dist/lib/superpowers-task-source-compile.js +93 -95
- package/dist/lib/superpowers-task-source-parser.js +1 -3
- package/dist/lib/superpowers-task-state-schema.d.ts +158 -3
- package/dist/lib/superpowers-task-state-schema.js +23 -1
- package/dist/lib/superpowers-task-state-shape.d.ts +3 -0
- package/dist/lib/superpowers-task-state-shape.js +50 -0
- package/dist/lib/superpowers-task-state.js +19 -39
- package/dist/lib/superpowers-task-status.js +11 -1
- package/dist/lib/superpowers-task-under-specified.d.ts +7 -0
- package/dist/lib/superpowers-task-under-specified.js +61 -0
- package/dist/lib/superpowers-task-validator.js +11 -37
- package/package.json +69 -69
- 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
|
-
|
|
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,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>;
|