@peterxiaoyang/superspec 0.1.14 → 0.1.15-alpha
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/dist/cli.d.ts +2 -0
- package/dist/cli.js +302 -0
- package/dist/format.d.ts +29 -0
- package/dist/format.js +141 -0
- package/dist/next.d.ts +3 -0
- package/dist/next.js +161 -0
- package/dist/openspec.d.ts +9 -0
- package/dist/openspec.js +41 -0
- package/dist/record.d.ts +20 -0
- package/dist/record.js +211 -0
- package/dist/skill_loop.d.ts +23 -0
- package/dist/skill_loop.js +58 -0
- package/dist/store.d.ts +31 -0
- package/dist/store.js +213 -0
- package/dist/sync.d.ts +3 -0
- package/dist/sync.js +135 -0
- package/dist/task.d.ts +7 -0
- package/dist/task.js +44 -0
- package/dist/transition.d.ts +34 -0
- package/dist/transition.js +400 -0
- package/dist/types.d.ts +138 -0
- package/dist/types.js +3 -0
- package/package.json +8 -53
- package/templates/workflow/skills/superspec-apply/SKILL.md +46 -118
- package/templates/workflow/skills/superspec-archive/SKILL.md +22 -47
- package/templates/workflow/skills/superspec-explore/SKILL.md +38 -69
- package/templates/workflow/skills/superspec-propose/SKILL.md +58 -60
- package/templates/workflow/skills/superspec-review/SKILL.md +36 -81
- package/adapters/codex/agents/architect.toml +0 -13
- package/adapters/codex/agents/code-reviewer.toml +0 -13
- package/adapters/codex/agents/critic.toml +0 -13
- package/adapters/codex/agents/executor.toml +0 -13
- package/adapters/codex/agents/explore.toml +0 -13
- package/adapters/codex/agents/test-engineer.toml +0 -13
- package/adapters/codex/agents/test-runner.toml +0 -13
- package/adapters/codex/agents/verifier.toml +0 -13
- package/adapters/codex/install-map.json +0 -116
- package/bin/launch.js +0 -37
- package/bin/superspec-check.js +0 -4
- package/bin/superspec-hook.js +0 -4
- package/bin/superspec-init.js +0 -4
- package/bin/superspec.js +0 -4
- package/dist/src/apply_worker_chain.d.ts +0 -60
- package/dist/src/apply_worker_chain.js +0 -1283
- package/dist/src/apply_worker_chain_lifecycle.d.ts +0 -21
- package/dist/src/apply_worker_chain_lifecycle.js +0 -409
- package/dist/src/archive.d.ts +0 -23
- package/dist/src/archive.js +0 -430
- package/dist/src/cli.d.ts +0 -1
- package/dist/src/cli.js +0 -33
- package/dist/src/cli_args.d.ts +0 -32
- package/dist/src/cli_args.js +0 -454
- package/dist/src/core.d.ts +0 -20
- package/dist/src/core.js +0 -394
- package/dist/src/disclosure.d.ts +0 -35
- package/dist/src/disclosure.js +0 -671
- package/dist/src/doctor.d.ts +0 -44
- package/dist/src/doctor.js +0 -230
- package/dist/src/evidence.d.ts +0 -29
- package/dist/src/evidence.js +0 -1107
- package/dist/src/gates.d.ts +0 -19
- package/dist/src/gates.js +0 -1631
- package/dist/src/git.d.ts +0 -8
- package/dist/src/git.js +0 -112
- package/dist/src/hooks/adapter.d.ts +0 -5
- package/dist/src/hooks/adapter.js +0 -347
- package/dist/src/hooks/guard_api.d.ts +0 -12
- package/dist/src/hooks/guard_api.js +0 -797
- package/dist/src/hooks/health.d.ts +0 -4
- package/dist/src/hooks/health.js +0 -86
- package/dist/src/hooks/policy_event.d.ts +0 -41
- package/dist/src/hooks/policy_event.js +0 -2634
- package/dist/src/hooks/types.d.ts +0 -72
- package/dist/src/hooks/types.js +0 -1
- package/dist/src/hooks/validation.d.ts +0 -3
- package/dist/src/hooks/validation.js +0 -70
- package/dist/src/i18n.d.ts +0 -21
- package/dist/src/i18n.js +0 -720
- package/dist/src/init_cli.d.ts +0 -28
- package/dist/src/init_cli.js +0 -404
- package/dist/src/install_engine.d.ts +0 -71
- package/dist/src/install_engine.js +0 -538
- package/dist/src/invariants.d.ts +0 -16
- package/dist/src/invariants.js +0 -363
- package/dist/src/openspec.d.ts +0 -37
- package/dist/src/openspec.js +0 -274
- package/dist/src/packet_render.d.ts +0 -5
- package/dist/src/packet_render.js +0 -1767
- package/dist/src/packet_schema.d.ts +0 -59
- package/dist/src/packet_schema.js +0 -1
- package/dist/src/paths.d.ts +0 -22
- package/dist/src/paths.js +0 -203
- package/dist/src/project_init.d.ts +0 -33
- package/dist/src/project_init.js +0 -191
- package/dist/src/self_update.d.ts +0 -14
- package/dist/src/self_update.js +0 -56
- package/dist/src/state.d.ts +0 -37
- package/dist/src/state.js +0 -464
- package/dist/src/tasks.d.ts +0 -38
- package/dist/src/tasks.js +0 -373
- package/dist/src/util.d.ts +0 -163
- package/dist/src/util.js +0 -792
- package/dist/superspec.d.ts +0 -6
- package/dist/superspec.js +0 -97
- package/dist/superspec_guard.d.ts +0 -4
- package/dist/superspec_guard.js +0 -19
- package/dist/superspec_hook.d.ts +0 -4
- package/dist/superspec_hook.js +0 -35
- package/dist/superspec_init.d.ts +0 -2
- package/dist/superspec_init.js +0 -17
- package/schemas/hook-event.schema.json +0 -27
- package/schemas/install-manifest.schema.json +0 -97
- package/templates/hooks/codex-hooks.json +0 -35
- package/templates/sidecar/archive-preservation.json +0 -11
- package/templates/sidecar/business-invariants.md +0 -38
- package/templates/sidecar/config.yaml +0 -13
- package/templates/sidecar/discovery.md +0 -33
- package/templates/sidecar/test-contract.md +0 -27
- package/templates/workflow/prompts/architect.md +0 -27
- package/templates/workflow/prompts/code-reviewer.md +0 -34
- package/templates/workflow/prompts/critic.md +0 -30
- package/templates/workflow/prompts/executor.md +0 -32
- package/templates/workflow/prompts/explore.md +0 -27
- package/templates/workflow/prompts/test-engineer.md +0 -28
- package/templates/workflow/prompts/test-runner.md +0 -35
- package/templates/workflow/prompts/verifier.md +0 -35
|
@@ -1,1283 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, isAbsolute, relative } from "node:path";
|
|
3
|
-
import { deepEqual, fingerprint_obj, GuardError, REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_SUPERSPEC_WORKFLOW_SKILLS, NO_TDD_REASONS, isObject, reason, renderList, runtime, safe_within, sha256_text, } from "./util.js";
|
|
4
|
-
import { dirty_worktree_paths, file_blob_sha } from "./git.js";
|
|
5
|
-
import { effective_superseded_ids } from "./openspec.js";
|
|
6
|
-
const APPLY_WORKER_ARTIFACT_KINDS = new Set(["worker_report", "raw_transcript", "diff_transcript", "status_report"]);
|
|
7
|
-
const APPLY_WORKER_ARTIFACT_ROLES = new Set(["test-runner", "executor", "code-reviewer", "verifier"]);
|
|
8
|
-
const DEFAULT_APPLY_WORKER_ARTIFACT_MAX_BYTES = 1024 * 1024;
|
|
9
|
-
export const APPLY_WORKER_MAX_INLINE_REPORT_CHARS = 12000;
|
|
10
|
-
export const APPLY_TEST_RUNNER_REPORT_REQUIRED_FIELDS = [
|
|
11
|
-
"role",
|
|
12
|
-
"command",
|
|
13
|
-
"command_source",
|
|
14
|
-
"cwd",
|
|
15
|
-
"phase",
|
|
16
|
-
"task_id",
|
|
17
|
-
"test_id",
|
|
18
|
-
"exit_code",
|
|
19
|
-
"semantic_status_candidate",
|
|
20
|
-
"result_summary",
|
|
21
|
-
"runtime_raw_transcript_ref",
|
|
22
|
-
"repo_head",
|
|
23
|
-
"pre_dirty_state",
|
|
24
|
-
"post_dirty_state",
|
|
25
|
-
"changed_files",
|
|
26
|
-
"untracked_files",
|
|
27
|
-
"invariant_refs",
|
|
28
|
-
"source_refs",
|
|
29
|
-
"origin_packet_fingerprint",
|
|
30
|
-
"input_ref_digest",
|
|
31
|
-
"source_implementation_fingerprint",
|
|
32
|
-
"observed_implementation_fingerprint",
|
|
33
|
-
"guard_fingerprint",
|
|
34
|
-
"unverified_items",
|
|
35
|
-
];
|
|
36
|
-
export const APPLY_EXECUTOR_REPORT_REQUIRED_FIELDS = [
|
|
37
|
-
"role",
|
|
38
|
-
"task_id",
|
|
39
|
-
"apply_worker_chain_id",
|
|
40
|
-
"cwd",
|
|
41
|
-
"repo_head",
|
|
42
|
-
"guard_fingerprint",
|
|
43
|
-
"changed_files",
|
|
44
|
-
"suggested_green_checks",
|
|
45
|
-
"test_invariant_mapping",
|
|
46
|
-
"runtime_artifact_refs",
|
|
47
|
-
"origin_packet_fingerprint",
|
|
48
|
-
"input_ref_digest",
|
|
49
|
-
"source_implementation_fingerprint",
|
|
50
|
-
"produced_implementation_fingerprint",
|
|
51
|
-
"unverified_items",
|
|
52
|
-
"risk_notes",
|
|
53
|
-
];
|
|
54
|
-
export const APPLY_CODE_REVIEW_REPORT_REQUIRED_FIELDS = [
|
|
55
|
-
"role",
|
|
56
|
-
"review_status_candidate",
|
|
57
|
-
"cwd",
|
|
58
|
-
"repo_head",
|
|
59
|
-
"guard_fingerprint",
|
|
60
|
-
"executor_report_ref",
|
|
61
|
-
"actual_changed_files",
|
|
62
|
-
"changed_files",
|
|
63
|
-
"untracked_files",
|
|
64
|
-
"implementation_dirty_file_list",
|
|
65
|
-
"implementation_fingerprint",
|
|
66
|
-
"guard_artifact_manifest_fingerprint",
|
|
67
|
-
"scope_verdict",
|
|
68
|
-
"protected_path_verdict",
|
|
69
|
-
"executor_report_mismatch",
|
|
70
|
-
"test_invariant_mapping_verdict",
|
|
71
|
-
"suggested_green_test_ids",
|
|
72
|
-
"risk_notes",
|
|
73
|
-
"runtime_raw_git_status_transcript_ref",
|
|
74
|
-
"runtime_raw_git_diff_name_status_transcript_ref",
|
|
75
|
-
"runtime_path_scoped_diff_transcript_refs",
|
|
76
|
-
"origin_packet_fingerprint",
|
|
77
|
-
"input_ref_digest",
|
|
78
|
-
"source_implementation_fingerprint",
|
|
79
|
-
"observed_implementation_fingerprint",
|
|
80
|
-
"unverified_items",
|
|
81
|
-
];
|
|
82
|
-
export const APPLY_VERIFIER_REPORT_REQUIRED_FIELDS = [
|
|
83
|
-
"role",
|
|
84
|
-
"completion_proof_kind",
|
|
85
|
-
"pre_edit_proof_kind",
|
|
86
|
-
"verification_status_candidate",
|
|
87
|
-
"task_completion_verdict",
|
|
88
|
-
"chain_consistency_verdict",
|
|
89
|
-
"acceptance_coverage_verdict",
|
|
90
|
-
"invariant_coverage_verdict",
|
|
91
|
-
"test_coverage_verdict",
|
|
92
|
-
"cwd",
|
|
93
|
-
"repo_head",
|
|
94
|
-
"guard_fingerprint",
|
|
95
|
-
"expected_freshness_fingerprint",
|
|
96
|
-
"observed_freshness_fingerprint",
|
|
97
|
-
"freshness_verdict",
|
|
98
|
-
"executor_report_ref",
|
|
99
|
-
"task_code_review_report_ref",
|
|
100
|
-
"actual_changed_files",
|
|
101
|
-
"changed_files",
|
|
102
|
-
"untracked_files",
|
|
103
|
-
"implementation_dirty_file_list",
|
|
104
|
-
"implementation_fingerprint",
|
|
105
|
-
"guard_artifact_manifest_fingerprint",
|
|
106
|
-
"unexpected_guard_owned_dirty_paths",
|
|
107
|
-
"scope_verdict",
|
|
108
|
-
"protected_path_verdict",
|
|
109
|
-
"executor_code_review_mismatch",
|
|
110
|
-
"test_evidence_mismatch",
|
|
111
|
-
"runtime_raw_git_status_transcript_ref",
|
|
112
|
-
"runtime_raw_git_diff_name_status_transcript_ref",
|
|
113
|
-
"runtime_path_scoped_diff_transcript_refs",
|
|
114
|
-
"diff_summary_refs",
|
|
115
|
-
"origin_packet_fingerprint",
|
|
116
|
-
"input_ref_digest",
|
|
117
|
-
"source_implementation_fingerprint",
|
|
118
|
-
"observed_implementation_fingerprint",
|
|
119
|
-
"risk_notes",
|
|
120
|
-
"triggered_stop_conditions",
|
|
121
|
-
"unverified_items",
|
|
122
|
-
];
|
|
123
|
-
function repo_rel(repoRoot, absPath) {
|
|
124
|
-
const rel = relative(repoRoot, absPath);
|
|
125
|
-
if (!rel || rel.startsWith("..") || isAbsolute(rel))
|
|
126
|
-
return null;
|
|
127
|
-
return rel.split("\\").join("/");
|
|
128
|
-
}
|
|
129
|
-
function repo_head(repoRoot) {
|
|
130
|
-
try {
|
|
131
|
-
const line = runtime.git_lines(repoRoot, "rev-parse", "HEAD")[0];
|
|
132
|
-
return line || "unknown";
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
return "unknown";
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function guard_state_path(pathValue) {
|
|
139
|
-
return pathValue.endsWith(".superspec/superspec-state.json")
|
|
140
|
-
|| pathValue.endsWith(".superspec/superspec-state.lock")
|
|
141
|
-
|| pathValue.endsWith(".superspec/ledger.jsonl")
|
|
142
|
-
|| pathValue.includes(".superspec/evidence/")
|
|
143
|
-
|| pathValue.includes(".superspec/state/");
|
|
144
|
-
}
|
|
145
|
-
function protected_change_path(changePath) {
|
|
146
|
-
const pathValue = changePath.split("\\").join("/");
|
|
147
|
-
return pathValue === "proposal.md"
|
|
148
|
-
|| pathValue === "design.md"
|
|
149
|
-
|| pathValue === "tasks.md"
|
|
150
|
-
|| pathValue.startsWith("specs/")
|
|
151
|
-
|| pathValue === ".superspec"
|
|
152
|
-
|| pathValue.startsWith(".superspec/");
|
|
153
|
-
}
|
|
154
|
-
function repo_path_snapshot(repoRoot, relPath) {
|
|
155
|
-
const absPath = safe_within(repoRoot, relPath);
|
|
156
|
-
if (absPath === null || !existsSync(absPath))
|
|
157
|
-
return { path: relPath, status: "deleted", blob_sha: "deleted" };
|
|
158
|
-
if (!statSync(absPath).isFile())
|
|
159
|
-
return { path: relPath, status: "non_file", blob_sha: "non_file" };
|
|
160
|
-
return { path: relPath, status: "present", blob_sha: runtime.file_blob_sha(absPath) };
|
|
161
|
-
}
|
|
162
|
-
function snapshot_digest(items) {
|
|
163
|
-
return fingerprint_obj(items);
|
|
164
|
-
}
|
|
165
|
-
function implementation_transcript_digest(kind, items) {
|
|
166
|
-
return sha256_text(`${kind}\n${items.map((item) => `${String(item.status ?? "")}\t${String(item.path ?? "")}\t${String(item.blob_sha ?? "")}`).join("\n")}\n`);
|
|
167
|
-
}
|
|
168
|
-
function ref_repo_paths(repoRoot, changeRoot, refs) {
|
|
169
|
-
const paths = new Set();
|
|
170
|
-
for (const refItem of refs) {
|
|
171
|
-
if (!isObject(refItem) || typeof refItem.path !== "string")
|
|
172
|
-
continue;
|
|
173
|
-
const target = safe_within(changeRoot, refItem.path);
|
|
174
|
-
if (target === null)
|
|
175
|
-
continue;
|
|
176
|
-
const rel = repo_rel(repoRoot, target);
|
|
177
|
-
if (rel)
|
|
178
|
-
paths.add(rel);
|
|
179
|
-
}
|
|
180
|
-
return paths;
|
|
181
|
-
}
|
|
182
|
-
function managed_codex_surface_paths(repoRoot) {
|
|
183
|
-
const candidates = [
|
|
184
|
-
...REQUIRED_SUPERSPEC_WORKFLOW_SKILLS.map((name) => `.codex/skills/${name}/SKILL.md`),
|
|
185
|
-
...REQUIRED_SUPERSPEC_AGENT_ROLES.map((name) => `.codex/prompts/${name}.md`),
|
|
186
|
-
...REQUIRED_SUPERSPEC_AGENT_ROLES.map((name) => `.codex/agents/${name}.toml`),
|
|
187
|
-
".codex/config.toml",
|
|
188
|
-
".codex/superspec/install-manifest.json",
|
|
189
|
-
];
|
|
190
|
-
return candidates.filter((pathValue) => {
|
|
191
|
-
const absPath = safe_within(repoRoot, pathValue);
|
|
192
|
-
return absPath !== null && existsSync(absPath);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
export function apply_worker_implementation_fingerprint(repoRoot, changeRoot, expectedGuardRefs = [], opts = {}) {
|
|
196
|
-
const changeRel = repo_rel(repoRoot, changeRoot) ?? "";
|
|
197
|
-
const expectedGuardPaths = ref_repo_paths(repoRoot, changeRoot, expectedGuardRefs);
|
|
198
|
-
const dirtyPaths = typeof runtime.dirty_worktree_paths === "function"
|
|
199
|
-
? runtime.dirty_worktree_paths(repoRoot)
|
|
200
|
-
: dirty_worktree_paths(repoRoot);
|
|
201
|
-
const unexpectedGuardOwnedDirtyPaths = [];
|
|
202
|
-
const protectedDirtyPaths = [];
|
|
203
|
-
const dirtyFiles = [...new Set(dirtyPaths)].sort().flatMap((relPath) => {
|
|
204
|
-
const pathValue = relPath.split("\\").join("/");
|
|
205
|
-
if (expectedGuardPaths.has(pathValue) || guard_state_path(pathValue))
|
|
206
|
-
return [];
|
|
207
|
-
if (changeRel && pathValue.startsWith(`${changeRel}/`)) {
|
|
208
|
-
const changePath = pathValue.slice(changeRel.length + 1);
|
|
209
|
-
if (protected_change_path(changePath))
|
|
210
|
-
protectedDirtyPaths.push(pathValue);
|
|
211
|
-
if (pathValue.startsWith(`${changeRel}/.superspec/reports/apply/`)
|
|
212
|
-
|| pathValue.startsWith(`${changeRel}/.superspec/raw/apply/`)) {
|
|
213
|
-
unexpectedGuardOwnedDirtyPaths.push(pathValue);
|
|
214
|
-
}
|
|
215
|
-
return [];
|
|
216
|
-
}
|
|
217
|
-
return [repo_path_snapshot(repoRoot, pathValue)];
|
|
218
|
-
});
|
|
219
|
-
const protectedDirtyFiles = [...new Set(protectedDirtyPaths)].sort().map((pathValue) => repo_path_snapshot(repoRoot, pathValue));
|
|
220
|
-
const protectedPathRefs = Array.isArray(opts.protectedPathRefs) && opts.protectedPathRefs.length > 0
|
|
221
|
-
? opts.protectedPathRefs.filter(isObject)
|
|
222
|
-
: protectedDirtyFiles;
|
|
223
|
-
const codexManagedFiles = managed_codex_surface_paths(repoRoot).map((pathValue) => repo_path_snapshot(repoRoot, pathValue));
|
|
224
|
-
const implementationDirtyFileList = dirtyFiles.map((item) => String(item.path ?? "")).filter(Boolean).sort();
|
|
225
|
-
const declaredTaskWriteScope = Array.isArray(opts.declaredTaskWriteScope) ? opts.declaredTaskWriteScope.map(String).filter(Boolean).sort() : [];
|
|
226
|
-
const scopedNameStatusTranscriptDigest = implementation_transcript_digest("git diff --name-status --", dirtyFiles);
|
|
227
|
-
const scopedDiffTranscriptDigest = implementation_transcript_digest("git diff --binary --", dirtyFiles);
|
|
228
|
-
const stable = {
|
|
229
|
-
repo_head: repo_head(repoRoot),
|
|
230
|
-
declared_task_write_scope: declaredTaskWriteScope,
|
|
231
|
-
protected_path_refs: protectedPathRefs,
|
|
232
|
-
implementation_dirty_file_list: implementationDirtyFileList,
|
|
233
|
-
scoped_name_status_transcript_digest: scopedNameStatusTranscriptDigest,
|
|
234
|
-
scoped_diff_transcript_digest: scopedDiffTranscriptDigest,
|
|
235
|
-
dirty_files: dirtyFiles,
|
|
236
|
-
codex_managed_files: codexManagedFiles,
|
|
237
|
-
protected_dirty_files: protectedDirtyFiles,
|
|
238
|
-
};
|
|
239
|
-
return {
|
|
240
|
-
...stable,
|
|
241
|
-
dirty_paths: dirtyFiles.map((item) => item.path),
|
|
242
|
-
dirty_files_digest: snapshot_digest(dirtyFiles),
|
|
243
|
-
codex_managed_paths: codexManagedFiles.map((item) => item.path),
|
|
244
|
-
unexpected_guard_owned_dirty_paths: unexpectedGuardOwnedDirtyPaths.sort(),
|
|
245
|
-
protected_dirty_paths: protectedDirtyFiles.map((item) => item.path),
|
|
246
|
-
protected_path_refs: protectedPathRefs,
|
|
247
|
-
fingerprint_digest: fingerprint_obj(stable),
|
|
248
|
-
helper_version: "apply-worker-fingerprint-v1",
|
|
249
|
-
computed_at: new Date().toISOString(),
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
export function apply_worker_protected_path_refs(repoRoot, changeRoot, expectedGuardRefs = []) {
|
|
253
|
-
const fingerprint = apply_worker_implementation_fingerprint(repoRoot, changeRoot, expectedGuardRefs);
|
|
254
|
-
return Array.isArray(fingerprint.protected_path_refs) ? fingerprint.protected_path_refs.filter(isObject) : [];
|
|
255
|
-
}
|
|
256
|
-
function pinned_summary(refItem) {
|
|
257
|
-
if (!isObject(refItem))
|
|
258
|
-
return null;
|
|
259
|
-
const result = {};
|
|
260
|
-
for (const key of [
|
|
261
|
-
"root",
|
|
262
|
-
"path",
|
|
263
|
-
"blob_sha",
|
|
264
|
-
"size_bytes",
|
|
265
|
-
"kind",
|
|
266
|
-
"role",
|
|
267
|
-
"task_id",
|
|
268
|
-
"worker_chain_context",
|
|
269
|
-
"apply_worker_chain_id",
|
|
270
|
-
"evidence_id",
|
|
271
|
-
"phase",
|
|
272
|
-
"semantic_status",
|
|
273
|
-
"guard_fingerprint",
|
|
274
|
-
"origin_packet_fingerprint",
|
|
275
|
-
"input_ref_digest",
|
|
276
|
-
]) {
|
|
277
|
-
if (refItem[key] !== undefined)
|
|
278
|
-
result[key] = refItem[key];
|
|
279
|
-
}
|
|
280
|
-
return result;
|
|
281
|
-
}
|
|
282
|
-
export function worker_input_ref_digest(refs) {
|
|
283
|
-
const stable = refs.map((refItem) => {
|
|
284
|
-
if (typeof refItem === "string")
|
|
285
|
-
return { evidence_id: refItem };
|
|
286
|
-
return pinned_summary(refItem) ?? refItem;
|
|
287
|
-
});
|
|
288
|
-
return fingerprint_obj(stable);
|
|
289
|
-
}
|
|
290
|
-
function evidence_summary(ev) {
|
|
291
|
-
if (!ev)
|
|
292
|
-
return null;
|
|
293
|
-
const result = {};
|
|
294
|
-
for (const key of ["evidence_id", "kind", "gate", "task_id", "test_id", "phase", "semantic_status", "command", "cwd", "exit_code", "runner_origin", "apply_execution_chain", "apply_worker_chain_id"]) {
|
|
295
|
-
if (ev[key] !== undefined)
|
|
296
|
-
result[key] = ev[key];
|
|
297
|
-
}
|
|
298
|
-
if (isObject(ev.implementation_fingerprint))
|
|
299
|
-
result.implementation_fingerprint = { fingerprint_digest: fingerprint_digest(ev.implementation_fingerprint) };
|
|
300
|
-
if (Array.isArray(ev.raw_log_refs))
|
|
301
|
-
result.raw_log_refs = [...ev.raw_log_refs].sort();
|
|
302
|
-
if (Array.isArray(ev.raw_log_pinned_refs))
|
|
303
|
-
result.raw_log_pinned_refs = ev.raw_log_pinned_refs.map(pinned_summary).filter(Boolean);
|
|
304
|
-
return result;
|
|
305
|
-
}
|
|
306
|
-
function evidence_file_ref(changeRoot, ev) {
|
|
307
|
-
if (!ev || typeof ev._path !== "string" || !ev._path)
|
|
308
|
-
return null;
|
|
309
|
-
const target = safe_within(changeRoot, ev._path);
|
|
310
|
-
if (target === null || !existsSync(target) || !statSync(target).isFile())
|
|
311
|
-
return null;
|
|
312
|
-
return {
|
|
313
|
-
kind: "evidence",
|
|
314
|
-
evidence_id: ev.evidence_id,
|
|
315
|
-
gate: ev.gate,
|
|
316
|
-
evidence_kind: ev.kind,
|
|
317
|
-
path: ev._path,
|
|
318
|
-
blob_sha: runtime.file_blob_sha(target),
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
export function apply_worker_executor_input_ref_digest(evidences, active) {
|
|
322
|
-
const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean).sort() : [];
|
|
323
|
-
const activeInput = {
|
|
324
|
-
kind: "apply_worker_chain",
|
|
325
|
-
evidence_id: active.evidence_id,
|
|
326
|
-
task_id: active.task_id,
|
|
327
|
-
apply_worker_chain_id: active.apply_worker_chain_id,
|
|
328
|
-
executor_packet_fingerprint: active.executor_packet_fingerprint,
|
|
329
|
-
source_implementation_fingerprint: active.source_implementation_fingerprint,
|
|
330
|
-
declared_task_write_scope: active.declared_task_write_scope,
|
|
331
|
-
pre_edit_evidence_refs: preIds,
|
|
332
|
-
};
|
|
333
|
-
for (const field of ["pre_edit_proof_kind", "apply_execution_surface", "tdd_required", "no_tdd_reason"]) {
|
|
334
|
-
if (active[field] !== undefined)
|
|
335
|
-
activeInput[field] = active[field];
|
|
336
|
-
}
|
|
337
|
-
return worker_input_ref_digest([
|
|
338
|
-
activeInput,
|
|
339
|
-
...preIds.map((id) => evidence_summary(evidences.find((ev) => String(ev.evidence_id ?? "") === id))).filter(Boolean),
|
|
340
|
-
]);
|
|
341
|
-
}
|
|
342
|
-
export function apply_worker_guard_artifact_manifest_fingerprint(items) {
|
|
343
|
-
const stable = {
|
|
344
|
-
completion_proof_kind: items.completion_proof_kind ?? "green_tests",
|
|
345
|
-
pre_edit_proof_kind: items.pre_edit_proof_kind ?? "red_or_characterization",
|
|
346
|
-
pre_edit_evidence: Array.isArray(items.pre_edit_evidence) ? items.pre_edit_evidence : [],
|
|
347
|
-
green_test_run: items.green_test_run ?? null,
|
|
348
|
-
green_test_runs: Array.isArray(items.green_test_runs) ? items.green_test_runs : [],
|
|
349
|
-
alternative_verification: items.alternative_verification ?? null,
|
|
350
|
-
alternative_verifications: Array.isArray(items.alternative_verifications) ? items.alternative_verifications : [],
|
|
351
|
-
executor_report_ref: pinned_summary(items.executor_report_ref),
|
|
352
|
-
task_code_review_report_ref: pinned_summary(items.task_code_review_report_ref),
|
|
353
|
-
accepted_test_runner_report_ref: pinned_summary(items.accepted_test_runner_report_ref),
|
|
354
|
-
accepted_test_runner_report_refs: Array.isArray(items.accepted_test_runner_report_refs) ? items.accepted_test_runner_report_refs.map(pinned_summary).filter(Boolean) : [],
|
|
355
|
-
raw_log_pinned_refs: Array.isArray(items.raw_log_pinned_refs) ? items.raw_log_pinned_refs.map(pinned_summary).filter(Boolean) : [],
|
|
356
|
-
evidence_file_refs: Array.isArray(items.evidence_file_refs) ? items.evidence_file_refs.map(pinned_summary).filter(Boolean) : [],
|
|
357
|
-
active_chain: items.active_chain ?? null,
|
|
358
|
-
};
|
|
359
|
-
return {
|
|
360
|
-
...stable,
|
|
361
|
-
fingerprint_digest: fingerprint_obj(stable),
|
|
362
|
-
helper_version: "apply-worker-guard-artifact-v1",
|
|
363
|
-
computed_at: new Date().toISOString(),
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
export function fingerprint_digest(value) {
|
|
367
|
-
if (typeof value === "string")
|
|
368
|
-
return value;
|
|
369
|
-
if (isObject(value) && typeof value.fingerprint_digest === "string")
|
|
370
|
-
return value.fingerprint_digest;
|
|
371
|
-
return "";
|
|
372
|
-
}
|
|
373
|
-
export function fingerprint_matches(actual, expected) {
|
|
374
|
-
const actualDigest = fingerprint_digest(actual);
|
|
375
|
-
const expectedDigest = fingerprint_digest(expected);
|
|
376
|
-
if (actualDigest && expectedDigest)
|
|
377
|
-
return actualDigest === expectedDigest;
|
|
378
|
-
return deepEqual(actual, expected);
|
|
379
|
-
}
|
|
380
|
-
export function read_pinned_artifact_json(changeRoot, refItem) {
|
|
381
|
-
if (!isObject(refItem) || typeof refItem.path !== "string")
|
|
382
|
-
return null;
|
|
383
|
-
const target = safe_within(changeRoot, refItem.path);
|
|
384
|
-
if (target === null || !existsSync(target) || !statSync(target).isFile() || statSync(target).size <= 0)
|
|
385
|
-
return null;
|
|
386
|
-
try {
|
|
387
|
-
const parsed = JSON.parse(readFileSync(target, "utf8"));
|
|
388
|
-
return isObject(parsed) ? parsed : null;
|
|
389
|
-
}
|
|
390
|
-
catch {
|
|
391
|
-
return null;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
function expected_dir(kind, taskId) {
|
|
395
|
-
if (!taskId)
|
|
396
|
-
return null;
|
|
397
|
-
if (kind === "raw_transcript")
|
|
398
|
-
return `.superspec/raw/apply/${taskId}/`;
|
|
399
|
-
if (kind === "worker_report" || kind === "status_report" || kind === "diff_transcript")
|
|
400
|
-
return `.superspec/reports/apply/${taskId}/`;
|
|
401
|
-
return null;
|
|
402
|
-
}
|
|
403
|
-
function ensure_materialized_sha(value, field) {
|
|
404
|
-
if (typeof value !== "string" || !value.startsWith("sha256:")) {
|
|
405
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: ${field} must be a sha256 fingerprint`);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function ensure_materialized_fingerprint(value, field) {
|
|
409
|
-
if (typeof value === "string" && value.startsWith("sha256:"))
|
|
410
|
-
return;
|
|
411
|
-
if (isObject(value) && typeof value.fingerprint_digest === "string" && value.fingerprint_digest.startsWith("sha256:"))
|
|
412
|
-
return;
|
|
413
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: ${field} must be a sha256 fingerprint`);
|
|
414
|
-
}
|
|
415
|
-
function materialized_bytes(content) {
|
|
416
|
-
if (Buffer.isBuffer(content))
|
|
417
|
-
return content;
|
|
418
|
-
if (typeof content === "string")
|
|
419
|
-
return Buffer.from(content);
|
|
420
|
-
if (isObject(content))
|
|
421
|
-
return Buffer.from(`${JSON.stringify(content, null, 2)}\n`);
|
|
422
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: content must be string, Buffer, or object");
|
|
423
|
-
}
|
|
424
|
-
function materialized_ref_path(artifactPath) {
|
|
425
|
-
return `${artifactPath.replace(/(\.[^/.]+)?$/u, "")}.ref.json`;
|
|
426
|
-
}
|
|
427
|
-
function write_materialized_file_atomic(pathValue, bytes) {
|
|
428
|
-
mkdirSync(dirname(pathValue), { recursive: true });
|
|
429
|
-
const tmp = `${pathValue}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
430
|
-
try {
|
|
431
|
-
writeFileSync(tmp, bytes);
|
|
432
|
-
renameSync(tmp, pathValue);
|
|
433
|
-
}
|
|
434
|
-
catch (err) {
|
|
435
|
-
rmSync(tmp, { force: true });
|
|
436
|
-
throw err;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
function materialized_file_snapshot(pathValue) {
|
|
440
|
-
if (!existsSync(pathValue))
|
|
441
|
-
return { existed: false };
|
|
442
|
-
const st = statSync(pathValue);
|
|
443
|
-
if (!st.isFile())
|
|
444
|
-
return { existed: false };
|
|
445
|
-
return { existed: true, bytes: readFileSync(pathValue) };
|
|
446
|
-
}
|
|
447
|
-
function restore_materialized_file(pathValue, snapshot) {
|
|
448
|
-
if (snapshot.existed) {
|
|
449
|
-
write_materialized_file_atomic(pathValue, snapshot.bytes);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
rmSync(pathValue, { force: true });
|
|
453
|
-
}
|
|
454
|
-
export function materialize_apply_worker_artifact_ref(changeRoot, input) {
|
|
455
|
-
const taskId = input.taskId;
|
|
456
|
-
const kind = input.kind;
|
|
457
|
-
const role = input.role;
|
|
458
|
-
if (typeof taskId !== "string" || !taskId || taskId.includes("/") || taskId.includes("..")) {
|
|
459
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: taskId must be a safe task id");
|
|
460
|
-
}
|
|
461
|
-
if (!APPLY_WORKER_ARTIFACT_KINDS.has(kind))
|
|
462
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: unsupported kind ${kind}`);
|
|
463
|
-
if (!APPLY_WORKER_ARTIFACT_ROLES.has(role))
|
|
464
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: unsupported role ${role}`);
|
|
465
|
-
const baseDir = expected_dir(kind, taskId);
|
|
466
|
-
if (!baseDir)
|
|
467
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: unsupported kind ${kind}`);
|
|
468
|
-
const filename = input.filename ?? `${role}-${kind}.${kind === "worker_report" || kind === "status_report" ? "json" : "log"}`;
|
|
469
|
-
if (filename.includes("/") || filename.includes("\\") || filename.includes("..") || !filename.trim()) {
|
|
470
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: filename must be a safe basename");
|
|
471
|
-
}
|
|
472
|
-
const artifactRel = input.path ?? `${baseDir}${filename}`;
|
|
473
|
-
if (!artifactRel.startsWith(baseDir))
|
|
474
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: path must stay under ${baseDir}`);
|
|
475
|
-
const artifactPath = safe_within(changeRoot, artifactRel);
|
|
476
|
-
if (artifactPath === null)
|
|
477
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: path escapes change root");
|
|
478
|
-
const refRel = input.refPath ?? materialized_ref_path(artifactRel);
|
|
479
|
-
if (!refRel.startsWith(baseDir))
|
|
480
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: refPath must stay under ${baseDir}`);
|
|
481
|
-
const refPath = safe_within(changeRoot, refRel);
|
|
482
|
-
if (refPath === null)
|
|
483
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: refPath escapes change root");
|
|
484
|
-
if (refPath === artifactPath)
|
|
485
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: refPath must differ from artifact path");
|
|
486
|
-
const workerChainContext = input.workerChainContext ?? (input.applyWorkerChainId ? "executor_worker" : "none");
|
|
487
|
-
if (workerChainContext !== "none" && workerChainContext !== "executor_worker") {
|
|
488
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: workerChainContext must be none or executor_worker");
|
|
489
|
-
}
|
|
490
|
-
if (workerChainContext === "executor_worker" && (typeof input.applyWorkerChainId !== "string" || !input.applyWorkerChainId)) {
|
|
491
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: executor_worker refs require applyWorkerChainId");
|
|
492
|
-
}
|
|
493
|
-
if (workerChainContext === "none" && input.applyWorkerChainId !== undefined) {
|
|
494
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: non-chain refs must not declare applyWorkerChainId");
|
|
495
|
-
}
|
|
496
|
-
ensure_materialized_sha(input.originPacketFingerprint, "originPacketFingerprint");
|
|
497
|
-
ensure_materialized_fingerprint(input.sourceImplementationFingerprint, "sourceImplementationFingerprint");
|
|
498
|
-
ensure_materialized_sha(input.inputRefDigest, "inputRefDigest");
|
|
499
|
-
const implementationField = role === "executor" ? "producedImplementationFingerprint" : "observedImplementationFingerprint";
|
|
500
|
-
ensure_materialized_fingerprint(input[implementationField], implementationField);
|
|
501
|
-
if (kind === "raw_transcript") {
|
|
502
|
-
for (const field of ["command", "cwd", "phase", "testId"]) {
|
|
503
|
-
if (typeof input[field] !== "string" || !input[field]) {
|
|
504
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: raw transcript requires ${field}`);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
if (typeof input.exitCode !== "number")
|
|
508
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: raw transcript requires exitCode");
|
|
509
|
-
}
|
|
510
|
-
const bytes = materialized_bytes(input.content);
|
|
511
|
-
const maxBytes = input.maxBytes ?? DEFAULT_APPLY_WORKER_ARTIFACT_MAX_BYTES;
|
|
512
|
-
if (bytes.length === 0)
|
|
513
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: artifact content is empty");
|
|
514
|
-
if (bytes.length > maxBytes)
|
|
515
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: artifact content exceeds maxBytes");
|
|
516
|
-
const metadata = input.metadata ?? {};
|
|
517
|
-
for (const reserved of [
|
|
518
|
-
"root",
|
|
519
|
-
"path",
|
|
520
|
-
"blob_sha",
|
|
521
|
-
"size_bytes",
|
|
522
|
-
"kind",
|
|
523
|
-
"role",
|
|
524
|
-
"task_id",
|
|
525
|
-
"created_at",
|
|
526
|
-
"worker_chain_context",
|
|
527
|
-
"apply_worker_chain_id",
|
|
528
|
-
"origin_packet_fingerprint",
|
|
529
|
-
"guard_fingerprint",
|
|
530
|
-
"source_implementation_fingerprint",
|
|
531
|
-
"produced_implementation_fingerprint",
|
|
532
|
-
"observed_implementation_fingerprint",
|
|
533
|
-
"input_ref_digest",
|
|
534
|
-
"command",
|
|
535
|
-
"cwd",
|
|
536
|
-
"phase",
|
|
537
|
-
"test_id",
|
|
538
|
-
"exit_code",
|
|
539
|
-
]) {
|
|
540
|
-
if (metadata[reserved] !== undefined)
|
|
541
|
-
throw new GuardError(`apply_worker_artifact_materialize_invalid: metadata must not override ${reserved}`);
|
|
542
|
-
}
|
|
543
|
-
const artifactSnapshot = materialized_file_snapshot(artifactPath);
|
|
544
|
-
write_materialized_file_atomic(artifactPath, bytes);
|
|
545
|
-
const st = statSync(artifactPath);
|
|
546
|
-
if (!st.isFile() || st.size <= 0)
|
|
547
|
-
throw new GuardError("apply_worker_artifact_materialize_invalid: artifact write failed");
|
|
548
|
-
const ref = {
|
|
549
|
-
root: "change",
|
|
550
|
-
path: artifactRel,
|
|
551
|
-
blob_sha: file_blob_sha(artifactPath),
|
|
552
|
-
size_bytes: st.size,
|
|
553
|
-
kind,
|
|
554
|
-
role,
|
|
555
|
-
task_id: taskId,
|
|
556
|
-
created_at: new Date().toISOString(),
|
|
557
|
-
worker_chain_context: workerChainContext,
|
|
558
|
-
origin_packet_fingerprint: input.originPacketFingerprint,
|
|
559
|
-
guard_fingerprint: input.originPacketFingerprint,
|
|
560
|
-
source_implementation_fingerprint: input.sourceImplementationFingerprint,
|
|
561
|
-
input_ref_digest: input.inputRefDigest,
|
|
562
|
-
...(workerChainContext === "executor_worker" ? { apply_worker_chain_id: input.applyWorkerChainId } : {}),
|
|
563
|
-
...(role === "executor"
|
|
564
|
-
? { produced_implementation_fingerprint: input.producedImplementationFingerprint }
|
|
565
|
-
: { observed_implementation_fingerprint: input.observedImplementationFingerprint }),
|
|
566
|
-
...(kind === "raw_transcript" ? {
|
|
567
|
-
command: input.command,
|
|
568
|
-
cwd: input.cwd,
|
|
569
|
-
phase: input.phase,
|
|
570
|
-
test_id: input.testId,
|
|
571
|
-
exit_code: input.exitCode,
|
|
572
|
-
} : {}),
|
|
573
|
-
...metadata,
|
|
574
|
-
};
|
|
575
|
-
try {
|
|
576
|
-
write_materialized_file_atomic(refPath, Buffer.from(`${JSON.stringify(ref, null, 2)}\n`));
|
|
577
|
-
}
|
|
578
|
-
catch (err) {
|
|
579
|
-
restore_materialized_file(artifactPath, artifactSnapshot);
|
|
580
|
-
throw err;
|
|
581
|
-
}
|
|
582
|
-
return { ...ref, ref_path: refRel };
|
|
583
|
-
}
|
|
584
|
-
const WORKER_REPORT_FIELD_TYPES = {
|
|
585
|
-
command: "string",
|
|
586
|
-
command_source: "string",
|
|
587
|
-
cwd: "string",
|
|
588
|
-
phase: "string",
|
|
589
|
-
task_id: "string",
|
|
590
|
-
test_id: "string",
|
|
591
|
-
exit_code: "number",
|
|
592
|
-
semantic_status_candidate: "string",
|
|
593
|
-
result_summary: "string",
|
|
594
|
-
runtime_raw_transcript_ref: "ref",
|
|
595
|
-
repo_head: "string",
|
|
596
|
-
pre_dirty_state: "object",
|
|
597
|
-
post_dirty_state: "object",
|
|
598
|
-
changed_files: "array",
|
|
599
|
-
untracked_files: "array",
|
|
600
|
-
invariant_refs: "array",
|
|
601
|
-
source_refs: "non_empty_array",
|
|
602
|
-
apply_worker_chain_id: "string",
|
|
603
|
-
guard_fingerprint: "string",
|
|
604
|
-
suggested_green_checks: "array",
|
|
605
|
-
test_invariant_mapping: "object",
|
|
606
|
-
runtime_artifact_refs: "array",
|
|
607
|
-
risk_notes: "array",
|
|
608
|
-
review_status_candidate: "string",
|
|
609
|
-
executor_report_ref: "ref",
|
|
610
|
-
actual_changed_files: "array",
|
|
611
|
-
implementation_dirty_file_list: "array",
|
|
612
|
-
implementation_fingerprint: "fingerprint",
|
|
613
|
-
source_implementation_fingerprint: "fingerprint",
|
|
614
|
-
produced_implementation_fingerprint: "fingerprint",
|
|
615
|
-
observed_implementation_fingerprint: "fingerprint",
|
|
616
|
-
guard_artifact_manifest_fingerprint: "fingerprint",
|
|
617
|
-
scope_verdict: "string",
|
|
618
|
-
protected_path_verdict: "string",
|
|
619
|
-
executor_report_mismatch: "mismatch",
|
|
620
|
-
test_invariant_mapping_verdict: "string",
|
|
621
|
-
suggested_green_test_ids: "array",
|
|
622
|
-
runtime_raw_git_status_transcript_ref: "ref",
|
|
623
|
-
runtime_raw_git_diff_name_status_transcript_ref: "ref",
|
|
624
|
-
runtime_path_scoped_diff_transcript_refs: "array",
|
|
625
|
-
verification_status_candidate: "string",
|
|
626
|
-
task_completion_verdict: "string",
|
|
627
|
-
chain_consistency_verdict: "string",
|
|
628
|
-
acceptance_coverage_verdict: "string",
|
|
629
|
-
invariant_coverage_verdict: "string",
|
|
630
|
-
test_coverage_verdict: "string",
|
|
631
|
-
expected_freshness_fingerprint: "fingerprint",
|
|
632
|
-
observed_freshness_fingerprint: "fingerprint",
|
|
633
|
-
freshness_verdict: "string",
|
|
634
|
-
completion_proof_kind: "string",
|
|
635
|
-
pre_edit_proof_kind: "string",
|
|
636
|
-
green_test_run_evidence_refs: "array",
|
|
637
|
-
alternative_verification_evidence_refs: "array",
|
|
638
|
-
apply_execution_surface: "string",
|
|
639
|
-
task_code_review_report_ref: "ref",
|
|
640
|
-
unexpected_guard_owned_dirty_paths: "array",
|
|
641
|
-
executor_code_review_mismatch: "mismatch",
|
|
642
|
-
test_evidence_mismatch: "mismatch",
|
|
643
|
-
diff_summary_refs: "array",
|
|
644
|
-
triggered_stop_conditions: "array",
|
|
645
|
-
unverified_items: "array",
|
|
646
|
-
};
|
|
647
|
-
function report_field_valid(value, fieldType) {
|
|
648
|
-
if (fieldType === "array")
|
|
649
|
-
return Array.isArray(value);
|
|
650
|
-
if (fieldType === "fingerprint")
|
|
651
|
-
return Boolean(fingerprint_digest(value));
|
|
652
|
-
if (fieldType === "mismatch")
|
|
653
|
-
return value !== undefined;
|
|
654
|
-
if (fieldType === "non_empty_array")
|
|
655
|
-
return Array.isArray(value) && value.length > 0;
|
|
656
|
-
if (fieldType === "number")
|
|
657
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
658
|
-
if (fieldType === "object")
|
|
659
|
-
return isObject(value);
|
|
660
|
-
if (fieldType === "ref")
|
|
661
|
-
return isObject(value) || (typeof value === "string" && value.trim().length > 0);
|
|
662
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
663
|
-
}
|
|
664
|
-
function report_required_field_reasons(content, fields, label, code) {
|
|
665
|
-
const problems = [];
|
|
666
|
-
for (const field of fields) {
|
|
667
|
-
const fieldType = WORKER_REPORT_FIELD_TYPES[field] ?? "string";
|
|
668
|
-
if (!report_field_valid(content[field], fieldType)) {
|
|
669
|
-
problems.push(reason(code, `${label}: report requires ${field} (${fieldType})`, [label, field]));
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
return problems;
|
|
673
|
-
}
|
|
674
|
-
function report_pass_verdict_reasons(content, fields, label, code) {
|
|
675
|
-
return fields.flatMap((field) => content[field] === "pass"
|
|
676
|
-
? []
|
|
677
|
-
: [reason(code, `${label}: report requires ${field}=pass`, [label, field])]);
|
|
678
|
-
}
|
|
679
|
-
function mismatch_clear(value) {
|
|
680
|
-
if (value === false || value === "none" || value === "pass")
|
|
681
|
-
return true;
|
|
682
|
-
if (Array.isArray(value) && value.length === 0)
|
|
683
|
-
return true;
|
|
684
|
-
if (isObject(value)) {
|
|
685
|
-
if (value.status === "pass" || value.status === "none")
|
|
686
|
-
return true;
|
|
687
|
-
if (value.mismatch === false || value.has_mismatch === false)
|
|
688
|
-
return true;
|
|
689
|
-
if (Array.isArray(value.items) && value.items.length === 0)
|
|
690
|
-
return true;
|
|
691
|
-
}
|
|
692
|
-
return false;
|
|
693
|
-
}
|
|
694
|
-
function report_mismatch_clear_reasons(content, fields, label, code) {
|
|
695
|
-
return fields.flatMap((field) => mismatch_clear(content[field])
|
|
696
|
-
? []
|
|
697
|
-
: [reason(code, `${label}: report requires ${field} to be clear`, [label, field])]);
|
|
698
|
-
}
|
|
699
|
-
function report_empty_array_reasons(content, fields, label, code) {
|
|
700
|
-
return fields.flatMap((field) => Array.isArray(content[field]) && content[field].length === 0
|
|
701
|
-
? []
|
|
702
|
-
: [reason(code, `${label}: report requires ${field} to be an empty array`, [label, field])]);
|
|
703
|
-
}
|
|
704
|
-
function worker_report_policy_reasons(content, label, code) {
|
|
705
|
-
const problems = [];
|
|
706
|
-
let inlineChars = 0;
|
|
707
|
-
for (const field of ["truncated", "is_truncated", "report_truncated", "output_truncated"]) {
|
|
708
|
-
if (content[field] === true)
|
|
709
|
-
problems.push(reason(code, `${label}: worker report must not be truncated (${field})`, [label, field]));
|
|
710
|
-
}
|
|
711
|
-
for (const [field, value] of Object.entries(content)) {
|
|
712
|
-
if (typeof value !== "string")
|
|
713
|
-
continue;
|
|
714
|
-
if (field.endsWith("_ref") || field.endsWith("_refs") || field.endsWith("_fingerprint") || field === "role")
|
|
715
|
-
continue;
|
|
716
|
-
inlineChars += value.length;
|
|
717
|
-
if (value.length > APPLY_WORKER_MAX_INLINE_REPORT_CHARS) {
|
|
718
|
-
problems.push(reason(code, `${label}: worker report field ${field} exceeds max_inline_report_chars=${APPLY_WORKER_MAX_INLINE_REPORT_CHARS}`, [label, field]));
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
if (inlineChars > APPLY_WORKER_MAX_INLINE_REPORT_CHARS) {
|
|
722
|
-
problems.push(reason(code, `${label}: worker report inline text exceeds max_inline_report_chars=${APPLY_WORKER_MAX_INLINE_REPORT_CHARS}`, [label]));
|
|
723
|
-
}
|
|
724
|
-
for (const field of ["raw_log", "raw_logs", "raw_output", "full_log", "full_logs", "full_diff", "inline_diff", "compile_output", "compiler_output", "build_output", "generated_code"]) {
|
|
725
|
-
const value = content[field];
|
|
726
|
-
if (typeof value === "string" && value.trim()) {
|
|
727
|
-
problems.push(reason(code, `${label}: worker report must use artifact refs instead of inline ${field}`, [label, field]));
|
|
728
|
-
}
|
|
729
|
-
else if (Array.isArray(value) && value.length > 0) {
|
|
730
|
-
problems.push(reason(code, `${label}: worker report must use artifact refs instead of inline ${field}`, [label, field]));
|
|
731
|
-
}
|
|
732
|
-
else if (isObject(value) && Object.keys(value).length > 0) {
|
|
733
|
-
problems.push(reason(code, `${label}: worker report must use artifact refs instead of inline ${field}`, [label, field]));
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return problems;
|
|
737
|
-
}
|
|
738
|
-
function validate_worker_report_content(content, refItem, label, expected, code) {
|
|
739
|
-
const problems = [];
|
|
740
|
-
if (!content)
|
|
741
|
-
return [reason(code, `${label}: worker report artifact must be a JSON object`, [label])];
|
|
742
|
-
problems.push(...worker_report_policy_reasons(content, label, code));
|
|
743
|
-
if (expected.role && content.role !== expected.role)
|
|
744
|
-
problems.push(reason(code, `${label}: report role must be ${expected.role}`, [label]));
|
|
745
|
-
if (expected.taskId && content.task_id !== expected.taskId)
|
|
746
|
-
problems.push(reason(code, `${label}: report task_id must be ${expected.taskId}`, [label]));
|
|
747
|
-
if (expected.chainId && content.apply_worker_chain_id !== expected.chainId)
|
|
748
|
-
problems.push(reason(code, `${label}: report apply_worker_chain_id mismatch`, [label]));
|
|
749
|
-
if (typeof refItem.created_at !== "string" || Number.isNaN(Date.parse(refItem.created_at))) {
|
|
750
|
-
problems.push(reason(code, `${label}: worker_report pinned ref requires created_at`, [label]));
|
|
751
|
-
}
|
|
752
|
-
for (const field of ["origin_packet_fingerprint", "input_ref_digest"]) {
|
|
753
|
-
if (typeof content[field] !== "string" || !String(content[field]).startsWith("sha256:")) {
|
|
754
|
-
problems.push(reason(code, `${label}: report requires ${field}`, [label]));
|
|
755
|
-
}
|
|
756
|
-
if (refItem[field] !== undefined && content[field] !== refItem[field]) {
|
|
757
|
-
problems.push(reason(code, `${label}: report ${field} must match pinned ref`, [label]));
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
if (typeof content.guard_fingerprint !== "string" || !content.guard_fingerprint.startsWith("sha256:")) {
|
|
761
|
-
problems.push(reason(code, `${label}: report requires guard_fingerprint`, [label]));
|
|
762
|
-
}
|
|
763
|
-
else if (content.guard_fingerprint !== content.origin_packet_fingerprint) {
|
|
764
|
-
problems.push(reason(code, `${label}: report guard_fingerprint must echo origin_packet_fingerprint`, [label]));
|
|
765
|
-
}
|
|
766
|
-
if (refItem.guard_fingerprint !== undefined && content.guard_fingerprint !== refItem.guard_fingerprint) {
|
|
767
|
-
problems.push(reason(code, `${label}: report guard_fingerprint must match pinned ref`, [label]));
|
|
768
|
-
}
|
|
769
|
-
if (!fingerprint_digest(content.source_implementation_fingerprint)) {
|
|
770
|
-
problems.push(reason(code, `${label}: report requires source_implementation_fingerprint`, [label]));
|
|
771
|
-
}
|
|
772
|
-
if (!fingerprint_digest(refItem.source_implementation_fingerprint)) {
|
|
773
|
-
problems.push(reason(code, `${label}: pinned ref requires source_implementation_fingerprint`, [label]));
|
|
774
|
-
}
|
|
775
|
-
if (fingerprint_digest(content.source_implementation_fingerprint)
|
|
776
|
-
&& fingerprint_digest(refItem.source_implementation_fingerprint)
|
|
777
|
-
&& !fingerprint_matches(content.source_implementation_fingerprint, refItem.source_implementation_fingerprint)) {
|
|
778
|
-
problems.push(reason(code, `${label}: report source_implementation_fingerprint must match pinned ref`, [label]));
|
|
779
|
-
}
|
|
780
|
-
const implementationField = expected.role === "executor" ? "produced_implementation_fingerprint" : "observed_implementation_fingerprint";
|
|
781
|
-
const contentImplementation = fingerprint_digest(content[implementationField]);
|
|
782
|
-
const refImplementation = fingerprint_digest(refItem[implementationField]);
|
|
783
|
-
if (!contentImplementation)
|
|
784
|
-
problems.push(reason(code, `${label}: report requires ${implementationField}`, [label]));
|
|
785
|
-
if (!refImplementation)
|
|
786
|
-
problems.push(reason(code, `${label}: pinned ref requires ${implementationField}`, [label]));
|
|
787
|
-
if (contentImplementation && refImplementation && contentImplementation !== refImplementation) {
|
|
788
|
-
problems.push(reason(code, `${label}: report ${implementationField} must match pinned ref`, [label]));
|
|
789
|
-
}
|
|
790
|
-
if (Array.isArray(content.unverified_items) && content.unverified_items.length > 0) {
|
|
791
|
-
problems.push(reason(code, `${label}: report unverified_items must be empty before it can be pinned for downstream guard use`, [label]));
|
|
792
|
-
}
|
|
793
|
-
if (!Array.isArray(content.unverified_items)) {
|
|
794
|
-
problems.push(reason(code, `${label}: report requires unverified_items array`, [label]));
|
|
795
|
-
}
|
|
796
|
-
if (expected.role === "verifier" && !fingerprint_digest(content.observed_freshness_fingerprint)) {
|
|
797
|
-
problems.push(reason(code, `${label}: verifier report requires observed_freshness_fingerprint`, [label]));
|
|
798
|
-
}
|
|
799
|
-
if (expected.role === "test-runner") {
|
|
800
|
-
problems.push(...report_required_field_reasons(content, APPLY_TEST_RUNNER_REPORT_REQUIRED_FIELDS, label, code));
|
|
801
|
-
}
|
|
802
|
-
if (expected.role === "executor") {
|
|
803
|
-
problems.push(...report_required_field_reasons(content, APPLY_EXECUTOR_REPORT_REQUIRED_FIELDS, label, code));
|
|
804
|
-
}
|
|
805
|
-
if (expected.role === "verifier") {
|
|
806
|
-
problems.push(...report_required_field_reasons(content, APPLY_VERIFIER_REPORT_REQUIRED_FIELDS, label, code));
|
|
807
|
-
const proofKind = String(content.completion_proof_kind ?? "green_tests");
|
|
808
|
-
if (proofKind !== "green_tests" && proofKind !== "alternative_verification") {
|
|
809
|
-
problems.push(reason(code, `${label}: verifier report completion_proof_kind must be green_tests or alternative_verification`, [label]));
|
|
810
|
-
}
|
|
811
|
-
else if (proofKind === "green_tests") {
|
|
812
|
-
if (String(content.pre_edit_proof_kind ?? "red_or_characterization") !== "red_or_characterization") {
|
|
813
|
-
problems.push(reason(code, `${label}: green_tests verifier report requires pre_edit_proof_kind=red_or_characterization`, [label]));
|
|
814
|
-
}
|
|
815
|
-
if (!Array.isArray(content.green_test_run_evidence_refs) || content.green_test_run_evidence_refs.length === 0) {
|
|
816
|
-
problems.push(reason(code, `${label}: green_tests verifier report requires green_test_run_evidence_refs`, [label]));
|
|
817
|
-
}
|
|
818
|
-
if (!Array.isArray(content.red_test_run_evidence_refs) && !Array.isArray(content.characterization_test_run_evidence_refs)) {
|
|
819
|
-
problems.push(reason(code, `${label}: green_tests verifier report requires red_test_run_evidence_refs or characterization_test_run_evidence_refs`, [label]));
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
else {
|
|
823
|
-
if (content.pre_edit_proof_kind !== "no_tdd_declared") {
|
|
824
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report requires pre_edit_proof_kind=no_tdd_declared`, [label]));
|
|
825
|
-
}
|
|
826
|
-
if (!Array.isArray(content.alternative_verification_evidence_refs) || content.alternative_verification_evidence_refs.length === 0) {
|
|
827
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report requires alternative_verification_evidence_refs`, [label]));
|
|
828
|
-
}
|
|
829
|
-
if (Array.isArray(content.green_test_run_evidence_refs) && content.green_test_run_evidence_refs.length > 0) {
|
|
830
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report must not claim green_test_run_evidence_refs`, [label]));
|
|
831
|
-
}
|
|
832
|
-
if (Array.isArray(content.red_test_run_evidence_refs) && content.red_test_run_evidence_refs.length > 0) {
|
|
833
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report must not claim red_test_run_evidence_refs`, [label]));
|
|
834
|
-
}
|
|
835
|
-
if (Array.isArray(content.characterization_test_run_evidence_refs) && content.characterization_test_run_evidence_refs.length > 0) {
|
|
836
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report must not claim characterization_test_run_evidence_refs`, [label]));
|
|
837
|
-
}
|
|
838
|
-
if (content.tdd_required !== false) {
|
|
839
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report requires tdd_required=false`, [label]));
|
|
840
|
-
}
|
|
841
|
-
if (content.apply_execution_surface !== "implementation" && content.apply_execution_surface !== "runtime_config") {
|
|
842
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report requires implementation/runtime_config apply_execution_surface`, [label]));
|
|
843
|
-
}
|
|
844
|
-
if (!NO_TDD_REASONS.has(String(content.no_tdd_reason ?? ""))) {
|
|
845
|
-
problems.push(reason(code, `${label}: alternative_verification verifier report requires valid no_tdd_reason`, [label]));
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
problems.push(...report_pass_verdict_reasons(content, [
|
|
849
|
-
"verification_status_candidate",
|
|
850
|
-
"task_completion_verdict",
|
|
851
|
-
"chain_consistency_verdict",
|
|
852
|
-
"acceptance_coverage_verdict",
|
|
853
|
-
"invariant_coverage_verdict",
|
|
854
|
-
"test_coverage_verdict",
|
|
855
|
-
"freshness_verdict",
|
|
856
|
-
"scope_verdict",
|
|
857
|
-
"protected_path_verdict",
|
|
858
|
-
], label, code));
|
|
859
|
-
problems.push(...report_mismatch_clear_reasons(content, ["executor_code_review_mismatch", "test_evidence_mismatch"], label, code));
|
|
860
|
-
problems.push(...report_empty_array_reasons(content, ["unexpected_guard_owned_dirty_paths", "triggered_stop_conditions"], label, code));
|
|
861
|
-
}
|
|
862
|
-
if (expected.role === "code-reviewer") {
|
|
863
|
-
problems.push(...report_required_field_reasons(content, APPLY_CODE_REVIEW_REPORT_REQUIRED_FIELDS, label, code));
|
|
864
|
-
const contentDigest = fingerprint_digest(content.observed_implementation_fingerprint);
|
|
865
|
-
const refDigest = fingerprint_digest(refItem.observed_implementation_fingerprint);
|
|
866
|
-
if (!contentDigest)
|
|
867
|
-
problems.push(reason(code, `${label}: code-reviewer report requires observed_implementation_fingerprint`, [label]));
|
|
868
|
-
if (!refDigest)
|
|
869
|
-
problems.push(reason(code, `${label}: code-reviewer pinned ref requires observed_implementation_fingerprint`, [label]));
|
|
870
|
-
if (contentDigest && refDigest && contentDigest !== refDigest) {
|
|
871
|
-
problems.push(reason(code, `${label}: report observed_implementation_fingerprint must match pinned ref`, [label]));
|
|
872
|
-
}
|
|
873
|
-
problems.push(...report_pass_verdict_reasons(content, ["review_status_candidate", "scope_verdict", "protected_path_verdict", "test_invariant_mapping_verdict"], label, code));
|
|
874
|
-
problems.push(...report_mismatch_clear_reasons(content, ["executor_report_mismatch"], label, code));
|
|
875
|
-
}
|
|
876
|
-
return problems;
|
|
877
|
-
}
|
|
878
|
-
function validate_status_report_content(content, label, expected, code) {
|
|
879
|
-
const problems = [];
|
|
880
|
-
if (!content)
|
|
881
|
-
return [reason(code, `${label}: status report artifact must be a JSON object`, [label])];
|
|
882
|
-
if (expected.taskId && content.task_id !== expected.taskId)
|
|
883
|
-
problems.push(reason(code, `${label}: status report task_id must be ${expected.taskId}`, [label]));
|
|
884
|
-
if (expected.chainId && content.apply_worker_chain_id !== expected.chainId && content.chain_id !== expected.chainId) {
|
|
885
|
-
problems.push(reason(code, `${label}: status report apply_worker_chain_id mismatch`, [label]));
|
|
886
|
-
}
|
|
887
|
-
if (!fingerprint_digest(content.implementation_fingerprint)) {
|
|
888
|
-
problems.push(reason(code, `${label}: status report requires implementation_fingerprint`, [label]));
|
|
889
|
-
}
|
|
890
|
-
return problems;
|
|
891
|
-
}
|
|
892
|
-
function validate_raw_transcript_ref(refItem, label, code) {
|
|
893
|
-
const problems = [];
|
|
894
|
-
for (const field of ["command", "cwd", "phase", "test_id"]) {
|
|
895
|
-
if (typeof refItem[field] !== "string" || !refItem[field])
|
|
896
|
-
problems.push(reason(code, `${label}: raw transcript requires ${field}`, [label]));
|
|
897
|
-
}
|
|
898
|
-
if (typeof refItem.exit_code !== "number")
|
|
899
|
-
problems.push(reason(code, `${label}: raw transcript requires numeric exit_code`, [label]));
|
|
900
|
-
return problems;
|
|
901
|
-
}
|
|
902
|
-
function validate_pinned_artifact_identity(refItem, label, code) {
|
|
903
|
-
const problems = [];
|
|
904
|
-
if (typeof refItem.created_at !== "string" || Number.isNaN(Date.parse(refItem.created_at))) {
|
|
905
|
-
problems.push(reason(code, `${label}: pinned artifact ref requires created_at`, [label]));
|
|
906
|
-
}
|
|
907
|
-
if (refItem.worker_chain_context !== "none" && refItem.worker_chain_context !== "executor_worker") {
|
|
908
|
-
problems.push(reason(code, `${label}: worker_chain_context must be none or executor_worker`, [label]));
|
|
909
|
-
}
|
|
910
|
-
if (refItem.worker_chain_context === "executor_worker" && (typeof refItem.apply_worker_chain_id !== "string" || !refItem.apply_worker_chain_id)) {
|
|
911
|
-
problems.push(reason(code, `${label}: executor_worker ref requires apply_worker_chain_id`, [label]));
|
|
912
|
-
}
|
|
913
|
-
if (refItem.worker_chain_context === "none" && refItem.apply_worker_chain_id !== undefined) {
|
|
914
|
-
problems.push(reason(code, `${label}: non-chain ref must not declare apply_worker_chain_id`, [label]));
|
|
915
|
-
}
|
|
916
|
-
for (const field of ["origin_packet_fingerprint", "guard_fingerprint", "input_ref_digest"]) {
|
|
917
|
-
if (typeof refItem[field] !== "string" || !String(refItem[field]).startsWith("sha256:")) {
|
|
918
|
-
problems.push(reason(code, `${label}: pinned artifact ref requires ${field}`, [label, field]));
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
if (refItem.origin_packet_fingerprint !== undefined
|
|
922
|
-
&& refItem.guard_fingerprint !== undefined
|
|
923
|
-
&& refItem.guard_fingerprint !== refItem.origin_packet_fingerprint) {
|
|
924
|
-
problems.push(reason(code, `${label}: guard_fingerprint must echo origin_packet_fingerprint`, [label]));
|
|
925
|
-
}
|
|
926
|
-
if (!fingerprint_digest(refItem.source_implementation_fingerprint)) {
|
|
927
|
-
problems.push(reason(code, `${label}: pinned artifact ref requires source_implementation_fingerprint`, [label]));
|
|
928
|
-
}
|
|
929
|
-
const implementationField = refItem.role === "executor" ? "produced_implementation_fingerprint" : "observed_implementation_fingerprint";
|
|
930
|
-
if (!fingerprint_digest(refItem[implementationField])) {
|
|
931
|
-
problems.push(reason(code, `${label}: pinned artifact ref requires ${implementationField}`, [label]));
|
|
932
|
-
}
|
|
933
|
-
return problems;
|
|
934
|
-
}
|
|
935
|
-
function field_mismatch_reasons(actual, expected, field, label, code) {
|
|
936
|
-
return deepEqual(actual, expected)
|
|
937
|
-
? []
|
|
938
|
-
: [reason(code, `${label}: ${field} mismatch`, [label, field])];
|
|
939
|
-
}
|
|
940
|
-
function non_chain_artifact_context_reasons(refItem, label, code) {
|
|
941
|
-
const problems = [];
|
|
942
|
-
if (refItem.worker_chain_context === "executor_worker" || typeof refItem.apply_worker_chain_id === "string") {
|
|
943
|
-
problems.push(reason(code, `${label}: non-chain test-runner artifact must not declare executor_worker chain fields`, [label]));
|
|
944
|
-
}
|
|
945
|
-
return problems;
|
|
946
|
-
}
|
|
947
|
-
function worker_report_matches_test_run_reasons(report, ev, taskId, chainId, code) {
|
|
948
|
-
const problems = [];
|
|
949
|
-
for (const field of ["command", "cwd", "phase", "test_id", "exit_code", "guard_fingerprint"]) {
|
|
950
|
-
problems.push(...field_mismatch_reasons(report[field], ev[field], `worker_report.${field}`, "accepted_test_runner_report_ref", code));
|
|
951
|
-
}
|
|
952
|
-
for (const field of ["source_refs", "pre_dirty_state", "post_dirty_state", "changed_files", "untracked_files"]) {
|
|
953
|
-
problems.push(...field_mismatch_reasons(report[field], ev[field], `worker_report.${field}`, "accepted_test_runner_report_ref", code));
|
|
954
|
-
}
|
|
955
|
-
for (const field of ["expected_failure_signature", "expected_failure_classifier"]) {
|
|
956
|
-
if (ev[field] !== undefined || report[field] !== undefined) {
|
|
957
|
-
problems.push(...field_mismatch_reasons(report[field], ev[field], `worker_report.${field}`, "accepted_test_runner_report_ref", code));
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
problems.push(...field_mismatch_reasons(report.task_id, taskId, "worker_report.task_id", "accepted_test_runner_report_ref", code));
|
|
961
|
-
problems.push(...field_mismatch_reasons(report.semantic_status_candidate, ev.semantic_status, "worker_report.semantic_status_candidate", "accepted_test_runner_report_ref", code));
|
|
962
|
-
if (chainId) {
|
|
963
|
-
problems.push(...field_mismatch_reasons(report.apply_worker_chain_id, chainId, "worker_report.apply_worker_chain_id", "accepted_test_runner_report_ref", code));
|
|
964
|
-
}
|
|
965
|
-
return problems;
|
|
966
|
-
}
|
|
967
|
-
function raw_transcript_matches_test_run_reasons(refItem, ev, taskId, chainId, code) {
|
|
968
|
-
const problems = [];
|
|
969
|
-
for (const field of ["command", "cwd", "phase", "test_id", "exit_code"]) {
|
|
970
|
-
problems.push(...field_mismatch_reasons(refItem[field], ev[field], `raw_transcript.${field}`, "raw_log_pinned_refs", code));
|
|
971
|
-
}
|
|
972
|
-
problems.push(...field_mismatch_reasons(refItem.task_id, taskId, "raw_transcript.task_id", "raw_log_pinned_refs", code));
|
|
973
|
-
if (chainId) {
|
|
974
|
-
problems.push(...field_mismatch_reasons(refItem.apply_worker_chain_id, chainId, "raw_transcript.apply_worker_chain_id", "raw_log_pinned_refs", code));
|
|
975
|
-
}
|
|
976
|
-
return problems;
|
|
977
|
-
}
|
|
978
|
-
export function pinned_artifact_ref_reasons(changeRoot, refItem, label, expected = {}, code = "pinned_artifact_ref_invalid") {
|
|
979
|
-
const problems = [];
|
|
980
|
-
if (!isObject(refItem))
|
|
981
|
-
return [reason(code, `${label}: ref must be object`, [label])];
|
|
982
|
-
const kind = expected.kind ?? (typeof refItem.kind === "string" ? refItem.kind : "");
|
|
983
|
-
if (refItem.root !== "change")
|
|
984
|
-
problems.push(reason(code, `${label}: root must be change`, [label]));
|
|
985
|
-
for (const key of ["path", "blob_sha", "kind", "role", "task_id"]) {
|
|
986
|
-
if (typeof refItem[key] !== "string" || !refItem[key])
|
|
987
|
-
problems.push(reason(code, `${label}: ${key} must be a non-empty string`, [label]));
|
|
988
|
-
}
|
|
989
|
-
if (expected.role && (typeof refItem.role !== "string" || !refItem.role))
|
|
990
|
-
problems.push(reason(code, `${label}: role must be a non-empty string`, [label]));
|
|
991
|
-
if (typeof refItem.size_bytes !== "number")
|
|
992
|
-
problems.push(reason(code, `${label}: size_bytes must be a number`, [label]));
|
|
993
|
-
if (expected.kind && refItem.kind !== expected.kind)
|
|
994
|
-
problems.push(reason(code, `${label}: kind must be ${expected.kind}`, [label]));
|
|
995
|
-
if (expected.role && refItem.role !== expected.role)
|
|
996
|
-
problems.push(reason(code, `${label}: role must be ${expected.role}`, [label]));
|
|
997
|
-
if (expected.taskId && refItem.task_id !== expected.taskId)
|
|
998
|
-
problems.push(reason(code, `${label}: task_id must be ${expected.taskId}`, [label]));
|
|
999
|
-
if (expected.chainId) {
|
|
1000
|
-
if (refItem.worker_chain_context !== "executor_worker")
|
|
1001
|
-
problems.push(reason(code, `${label}: worker_chain_context must be executor_worker`, [label]));
|
|
1002
|
-
if (refItem.apply_worker_chain_id !== expected.chainId)
|
|
1003
|
-
problems.push(reason(code, `${label}: apply_worker_chain_id mismatch`, [label]));
|
|
1004
|
-
}
|
|
1005
|
-
const dir = expected_dir(kind, expected.taskId ?? (typeof refItem.task_id === "string" ? refItem.task_id : undefined));
|
|
1006
|
-
if (dir && typeof refItem.path === "string" && !refItem.path.startsWith(dir)) {
|
|
1007
|
-
problems.push(reason(code, `${label}: path must stay under ${dir}`, [label]));
|
|
1008
|
-
}
|
|
1009
|
-
const rel = typeof refItem.path === "string" ? refItem.path : "";
|
|
1010
|
-
const target = rel ? safe_within(changeRoot, rel) : null;
|
|
1011
|
-
if (target === null) {
|
|
1012
|
-
problems.push(reason(code, `${label}: path escapes change root`, [label]));
|
|
1013
|
-
return problems;
|
|
1014
|
-
}
|
|
1015
|
-
if (!existsSync(target) || !statSync(target).isFile()) {
|
|
1016
|
-
problems.push(reason(code, `${label}: path is not readable: ${rel}`, [label]));
|
|
1017
|
-
return problems;
|
|
1018
|
-
}
|
|
1019
|
-
const st = statSync(target);
|
|
1020
|
-
if (st.size <= 0)
|
|
1021
|
-
problems.push(reason(code, `${label}: path is empty: ${rel}`, [label]));
|
|
1022
|
-
if (typeof refItem.size_bytes === "number" && refItem.size_bytes !== st.size)
|
|
1023
|
-
problems.push(reason(code, `${label}: size_bytes is stale for ${rel}`, [label]));
|
|
1024
|
-
if (typeof refItem.blob_sha !== "string" || runtime.file_blob_sha(target) !== refItem.blob_sha)
|
|
1025
|
-
problems.push(reason(code, `${label}: blob_sha is stale for ${rel}`, [label]));
|
|
1026
|
-
problems.push(...validate_pinned_artifact_identity(refItem, label, code));
|
|
1027
|
-
if (kind === "raw_transcript")
|
|
1028
|
-
problems.push(...validate_raw_transcript_ref(refItem, label, code));
|
|
1029
|
-
if (kind === "worker_report")
|
|
1030
|
-
problems.push(...validate_worker_report_content(read_pinned_artifact_json(changeRoot, refItem), refItem, label, expected, code));
|
|
1031
|
-
if (kind === "status_report")
|
|
1032
|
-
problems.push(...validate_status_report_content(read_pinned_artifact_json(changeRoot, refItem), label, expected, code));
|
|
1033
|
-
return problems;
|
|
1034
|
-
}
|
|
1035
|
-
export function worker_test_run_reasons(changeRoot, ev, taskId, chainId, code = "test_run_worker_ref_missing") {
|
|
1036
|
-
const problems = [];
|
|
1037
|
-
if (ev.runner_origin !== "test-runner")
|
|
1038
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires runner_origin=test-runner`));
|
|
1039
|
-
if (typeof ev.phase !== "string" || !ev.phase)
|
|
1040
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires phase`));
|
|
1041
|
-
if (chainId) {
|
|
1042
|
-
if (ev.apply_execution_chain !== "executor_worker")
|
|
1043
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires apply_execution_chain=executor_worker`));
|
|
1044
|
-
if (ev.apply_worker_chain_id !== chainId)
|
|
1045
|
-
problems.push(reason(code, `${ev._path}: apply_worker_chain_id mismatch`));
|
|
1046
|
-
}
|
|
1047
|
-
else if (ev.apply_execution_chain === "executor_worker" || typeof ev.apply_worker_chain_id === "string") {
|
|
1048
|
-
problems.push(reason(code, `${ev._path}: non-chain test-runner test_run must not declare executor_worker chain fields`));
|
|
1049
|
-
}
|
|
1050
|
-
for (const field of ["command", "cwd", "repo_head", "guard_fingerprint"]) {
|
|
1051
|
-
if (typeof ev[field] !== "string" || !ev[field])
|
|
1052
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires ${field}`));
|
|
1053
|
-
}
|
|
1054
|
-
if (!Array.isArray(ev.source_refs) || ev.source_refs.length === 0)
|
|
1055
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires non-empty source_refs`));
|
|
1056
|
-
for (const field of ["pre_dirty_state", "post_dirty_state"]) {
|
|
1057
|
-
if (!isObject(ev[field]))
|
|
1058
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires ${field}`));
|
|
1059
|
-
}
|
|
1060
|
-
for (const field of ["changed_files", "untracked_files"]) {
|
|
1061
|
-
if (!Array.isArray(ev[field]))
|
|
1062
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires ${field}`));
|
|
1063
|
-
}
|
|
1064
|
-
if (typeof ev.exit_code !== "number")
|
|
1065
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires numeric exit_code`));
|
|
1066
|
-
if (!isObject(ev.implementation_fingerprint) || !fingerprint_digest(ev.implementation_fingerprint))
|
|
1067
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires implementation_fingerprint`));
|
|
1068
|
-
if (!isObject(ev.guard_artifact_manifest_fingerprint) || !fingerprint_digest(ev.guard_artifact_manifest_fingerprint))
|
|
1069
|
-
problems.push(reason(code, `${ev._path}: executor_worker test_run requires guard_artifact_manifest_fingerprint`));
|
|
1070
|
-
if (!isObject(ev.accepted_test_runner_report_ref)) {
|
|
1071
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires accepted_test_runner_report_ref`));
|
|
1072
|
-
}
|
|
1073
|
-
else {
|
|
1074
|
-
const reportRef = ev.accepted_test_runner_report_ref;
|
|
1075
|
-
problems.push(...pinned_artifact_ref_reasons(changeRoot, reportRef, "accepted_test_runner_report_ref", {
|
|
1076
|
-
kind: "worker_report",
|
|
1077
|
-
role: "test-runner",
|
|
1078
|
-
taskId,
|
|
1079
|
-
chainId: chainId ?? undefined,
|
|
1080
|
-
}, code));
|
|
1081
|
-
if (!chainId)
|
|
1082
|
-
problems.push(...non_chain_artifact_context_reasons(reportRef, "accepted_test_runner_report_ref", code));
|
|
1083
|
-
const report = read_pinned_artifact_json(changeRoot, reportRef);
|
|
1084
|
-
if (report)
|
|
1085
|
-
problems.push(...worker_report_matches_test_run_reasons(report, ev, taskId, chainId, code));
|
|
1086
|
-
}
|
|
1087
|
-
const rawRefs = ev.raw_log_pinned_refs;
|
|
1088
|
-
if (!Array.isArray(rawRefs) || rawRefs.length === 0 || !rawRefs.every(isObject)) {
|
|
1089
|
-
problems.push(reason(code, `${ev._path}: runner_origin=test-runner requires non-empty raw_log_pinned_refs`));
|
|
1090
|
-
}
|
|
1091
|
-
else {
|
|
1092
|
-
for (const refItem of rawRefs) {
|
|
1093
|
-
problems.push(...pinned_artifact_ref_reasons(changeRoot, refItem, "raw_log_pinned_refs", {
|
|
1094
|
-
kind: "raw_transcript",
|
|
1095
|
-
role: "test-runner",
|
|
1096
|
-
taskId,
|
|
1097
|
-
chainId: chainId ?? undefined,
|
|
1098
|
-
}, code));
|
|
1099
|
-
if (!chainId)
|
|
1100
|
-
problems.push(...non_chain_artifact_context_reasons(refItem, "raw_log_pinned_refs", code));
|
|
1101
|
-
problems.push(...raw_transcript_matches_test_run_reasons(refItem, ev, taskId, chainId, code));
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
const rawLogRefs = Array.isArray(ev.raw_log_refs) ? ev.raw_log_refs.map(String).sort() : [];
|
|
1105
|
-
const pinnedPaths = Array.isArray(rawRefs) ? rawRefs.filter(isObject).map((item) => String(item.path ?? "")).filter(Boolean).sort() : [];
|
|
1106
|
-
if (rawLogRefs.length === 0 || !deepEqual(rawLogRefs, pinnedPaths)) {
|
|
1107
|
-
problems.push(reason(code, `${ev._path}: raw_log_refs must match raw_log_pinned_refs paths exactly: ${renderList(rawLogRefs)} != ${renderList(pinnedPaths)}`));
|
|
1108
|
-
}
|
|
1109
|
-
return problems;
|
|
1110
|
-
}
|
|
1111
|
-
export function pre_edit_worker_test_run_reasons(changeRoot, ev, taskId, code = "pre_edit_test_run_invalid") {
|
|
1112
|
-
const problems = [];
|
|
1113
|
-
if (ev.kind !== "test_run")
|
|
1114
|
-
problems.push(reason(code, `${ev._path}: pre-edit evidence must be kind=test_run`));
|
|
1115
|
-
if (ev.gate !== "task_edit")
|
|
1116
|
-
problems.push(reason(code, `${ev._path}: pre-edit evidence must be gate=task_edit`));
|
|
1117
|
-
if (ev.task_id !== taskId)
|
|
1118
|
-
problems.push(reason(code, `${ev._path}: pre-edit evidence task_id must be ${taskId}`));
|
|
1119
|
-
const phase = typeof ev.phase === "string" ? ev.phase : "";
|
|
1120
|
-
const redOk = ev.semantic_status === "expected_failure" && (phase === "" || phase === "red");
|
|
1121
|
-
const characterizationOk = ev.semantic_status === "expected_success" && phase === "characterization";
|
|
1122
|
-
if (!redOk && !characterizationOk) {
|
|
1123
|
-
problems.push(reason(code, `${ev._path}: pre-edit evidence must be worker RED or characterization test_run`));
|
|
1124
|
-
}
|
|
1125
|
-
problems.push(...worker_test_run_reasons(changeRoot, ev, taskId, null, code));
|
|
1126
|
-
return problems;
|
|
1127
|
-
}
|
|
1128
|
-
function superseded_ids(evidences) {
|
|
1129
|
-
return effective_superseded_ids(evidences);
|
|
1130
|
-
}
|
|
1131
|
-
function live_pass_by_id(evidences, evidenceId) {
|
|
1132
|
-
const dead = superseded_ids(evidences);
|
|
1133
|
-
return evidences.find((ev) => isObject(ev)
|
|
1134
|
-
&& !ev._invalid
|
|
1135
|
-
&& ev.status === "pass"
|
|
1136
|
-
&& String(ev.evidence_id ?? "") === evidenceId
|
|
1137
|
-
&& !dead.has(evidenceId));
|
|
1138
|
-
}
|
|
1139
|
-
export function pre_edit_evidence_ref_reasons(changeRoot, evidences, active, taskId, code = "pre_edit_evidence_ref_invalid") {
|
|
1140
|
-
const problems = [];
|
|
1141
|
-
if (!isObject(active))
|
|
1142
|
-
return [reason(code, `task ${taskId} requires an active apply_worker_chain marker for pre-edit evidence validation`)];
|
|
1143
|
-
const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean) : [];
|
|
1144
|
-
const proofKind = String(active.pre_edit_proof_kind ?? "red_or_characterization");
|
|
1145
|
-
if (proofKind !== "red_or_characterization" && proofKind !== "no_tdd_declared") {
|
|
1146
|
-
return [reason(code, `task ${taskId} active apply_worker_chain has invalid pre_edit_proof_kind=${proofKind}`)];
|
|
1147
|
-
}
|
|
1148
|
-
if (proofKind === "no_tdd_declared") {
|
|
1149
|
-
if (preIds.length > 0)
|
|
1150
|
-
problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared must have empty pre_edit_evidence_refs`, preIds));
|
|
1151
|
-
if (active.tdd_required !== false)
|
|
1152
|
-
problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires tdd_required=false`));
|
|
1153
|
-
if (active.apply_execution_surface !== "implementation" && active.apply_execution_surface !== "runtime_config") {
|
|
1154
|
-
problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires implementation/runtime_config apply_execution_surface`));
|
|
1155
|
-
}
|
|
1156
|
-
if (!NO_TDD_REASONS.has(String(active.no_tdd_reason ?? ""))) {
|
|
1157
|
-
problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires valid no_tdd_reason`));
|
|
1158
|
-
}
|
|
1159
|
-
return problems;
|
|
1160
|
-
}
|
|
1161
|
-
if (preIds.length === 0)
|
|
1162
|
-
return [reason(code, `task ${taskId} active apply_worker_chain has no pre_edit_evidence_refs`)];
|
|
1163
|
-
for (const evidenceId of preIds) {
|
|
1164
|
-
const ev = live_pass_by_id(evidences, evidenceId);
|
|
1165
|
-
if (!ev) {
|
|
1166
|
-
problems.push(reason(code, `pre_edit_evidence_ref is not live/pass: ${evidenceId}`, [evidenceId]));
|
|
1167
|
-
continue;
|
|
1168
|
-
}
|
|
1169
|
-
problems.push(...pre_edit_worker_test_run_reasons(changeRoot, ev, taskId, code)
|
|
1170
|
-
.map((item) => ({ ...item, refs: item.refs.length > 0 ? item.refs : [evidenceId] })));
|
|
1171
|
-
}
|
|
1172
|
-
return problems;
|
|
1173
|
-
}
|
|
1174
|
-
export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences, taskId, chainId, refs) {
|
|
1175
|
-
const passEvidences = evidences.filter((ev) => isObject(ev) && !ev._invalid && ev.status === "pass");
|
|
1176
|
-
const active = passEvidences
|
|
1177
|
-
.filter((ev) => ev.gate === "task_complete" && ev.kind === "apply_worker_chain" && ev.task_id === taskId)
|
|
1178
|
-
.find((ev) => ev.chain_state === "active" && ev.apply_worker_chain_id === chainId);
|
|
1179
|
-
const greenIds = [...new Set([
|
|
1180
|
-
...(Array.isArray(refs.green_test_run_evidence_refs) ? refs.green_test_run_evidence_refs : []),
|
|
1181
|
-
refs.green_test_run_evidence_ref,
|
|
1182
|
-
].map(String).filter(Boolean))].sort();
|
|
1183
|
-
const greens = greenIds.map((greenId) => passEvidences
|
|
1184
|
-
.filter((ev) => ev.gate === "task_complete" && ev.kind === "test_run" && ev.task_id === taskId)
|
|
1185
|
-
.find((ev) => String(ev.evidence_id ?? "") === greenId)).filter((ev) => isObject(ev));
|
|
1186
|
-
const green = greens[0];
|
|
1187
|
-
const alternativeIds = [...new Set((Array.isArray(refs.alternative_verification_evidence_refs) ? refs.alternative_verification_evidence_refs : []).map(String).filter(Boolean))].sort();
|
|
1188
|
-
const alternatives = alternativeIds.map((evidenceId) => passEvidences
|
|
1189
|
-
.filter((ev) => (ev.kind === "alternative_verification" || ev.kind === "manual_verification") && ev.task_id === taskId)
|
|
1190
|
-
.find((ev) => String(ev.evidence_id ?? "") === evidenceId)).filter((ev) => isObject(ev));
|
|
1191
|
-
const alternative = alternatives[0];
|
|
1192
|
-
const completionProofKind = refs.completion_proof_kind ?? (alternativeIds.length > 0 ? "alternative_verification" : "green_tests");
|
|
1193
|
-
const preEditProofKind = String(active?.pre_edit_proof_kind ?? "red_or_characterization");
|
|
1194
|
-
const preIds = Array.isArray(active?.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String) : [];
|
|
1195
|
-
const preEditEvidence = preIds.map((id) => evidences.find((ev) => String(ev.evidence_id ?? "") === id)).filter((ev) => isObject(ev));
|
|
1196
|
-
const preEdit = preEditEvidence.map(evidence_summary).filter(Boolean);
|
|
1197
|
-
const rawRefs = greens.flatMap((item) => Array.isArray(item.raw_log_pinned_refs) ? item.raw_log_pinned_refs : []);
|
|
1198
|
-
const acceptedTestRunnerRefs = greens.map((item) => item.accepted_test_runner_report_ref).filter(Boolean);
|
|
1199
|
-
const evidenceFileRefs = [
|
|
1200
|
-
evidence_file_ref(changeRoot, active),
|
|
1201
|
-
...preEditEvidence.map((ev) => evidence_file_ref(changeRoot, ev)),
|
|
1202
|
-
...greens.map((ev) => evidence_file_ref(changeRoot, ev)),
|
|
1203
|
-
...alternatives.map((ev) => evidence_file_ref(changeRoot, ev)),
|
|
1204
|
-
].filter((item) => isObject(item));
|
|
1205
|
-
const expectedGuardRefs = [
|
|
1206
|
-
refs.executor_report_ref,
|
|
1207
|
-
refs.task_code_review_report_ref,
|
|
1208
|
-
refs.verifier_report_ref,
|
|
1209
|
-
...acceptedTestRunnerRefs,
|
|
1210
|
-
...rawRefs,
|
|
1211
|
-
...evidenceFileRefs,
|
|
1212
|
-
];
|
|
1213
|
-
const activeScope = Array.isArray(active?.declared_task_write_scope) ? active.declared_task_write_scope.map(String).filter(Boolean) : [];
|
|
1214
|
-
const implementation = apply_worker_implementation_fingerprint(repoRoot, changeRoot, expectedGuardRefs, { declaredTaskWriteScope: activeScope });
|
|
1215
|
-
const greenImplementationDigest = fingerprint_digest(green?.implementation_fingerprint);
|
|
1216
|
-
const guardArtifact = apply_worker_guard_artifact_manifest_fingerprint({
|
|
1217
|
-
completion_proof_kind: completionProofKind,
|
|
1218
|
-
pre_edit_proof_kind: preEditProofKind,
|
|
1219
|
-
pre_edit_evidence: preEdit,
|
|
1220
|
-
green_test_run: evidence_summary(green),
|
|
1221
|
-
green_test_runs: greens.map(evidence_summary).filter(Boolean),
|
|
1222
|
-
alternative_verification: evidence_summary(alternative),
|
|
1223
|
-
alternative_verifications: alternatives.map(evidence_summary).filter(Boolean),
|
|
1224
|
-
executor_report_ref: refs.executor_report_ref,
|
|
1225
|
-
task_code_review_report_ref: refs.task_code_review_report_ref,
|
|
1226
|
-
accepted_test_runner_report_ref: green?.accepted_test_runner_report_ref,
|
|
1227
|
-
accepted_test_runner_report_refs: acceptedTestRunnerRefs,
|
|
1228
|
-
raw_log_pinned_refs: rawRefs,
|
|
1229
|
-
evidence_file_refs: evidenceFileRefs,
|
|
1230
|
-
active_chain: active ? {
|
|
1231
|
-
evidence_id: active.evidence_id,
|
|
1232
|
-
task_id: active.task_id,
|
|
1233
|
-
apply_worker_chain_id: active.apply_worker_chain_id,
|
|
1234
|
-
executor_packet_fingerprint: active.executor_packet_fingerprint,
|
|
1235
|
-
source_implementation_fingerprint: active.source_implementation_fingerprint,
|
|
1236
|
-
declared_task_write_scope: active.declared_task_write_scope,
|
|
1237
|
-
pre_edit_evidence_refs: active.pre_edit_evidence_refs,
|
|
1238
|
-
pre_edit_proof_kind: active.pre_edit_proof_kind,
|
|
1239
|
-
apply_execution_surface: active.apply_execution_surface,
|
|
1240
|
-
tdd_required: active.tdd_required,
|
|
1241
|
-
no_tdd_reason: active.no_tdd_reason,
|
|
1242
|
-
} : null,
|
|
1243
|
-
});
|
|
1244
|
-
const stable = {
|
|
1245
|
-
task_id: taskId,
|
|
1246
|
-
apply_worker_chain_id: chainId,
|
|
1247
|
-
completion_proof_kind: completionProofKind,
|
|
1248
|
-
pre_edit_proof_kind: preEditProofKind,
|
|
1249
|
-
repo_head: repo_head(repoRoot),
|
|
1250
|
-
implementation_fingerprint: {
|
|
1251
|
-
repo_head: implementation.repo_head,
|
|
1252
|
-
declared_task_write_scope: implementation.declared_task_write_scope,
|
|
1253
|
-
protected_path_refs: implementation.protected_path_refs,
|
|
1254
|
-
implementation_dirty_file_list: implementation.implementation_dirty_file_list,
|
|
1255
|
-
scoped_name_status_transcript_digest: implementation.scoped_name_status_transcript_digest,
|
|
1256
|
-
scoped_diff_transcript_digest: implementation.scoped_diff_transcript_digest,
|
|
1257
|
-
dirty_files: implementation.dirty_files,
|
|
1258
|
-
fingerprint_digest: implementation.fingerprint_digest,
|
|
1259
|
-
},
|
|
1260
|
-
guard_artifact_manifest_fingerprint: {
|
|
1261
|
-
fingerprint_digest: guardArtifact.fingerprint_digest,
|
|
1262
|
-
},
|
|
1263
|
-
green_implementation_fingerprint: greenImplementationDigest ? { fingerprint_digest: greenImplementationDigest } : null,
|
|
1264
|
-
pre_edit_evidence_refs: preIds,
|
|
1265
|
-
green_test_run_evidence_ref: refs.green_test_run_evidence_ref,
|
|
1266
|
-
green_test_run_evidence_refs: greenIds,
|
|
1267
|
-
alternative_verification_evidence_ref: alternativeIds[0] ?? null,
|
|
1268
|
-
alternative_verification_evidence_refs: alternativeIds,
|
|
1269
|
-
executor_report_ref: pinned_summary(refs.executor_report_ref),
|
|
1270
|
-
task_code_review_report_ref: pinned_summary(refs.task_code_review_report_ref),
|
|
1271
|
-
};
|
|
1272
|
-
return {
|
|
1273
|
-
...stable,
|
|
1274
|
-
implementation_dirty_file_list: implementation.implementation_dirty_file_list,
|
|
1275
|
-
guard_artifact_manifest: guardArtifact,
|
|
1276
|
-
unexpected_guard_owned_dirty_paths: implementation.unexpected_guard_owned_dirty_paths,
|
|
1277
|
-
protected_dirty_paths: implementation.protected_dirty_paths,
|
|
1278
|
-
protected_path_refs: implementation.protected_path_refs,
|
|
1279
|
-
fingerprint_digest: fingerprint_obj(stable),
|
|
1280
|
-
helper_version: "apply-worker-freshness-v1",
|
|
1281
|
-
computed_at: new Date().toISOString(),
|
|
1282
|
-
};
|
|
1283
|
-
}
|