@deksden-com/dd-flow-cli 0.9.0-beta.150 → 0.9.0-beta.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +17 -22
  3. package/dist/build-info.json +6 -6
  4. package/dist/harness-runtime/lib/agy-error-boundary.mjs +26 -5
  5. package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +67 -0
  6. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +10 -14
  7. package/dist/harness-runtime/lib/dd-agy.mjs +3 -3
  8. package/dist/harness-runtime/lib/dd-droid.mjs +2 -2
  9. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +8 -3
  10. package/dist/harness-runtime/lib/dd-opencode.mjs +2 -2
  11. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +1 -1
  12. package/dist/harness-runtime/lib/dd-zcode.mjs +37 -12
  13. package/dist/harness-runtime/lib/delegation-instructions.d.mts +1 -1
  14. package/dist/harness-runtime/lib/delegation-instructions.mjs +13 -4
  15. package/dist/harness-runtime/lib/model-observations.mjs +19 -7
  16. package/dist/harness-runtime/lib/native-children.d.mts +12 -1
  17. package/dist/harness-runtime/lib/native-children.mjs +47 -1
  18. package/dist/harness-runtime/lib/provider-overload-policy.d.mts +9 -1
  19. package/dist/harness-runtime/lib/provider-overload-policy.mjs +97 -6
  20. package/dist/services/check-runner-evidence.js +17 -302
  21. package/dist/services/check-runner-proof.js +305 -0
  22. package/dist/services/code-checks.js +4 -1
  23. package/dist/services/controller-child-capacity.js +58 -0
  24. package/dist/services/controller-child-observer.js +9 -3
  25. package/dist/services/memory-init-native-capacity.js +1 -1
  26. package/dist/services/provider-capacity.js +15 -7
  27. package/dist/services/run-controller-adapter.js +1 -1
  28. package/dist/services/run-controller.js +87 -18
  29. package/dist/services/run-recovery-guard.js +1 -1
  30. package/dist/services/run-recovery-runtime.js +1 -1
  31. package/dist/services/stage-context.js +56 -8
  32. package/dist/services/vnext-fanout.js +1 -1
  33. package/dist/verification-components.json +299 -0
  34. package/package.json +7 -6
