project-tiny-context-harness 0.8.12 → 0.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -19
- package/assets/README.md +81 -40
- package/assets/README.zh-CN.md +44 -22
- package/assets/agents/AGENTS_CORE.md +8 -4
- package/assets/skills/context_development_engineer/SKILL.md +9 -1
- package/assets/skills/design-resource-authoring/SKILL.md +7 -5
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +2 -2
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +22 -2
- package/assets/skills/design-resource-authoring/references/recovery-and-writeback.md +199 -0
- package/assets/skills/design-resource-authoring/references/resource-selection.md +2 -2
- package/assets/skills/long-task-workflow/SKILL.md +6 -6
- package/assets/skills/long-task-workflow/references/contract-authoring.md +27 -22
- package/assets/skills/long-task-workflow/references/evidence-design.md +49 -32
- package/assets/skills/long-task-workflow/references/source-authoring.md +2 -2
- package/dist/commands/design-resource-recovery.d.ts +1 -0
- package/dist/commands/design-resource-recovery.js +152 -0
- package/dist/commands/design-resource.js +20 -1
- package/dist/commands/index.js +1 -1
- package/dist/lib/design-resource-reconciliation-codec.d.ts +2 -0
- package/dist/lib/design-resource-reconciliation-codec.js +174 -0
- package/dist/lib/design-resource-reconciliation-types.d.ts +62 -0
- package/dist/lib/design-resource-reconciliation-types.js +1 -0
- package/dist/lib/design-resource-reconciliation.d.ts +3 -0
- package/dist/lib/design-resource-reconciliation.js +224 -0
- package/dist/lib/design-resource-recovery-authority-policy.d.ts +8 -0
- package/dist/lib/design-resource-recovery-authority-policy.js +123 -0
- package/dist/lib/design-resource-recovery-catalog-resources.d.ts +6 -0
- package/dist/lib/design-resource-recovery-catalog-resources.js +121 -0
- package/dist/lib/design-resource-recovery-catalog-shape.d.ts +3 -0
- package/dist/lib/design-resource-recovery-catalog-shape.js +104 -0
- package/dist/lib/design-resource-recovery-catalog.d.ts +9 -0
- package/dist/lib/design-resource-recovery-catalog.js +103 -0
- package/dist/lib/design-resource-recovery-cleanup.d.ts +2 -0
- package/dist/lib/design-resource-recovery-cleanup.js +11 -0
- package/dist/lib/design-resource-recovery-codec-primitives.d.ts +19 -0
- package/dist/lib/design-resource-recovery-codec-primitives.js +92 -0
- package/dist/lib/design-resource-recovery-codec.d.ts +4 -0
- package/dist/lib/design-resource-recovery-codec.js +93 -0
- package/dist/lib/design-resource-recovery-current.d.ts +9 -0
- package/dist/lib/design-resource-recovery-current.js +41 -0
- package/dist/lib/design-resource-recovery-delta-policy.d.ts +5 -0
- package/dist/lib/design-resource-recovery-delta-policy.js +108 -0
- package/dist/lib/design-resource-recovery-files.d.ts +37 -0
- package/dist/lib/design-resource-recovery-files.js +204 -0
- package/dist/lib/design-resource-recovery-final-disposition-shape.d.ts +2 -0
- package/dist/lib/design-resource-recovery-final-disposition-shape.js +47 -0
- package/dist/lib/design-resource-recovery-patch-types.d.ts +54 -0
- package/dist/lib/design-resource-recovery-patch-types.js +1 -0
- package/dist/lib/design-resource-recovery-replay.d.ts +7 -0
- package/dist/lib/design-resource-recovery-replay.js +112 -0
- package/dist/lib/design-resource-recovery-repository-bindings.d.ts +9 -0
- package/dist/lib/design-resource-recovery-repository-bindings.js +49 -0
- package/dist/lib/design-resource-recovery-schema.d.ts +5 -0
- package/dist/lib/design-resource-recovery-schema.js +5 -0
- package/dist/lib/design-resource-recovery-shape.d.ts +10 -0
- package/dist/lib/design-resource-recovery-shape.js +184 -0
- package/dist/lib/design-resource-recovery-source-authority.d.ts +5 -0
- package/dist/lib/design-resource-recovery-source-authority.js +219 -0
- package/dist/lib/design-resource-recovery-text.d.ts +17 -0
- package/dist/lib/design-resource-recovery-text.js +186 -0
- package/dist/lib/design-resource-recovery-types.d.ts +197 -0
- package/dist/lib/design-resource-recovery-types.js +1 -0
- package/dist/lib/design-resource-recovery-writeback-policy.d.ts +5 -0
- package/dist/lib/design-resource-recovery-writeback-policy.js +326 -0
- package/dist/lib/design-resource-recovery-writeback-shape.d.ts +6 -0
- package/dist/lib/design-resource-recovery-writeback-shape.js +155 -0
- package/dist/lib/design-resource-recovery.d.ts +44 -0
- package/dist/lib/design-resource-recovery.js +216 -0
- package/dist/lib/long-task-acceptance-shape.js +8 -2
- package/dist/lib/long-task-activation-validation.js +13 -3
- package/dist/lib/long-task-admitted-observation-records.d.ts +25 -0
- package/dist/lib/long-task-admitted-observation-records.js +40 -0
- package/dist/lib/long-task-admitted-observation.d.ts +93 -0
- package/dist/lib/long-task-admitted-observation.js +201 -0
- package/dist/lib/long-task-artifacts.d.ts +1 -0
- package/dist/lib/long-task-artifacts.js +1 -0
- package/dist/lib/long-task-authority-material-diff.js +1 -0
- package/dist/lib/long-task-authority-policy.d.ts +2 -0
- package/dist/lib/long-task-authority-policy.js +2 -0
- package/dist/lib/long-task-authority-revision-details.js +3 -1
- package/dist/lib/long-task-authority.js +2 -1
- package/dist/lib/long-task-check-execution-policy.js +5 -0
- package/dist/lib/long-task-check-runner.d.ts +2 -2
- package/dist/lib/long-task-check-runner.js +440 -23
- package/dist/lib/long-task-claims.d.ts +18 -0
- package/dist/lib/long-task-claims.js +35 -0
- package/dist/lib/long-task-compact-structure-targets.js +1 -0
- package/dist/lib/long-task-conformance-policy.js +3 -1
- package/dist/lib/long-task-counterfactual-claim-policy.d.ts +3 -4
- package/dist/lib/long-task-counterfactual-claim-policy.js +11 -3
- package/dist/lib/long-task-counterfactual-sandbox.js +1 -0
- package/dist/lib/long-task-counterfactual-types.d.ts +2 -0
- package/dist/lib/long-task-delivery-compiler.js +2 -0
- package/dist/lib/long-task-evidence-capability-policy.d.ts +3 -2
- package/dist/lib/long-task-evidence-capability-policy.js +114 -8
- package/dist/lib/long-task-evidence-capability-runtime.d.ts +5 -2
- package/dist/lib/long-task-evidence-capability-runtime.js +149 -5
- package/dist/lib/long-task-evidence-sensitivity-policy.d.ts +9 -0
- package/dist/lib/long-task-evidence-sensitivity-policy.js +31 -1
- package/dist/lib/long-task-evidence-v2.d.ts +4 -4
- package/dist/lib/long-task-evidence-v2.js +321 -43
- package/dist/lib/long-task-exact-comparison.d.ts +16 -0
- package/dist/lib/long-task-exact-comparison.js +28 -0
- package/dist/lib/long-task-execution-observation.d.ts +24 -0
- package/dist/lib/long-task-execution-observation.js +332 -0
- package/dist/lib/long-task-explain-acceptance-link.d.ts +4 -0
- package/dist/lib/long-task-explain-acceptance-link.js +4 -0
- package/dist/lib/long-task-explain-claim-links.d.ts +2 -0
- package/dist/lib/long-task-explain-claim-links.js +2 -0
- package/dist/lib/long-task-explain-source-links.d.ts +6 -0
- package/dist/lib/long-task-final-v2.js +7 -4
- package/dist/lib/long-task-json-pointer-observation.d.ts +59 -0
- package/dist/lib/long-task-json-pointer-observation.js +184 -0
- package/dist/lib/long-task-observation-artifact.d.ts +8 -0
- package/dist/lib/long-task-observation-artifact.js +58 -0
- package/dist/lib/long-task-observation-authority.d.ts +17 -0
- package/dist/lib/long-task-observation-authority.js +348 -0
- package/dist/lib/long-task-paths.js +1 -1
- package/dist/lib/long-task-process-observation.d.ts +6 -0
- package/dist/lib/long-task-process-observation.js +117 -0
- package/dist/lib/long-task-process-runtime-closure.d.ts +13 -0
- package/dist/lib/long-task-process-runtime-closure.js +175 -0
- package/dist/lib/long-task-progress.js +2 -0
- package/dist/lib/long-task-protected-files.d.ts +1 -1
- package/dist/lib/long-task-protected-files.js +1 -30
- package/dist/lib/long-task-risk.js +8 -3
- package/dist/lib/long-task-root-shape.js +10 -1
- package/dist/lib/long-task-runner-environment.d.ts +1 -1
- package/dist/lib/long-task-runner-environment.js +4 -4
- package/dist/lib/long-task-runner-freeze.d.ts +4 -2
- package/dist/lib/long-task-runner-freeze.js +128 -28
- package/dist/lib/long-task-runtime-types.d.ts +111 -0
- package/dist/lib/long-task-scoped-binding.d.ts +13 -0
- package/dist/lib/long-task-scoped-binding.js +11 -0
- package/dist/lib/long-task-semantic-contract-types.d.ts +1 -0
- package/dist/lib/long-task-semantic-fact-contract-closure.js +3 -3
- package/dist/lib/long-task-semantic-fact-evidence.d.ts +3 -3
- package/dist/lib/long-task-semantic-fact-evidence.js +75 -58
- package/dist/lib/long-task-source-claim-validation.js +4 -1
- package/dist/lib/long-task-source-target-continuity.d.ts +2 -2
- package/dist/lib/long-task-source-target-continuity.js +35 -2
- package/dist/lib/long-task-source-target-index.d.ts +3 -0
- package/dist/lib/long-task-source-target-index.js +19 -0
- package/dist/lib/long-task-stage-policy.js +10 -4
- package/dist/lib/long-task-static-observation-freeze.d.ts +83 -0
- package/dist/lib/long-task-static-observation-freeze.js +428 -0
- package/dist/lib/long-task-status-projection.js +5 -1
- package/dist/lib/long-task-target-policy.d.ts +1 -1
- package/dist/lib/long-task-target-policy.js +3 -0
- package/dist/lib/long-task-verifier-dependency-closure.js +7 -3
- package/dist/lib/long-task-verifier-v2.js +70 -9
- package/dist/lib/long-task-workspace.d.ts +1 -1
- package/dist/lib/long-task-workspace.js +1 -12
- package/dist/lib/repository-path-safety.d.ts +14 -0
- package/dist/lib/repository-path-safety.js +126 -0
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +53 -8
- package/migrations/README.md +77 -0
- package/package.json +1 -1
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
1
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { access, realpath } from "node:fs/promises";
|
|
3
4
|
import net from "node:net";
|
|
4
5
|
import path from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
5
7
|
import { decodeCheckEvidence, invalidEvidence, } from "./long-task-check-evidence-decoder.js";
|
|
6
8
|
import { declaredEnvironmentValues, outputContainsDeclaredEnvironmentValue, runnerEnvironment, } from "./long-task-runner-environment.js";
|
|
9
|
+
import { decodeProductObservationEnvelope } from "./long-task-process-observation.js";
|
|
7
10
|
import { resolveInsideRepository } from "./long-task-workspace.js";
|
|
8
|
-
import { sha256Hex } from "./strict-codec.js";
|
|
11
|
+
import { canonicalValueJson, sha256Hex } from "./strict-codec.js";
|
|
9
12
|
const OUTPUT_LIMIT = 2 * 1024 * 1024;
|
|
10
|
-
|
|
13
|
+
const PROCESS_TREE_GRACE_MS = 1_000;
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
export async function executeCheckRunner(check, snapshotRoot, context) {
|
|
11
16
|
const started = Date.now();
|
|
17
|
+
let processAuthorities;
|
|
18
|
+
try {
|
|
19
|
+
processAuthorities = processObservationAuthorities(check.observation_authorities ?? [], context?.observation_authorities ?? []);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return invalidRawExecution(check, started, message(error));
|
|
23
|
+
}
|
|
24
|
+
const processObserverIssue = validateProcessObserverActivation(check, snapshotRoot, processAuthorities, context);
|
|
25
|
+
if (processObserverIssue)
|
|
26
|
+
return invalidRawExecution(check, started, processObserverIssue);
|
|
12
27
|
const unavailable = await probeEnvironment(check.environment_requirements, snapshotRoot);
|
|
13
28
|
if (unavailable)
|
|
14
29
|
return {
|
|
@@ -31,11 +46,27 @@ export async function executeCheckRunner(check, snapshotRoot) {
|
|
|
31
46
|
const maximumAttempts = retryAllowed ? 2 : 1;
|
|
32
47
|
for (let attempt = 1; attempt <= maximumAttempts; attempt += 1) {
|
|
33
48
|
try {
|
|
34
|
-
const raw = await runOnce(check, snapshotRoot);
|
|
49
|
+
const raw = await runOnce(check, snapshotRoot, processAuthorities, context?.snapshot_sha256, context?.process_runtime_closure_identity);
|
|
35
50
|
const secrets = declaredEnvironmentValues(check.environment_requirements);
|
|
36
|
-
|
|
51
|
+
let decoded = outputContainsDeclaredEnvironmentValue(raw, secrets)
|
|
37
52
|
? invalidEvidence(raw.exit_code, "check_evidence_contains_declared_environment_value")
|
|
38
|
-
:
|
|
53
|
+
: raw.process_observation
|
|
54
|
+
? {
|
|
55
|
+
execution_status: "completed",
|
|
56
|
+
exit_code: raw.exit_code,
|
|
57
|
+
observations: {},
|
|
58
|
+
evidence_records: [],
|
|
59
|
+
error: null,
|
|
60
|
+
}
|
|
61
|
+
: decodeCheckEvidence(check, raw.exit_code, raw.stdout, raw.stderr);
|
|
62
|
+
if (raw.process_observation && raw.exit_code !== 0)
|
|
63
|
+
decoded = invalidEvidence(raw.exit_code, "process_observer_nonzero_exit");
|
|
64
|
+
else if (raw.process_observation &&
|
|
65
|
+
decoded.execution_status !== "completed")
|
|
66
|
+
decoded = invalidEvidence(raw.exit_code, "project_submitted_execution_status_disagrees_with_harness");
|
|
67
|
+
if (raw.process_observation &&
|
|
68
|
+
packageObservationContainsDeclaredEnvironmentValue(raw.process_observation, secrets))
|
|
69
|
+
decoded = invalidEvidence(raw.exit_code, "check_evidence_contains_declared_environment_value");
|
|
39
70
|
return {
|
|
40
71
|
raw_execution_identity: check.raw_execution_identity,
|
|
41
72
|
execution_identity: check.raw_execution_identity,
|
|
@@ -44,6 +75,8 @@ export async function executeCheckRunner(check, snapshotRoot) {
|
|
|
44
75
|
stderr_sha256: sha256Hex(raw.stderr),
|
|
45
76
|
attempts: attempt,
|
|
46
77
|
duration_ms: Date.now() - started,
|
|
78
|
+
package_observations: raw.process_observation?.package_observations ?? [],
|
|
79
|
+
host_execution_attestation: raw.host_execution_attestation,
|
|
47
80
|
};
|
|
48
81
|
}
|
|
49
82
|
catch (error) {
|
|
@@ -53,7 +86,9 @@ export async function executeCheckRunner(check, snapshotRoot) {
|
|
|
53
86
|
return {
|
|
54
87
|
raw_execution_identity: check.raw_execution_identity,
|
|
55
88
|
execution_identity: check.raw_execution_identity,
|
|
56
|
-
execution_status:
|
|
89
|
+
execution_status: isProcessObservationError(reason)
|
|
90
|
+
? "invalid_evidence"
|
|
91
|
+
: "infrastructure_error",
|
|
57
92
|
exit_code: -1,
|
|
58
93
|
observations: {},
|
|
59
94
|
evidence_records: [],
|
|
@@ -62,37 +97,100 @@ export async function executeCheckRunner(check, snapshotRoot) {
|
|
|
62
97
|
attempts: attempt,
|
|
63
98
|
duration_ms: Date.now() - started,
|
|
64
99
|
error: reason,
|
|
100
|
+
package_observations: [],
|
|
101
|
+
host_execution_attestation: null,
|
|
65
102
|
};
|
|
66
103
|
}
|
|
67
104
|
}
|
|
68
105
|
throw new Error("unreachable");
|
|
69
106
|
}
|
|
70
|
-
async function runOnce(check, snapshotRoot) {
|
|
107
|
+
async function runOnce(check, snapshotRoot, processAuthorities, snapshotSha256, processRuntimeClosureIdentity) {
|
|
71
108
|
const runner = check.runner;
|
|
72
109
|
const cwd = resolveInsideRepository(snapshotRoot, runner.resolved_cwd || ".", "runner.resolved_cwd");
|
|
73
110
|
const executable = runner.type === "project_binary"
|
|
74
111
|
? resolveInsideRepository(snapshotRoot, runner.resolved_target, "runner.resolved_target")
|
|
75
112
|
: runner.executable;
|
|
76
113
|
const argv = [...runner.executable_argv_prefix, ...runner.argv];
|
|
114
|
+
if (!processAuthorities.length) {
|
|
115
|
+
const execution = await spawnOnce(executable, argv, cwd, runner.timeout_ms, runnerEnvironment(check.environment_requirements), false);
|
|
116
|
+
return {
|
|
117
|
+
...execution,
|
|
118
|
+
process_observation: null,
|
|
119
|
+
host_execution_attestation: null,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const executionNonce = randomBytes(32).toString("hex");
|
|
123
|
+
const execution = await spawnOnce(executable, argv, cwd, runner.timeout_ms, runnerEnvironment(check.environment_requirements, "product_observation"), true);
|
|
124
|
+
const processObservation = decodeProductObservationEnvelope({
|
|
125
|
+
bytes: execution.stdout,
|
|
126
|
+
authorities: processAuthorities,
|
|
127
|
+
});
|
|
128
|
+
const declaredRoot = resolveInsideRepository(snapshotRoot, processAuthorities[0].runtime_requirements.declared_root_entrypoint, "process_observer.declared_root_entrypoint");
|
|
129
|
+
const [actualExecutable, actualDeclaredRoot] = await Promise.all([
|
|
130
|
+
realpath(executable),
|
|
131
|
+
realpath(declaredRoot),
|
|
132
|
+
]);
|
|
133
|
+
const directRootMatch = sameHostPath(actualExecutable, actualDeclaredRoot) &&
|
|
134
|
+
sameStringArray(argv, processAuthorities[0].runtime_requirements.declared_root_argv ?? []);
|
|
135
|
+
if (!directRootMatch)
|
|
136
|
+
throw new Error("process_observer_direct_root_required");
|
|
137
|
+
return {
|
|
138
|
+
exit_code: execution.exit_code,
|
|
139
|
+
stdout: execution.stdout,
|
|
140
|
+
stderr: execution.stderr,
|
|
141
|
+
process_observation: processObservation,
|
|
142
|
+
host_execution_attestation: {
|
|
143
|
+
raw_execution_identity: check.raw_execution_identity,
|
|
144
|
+
executable_path: actualExecutable,
|
|
145
|
+
declared_root_entrypoint: actualDeclaredRoot,
|
|
146
|
+
actual_argv: [...argv],
|
|
147
|
+
declared_root_argv: [
|
|
148
|
+
...(processAuthorities[0].runtime_requirements.declared_root_argv ??
|
|
149
|
+
[]),
|
|
150
|
+
],
|
|
151
|
+
direct_root_match: directRootMatch,
|
|
152
|
+
pid: execution.pid,
|
|
153
|
+
started_at: execution.started_at,
|
|
154
|
+
completed_at: execution.completed_at,
|
|
155
|
+
exit_code: execution.exit_code,
|
|
156
|
+
snapshot_sha256: snapshotSha256,
|
|
157
|
+
observation_execution_nonce: executionNonce,
|
|
158
|
+
observation_artifact_sha256: processObservation.artifact_sha256,
|
|
159
|
+
process_runtime_closure_identity: processRuntimeClosureIdentity,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
async function spawnOnce(executable, argv, cwd, timeoutMs, environment, containProcessTree) {
|
|
77
164
|
return new Promise((resolve, reject) => {
|
|
165
|
+
const startedAt = new Date().toISOString();
|
|
78
166
|
const child = spawn(executable, argv, {
|
|
79
167
|
cwd,
|
|
80
168
|
shell: false,
|
|
81
169
|
windowsHide: true,
|
|
82
|
-
env:
|
|
170
|
+
env: environment,
|
|
171
|
+
detached: containProcessTree && process.platform !== "win32",
|
|
83
172
|
});
|
|
173
|
+
const pid = child.pid ?? -1;
|
|
174
|
+
let stopTreeMonitor = false;
|
|
175
|
+
let treeMonitorError = null;
|
|
176
|
+
const observedDescendants = new Set();
|
|
177
|
+
const treeMonitor = containProcessTree && pid > 0
|
|
178
|
+
? observeDescendantProcesses(pid, observedDescendants, () => stopTreeMonitor).catch((error) => {
|
|
179
|
+
treeMonitorError = error;
|
|
180
|
+
})
|
|
181
|
+
: Promise.resolve();
|
|
84
182
|
const stdout = [];
|
|
85
183
|
const stderr = [];
|
|
86
184
|
let size = 0;
|
|
87
185
|
let settled = false;
|
|
186
|
+
let terminationReason = null;
|
|
187
|
+
let terminationTask = null;
|
|
188
|
+
let forceTimer = null;
|
|
189
|
+
let abandonTimer = null;
|
|
88
190
|
const capture = (target) => (chunk) => {
|
|
89
191
|
size += chunk.length;
|
|
90
192
|
if (size > OUTPUT_LIMIT) {
|
|
91
|
-
|
|
92
|
-
if (!settled) {
|
|
93
|
-
settled = true;
|
|
94
|
-
reject(new Error("command_output_limit_exceeded"));
|
|
95
|
-
}
|
|
193
|
+
terminate("command_output_limit_exceeded");
|
|
96
194
|
return;
|
|
97
195
|
}
|
|
98
196
|
target.push(Buffer.from(chunk));
|
|
@@ -102,29 +200,348 @@ async function runOnce(check, snapshotRoot) {
|
|
|
102
200
|
child.on("error", (error) => {
|
|
103
201
|
if (!settled) {
|
|
104
202
|
settled = true;
|
|
105
|
-
|
|
203
|
+
stopTreeMonitor = true;
|
|
204
|
+
clearTimeout(timer);
|
|
205
|
+
if (forceTimer)
|
|
206
|
+
clearTimeout(forceTimer);
|
|
207
|
+
if (abandonTimer)
|
|
208
|
+
clearTimeout(abandonTimer);
|
|
209
|
+
const spawnError = new Error(`command_spawn_error:${message(error)}`);
|
|
210
|
+
if (containProcessTree && pid > 0)
|
|
211
|
+
void terminateProcessTree(pid, true, [...observedDescendants])
|
|
212
|
+
.catch(() => undefined)
|
|
213
|
+
.finally(() => reject(spawnError));
|
|
214
|
+
else
|
|
215
|
+
reject(spawnError);
|
|
106
216
|
}
|
|
107
217
|
});
|
|
108
218
|
const timer = setTimeout(() => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
child.on("close", (code) => {
|
|
219
|
+
terminate("command_timeout");
|
|
220
|
+
}, timeoutMs);
|
|
221
|
+
if (pid < 0)
|
|
222
|
+
terminate("command_spawn_pid_unavailable");
|
|
223
|
+
child.on("close", async (code) => {
|
|
224
|
+
stopTreeMonitor = true;
|
|
116
225
|
clearTimeout(timer);
|
|
226
|
+
if (forceTimer)
|
|
227
|
+
clearTimeout(forceTimer);
|
|
228
|
+
if (abandonTimer)
|
|
229
|
+
clearTimeout(abandonTimer);
|
|
117
230
|
if (settled)
|
|
118
231
|
return;
|
|
119
232
|
settled = true;
|
|
233
|
+
if (terminationReason) {
|
|
234
|
+
try {
|
|
235
|
+
await terminationTask;
|
|
236
|
+
await treeMonitor;
|
|
237
|
+
if (containProcessTree)
|
|
238
|
+
await forceProcessTreeQuiescence(pid, observedDescendants);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// The original bounded termination reason remains the public error;
|
|
242
|
+
// cleanup is best-effort after the hard process-tree kill attempt.
|
|
243
|
+
}
|
|
244
|
+
reject(terminationReason);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (containProcessTree) {
|
|
248
|
+
try {
|
|
249
|
+
await treeMonitor;
|
|
250
|
+
if (treeMonitorError)
|
|
251
|
+
throw treeMonitorError;
|
|
252
|
+
await assertProcessTreeQuiescent(pid, observedDescendants);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
await terminateProcessTree(pid, true, [...observedDescendants]).catch(() => undefined);
|
|
256
|
+
reject(error);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
120
260
|
resolve({
|
|
121
261
|
exit_code: code ?? -1,
|
|
122
262
|
stdout: Buffer.concat(stdout),
|
|
123
263
|
stderr: Buffer.concat(stderr),
|
|
264
|
+
pid,
|
|
265
|
+
started_at: startedAt,
|
|
266
|
+
completed_at: new Date().toISOString(),
|
|
124
267
|
});
|
|
125
268
|
});
|
|
269
|
+
function terminate(reason) {
|
|
270
|
+
if (settled || terminationReason)
|
|
271
|
+
return;
|
|
272
|
+
terminationReason = new Error(reason);
|
|
273
|
+
stopTreeMonitor = true;
|
|
274
|
+
if (containProcessTree)
|
|
275
|
+
terminationTask = terminateProcessTree(pid, false).catch((error) => {
|
|
276
|
+
treeMonitorError ??= error;
|
|
277
|
+
});
|
|
278
|
+
else {
|
|
279
|
+
child.kill();
|
|
280
|
+
terminationTask = Promise.resolve();
|
|
281
|
+
}
|
|
282
|
+
forceTimer = setTimeout(() => {
|
|
283
|
+
if (containProcessTree)
|
|
284
|
+
terminationTask = terminateProcessTree(pid, true, [
|
|
285
|
+
...observedDescendants,
|
|
286
|
+
]).catch((error) => {
|
|
287
|
+
treeMonitorError ??= error;
|
|
288
|
+
});
|
|
289
|
+
else
|
|
290
|
+
child.kill("SIGKILL");
|
|
291
|
+
}, PROCESS_TREE_GRACE_MS);
|
|
292
|
+
forceTimer.unref();
|
|
293
|
+
abandonTimer = setTimeout(() => {
|
|
294
|
+
if (settled)
|
|
295
|
+
return;
|
|
296
|
+
settled = true;
|
|
297
|
+
child.stdout.destroy();
|
|
298
|
+
child.stderr.destroy();
|
|
299
|
+
const cleanup = containProcessTree
|
|
300
|
+
? forceProcessTreeQuiescence(pid, observedDescendants).catch(() => undefined)
|
|
301
|
+
: Promise.resolve();
|
|
302
|
+
void cleanup.finally(() => reject(terminationReason));
|
|
303
|
+
}, PROCESS_TREE_GRACE_MS * 2);
|
|
304
|
+
abandonTimer.unref();
|
|
305
|
+
}
|
|
126
306
|
});
|
|
127
307
|
}
|
|
308
|
+
async function forceProcessTreeQuiescence(rootPid, observed) {
|
|
309
|
+
await terminateProcessTree(rootPid, true, [...observed]);
|
|
310
|
+
const deadline = Date.now() + PROCESS_TREE_GRACE_MS;
|
|
311
|
+
while (Date.now() < deadline) {
|
|
312
|
+
const liveObserved = [rootPid, ...observed].some(processIdExists);
|
|
313
|
+
const groupAlive = process.platform !== "win32" && processGroupExists(rootPid);
|
|
314
|
+
if (!liveObserved && !groupAlive)
|
|
315
|
+
return;
|
|
316
|
+
await new Promise((resolve) => setTimeout(resolve, process.platform === "win32" ? 100 : 25));
|
|
317
|
+
}
|
|
318
|
+
throw new Error("process_observer_descendant_process_alive");
|
|
319
|
+
}
|
|
320
|
+
async function observeDescendantProcesses(rootPid, observed, stopped) {
|
|
321
|
+
do {
|
|
322
|
+
for (const pid of await descendantProcessIds(rootPid))
|
|
323
|
+
observed.add(pid);
|
|
324
|
+
if (stopped())
|
|
325
|
+
return;
|
|
326
|
+
await new Promise((resolve) => setTimeout(resolve, process.platform === "win32" ? 100 : 25));
|
|
327
|
+
} while (!stopped());
|
|
328
|
+
}
|
|
329
|
+
async function assertProcessTreeQuiescent(rootPid, observed) {
|
|
330
|
+
const finalDescendants = await descendantProcessIds(rootPid);
|
|
331
|
+
const descendants = [...new Set([...observed, ...finalDescendants])].filter(processIdExists);
|
|
332
|
+
const processGroupAlive = process.platform !== "win32" && processGroupExists(rootPid);
|
|
333
|
+
if (!descendants.length && !processGroupAlive)
|
|
334
|
+
return;
|
|
335
|
+
await terminateProcessTree(rootPid, true, descendants);
|
|
336
|
+
throw new Error("process_observer_descendant_process_alive");
|
|
337
|
+
}
|
|
338
|
+
function processIdExists(pid) {
|
|
339
|
+
try {
|
|
340
|
+
process.kill(pid, 0);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
if (nodeErrorCode(error) === "ESRCH")
|
|
345
|
+
return false;
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async function terminateProcessTree(rootPid, force, knownDescendants) {
|
|
350
|
+
if (!Number.isSafeInteger(rootPid) || rootPid <= 0)
|
|
351
|
+
return;
|
|
352
|
+
if (process.platform === "win32") {
|
|
353
|
+
const targets = [
|
|
354
|
+
rootPid,
|
|
355
|
+
...[...new Set(knownDescendants ?? [])]
|
|
356
|
+
.filter((pid) => pid !== rootPid)
|
|
357
|
+
.reverse(),
|
|
358
|
+
];
|
|
359
|
+
for (const pid of targets)
|
|
360
|
+
await execFileAsync("taskkill.exe", ["/PID", String(pid), "/T", "/F"], {
|
|
361
|
+
windowsHide: true,
|
|
362
|
+
timeout: PROCESS_TREE_GRACE_MS,
|
|
363
|
+
}).catch(() => undefined);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const signal = force ? "SIGKILL" : "SIGTERM";
|
|
367
|
+
try {
|
|
368
|
+
process.kill(-rootPid, signal);
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
if (nodeErrorCode(error) !== "ESRCH")
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
const descendants = knownDescendants ?? (await descendantProcessIds(rootPid));
|
|
375
|
+
for (const pid of [...descendants].reverse())
|
|
376
|
+
try {
|
|
377
|
+
process.kill(pid, signal);
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
if (nodeErrorCode(error) !== "ESRCH")
|
|
381
|
+
throw error;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async function descendantProcessIds(rootPid) {
|
|
385
|
+
let stdout;
|
|
386
|
+
try {
|
|
387
|
+
const result = process.platform === "win32"
|
|
388
|
+
? await execFileAsync("powershell.exe", [
|
|
389
|
+
"-NoLogo",
|
|
390
|
+
"-NoProfile",
|
|
391
|
+
"-NonInteractive",
|
|
392
|
+
"-Command",
|
|
393
|
+
'Get-CimInstance Win32_Process | ForEach-Object { "$($_.ProcessId) $($_.ParentProcessId)" }',
|
|
394
|
+
], {
|
|
395
|
+
encoding: "utf8",
|
|
396
|
+
windowsHide: true,
|
|
397
|
+
timeout: 5_000,
|
|
398
|
+
maxBuffer: OUTPUT_LIMIT,
|
|
399
|
+
})
|
|
400
|
+
: await execFileAsync("ps", ["-A", "-o", "pid=,ppid="], {
|
|
401
|
+
encoding: "utf8",
|
|
402
|
+
timeout: 5_000,
|
|
403
|
+
maxBuffer: OUTPUT_LIMIT,
|
|
404
|
+
});
|
|
405
|
+
stdout = result.stdout;
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
throw new Error(`process_observer_process_tree_inspection_unavailable:${message(error)}`);
|
|
409
|
+
}
|
|
410
|
+
const children = new Map();
|
|
411
|
+
for (const line of stdout.split(/\r?\n/u)) {
|
|
412
|
+
const [pidText, parentText] = line.trim().split(/\s+/u);
|
|
413
|
+
const pid = Number.parseInt(pidText ?? "", 10);
|
|
414
|
+
const parent = Number.parseInt(parentText ?? "", 10);
|
|
415
|
+
if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(parent))
|
|
416
|
+
continue;
|
|
417
|
+
const row = children.get(parent);
|
|
418
|
+
if (row)
|
|
419
|
+
row.push(pid);
|
|
420
|
+
else
|
|
421
|
+
children.set(parent, [pid]);
|
|
422
|
+
}
|
|
423
|
+
const result = [];
|
|
424
|
+
const pending = [...(children.get(rootPid) ?? [])];
|
|
425
|
+
const seen = new Set();
|
|
426
|
+
while (pending.length) {
|
|
427
|
+
const pid = pending.shift();
|
|
428
|
+
if (seen.has(pid))
|
|
429
|
+
continue;
|
|
430
|
+
seen.add(pid);
|
|
431
|
+
result.push(pid);
|
|
432
|
+
pending.push(...(children.get(pid) ?? []));
|
|
433
|
+
}
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
function processGroupExists(rootPid) {
|
|
437
|
+
try {
|
|
438
|
+
process.kill(-rootPid, 0);
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
if (nodeErrorCode(error) === "ESRCH")
|
|
443
|
+
return false;
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function nodeErrorCode(error) {
|
|
448
|
+
return error && typeof error === "object" && "code" in error
|
|
449
|
+
? String(error.code)
|
|
450
|
+
: null;
|
|
451
|
+
}
|
|
452
|
+
function validateProcessObserverActivation(check, snapshotRoot, authorities, context) {
|
|
453
|
+
if (!authorities.length)
|
|
454
|
+
return null;
|
|
455
|
+
if (!context?.snapshot_sha256)
|
|
456
|
+
return "process_observer_snapshot_identity_required";
|
|
457
|
+
if (!context.process_runtime_closure_identity ||
|
|
458
|
+
!check.process_runtime_closure ||
|
|
459
|
+
context.process_runtime_closure_identity !==
|
|
460
|
+
check.process_runtime_closure.closure_identity)
|
|
461
|
+
return "process_runtime_closure_identity_mismatch";
|
|
462
|
+
if (check.environment_requirements.some((requirement) => requirement.kind === "env_var" &&
|
|
463
|
+
(requirement.target.toUpperCase() === "TY_CONTEXT_OBSERVATION_OUTPUT" ||
|
|
464
|
+
requirement.target.toUpperCase() ===
|
|
465
|
+
"TY_CONTEXT_OBSERVATION_CHALLENGE" ||
|
|
466
|
+
requirement.target.toUpperCase() === "TY_CONTEXT_CHECK_PROTOCOL")))
|
|
467
|
+
return "process_observer_reserved_environment_requirement";
|
|
468
|
+
if (check.runner.type !== "project_binary" ||
|
|
469
|
+
check.execution_target.entrypoint !== "root")
|
|
470
|
+
return "process_observer_direct_root_required";
|
|
471
|
+
const executable = resolveInsideRepository(snapshotRoot, check.runner.resolved_target, "process_observer.runner_target");
|
|
472
|
+
const actualArgv = [
|
|
473
|
+
...check.runner.executable_argv_prefix,
|
|
474
|
+
...check.runner.argv,
|
|
475
|
+
];
|
|
476
|
+
for (const authority of authorities) {
|
|
477
|
+
const requirements = authority.runtime_requirements;
|
|
478
|
+
if (requirements.runtime_family !== "process" ||
|
|
479
|
+
requirements.target_role !== "product" ||
|
|
480
|
+
requirements.entrypoint !== "root" ||
|
|
481
|
+
requirements.runner_type !== "project_binary" ||
|
|
482
|
+
requirements.resolved_runner_target !== check.runner.resolved_target ||
|
|
483
|
+
requirements.declared_root_argv === null ||
|
|
484
|
+
!sameStringArray(requirements.resolved_runner_argv, check.runner.argv) ||
|
|
485
|
+
!sameStringArray(requirements.declared_root_argv, actualArgv) ||
|
|
486
|
+
check.runner.executable_argv_prefix.length !== 0 ||
|
|
487
|
+
!requirements.direct_root_match)
|
|
488
|
+
return "process_observer_direct_root_required";
|
|
489
|
+
const declaredRoot = resolveInsideRepository(snapshotRoot, requirements.declared_root_entrypoint, "process_observer.declared_root_entrypoint");
|
|
490
|
+
if (!sameHostPath(executable, declaredRoot))
|
|
491
|
+
return "process_observer_direct_root_required";
|
|
492
|
+
}
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
function processObservationAuthorities(checkAuthorities, groupedAuthorities) {
|
|
496
|
+
const byIdentity = new Map();
|
|
497
|
+
for (const authority of [...checkAuthorities, ...groupedAuthorities]) {
|
|
498
|
+
if (authority.authority !== "package_process_json_exact")
|
|
499
|
+
continue;
|
|
500
|
+
const identity = `${authority.assertion_ref}\0${authority.obligation_ref}\0${authority.method}`;
|
|
501
|
+
const existing = byIdentity.get(identity);
|
|
502
|
+
if (existing &&
|
|
503
|
+
canonicalValueJson(existing) !== canonicalValueJson(authority))
|
|
504
|
+
throw new Error("process_observation_authority_group_mismatch");
|
|
505
|
+
byIdentity.set(identity, authority);
|
|
506
|
+
}
|
|
507
|
+
return [...byIdentity.values()];
|
|
508
|
+
}
|
|
509
|
+
function invalidRawExecution(check, started, reason) {
|
|
510
|
+
return {
|
|
511
|
+
raw_execution_identity: check.raw_execution_identity,
|
|
512
|
+
execution_identity: check.raw_execution_identity,
|
|
513
|
+
execution_status: "invalid_evidence",
|
|
514
|
+
exit_code: -1,
|
|
515
|
+
observations: {},
|
|
516
|
+
evidence_records: [],
|
|
517
|
+
stdout_sha256: sha256Hex(""),
|
|
518
|
+
stderr_sha256: sha256Hex(reason),
|
|
519
|
+
attempts: 0,
|
|
520
|
+
duration_ms: Date.now() - started,
|
|
521
|
+
error: reason,
|
|
522
|
+
package_observations: [],
|
|
523
|
+
host_execution_attestation: null,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function packageObservationContainsDeclaredEnvironmentValue(observation, values) {
|
|
527
|
+
if (!values.length)
|
|
528
|
+
return false;
|
|
529
|
+
const serialized = JSON.stringify(observation.observations);
|
|
530
|
+
return values.some((value) => serialized.includes(value));
|
|
531
|
+
}
|
|
532
|
+
function isProcessObservationError(reason) {
|
|
533
|
+
return (reason.startsWith("process_observation_") ||
|
|
534
|
+
reason.startsWith("process_observer_"));
|
|
535
|
+
}
|
|
536
|
+
function sameHostPath(left, right) {
|
|
537
|
+
return process.platform === "win32"
|
|
538
|
+
? path.resolve(left).toLowerCase() === path.resolve(right).toLowerCase()
|
|
539
|
+
: path.resolve(left) === path.resolve(right);
|
|
540
|
+
}
|
|
541
|
+
function sameStringArray(left, right) {
|
|
542
|
+
return (left.length === right.length &&
|
|
543
|
+
left.every((value, index) => value === right[index]));
|
|
544
|
+
}
|
|
128
545
|
async function probeEnvironment(requirements, snapshotRoot) {
|
|
129
546
|
for (const requirement of requirements) {
|
|
130
547
|
let available = false;
|
|
@@ -4,7 +4,25 @@ export interface CompiledClaimsV2 {
|
|
|
4
4
|
by_outcome: Record<string, ProductClaimV2[]>;
|
|
5
5
|
summary: ClaimCoverageSummaryV2;
|
|
6
6
|
}
|
|
7
|
+
interface ExternalConfirmationProjectionInput {
|
|
8
|
+
global: {
|
|
9
|
+
acceptance: {
|
|
10
|
+
external_confirmations: readonly {
|
|
11
|
+
blocks_target: boolean;
|
|
12
|
+
impact_claims: readonly string[];
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface AllOutcomeExternalConfirmationProjectionInput extends ExternalConfirmationProjectionInput {
|
|
18
|
+
outcomes: readonly {
|
|
19
|
+
key: string;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
export declare function outcomeResultExternallyBlocked(contract: ExternalConfirmationProjectionInput, outcomeKey: string): boolean;
|
|
23
|
+
export declare function allOutcomeResultsExternallyBlocked(contract: AllOutcomeExternalConfirmationProjectionInput): boolean;
|
|
7
24
|
export declare function compileProductClaimCoverage(contract: DeliveryContractV2, options?: {
|
|
8
25
|
allow_uncovered?: boolean;
|
|
9
26
|
}): CompiledClaimsV2;
|
|
10
27
|
export declare function assertCompiledClaimsCovered(compiled: CompiledClaimsV2): void;
|
|
28
|
+
export {};
|
|
@@ -2,6 +2,15 @@ import { assertAllClaimsCovered, assertAllGlobalClaimsCovered, generateClaims, g
|
|
|
2
2
|
import { fail } from "./long-task-delivery-shape.js";
|
|
3
3
|
import { validateClaimAssertionOperator, validateGlobalAssertionOperator, } from "./long-task-claim-proof-policy.js";
|
|
4
4
|
import { matchesRepoPattern } from "./long-task-paths.js";
|
|
5
|
+
export function outcomeResultExternallyBlocked(contract, outcomeKey) {
|
|
6
|
+
const resultClaim = `${outcomeKey}.result`;
|
|
7
|
+
return contract.global.acceptance.external_confirmations.some((confirmation) => confirmation.blocks_target &&
|
|
8
|
+
confirmation.impact_claims.includes(resultClaim));
|
|
9
|
+
}
|
|
10
|
+
export function allOutcomeResultsExternallyBlocked(contract) {
|
|
11
|
+
return (contract.outcomes.length > 0 &&
|
|
12
|
+
contract.outcomes.every((outcome) => outcomeResultExternallyBlocked(contract, outcome.key)));
|
|
13
|
+
}
|
|
5
14
|
export function compileProductClaimCoverage(contract, options = {}) {
|
|
6
15
|
const byGlobal = generateGlobalClaims(contract.global);
|
|
7
16
|
const byOutcome = Object.fromEntries(contract.outcomes.map((outcome) => [outcome.key, generateClaims(outcome)]));
|
|
@@ -69,6 +78,8 @@ function compileGlobalScope(contract, claims, profiles) {
|
|
|
69
78
|
validateGlobalAssertionOperator(proof.assertion, proof.check.key);
|
|
70
79
|
addProof(proofs, claimKey, claimProof);
|
|
71
80
|
}
|
|
81
|
+
for (const claim of claims)
|
|
82
|
+
addBlockingExternalConfirmationProofs(contract, claim, proofs);
|
|
72
83
|
validateProfileUse("GLOBAL", profiles, claims);
|
|
73
84
|
return Object.fromEntries(claims.map((claim) => {
|
|
74
85
|
const claimProofs = proofs.get(claim.local_key) ?? [];
|
|
@@ -141,6 +152,9 @@ function compileOutcomeScope(contract, outcomeKey, claims, profiles, outcomeKeys
|
|
|
141
152
|
applicability_ref: factBinding.applicability_ref,
|
|
142
153
|
});
|
|
143
154
|
}
|
|
155
|
+
for (const claim of claims)
|
|
156
|
+
if (claim.kind !== "semantic_fact")
|
|
157
|
+
addBlockingExternalConfirmationProofs(contract, claim, proofs);
|
|
144
158
|
validatePopulationReferences(outcome, claimMap);
|
|
145
159
|
validateCounterfactualReferences(outcome, claimMap);
|
|
146
160
|
validateProfileUse(outcomeKey, profiles, claims);
|
|
@@ -254,6 +268,7 @@ function validateCounterfactualReferences(outcome, claims) {
|
|
|
254
268
|
for (const assertion of [
|
|
255
269
|
...control.expected_assertion_failures,
|
|
256
270
|
...control.preserved_assertions,
|
|
271
|
+
...control.allowed_fanout_assertions,
|
|
257
272
|
])
|
|
258
273
|
if (!assertions.has(assertion))
|
|
259
274
|
fail("counterfactual_assertion_unknown", `${outcome.key}:${control.key}:${assertion}`);
|
|
@@ -306,6 +321,26 @@ function addProof(proofs, claim, proof) {
|
|
|
306
321
|
rows.push(proof);
|
|
307
322
|
proofs.set(claim, rows);
|
|
308
323
|
}
|
|
324
|
+
function addBlockingExternalConfirmationProofs(contract, claim, proofs) {
|
|
325
|
+
const confirmations = contract.global.acceptance.external_confirmations.filter((confirmation) => confirmation.blocks_target &&
|
|
326
|
+
confirmation.impact_claims.includes(claim.id));
|
|
327
|
+
if (!confirmations.length)
|
|
328
|
+
return;
|
|
329
|
+
const proofSurfaces = "required_proof_surfaces" in claim &&
|
|
330
|
+
claim.required_proof_surfaces.length > 0
|
|
331
|
+
? claim.required_proof_surfaces
|
|
332
|
+
: ["runtime_behavior"];
|
|
333
|
+
for (const confirmation of confirmations)
|
|
334
|
+
for (const applicabilityRef of claim.applicability_refs)
|
|
335
|
+
for (const proofSurface of proofSurfaces)
|
|
336
|
+
addProof(proofs, claim.local_key, {
|
|
337
|
+
check_key: `EXTERNAL.${confirmation.key}`,
|
|
338
|
+
assertion_key: null,
|
|
339
|
+
polarity: claim.required_polarity,
|
|
340
|
+
proof_surface: proofSurface,
|
|
341
|
+
applicability_ref: applicabilityRef,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
309
344
|
function sameSet(left, right) {
|
|
310
345
|
return (left.length === right.length &&
|
|
311
346
|
new Set(left).size === left.length &&
|
|
@@ -11,6 +11,7 @@ const BASE_STRUCTURE_BOUNDARY_BY_FIELD = {
|
|
|
11
11
|
journey_roles: "contract.check.journey-roles",
|
|
12
12
|
carrier_paths: "contract.binding.carrier-paths",
|
|
13
13
|
preserved_assertions: "contract.counterfactual.preserved-assertions",
|
|
14
|
+
allowed_fanout_assertions: "contract.counterfactual.allowed-fanout-assertions",
|
|
14
15
|
expected_assertion_failures: "contract.counterfactual.expected-assertion-failures",
|
|
15
16
|
};
|
|
16
17
|
export function longTaskCompactSharedStructureTargets(root, carrier) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { allOutcomeResultsExternallyBlocked } from "./long-task-claims.js";
|
|
1
2
|
export function semanticConformanceRequired(contract, _effectiveRisk) {
|
|
2
3
|
const productFamilies = new Set(contract.task.execution_targets
|
|
3
4
|
.filter((target) => contract.task.target_profile.required_target_refs.includes(target.key))
|
|
@@ -8,7 +9,8 @@ export function semanticConformanceRequired(contract, _effectiveRisk) {
|
|
|
8
9
|
export function validateSemanticConformance(contract, effectiveRisk, compiledChecks, report) {
|
|
9
10
|
const declared = contract.global.acceptance.checks.filter((check) => check.journey_roles.includes("conformance"));
|
|
10
11
|
if (semanticConformanceRequired(contract, effectiveRisk) &&
|
|
11
|
-
!declared.length
|
|
12
|
+
!declared.length &&
|
|
13
|
+
!allOutcomeResultsExternallyBlocked(contract)) {
|
|
12
14
|
issue(report, "semantic_conformance_check_required", contract.task.id);
|
|
13
15
|
return;
|
|
14
16
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { CounterfactualControlV2, DeliveryContractV2, DeliveryBindingV2, DeliveryOutcomeV2, GlobalCounterfactualControlV2 } from "./long-task-delivery-types.js";
|
|
2
|
+
import { type ScopedDeliveryBindingV2 } from "./long-task-scoped-binding.js";
|
|
2
3
|
export declare function validateCounterfactualBindingClaims(outcome: DeliveryOutcomeV2, control: CounterfactualControlV2, binding: DeliveryBindingV2): void;
|
|
3
|
-
export declare function resolveGlobalCounterfactualBinding(contract: DeliveryContractV2, control: GlobalCounterfactualControlV2): {
|
|
4
|
+
export declare function resolveGlobalCounterfactualBinding(contract: DeliveryContractV2, control: GlobalCounterfactualControlV2): ScopedDeliveryBindingV2 & {
|
|
4
5
|
outcome: DeliveryOutcomeV2;
|
|
5
|
-
binding: DeliveryBindingV2;
|
|
6
6
|
};
|
|
7
|
-
export declare function validateGlobalCounterfactualBindingClaims(contract: DeliveryContractV2, control: GlobalCounterfactualControlV2): {
|
|
7
|
+
export declare function validateGlobalCounterfactualBindingClaims(contract: DeliveryContractV2, control: GlobalCounterfactualControlV2): ScopedDeliveryBindingV2 & {
|
|
8
8
|
outcome: DeliveryOutcomeV2;
|
|
9
|
-
binding: DeliveryBindingV2;
|
|
10
9
|
};
|