@@ -0,0 +1,305 @@
1
+ import crypto from "node:crypto";
2
+ import path from "node:path";
3
+ import { isDeepStrictEqual, stripVTControlCharacters } from "node:util";
4
+ import { fileURLToPath } from "node:url";
5
+ export const RUNNER_PROOF_CONTRACT = "dd-flow/check-runner-proof@1";
6
+ function object(value) { return Boolean(value) && typeof value === "object" && !Array.isArray(value); }
7
+ function boundedString(value, bytes) { return typeof value === "string" && Buffer.byteLength(value) <= bytes; }
8
+ const validatedBrowserProofs = new WeakSet();
9
+ const unsupportedObservationContracts = new WeakSet();
10
+ const validatedNativeProofs = new WeakSet();
11
+ const validatedChildren = new WeakMap();
12
+ const validatedReports = new WeakMap();
13
+ const hash = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
14
+ const absoluteFile = (value) => typeof value === "string" && value.length > 0 && value.length <= 4096 && !value.includes("\0") && path.isAbsolute(value);
15
+ export function candidateAbsencesValid(value) { return Array.isArray(value) && value.length <= 64 && value.every(item => object(item) && absoluteFile(item.file) && item.path_state === "missing" && object(item.declaration) && absoluteFile(item.declaration.file) && hash(item.declaration.sha256)); }
16
+ function relativeProofPath(value) { return typeof value === "string" && value.length > 0 && Buffer.byteLength(value) <= 4096 && !path.isAbsolute(value) && !value.includes("\\") && value.split("/").every(part => part !== "" && part !== "." && part !== ".."); }
17
+ function proofArtifact(value) { return object(value) && relativeProofPath(value.relative_path) && typeof value.sha256 === "string" && /^[a-f0-9]{64}$/.test(value.sha256); }
18
+ function browserProofShape(proof) {
19
+ const attempt = proof.attempt, step = proof.step;
20
+ return (proof.observation_contract === undefined || proof.observation_contract === "dd-tasks/browser-observation@2" && object(proof.target) && [proof.target.page_id, proof.target.context_id].every(value => boundedString(value, 256) && Boolean(value)) && Number.isSafeInteger(proof.window_epoch) && Number(proof.window_epoch) > 0)
21
+ && proof.native_code === "PLAYWRIGHT_ACTION_INACTIVITY" && object(attempt) && boundedString(attempt.invocation_id, 4096) && boundedString(attempt.test_id, 4096) && Boolean(attempt.test_id)
22
+ && [attempt.retry, attempt.repeat_each_index, attempt.worker_index].every(value => Number.isSafeInteger(value) && value >= 0)
23
+ && object(step) && boundedString(step.id, 4096) && Boolean(step.id) && ["pw:api", "expect"].includes(String(step.category)) && step.file === proof.file && Number.isSafeInteger(step.line) && step.line > 0
24
+ && proofArtifact(proof.worker_snapshot) && proofArtifact(proof.native_result);
25
+ }
26
+ export function runnerFailureValid(value) {
27
+ if (!object(value) || typeof value.category !== "string" || !["assertion", "tooling", "unclassified"].includes(value.category))
28
+ return false;
29
+ if (value.diagnostic_artifact !== undefined && !proofArtifact(value.diagnostic_artifact))
30
+ return false;
31
+ for (const key of ["code", "message", "file", "test_id", "native_code", "classification_reason"])
32
+ if (value[key] !== undefined && !boundedString(value[key], 4096))
33
+ return false;
34
+ if (value.stack !== undefined && !boundedString(value.stack, 16384) || value.origin !== undefined && (typeof value.origin !== "string" || !["candidate", "tooling", "unknown"].includes(value.origin)) || value.phase !== undefined && (typeof value.phase !== "string" || !["test", "setup", "teardown", "collection", "runner"].includes(value.phase)))
35
+ return false;
36
+ if (value.repair_evidence !== undefined) {
37
+ const proof = value.repair_evidence;
38
+ if (object(proof) && proof.rule === "candidate_test_runtime_error")
39
+ return ["TypeError", "ReferenceError", "Error"].includes(String(proof.exception_type)) && (proof.exception_type !== "Error" || proof.phase === "test")
40
+ && absoluteFile(proof.file) && hash(proof.file_sha256) && ["test", "setup", "collection"].includes(String(proof.phase))
41
+ && [proof.line, proof.column].every(value => Number.isSafeInteger(value) && Number(value) > 0) && proofArtifact(proof.native_artifact);
42
+ if (object(proof) && proof.rule === "candidate_migration_sql")
43
+ return proof.native_code === "42601" && absoluteFile(proof.file) && hash(proof.file_sha256)
44
+ && boundedString(proof.operation_id, 4096) && Boolean(proof.operation_id) && proofArtifact(proof.native_artifact) && object(proof.world)
45
+ && boundedString(proof.world.invocation_id, 4096) && typeof proof.world.world_id === "string" && /^[a-f0-9]{32}$/.test(proof.world.world_id)
46
+ && boundedString(proof.world.role, 128) && Boolean(proof.world.role) && hash(proof.world.migrations_sha256) && proof.world.phase === "migrating" && proof.world.setup_completed === false;
47
+ if (object(proof) && proof.rule === "candidate_tool_diagnostic")
48
+ return absoluteFile(proof.file) && proofArtifact(proof.native_artifact)
49
+ && object(proof.tool) && { biome: "2.5.6", typescript: "5.9.3", docs: "1", "value-absence": "1" }[String(proof.tool.name)] === proof.tool.version
50
+ && object(proof.step) && boundedString(proof.step.id, 256) && Boolean(proof.step.id) && Number.isSafeInteger(proof.step.ordinal) && proof.step.ordinal >= 0 && hash(proof.step.command_sha256)
51
+ && boundedString(proof.diagnostic_code, 256) && (proof.tool.name === "biome" ? ["format", "assist/source/organizeImports"].includes(String(proof.diagnostic_code)) || /^lint\/[\w/-]+$/.test(String(proof.diagnostic_code)) : proof.tool.name === "typescript" ? /^TS\d+$/.test(String(proof.diagnostic_code)) : proof.tool.name === "docs" ? ["required_path_missing", "docs_contract"].includes(String(proof.diagnostic_code)) : proof.diagnostic_code === "value_absence")
52
+ && (proof.path_state === "present" && hash(proof.file_sha256) || proof.path_state === "missing" && proof.tool.name === "docs" && proof.diagnostic_code === "required_path_missing" && proof.file_sha256 === null && object(proof.declaration) && absoluteFile(proof.declaration.file) && hash(proof.declaration.sha256));
53
+ if (!object(proof) || !boundedString(proof.rule, 128) || !boundedString(proof.native_code, 128) || !boundedString(proof.file, 4096) || !object(proof.world))
54
+ return false;
55
+ const world = proof.world;
56
+ if (world.schema_id !== "dd-tasks/test-world-ready@1" || !boundedString(world.invocation_id, 4096) || typeof world.world_id !== "string" || !/^[a-f0-9]{32}$/.test(world.world_id) || typeof world.migrations_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(world.migrations_sha256) || world.ready !== true || world.setup_completed !== true || !boundedString(world.role, 128) || !world.role)
57
+ return false;
58
+ if (proof.rule === "candidate_browser_action_inactivity" && !browserProofShape(proof))
59
+ return false;
60
+ if (!["candidate_sql_integrity", "candidate_browser_action_inactivity"].includes(String(proof.rule)))
61
+ return false;
62
+ }
63
+ return true;
64
+ }
65
+ function readBytes(context, relative, limit) {
66
+ if (!relativeProofPath(relative))
67
+ throw new Error("Unsafe proof path");
68
+ const bytes = context.readArtifact(relative);
69
+ if (!Buffer.isBuffer(bytes) || bytes.length > limit)
70
+ throw new Error("Evidence is not bounded bytes");
71
+ context.consumed += bytes.length;
72
+ if (context.consumed > 128 * 1024 * 1024)
73
+ throw Object.assign(new Error("Proof byte budget exceeded"), { code: "proof_budget_exceeded" });
74
+ return bytes;
75
+ }
76
+ function readProofArtifact(root, ref, context, limit = 2 * 1024 * 1024) {
77
+ const bytes = readBytes(context, path.posix.join(root, ref.relative_path), limit);
78
+ if (crypto.createHash("sha256").update(bytes).digest("hex") !== ref.sha256)
79
+ throw new Error("Proof hash differs");
80
+ const value = JSON.parse(bytes.toString("utf8"));
81
+ if (!object(value))
82
+ throw new Error("Invalid proof object");
83
+ return value;
84
+ }
85
+ function matches(actual, expected) { return object(actual) && Object.entries(expected).every(([key, value]) => actual[key] === value); }
86
+ function validateBrowserArtifacts(root, proof, binding, context) {
87
+ const snapshot = readProofArtifact(root, proof.worker_snapshot, context), native = readProofArtifact(root, proof.native_result, context);
88
+ if (proof.observation_contract !== undefined && (proof.observation_contract !== "dd-tasks/browser-observation@2" || snapshot.observation_contract !== proof.observation_contract || native.observation_contract !== proof.observation_contract
89
+ || !isDeepStrictEqual(snapshot.target, proof.target) || !isDeepStrictEqual(native.target, proof.target) || snapshot.window_epoch !== proof.window_epoch || native.window_epoch !== proof.window_epoch))
90
+ return false;
91
+ if (!Array.isArray(native.errors) || native.errors.length < 1 || native.errors.length > 64 || native.errors.some(error => !boundedString(error, 4096) || !/^(?:Error: )?(?:[A-Za-z][\w.]*: )?Test timeout of [1-9]\d*ms exceeded\.(?:\nCall log:[\s\S]*)?$/.test(stripVTControlCharacters(String(error)))))
92
+ return false;
93
+ if (!matches(snapshot.binding, binding) || !matches(native.binding, binding) || !matches(snapshot.attempt, proof.attempt) || !matches(native.attempt, proof.attempt)
94
+ || !matches(snapshot.step, proof.step) || !matches(native.step, proof.step) || !matches(snapshot.world, proof.world) || proof.world.invocation_id !== binding.invocation_id
95
+ || native.status !== "timedOut" || native.phase !== "test" || native.file !== proof.file || snapshot.phase !== "body" || snapshot.observation_gap !== false || !matches(snapshot.browser, { connected: true, page_closed: false, crashed: false })
96
+ || !matches(snapshot.world_health, { api: true, web: true, db: true }))
97
+ return false;
98
+ const quiet = snapshot.quiet_ms, last = Date.parse(String(snapshot.last_progress_at)), deadline = Date.parse(String(snapshot.deadline_at)), observed = Date.parse(String(snapshot.observed_at)), health = Date.parse(String(snapshot.health_observed_at)), ended = Date.parse(String(native.ended_at));
99
+ return Number.isSafeInteger(quiet) && quiet > 0 && [last, deadline, observed, health, ended].every(Number.isFinite) && Math.abs(deadline - last - quiet) <= 2 && observed >= last && observed <= deadline && health <= observed && health >= last && deadline - health <= Math.min(1000, quiet / 4) && ended >= deadline && ended <= Date.now() && ended - deadline <= 5000;
100
+ }
101
+ export function runnerProofArtifacts(evidence) {
102
+ return [...new Set([...(evidence?.failures ?? []).flatMap(failure => {
103
+ const child = validatedChildren.get(failure);
104
+ if (child && failure.child_evidence)
105
+ return [failure.child_evidence.report.relative_path, ...runnerProofArtifacts(child.evidence).map(file => path.posix.join(path.posix.dirname(failure.child_evidence.report.relative_path), file))];
106
+ const proof = failure.repair_evidence;
107
+ return [...(failure.diagnostic_artifact ? [failure.diagnostic_artifact.relative_path] : []), ...(proof?.rule === "candidate_browser_action_inactivity" ? [proof.worker_snapshot.relative_path, proof.native_result.relative_path] : proof && "native_artifact" in proof ? [proof.native_artifact.relative_path] : [])];
108
+ }), ...(evidence ? validatedReports.get(evidence) ?? [] : []).flatMap(child => [child.report.relative_path, ...runnerProofArtifacts(child.evidence).map(file => path.posix.join(path.posix.dirname(child.report.relative_path), file))])])];
109
+ }
110
+ function diagnostic(context, value) {
111
+ // Diagnostics are locators, never another copy of untrusted report content.
112
+ if (context.diagnostics.length >= 64 || context.bytes + Buffer.byteLength(JSON.stringify(value)) > 32 * 1024 - 64) {
113
+ context.truncated = true;
114
+ return;
115
+ }
116
+ context.diagnostics.push(value);
117
+ context.bytes += Buffer.byteLength(JSON.stringify(value));
118
+ }
119
+ export function validateRunnerProof(contract, binding, readArtifact) {
120
+ const context = { diagnostics: [], bytes: 0, consumed: 0, truncated: false, readArtifact };
121
+ const evidence = readRunnerEvidenceInternal("", contract, binding, 0, { reports: 0 }, context, "");
122
+ return { contract: RUNNER_PROOF_CONTRACT, evidence, required_artifacts: evidence ? runnerProofArtifacts(evidence) : [], diagnostics: context.diagnostics, ...(context.truncated ? { diagnostics_truncated: true } : {}) };
123
+ }
124
+ function readRunnerEvidenceInternal(root, contract, binding, depth, budget, context, prefix) {
125
+ const report = relativeProofPath(contract.path) ? path.posix.join(prefix, contract.path) : "<invalid-report-path>";
126
+ const count = context.diagnostics.length;
127
+ let accepted = false;
128
+ let failureReason = "invalid_shape";
129
+ const invalid = () => { if (context.diagnostics.length === count)
130
+ diagnostic(context, { reason: failureReason, report }); return null; };
131
+ try {
132
+ if (!relativeProofPath(contract.path))
133
+ return invalid();
134
+ if (depth > 4 || ++budget.reports > 64) {
135
+ failureReason = "proof_budget_exceeded";
136
+ return invalid();
137
+ }
138
+ const bytes = readBytes(context, path.posix.join(root, contract.path), 1024 * 1024);
139
+ failureReason = "invalid_json";
140
+ const evidence = JSON.parse(bytes.toString("utf8"));
141
+ failureReason = "invalid_shape";
142
+ if (!object(evidence))
143
+ return invalid();
144
+ if (!["dd-flow/check-runner-evidence@1", "dd-flow/check-runner-evidence@2"].includes(contract.schema_id))
145
+ return null;
146
+ const partial = evidence.failure_projection;
147
+ if (partial !== undefined && (evidence.schema_id !== "dd-flow/check-runner-evidence@2" || !object(partial) || partial.state !== "partial" || !["count_bound", "byte_bound", "interrupt"].includes(partial.reason)
148
+ || ![partial.represented, partial.omitted].every(value => Number.isSafeInteger(value) && value >= 0)))
149
+ return null;
150
+ if (evidence.schema_id !== contract.schema_id) {
151
+ diagnostic(context, { reason: "invalid_shape", report, expected: contract.schema_id, observed: ["dd-flow/check-runner-evidence@1", "dd-flow/check-runner-evidence@2"].includes(evidence.schema_id) ? evidence.schema_id : "unsupported" });
152
+ return null;
153
+ }
154
+ if (!evidence.binding || Object.entries(binding).some(([key, value]) => evidence.binding[key] !== value)) {
155
+ diagnostic(context, { reason: "binding_mismatch", report });
156
+ return null;
157
+ }
158
+ if (typeof evidence.runner?.name !== "string" || !evidence.runner.name || typeof evidence.runner.version !== "string" || !evidence.runner.version || typeof evidence.completed !== "boolean" || !evidence.counts
159
+ || ![evidence.counts.passed, evidence.counts.failed, evidence.counts.skipped].every(n => Number.isSafeInteger(n) && n >= 0)
160
+ || !Array.isArray(evidence.failures) || evidence.failures.length > 64 || evidence.failures.some(f => !runnerFailureValid(f))
161
+ || !partial && evidence.counts.failed > evidence.failures.length || evidence.observation_unknown !== undefined && typeof evidence.observation_unknown !== "boolean")
162
+ return null;
163
+ const children = new Map();
164
+ const consumed = new Map();
165
+ if (evidence.steps !== undefined) {
166
+ if (!Array.isArray(evidence.steps) || evidence.steps.length > 64)
167
+ return null;
168
+ const ids = new Set(), invocations = new Set();
169
+ let stopped = false;
170
+ for (const [ordinal, step] of evidence.steps.entries()) {
171
+ if (!step || !boundedString(step.id, 256) || !step.id || ids.has(step.id) || step.ordinal !== ordinal || !hash(step.command_sha256) || !["passed", "failed", "unreached"].includes(step.state))
172
+ return null;
173
+ ids.add(step.id);
174
+ if (step.state === "unreached") {
175
+ if (!stopped || step.binding !== undefined || step.report !== undefined || step.exit_code !== undefined)
176
+ return null;
177
+ continue;
178
+ }
179
+ if (stopped)
180
+ return null;
181
+ if (step.state === "failed")
182
+ stopped = true;
183
+ if (!step.binding || !proofArtifact(step.report) || !Number.isSafeInteger(step.exit_code) || step.state === "passed" && step.exit_code !== 0 || step.state === "failed" && step.exit_code === 0 || invocations.has(step.binding.invocation_id) || step.binding.invocation_id === binding.invocation_id)
184
+ return null;
185
+ if (step.binding.invocation_id !== `${binding.invocation_id}:step:${step.id}` || step.binding.check_id !== `${binding.check_id}/${step.id}` || step.binding.verification_epoch !== binding.verification_epoch || step.binding.input_hash !== crypto.createHash("sha256").update(JSON.stringify([binding.input_hash, step.command_sha256])).digest("hex"))
186
+ return null;
187
+ if (crypto.createHash("sha256").update(step.binding.command).digest("hex") !== step.command_sha256)
188
+ return null;
189
+ invocations.add(step.binding.invocation_id);
190
+ failureReason = "artifact_mismatch";
191
+ readProofArtifact(root, step.report, context, 1024 * 1024);
192
+ failureReason = "invalid_shape";
193
+ const child = readRunnerEvidenceInternal(path.posix.join(root, path.posix.dirname(step.report.relative_path)), { schema_id: contract.schema_id, path: path.basename(step.report.relative_path) }, step.binding, depth + 1, budget, context, path.posix.join(prefix, path.posix.dirname(step.report.relative_path)));
194
+ if (!child || step.state === "passed" && (child.counts.failed !== 0 || child.failures.length !== 0) || step.state === "failed" && !child.failures.length && child.completed && !child.observation_unknown)
195
+ return null;
196
+ if (!child.completed || child.observation_unknown)
197
+ stopped = true;
198
+ children.set(step.id, child);
199
+ }
200
+ for (const key of ["passed", "failed", "skipped"])
201
+ if (evidence.counts[key] !== [...children.values()].reduce((total, child) => total + child.counts[key], 0))
202
+ return null;
203
+ }
204
+ for (const failure of evidence.failures) {
205
+ failureReason = "artifact_mismatch";
206
+ if (failure.child_evidence) {
207
+ const ref = failure.child_evidence, step = evidence.steps?.find(item => item.id === ref.step_id), child = children.get(ref.step_id);
208
+ if (!step || !child || !isDeepStrictEqual(ref.binding, step.binding) || !isDeepStrictEqual(ref.report, step.report))
209
+ return null;
210
+ const original = { ...failure };
211
+ delete original.child_evidence;
212
+ const used = consumed.get(child) ?? new Set();
213
+ consumed.set(child, used);
214
+ const index = child.failures.findIndex((item, index) => { const native = { ...item }; delete native.child_evidence; return !used.has(index) && isDeepStrictEqual(native, original); });
215
+ if (index < 0)
216
+ return null;
217
+ used.add(index);
218
+ const matched = child.failures[index];
219
+ if (!matched.child_evidence && matched.repair_evidence?.rule === "candidate_tool_diagnostic" && !isDeepStrictEqual(matched.repair_evidence.step, { id: step.id, ordinal: step.ordinal, command_sha256: step.command_sha256 }))
220
+ return null;
221
+ validatedChildren.set(failure, { failure: matched, evidence: child });
222
+ continue;
223
+ }
224
+ if (failure.diagnostic_artifact && !matches(readProofArtifact(root, failure.diagnostic_artifact, context, 2 * 1024 * 1024).binding, binding))
225
+ return null;
226
+ const proof = failure.repair_evidence;
227
+ if (proof?.rule === "candidate_migration_sql" || proof?.rule === "candidate_tool_diagnostic" || proof?.rule === "candidate_test_runtime_error") {
228
+ const native = readProofArtifact(root, proof.native_artifact, context, 2 * 1024 * 1024), facts = Object.fromEntries(Object.entries(proof).filter(([key]) => key !== "native_artifact"));
229
+ if (!isDeepStrictEqual(native.binding, binding) || Object.entries(facts).some(([key, value]) => !isDeepStrictEqual(native[key], value)))
230
+ return null;
231
+ if (proof.rule === "candidate_test_runtime_error") {
232
+ failureReason = "attribution_unproven";
233
+ if (evidence.schema_id !== "dd-flow/check-runner-evidence@2" || native.executing_file !== proof.file || native.exception_name !== proof.exception_type
234
+ || !isDeepStrictEqual(native.top_frame, { file: proof.file, line: proof.line, column: proof.column }) || !boundedString(native.stack, 16384) || !String(native.stack).startsWith(`${proof.exception_type}:`))
235
+ return null;
236
+ const firstFrame = String(native.stack).split("\n").find(line => /^\s*at\s/.test(line));
237
+ const frame = firstFrame?.match(/^\s*at\s+(?:.*?\()?((?:file:\/\/)?\/[^\n]+):(\d+):(\d+)\)?$/);
238
+ if (!frame || (frame[1].startsWith("file://") ? fileURLToPath(frame[1]) : frame[1]) !== proof.file || Number(frame[2]) !== proof.line || Number(frame[3]) !== proof.column)
239
+ return null;
240
+ }
241
+ validatedNativeProofs.add(proof);
242
+ }
243
+ if (proof?.rule === "candidate_browser_action_inactivity") {
244
+ if (proof.observation_contract === undefined && evidence.schema_id === "dd-flow/check-runner-evidence@1") {
245
+ // Legacy diagnostics remain readable; they do not prove the new window/target guarantee.
246
+ if (!validateBrowserArtifacts(root, proof, binding, context))
247
+ return null;
248
+ evidence.completed = false;
249
+ unsupportedObservationContracts.add(evidence);
250
+ continue;
251
+ }
252
+ if (proof.observation_contract !== "dd-tasks/browser-observation@2" || !validateBrowserArtifacts(root, proof, binding, context))
253
+ return null;
254
+ validatedBrowserProofs.add(proof);
255
+ }
256
+ }
257
+ failureReason = "invalid_shape";
258
+ const represented = [...consumed.values()].reduce((total, used) => total + used.size, 0), childFailures = [...children.values()].reduce((total, child) => total + child.failures.length, 0);
259
+ if (partial) {
260
+ if (children.size ? partial.represented !== represented || partial.omitted !== childFailures - represented : partial.represented !== evidence.failures.filter(failure => failure.code !== "report_truncated").length)
261
+ return null;
262
+ evidence.completed = false;
263
+ }
264
+ else if (represented !== childFailures)
265
+ return null;
266
+ // Valid but incomplete native observation is diagnostic evidence, not a
267
+ // malformed schema. Preserve the primary failure and references through
268
+ // every composite, including a parent that incorrectly claims completion.
269
+ if ([...children.values()].some(child => !child.completed || child.observation_unknown)) {
270
+ evidence.completed = false;
271
+ if ([...children.values()].some(child => unsupportedObservationContracts.has(child)))
272
+ unsupportedObservationContracts.add(evidence);
273
+ if (evidence.schema_id === "dd-flow/check-runner-evidence@1" && [...children.values()].some(child => !child.completed && !unsupportedObservationContracts.has(child)) || [...children.values()].some(child => child.observation_unknown))
274
+ evidence.observation_unknown = true;
275
+ }
276
+ validatedReports.set(evidence, (evidence.steps ?? []).flatMap(step => step.report && children.has(step.id) ? [{ report: step.report, evidence: children.get(step.id) }] : []));
277
+ if (unsupportedObservationContracts.has(evidence))
278
+ diagnostic(context, { reason: "unsupported_observation_contract", report, expected: "dd-tasks/browser-observation@2", observed: "legacy" });
279
+ else if (!evidence.completed || evidence.observation_unknown)
280
+ diagnostic(context, { reason: "observation_incomplete", report });
281
+ for (const failure of evidence.failures)
282
+ if (failure.origin === "unknown" || failure.category === "unclassified" && !failure.repair_evidence) {
283
+ diagnostic(context, { reason: "attribution_unproven", report });
284
+ break;
285
+ }
286
+ accepted = true;
287
+ return evidence;
288
+ }
289
+ catch (error) {
290
+ if (error.code === "ENOENT")
291
+ failureReason = "missing";
292
+ else if (error.code === "proof_budget_exceeded")
293
+ failureReason = "proof_budget_exceeded";
294
+ return invalid();
295
+ }
296
+ finally {
297
+ if (!accepted && context.diagnostics.length === count)
298
+ diagnostic(context, { reason: failureReason, report });
299
+ }
300
+ }
301
+ export function runnerEvidencePass(evidence) { return Boolean(evidence?.completed && !evidence.failure_projection && !evidence.observation_unknown && evidence.counts.failed === 0 && evidence.failures.length === 0); }
302
+ export const validatedRunnerChild = (failure) => validatedChildren.get(failure);
303
+ export const hasValidatedNativeProof = (proof) => validatedNativeProofs.has(proof);
304
+ export const hasValidatedBrowserProof = (proof) => validatedBrowserProofs.has(proof);
305
+ export const hasUnsupportedObservation = (evidence) => unsupportedObservationContracts.has(evidence);
@@ -17,6 +17,7 @@ import { admitRuntimeCheck, runtimeBudgetForRun } from "./runtime-budget.js";
17
17
  import { getResourceDatabase } from "../storage/database.js";
18
18
  import { readBoundedReleaseFile } from "./release-source.js";
19
19
  import { ownedCheckEnvironment, validateCheckEnvironment } from "./check-environment.js";
20
+ import { browserCheckCapabilityEnvironment } from "./stage-context.js";
20
21
  const profileRelativePath = path.join(".memory-bank", "spec", "engineering", "code-check-profile.json");
21
22
  // Receipt reservation precedes child spawn so an interrupted CLI leaves an
22
23
  // auditable attempt. A second caller must not mistake that small handoff window
@@ -68,6 +69,8 @@ export function codeExecutionEnvironment(workspaceRoot, checkEnvironment) {
68
69
  // provider can otherwise run x64 checks against arm64-installed modules.
69
70
  const environment = { ...process.env, PATH: `${path.dirname(process.execPath)}${path.delimiter}${process.env.PATH ?? ""}`, DD_FLOW_LOCAL_DATABASE_SUFFIX: suffix };
70
71
  delete environment.NODE_PATH;
72
+ delete environment.DD_FLOW_BROWSER_CAPABILITY_PATH;
73
+ delete environment.DD_FLOW_BROWSER_CAPABILITY_SHA256;
71
74
  for (const key of ["DD_FLOW_CHECK_RUNNER_EVIDENCE_PATH", "DD_FLOW_CHECK_RUNNER_PROGRESS_PATH", "DD_FLOW_CHECK_INVOCATION_ID", "DD_FLOW_CHECK_ID", "DD_FLOW_CHECK_INPUT_HASH", "DD_FLOW_CHECK_VERIFICATION_EPOCH", "DD_FLOW_CHECK_COMMAND"])
72
75
  delete environment[key];
73
76
  Object.assign(environment, selected);
@@ -621,7 +624,7 @@ async function runCodeChecksOwned(context, input, workspaceGateId, generation, s
621
624
  const runnerEnvironment = group.runnerEvidence ? { DD_FLOW_CHECK_RUNNER_EVIDENCE_PATH: path.join(evidenceDir, group.runnerEvidence.path), DD_FLOW_CHECK_RUNNER_PROGRESS_PATH: path.join(evidenceDir, "runner-progress.jsonl"), DD_FLOW_CHECK_INVOCATION_ID: id, DD_FLOW_CHECK_ID: id, DD_FLOW_CHECK_INPUT_HASH: inputHash, DD_FLOW_CHECK_VERIFICATION_EPOCH: epoch } : {};
622
625
  if (group.runnerEvidence)
623
626
  fs.mkdirSync(path.dirname(path.join(evidenceDir, group.runnerEvidence.path)), { recursive: true });
624
- result = await runCheck(group.command, input.workspaceRoot, { ...codeExecutionEnvironment(input.workspaceRoot, input.checkEnvironment), DD_FLOW_EVIDENCE_DIR: evidenceDir, DD_FLOW_CHECK_COMPLETION_FILE: completionPath, ...runnerEnvironment, ...portEnvironment(resources) }, stdout, stderr, (elapsed) => input.progress?.(`check ${index + 1}/${groups.length} still running (${elapsed}s): ${group.command}`), (pid) => {
627
+ result = await runCheck(group.command, input.workspaceRoot, { ...codeExecutionEnvironment(input.workspaceRoot, input.checkEnvironment), ...browserCheckCapabilityEnvironment(context, input.runId, input.runHome), DD_FLOW_EVIDENCE_DIR: evidenceDir, DD_FLOW_CHECK_COMPLETION_FILE: completionPath, ...runnerEnvironment, ...portEnvironment(resources) }, stdout, stderr, (elapsed) => input.progress?.(`check ${index + 1}/${groups.length} still running (${elapsed}s): ${group.command}`), (pid) => {
625
628
  confirmedExpiry = confirmManagedProcess(context, { id: managed.id, leaseToken: managed.lease_token, pid, processGroupId: process.platform === "win32" ? null : pid }).lease_expires_at;
626
629
  assertRunMutationAllowed(context, input.projectId, input.runId, generation);
627
630
  if (budget)
@@ -1,3 +1,58 @@
1
+ import { nativeContinuationSuccessor, nativeContinuationAdmitted } from "../harness-runtime/lib/native-children.mjs";
2
+ /** The failure fence forbids fanout, not the exact retained child's recovery. */
3
+ export function childCapacityDispatchAllowed(state, failures, parentId, operationId, promptSha256) {
4
+ return Object.entries(state.child_capacity ?? {}).some(([sessionId, intent]) => intent.operation_id === operationId
5
+ && intent.dispatched === true && intent.phase === "dispatched" && intent.prompt_sha256 === promptSha256
6
+ && failures.some(child => child.session_id === sessionId && child.parent_session_id === parentId
7
+ && child.status === "failed" && child.provenance !== "parent_mismatch" && child.terminal_turn_id === intent.turn_id));
8
+ }
9
+ /** An overloaded parent may have sent the message, but activity is not admission. */
10
+ export function childCapacityRecoveryDecision(state, children, parentId, operationId, parentTurnId) {
11
+ const target = Object.entries(state.child_capacity ?? {}).find(([, intent]) => intent.operation_id === operationId);
12
+ if (!target)
13
+ return "reconciliation_blocked";
14
+ const child = children.find(item => item.session_id === target[0]);
15
+ if (child && (child.parent_session_id !== parentId || child.provenance === "parent_mismatch"))
16
+ return "reconciliation_blocked";
17
+ if (!child)
18
+ return "continue";
19
+ if (parentTurnId && child.continuation_admission?.parent_turn_id === parentTurnId && target[1].phase === "dispatched")
20
+ target[1].parent_turn_id = parentTurnId;
21
+ reconcileChildCapacity(state, [child], parentId);
22
+ if (["native_message_accepted", "successor_observed"].includes(target[1].phase ?? ""))
23
+ return "completed";
24
+ return child.status === "running" || child.terminal_turn_id && child.terminal_turn_id !== target[1].turn_id ? "reconciliation_blocked" : "continue";
25
+ }
26
+ /** Bind native admission to a durable managed parent Turn, never to child prose. */
27
+ export function reconcileChildCapacity(state, children, parentId, observedAt = new Date().toISOString()) {
28
+ let changed = false;
29
+ for (const child of children) {
30
+ const intent = state.child_capacity?.[child.session_id], admission = child.continuation_admission;
31
+ if (!intent?.dispatched || !intent.operation_id || !intent.parent_turn_id || !intent.continuation_ref || !admission
32
+ || child.parent_session_id !== parentId || child.provenance === "parent_mismatch" || admission.parent_session_id !== parentId
33
+ || admission.parent_turn_id !== intent.parent_turn_id || admission.agent_id !== intent.continuation_ref.agent_id)
34
+ continue;
35
+ const bound = { ...admission, operation_id: intent.operation_id, predecessor_turn_id: intent.turn_id };
36
+ child.continuation_admission = bound;
37
+ const successor = nativeContinuationSuccessor(child, intent.turn_id, intent.continuation_ref.ended_at);
38
+ if (admission.proof_kind === "parent_tool_successor" && !successor)
39
+ continue;
40
+ if (admission.proof_kind === "parent_tool_admission" && !nativeContinuationAdmitted(child, intent.turn_id, intent.continuation_ref.ended_at))
41
+ continue;
42
+ const phase = successor ? "successor_observed" : "native_message_accepted";
43
+ if (intent.phase === "successor_observed" && !successor)
44
+ continue;
45
+ if (intent.phase !== phase || JSON.stringify(intent.admission) !== JSON.stringify(bound)) {
46
+ // A refreshed proof digest/status poll is not a new model signal.
47
+ if (intent.phase !== phase || !intent.last_signal_at)
48
+ intent.last_signal_at = observedAt;
49
+ intent.phase = phase;
50
+ intent.admission = bound;
51
+ changed = true;
52
+ }
53
+ }
54
+ return changed;
55
+ }
1
56
  /** Only a proven new successful terminal Turn closes a child's retry episode. */
2
57
  export function closeSuccessfulChildCapacity(state, children, parentId) {
3
58
  const closed = [];
@@ -6,6 +61,9 @@ export function closeSuccessfulChildCapacity(state, children, parentId) {
6
61
  if (!retained || child.parent_session_id !== parentId || child.provenance === "parent_mismatch"
7
62
  || child.status !== "completed" || !child.terminal_turn_id || child.terminal_turn_id === retained.turn_id)
8
63
  continue;
64
+ if (retained.continuation_ref && retained.phase !== "successor_observed")
65
+ continue;
66
+ retained.phase = "settled";
9
67
  delete state.child_capacity[child.session_id];
10
68
  closed.push(child.session_id);
11
69
  }
@@ -1,5 +1,5 @@
1
1
  import fs from "node:fs";
2
- import { normalizeNativeChildren, safeNativeFailure } from "../harness-runtime/lib/native-children.mjs";
2
+ import { normalizeNativeChildren, safeNativeFailure, nativeContinuationSuccessor } from "../harness-runtime/lib/native-children.mjs";
3
3
  /** A durable observation is a dispatch fence, not authority to complete Work. */
4
4
  export function retainedChildObserver(input) {
5
5
  let active = true, pending;
@@ -13,6 +13,11 @@ export function retainedChildObserver(input) {
13
13
  return { session_id: child.session_id, parent_session_id: child.parent_session_id, status: "failed", source: child.source, terminal_turn_id: child.terminal_turn_id,
14
14
  ...(typeof child.terminal_observed_at === "string" && Number.isFinite(Date.parse(child.terminal_observed_at)) ? { terminal_observed_at: child.terminal_observed_at } : {}),
15
15
  ...(child.native_source ? { native_source: child.native_source } : {}),
16
+ ...(child.continuation_ref ? { continuation_ref: child.continuation_ref } : {}),
17
+ ...(child.recovery_unavailable_reason ? { recovery_unavailable_reason: child.recovery_unavailable_reason } : {}),
18
+ ...(child.continuation_admission ? { continuation_admission: child.continuation_admission } : {}),
19
+ ...(child.resumed_from_message_id ? { resumed_from_message_id: child.resumed_from_message_id } : {}),
20
+ ...(child.current_turn_id ? { current_turn_id: child.current_turn_id } : {}),
16
21
  ...(child.native_turn_items ? { native_turn_items: {
17
22
  ...(typeof child.native_turn_items.observed === "boolean" ? { observed: child.native_turn_items.observed } : {}),
18
23
  ...(typeof child.native_turn_items.possible_effects === "boolean" ? { possible_effects: child.native_turn_items.possible_effects } : {}),
@@ -46,8 +51,9 @@ export function retainedChildObserver(input) {
46
51
  // This is an authoritative current native snapshot. Older failed Turns
47
52
  // remain in the journal/episode history, not in the current-outcome fence.
48
53
  const resolved = [...retained].filter(([, old]) => children.some(child => child.parent_session_id === input.scope.root_session_id
49
- && child.provenance !== "parent_mismatch" && child.session_id === old.session_id && ["completed", "failed"].includes(child.status)
50
- && child.terminal_turn_id && child.terminal_turn_id !== old.terminal_turn_id)).map(([key]) => key);
54
+ && child.provenance !== "parent_mismatch" && child.session_id === old.session_id
55
+ && (!old.continuation_ref && ["completed", "failed"].includes(child.status) && child.terminal_turn_id && child.terminal_turn_id !== old.terminal_turn_id
56
+ || nativeContinuationSuccessor(child, old.terminal_turn_id, old.continuation_ref?.ended_at)))).map(([key]) => key);
51
57
  if (!failed.length && !resolved.length && !gap)
52
58
  return;
53
59
  const fd = fs.openSync(input.file, "a", 0o600);
@@ -14,7 +14,7 @@ import { inspectDaemonOperation } from "../harness-runtime/lib/daemon-operations
14
14
  import { nativeCommandFingerprint } from "../harness-runtime/lib/native-request-proof.mjs";
15
15
  import { validateMemoryInitStartupScope } from "./memory-init-startup-custody.js";
16
16
  import { continueProviderCapacity } from "./provider-capacity.js";
17
- import { CAPACITY_POLICY, MAX_OVERLOAD_RETRIES, refusalObservation, terminalProviderOverload } from "../harness-runtime/lib/provider-overload-policy.mjs";
17
+ import { RECOVERY_POLICY as CAPACITY_POLICY, MAX_OVERLOAD_RETRIES, recoveryRefusal as refusalObservation, terminalProviderRecovery as terminalProviderOverload } from "../harness-runtime/lib/provider-overload-policy.mjs";
18
18
  const sha = (bytes) => createHash("sha256").update(bytes).digest("hex");
19
19
  function refuse(reason, effect = "no_effect") {
20
20
  throw new AppError("memory_init_native_capacity_required", "Native startup requires its exact qualified probe", 1, { reason, effect, next_action: "reconcile_exact_native_probe" });
@@ -1,6 +1,6 @@
1
1
  import { setTimeout as delay } from "node:timers/promises";
2
2
  import crypto from "node:crypto";
3
- import { CAPACITY_POLICY, MAX_OVERLOAD_RETRIES, capacityBackoff, nativeItemsSettled, normalizeProviderFailure, overloadExhausted, parseCapacityOperation, refusalObservation, terminalProviderOverload, streamRequestKey } from "../harness-runtime/lib/provider-overload-policy.mjs";
3
+ import { RECOVERY_POLICY as CAPACITY_POLICY, MAX_OVERLOAD_RETRIES, classifyRecoveryError, recoveryBackoff as capacityBackoff, nativeItemsSettled, normalizeRecoveryFailure as normalizeProviderFailure, recoveryExhausted as overloadExhausted, parseCapacityOperation, recoveryRefusal as refusalObservation, terminalProviderRecovery as terminalProviderOverload, streamRequestKey } from "../harness-runtime/lib/provider-overload-policy.mjs";
4
4
  import { AppError } from "../shared/errors.js";
5
5
  import { isObservationLoss } from "../harness-runtime/lib/operation-errors.mjs";
6
6
  import { parseLifecycleCommand, commandOption } from "./lifecycle-command.js";
@@ -48,12 +48,20 @@ export function ownedProviderBoundary(context, input, boundary) {
48
48
  return boundary.outcome === "completed" && (input.scope === "work" ? rows[0].status === "completed" : stage.status === "done");
49
49
  }
50
50
  export function providerChildFailure(child) {
51
- return child.provider_failure ?? { code: child.native_source ? "provider_capacity_transient" : "turn_interrupted", details: { native_source: child.native_source, provider_session_id: child.session_id, turn_id: child.terminal_turn_id, native_turn_id: child.terminal_turn_id, terminal_status: child.status, observed_at: child.terminal_observed_at ?? null, provider_error: child.provider_error, native_turn_items: child.native_turn_items } };
51
+ return child.provider_failure ?? { code: child.native_source ? classifyRecoveryError(child.provider_error) : "turn_interrupted", details: { native_source: child.native_source, provider_session_id: child.session_id, turn_id: child.terminal_turn_id, native_turn_id: child.terminal_turn_id, terminal_status: child.status, observed_at: child.terminal_observed_at ?? null, provider_error: child.provider_error, native_turn_items: child.native_turn_items } };
52
52
  }
53
53
  export function eligibleProviderChildOverload(child, parentSessionId) {
54
54
  return typeof child.session_id === "string" && child.session_id !== parentSessionId && child.parent_session_id === parentSessionId && child.provenance !== "parent_mismatch" && child.status === "failed" && typeof child.terminal_turn_id === "string" && nativeItemsSettled(child.native_turn_items)
55
55
  && terminalProviderOverload(providerChildFailure(child), child.session_id, child.terminal_turn_id);
56
56
  }
57
+ export function unavailableProviderChildRecovery(child, parentSessionId) {
58
+ if (typeof child.session_id !== "string" || child.parent_session_id !== parentSessionId || child.provenance === "parent_mismatch" || child.status !== "failed"
59
+ || typeof child.terminal_turn_id !== "string" || typeof child.recovery_unavailable_reason !== "string" || !/^[a-z][a-z0-9_]{0,127}$/.test(child.recovery_unavailable_reason))
60
+ return null;
61
+ const primary = providerChildFailure(child);
62
+ return terminalProviderOverload(primary, child.session_id, child.terminal_turn_id)
63
+ ? new AppError("provider_recovery_unavailable", "Native provider refusal is retained, but same-child continuation is not safely supported", 1, { reason: child.recovery_unavailable_reason, child_session_id: child.session_id, terminal_turn_id: child.terminal_turn_id, primary_error: primary }) : null;
64
+ }
57
65
  /** A terminal root is not a settled tree. Only the daemon's exact owned tree
58
66
  * with a settled root and positively live descendants permits waiting. */
59
67
  export function capacityReadiness(seen, sessionId, operationId, turnId, items, allowDescendants = false, requestProof) {
@@ -227,7 +235,7 @@ export async function continueProviderCapacity(input) {
227
235
  while (["prepared", "dispatching", "running", "awaiting_provider", "outcome_unknown"].includes(String(observed.state))) {
228
236
  input.signal?.throwIfAborted();
229
237
  input.assertCurrent();
230
- const boundary = await observe(async () => await input.decision?.() ?? "continue", intent.operation_id);
238
+ const boundary = await observe(async () => await input.decision?.(undefined, error) ?? "continue", intent.operation_id);
231
239
  if (boundary === "completed" || boundary === "paused")
232
240
  return { provider_session_id: input.sessionId, capacity_decision: boundary };
233
241
  if (boundary === "reconciliation_blocked")
@@ -246,7 +254,7 @@ export async function continueProviderCapacity(input) {
246
254
  if (observed.state === "completed" && observed.result && typeof observed.result === "object") {
247
255
  input.signal?.throwIfAborted();
248
256
  input.assertCurrent();
249
- const boundary = await observe(async () => await input.decision?.() ?? "continue", intent.operation_id);
257
+ const boundary = await observe(async () => await input.decision?.(undefined, error) ?? "continue", intent.operation_id);
250
258
  input.signal?.throwIfAborted();
251
259
  input.assertCurrent();
252
260
  if (boundary === "reconciliation_blocked")
@@ -266,7 +274,7 @@ export async function continueProviderCapacity(input) {
266
274
  input.assertCurrent();
267
275
  const normalized = normalizeProviderFailure(error, input.sessionId);
268
276
  const candidate = normalized?.request_proof.kind === "stream_request" ? normalized.primary_error.details?.recovered_error_boundary : undefined;
269
- const decision = await observe(async () => await input.decision?.(candidate?.receipt) ?? "continue", observedOperationId);
277
+ const decision = await observe(async () => await input.decision?.(candidate?.receipt, error) ?? "continue", observedOperationId);
270
278
  input.signal?.throwIfAborted();
271
279
  input.assertCurrent();
272
280
  if (normalized?.request_proof.kind === "stream_request" && ["completed", "paused"].includes(decision) && !candidate?.receipt)
@@ -445,11 +453,11 @@ export async function continueProviderCapacity(input) {
445
453
  // A task can complete/pause while the daemon queues for its permit.
446
454
  // Admission then refuses the stale prompt; accept that owner decision
447
455
  // before treating the transport's rejection as another provider failure.
456
+ error = nextError;
457
+ operationId = nextId;
448
458
  const finished = await decide(nextId);
449
459
  if (finished)
450
460
  return finished;
451
- error = nextError;
452
- operationId = nextId;
453
461
  }
454
462
  }
455
463
  }
@@ -6,7 +6,7 @@ import { adapterSessionId, runHarnessAdapter } from "./harness-adapter.js";
6
6
  import { runtimeHarness } from "./execution-policy.js";
7
7
  import { appendEvent, digest, digestBytes, errorRecord, requireRun } from "./run-controller-state.js";
8
8
  import { managedProcessStatus } from "./managed-processes.js";
9
- import { CAPACITY_POLICY, parseCapacityOperation } from "../harness-runtime/lib/provider-overload-policy.mjs";
9
+ import { RECOVERY_POLICY as CAPACITY_POLICY, parseCapacityOperation } from "../harness-runtime/lib/provider-overload-policy.mjs";
10
10
  import { recoveryObservationBudget } from "./recovery-observation-budget.js";
11
11
  import { canonicalNativeOperation } from "../harness-runtime/lib/adapter-timeouts.mjs";
12
12
  import { retainedDaemonReply } from "../harness-runtime/lib/daemon-observation.mjs";