@vela-science/canopus 0.6.5 → 0.8.0
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/CHANGELOG.md +97 -0
- package/README.md +67 -139
- package/SECURITY.md +3 -2
- package/capsules/erdos1056-k15/bin/linux-arm64/{10428801-10429000 → 10429201-10429400}/verifier +0 -0
- package/capsules/erdos1056-k15/bin/linux-x86_64/{10428801-10429000 → 10429201-10429400}/verifier +0 -0
- package/compatibility.json +25 -0
- package/dist/src/activity/events.d.ts +4 -1
- package/dist/src/activity/events.js +8 -2
- package/dist/src/activity/store.d.ts +2 -2
- package/dist/src/activity/store.js +4 -3
- package/dist/src/{receipt/map.d.ts → candidate/finalize.d.ts} +2 -9
- package/dist/src/candidate/finalize.js +71 -0
- package/dist/src/cli.js +88 -229
- package/dist/src/contracts/mission.d.ts +1 -13
- package/dist/src/contracts/mission.js +4 -42
- package/dist/src/contracts/validation.d.ts +1 -25
- package/dist/src/contracts/validation.js +1 -95
- package/dist/src/engines/codex-tools-native.js +2 -2
- package/dist/src/index.d.ts +5 -34
- package/dist/src/index.js +4 -34
- package/dist/src/mission/prepare.d.ts +10 -1
- package/dist/src/mission/prepare.js +29 -30
- package/dist/src/product/coverage.d.ts +17 -0
- package/dist/src/product/coverage.js +137 -0
- package/dist/src/product/doctor.d.ts +1 -2
- package/dist/src/product/doctor.js +29 -8
- package/dist/src/product/profile.js +8 -2
- package/dist/src/product/replay.js +11 -12
- package/dist/src/product/run.d.ts +5 -9
- package/dist/src/product/run.js +17 -88
- package/dist/src/product/submission.d.ts +40 -0
- package/dist/src/product/submission.js +217 -0
- package/dist/src/product/submit.d.ts +22 -0
- package/dist/src/product/submit.js +264 -0
- package/dist/src/product/version.d.ts +2 -2
- package/dist/src/product/version.js +27 -4
- package/dist/src/projection/current-run.d.ts +12 -0
- package/dist/src/projection/current-run.js +94 -0
- package/dist/src/projection/failure.d.ts +17 -7
- package/dist/src/projection/failure.js +43 -12
- package/dist/src/projection/retained-mission.d.ts +6 -0
- package/dist/src/projection/retained-mission.js +41 -0
- package/dist/src/projection/retained-run.d.ts +7 -0
- package/dist/src/projection/retained-run.js +50 -0
- package/dist/src/run.d.ts +43 -41
- package/dist/src/run.js +34 -412
- package/dist/src/util/canonical.d.ts +1 -5
- package/dist/src/util/canonical.js +1 -53
- package/dist/src/vela/cli.d.ts +7 -51
- package/dist/src/vela/cli.js +102 -523
- package/dist/src/vela/types.d.ts +3 -19
- package/dist/src/verifier/run.js +1 -1
- package/dist/src/workspace/prepare.d.ts +1 -1
- package/dist/src/workspace/prepare.js +15 -15
- package/docs/EVALUATION.md +142 -0
- package/docs/MISSIONS.md +42 -80
- package/docs/RUN_RECORD.md +77 -99
- package/docs/adr/0010-nonmutating-runs-and-explicit-submission.md +191 -0
- package/missions/erdos1056-k15-next/mission.draft.json +10 -8
- package/package.json +18 -22
- package/profiles/{erdos1056-k15-10428801-10429000.json → erdos1056-k15-10429201-10429400.json} +10 -10
- package/schemas/failure.v1.json +17 -0
- package/schemas/mission.v0.json +3 -4
- package/schemas/mission.v1.json +7 -28
- package/schemas/{run.v1.json → run.v2.json} +58 -116
- package/schemas/submission-bundle.v1.json +63 -0
- package/toolchain.lock.json +31 -0
- package/BUILD_WEEK.md +0 -198
- package/advisories/erdos1056-claim-fidelity/output.schema.json +0 -90
- package/advisories/erdos1056-claim-fidelity/registration.json +0 -42
- package/advisories/erdos1056-claim-fidelity/results/assessment.json +0 -1
- package/advisories/erdos1056-claim-fidelity/results/verification.json +0 -1
- package/capsules/formal-erdos-505-test-dim-one/verifier +0 -105
- package/capsules/quantum-10-1-4/verifier.py +0 -152
- package/capsules/sidon-a24/bin/linux-arm64/verifier +0 -0
- package/capsules/sidon-a24/bin/linux-x86_64/verifier +0 -0
- package/dist/src/capability/withdrawal.d.ts +0 -47
- package/dist/src/capability/withdrawal.js +0 -487
- package/dist/src/engines/codex-exec.d.ts +0 -17
- package/dist/src/engines/codex-exec.js +0 -136
- package/dist/src/engines/codex-tool-free.d.ts +0 -26
- package/dist/src/engines/codex-tool-free.js +0 -213
- package/dist/src/product/withdraw.d.ts +0 -8
- package/dist/src/product/withdraw.js +0 -255
- package/dist/src/projection/diagnostic.d.ts +0 -12
- package/dist/src/projection/diagnostic.js +0 -61
- package/dist/src/projection/public-run.d.ts +0 -59
- package/dist/src/projection/public-run.js +0 -106
- package/dist/src/projection/publication.d.ts +0 -36
- package/dist/src/projection/publication.js +0 -47
- package/dist/src/projection/run.d.ts +0 -95
- package/dist/src/projection/run.js +0 -173
- package/dist/src/receipt/map.js +0 -168
- package/dist/src/repair/plan.d.ts +0 -2
- package/dist/src/repair/plan.js +0 -22
- package/dist/src/roles.d.ts +0 -2
- package/dist/src/roles.js +0 -9
- package/docs/RELEASES.md +0 -1389
- package/evidence/build-week/run_eb6bcd46-cffd-4ae8-b630-2681bd84da71.public.json +0 -1
- package/evidence/build-week/run_f68e4cfc-e5c7-4c73-86cb-d79807c47ec4.public.json +0 -1
- package/evidence/erdos/run_192b3bef-9d6e-49e5-b72d-7ae903b29d5e/pending-commands.json +0 -1
- package/evidence/erdos/run_192b3bef-9d6e-49e5-b72d-7ae903b29d5e/public-run.json +0 -1
- package/evidence/erdos/run_192b3bef-9d6e-49e5-b72d-7ae903b29d5e/root-manifest.json +0 -1
- package/evidence/erdos/run_192b3bef-9d6e-49e5-b72d-7ae903b29d5e/web-import.json +0 -1
- package/evidence/erdos/run_b3b0cf07-b149-4d53-8258-76ba0e1fc0a5/pending-commands.json +0 -1
- package/evidence/erdos/run_b3b0cf07-b149-4d53-8258-76ba0e1fc0a5/public-run.json +0 -1
- package/evidence/erdos/run_b3b0cf07-b149-4d53-8258-76ba0e1fc0a5/root-manifest.json +0 -1
- package/evidence/erdos/run_b3b0cf07-b149-4d53-8258-76ba0e1fc0a5/web-import.json +0 -1
- package/missions/formal-erdos-505-test-dim-one-gpt56/mission.draft.json +0 -40
- package/missions/quantum-10-1-4-retry/mission.draft.json +0 -40
- package/missions/sidon-a24-at-least-7194-gpt56/mission.draft.json +0 -42
- package/missions/sidon-a24-at-least-7194-gpt56-v2/mission.draft.json +0 -42
- package/missions/sidon-a24-at-least-7194-gpt56-v3/mission.draft.json +0 -42
- package/profiles/formal-erdos-505-test-dim-one-gpt56.json +0 -35
- package/profiles/quantum-10-1-4-stabilizer-retry.json +0 -35
- package/profiles/sidon-a24-at-least-7194-gpt56-v2.json +0 -35
- package/profiles/sidon-a24-at-least-7194-gpt56-v3.json +0 -35
- package/profiles/sidon-a24-at-least-7194-gpt56.json +0 -35
- package/schemas/canopus.public-run.v1.json +0 -116
- package/scripts/run-claim-fidelity-advisory.mjs +0 -235
package/dist/src/cli.js
CHANGED
|
@@ -3,48 +3,37 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import { readdir, stat } from "node:fs/promises";
|
|
7
7
|
import { parseMission } from "./contracts/mission.js";
|
|
8
|
-
import { CodexExecEngine } from "./engines/codex-exec.js";
|
|
9
|
-
import { CodexToolsNativeEngine } from "./engines/codex-tools-native.js";
|
|
10
8
|
import { prepareMission, validateMissionBundle } from "./mission/prepare.js";
|
|
11
|
-
import {
|
|
9
|
+
import { projectCurrentRun } from "./projection/current-run.js";
|
|
10
|
+
import { parseRetainedRunRecord } from "./projection/retained-run.js";
|
|
12
11
|
import { parseFailureRecord, projectFailure } from "./projection/failure.js";
|
|
13
|
-
import { parseRunRecord, projectRun } from "./projection/run.js";
|
|
14
|
-
import { projectPublicRun } from "./projection/public-run.js";
|
|
15
|
-
import { buildPublicationBundle } from "./projection/publication.js";
|
|
16
12
|
import { doctorProduct } from "./product/doctor.js";
|
|
17
13
|
import { replayProduct } from "./product/replay.js";
|
|
18
14
|
import { runProduct } from "./product/run.js";
|
|
19
|
-
import {
|
|
15
|
+
import { exportSubmission } from "./product/submission.js";
|
|
16
|
+
import { submitBundle } from "./product/submit.js";
|
|
20
17
|
import { CANOPUS_VERSION } from "./product/version.js";
|
|
21
18
|
import { listProductProfiles, packProductProfile, validateProductProfile, } from "./product/profile-bundle.js";
|
|
22
19
|
import { loadProductProfile } from "./product/profile.js";
|
|
23
|
-
import { runCanopus } from "./run.js";
|
|
24
20
|
import { readBoundedRegularFile } from "./util/files.js";
|
|
25
|
-
import { canonicalJson, contentDigest } from "./util/canonical.js";
|
|
26
|
-
import { VelaClient } from "./vela/cli.js";
|
|
27
|
-
import { withdrawalCapabilityStatus } from "./capability/withdrawal.js";
|
|
28
21
|
function usage() {
|
|
29
22
|
return `Canopus — bounded Vela research harness
|
|
30
23
|
|
|
31
24
|
Primary workflow:
|
|
32
|
-
canopus --version
|
|
33
25
|
canopus doctor [frontier] [--profile <name>]
|
|
34
|
-
canopus run [frontier] [--first | --target <id>] [--profile <name>]
|
|
35
|
-
|
|
36
|
-
canopus inspect [run.json | latest]
|
|
37
|
-
canopus public-run <run.json> --mission <mission.json> \
|
|
38
|
-
--repository <public-url> --output <file>
|
|
39
|
-
canopus publish-run <run.json> --mission <mission.json> \
|
|
40
|
-
--repository <public-url> --output <new-directory>
|
|
26
|
+
canopus run [frontier] [--first | --target <id>] [--profile <name>] [--output <dir>]
|
|
27
|
+
canopus show [run.json | failure.json | latest]
|
|
41
28
|
canopus replay <run.json>
|
|
42
|
-
canopus
|
|
29
|
+
canopus export <run.json | latest> [--output <new-directory>] [--as <agent:id>] \\
|
|
30
|
+
[--claim <corrected-bounded-claim> --scope-limit <limit>]
|
|
31
|
+
canopus submit <submission-bundle> [frontier] [--vela <binary>]
|
|
43
32
|
|
|
44
33
|
Mission v1 prepare/validate remains available under advanced help.
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
Run and export never mutate Vela. submit explicitly registers an authenticated
|
|
36
|
+
Submission as pending review. Canopus cannot verify, decide, or change Standing.`;
|
|
48
37
|
}
|
|
49
38
|
function missionUsage() {
|
|
50
39
|
return `Usage:
|
|
@@ -69,19 +58,19 @@ remain replay-only; new tool-using missions require a validated version 2 profil
|
|
|
69
58
|
function runUsage() {
|
|
70
59
|
return `Usage:
|
|
71
60
|
canopus run [frontier] [--first | --target <id>] [--profile <name>] \\
|
|
72
|
-
[--output <dir>]
|
|
61
|
+
[--output <dir>]
|
|
73
62
|
|
|
74
63
|
Discovers and binds Vela, Codex, Git, Docker, the exact frontier roots, and the
|
|
75
|
-
registered verifier profile.
|
|
76
|
-
|
|
64
|
+
registered verifier profile. Runs the worker and verifier in disposable clones
|
|
65
|
+
and always leaves the source frontier unchanged.`;
|
|
77
66
|
}
|
|
78
|
-
function
|
|
67
|
+
function showUsage() {
|
|
79
68
|
return `Usage:
|
|
80
|
-
canopus
|
|
69
|
+
canopus show [run.json | failure.json | latest]
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
Shows the newest completed or safely stopped non-authoritative Run without
|
|
72
|
+
mutating Vela. Historical formats remain readable through their exact Canopus
|
|
73
|
+
release; the current product accepts only Run v2 and failure records.`;
|
|
85
74
|
}
|
|
86
75
|
function doctorUsage() {
|
|
87
76
|
return `Usage:
|
|
@@ -98,31 +87,23 @@ function replayUsage() {
|
|
|
98
87
|
Re-runs the frozen verifier over the content-addressed candidate without a
|
|
99
88
|
model call, Vela mutation, network, or authority action.`;
|
|
100
89
|
}
|
|
101
|
-
function
|
|
102
|
-
return `Usage:
|
|
103
|
-
canopus public-run <run.json> --mission <mission.json> \\
|
|
104
|
-
--repository <public-url> --output <file>
|
|
105
|
-
|
|
106
|
-
Generates one canonical, sanitized canopus.public-run.v1 projection from a
|
|
107
|
-
submission-ready completed run. Raw worker logs, homes, credentials, private
|
|
108
|
-
paths, and unrestricted transcripts are never copied.`;
|
|
109
|
-
}
|
|
110
|
-
function publishRunUsage() {
|
|
90
|
+
function exportUsage() {
|
|
111
91
|
return `Usage:
|
|
112
|
-
canopus
|
|
113
|
-
--
|
|
92
|
+
canopus export <run.json | latest> [--output <new-directory>] [--as <agent:id>] \\
|
|
93
|
+
[--claim <corrected-bounded-claim> --scope-limit <limit>]
|
|
114
94
|
|
|
115
|
-
Creates a
|
|
116
|
-
|
|
117
|
-
|
|
95
|
+
Creates a signed portable vela.submission.v1 bundle from a successful Run.
|
|
96
|
+
Export does not touch a frontier and does not create Verification or Standing.
|
|
97
|
+
The correction pair is accepted only when the retained Run Claim has stale
|
|
98
|
+
verifier wording or control bytes; the immutable Run remains unchanged.`;
|
|
118
99
|
}
|
|
119
|
-
function
|
|
100
|
+
function submitUsage() {
|
|
120
101
|
return `Usage:
|
|
121
|
-
canopus
|
|
102
|
+
canopus submit <submission-bundle> [frontier] [--vela <binary>]
|
|
122
103
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
104
|
+
Explicitly registers one authenticated Submission through Vela in a disposable
|
|
105
|
+
exact-head clone, then fast-forwards the clean source checkout. The result is
|
|
106
|
+
pending review with zero accepted-event delta.`;
|
|
126
107
|
}
|
|
127
108
|
function isHelp(value) {
|
|
128
109
|
return value === "--help" || value === "-h" || value === "help";
|
|
@@ -179,9 +160,6 @@ function required(values, key) {
|
|
|
179
160
|
throw new Error(`${key} is required`);
|
|
180
161
|
return value;
|
|
181
162
|
}
|
|
182
|
-
function authHome(values) {
|
|
183
|
-
return path.resolve(values.get("--codex-home") ?? process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex"));
|
|
184
|
-
}
|
|
185
163
|
function packagedOutputSchema() {
|
|
186
164
|
return fileURLToPath(new URL("../../schemas/engine-output.v0.json", import.meta.url));
|
|
187
165
|
}
|
|
@@ -285,67 +263,6 @@ async function profileCommand(args) {
|
|
|
285
263
|
}
|
|
286
264
|
throw new Error(`unknown profile command ${subcommand}`);
|
|
287
265
|
}
|
|
288
|
-
async function runMission(file, rest) {
|
|
289
|
-
const values = options(rest, [
|
|
290
|
-
"--source",
|
|
291
|
-
"--run-root",
|
|
292
|
-
"--vela",
|
|
293
|
-
"--docker",
|
|
294
|
-
"--codex",
|
|
295
|
-
"--codex-version",
|
|
296
|
-
"--codex-sha256",
|
|
297
|
-
"--model",
|
|
298
|
-
"--codex-home",
|
|
299
|
-
]);
|
|
300
|
-
const mission = parseMission(await jsonFile(file));
|
|
301
|
-
const sourceRepo = path.resolve(required(values, "--source"));
|
|
302
|
-
const runRoot = path.resolve(required(values, "--run-root"));
|
|
303
|
-
const velaBinary = path.resolve(required(values, "--vela"));
|
|
304
|
-
const outputSchema = mission.schema === "canopus.mission.v1"
|
|
305
|
-
? path.join(path.dirname(path.resolve(file)), "contract", "engine-output.v0.json")
|
|
306
|
-
: packagedOutputSchema();
|
|
307
|
-
const vela = new VelaClient({
|
|
308
|
-
binary: velaBinary,
|
|
309
|
-
expectedVersion: mission.vela_version,
|
|
310
|
-
expectedSha256: mission.vela_sha256,
|
|
311
|
-
home: path.join(runRoot, "vela-home"),
|
|
312
|
-
});
|
|
313
|
-
const engine = mission.schema === "canopus.mission.v1"
|
|
314
|
-
? new CodexToolsNativeEngine({
|
|
315
|
-
binary: path.resolve(required(values, "--codex")),
|
|
316
|
-
authHome: authHome(values),
|
|
317
|
-
outputSchema,
|
|
318
|
-
permissionProfile: path.join(path.dirname(path.resolve(file)), mission.worker.permission_profile_path),
|
|
319
|
-
})
|
|
320
|
-
: new CodexExecEngine({
|
|
321
|
-
binary: path.resolve(required(values, "--codex")),
|
|
322
|
-
expectedSha256: required(values, "--codex-sha256"),
|
|
323
|
-
expectedVersion: required(values, "--codex-version"),
|
|
324
|
-
model: required(values, "--model"),
|
|
325
|
-
authHome: authHome(values),
|
|
326
|
-
outputSchema,
|
|
327
|
-
});
|
|
328
|
-
const result = await runCanopus({
|
|
329
|
-
mission,
|
|
330
|
-
sourceRepo,
|
|
331
|
-
runRoot,
|
|
332
|
-
vela,
|
|
333
|
-
engine,
|
|
334
|
-
bundleRoot: path.dirname(path.resolve(file)),
|
|
335
|
-
dockerBinary: values.get("--docker") ?? "docker",
|
|
336
|
-
});
|
|
337
|
-
process.stdout.write(`${JSON.stringify({
|
|
338
|
-
ok: true,
|
|
339
|
-
command: "run",
|
|
340
|
-
run_id: result.record.run_id,
|
|
341
|
-
candidate_digest: result.record.candidate.digest,
|
|
342
|
-
receipt_root: result.record.landing.receipt_root,
|
|
343
|
-
route: result.record.landing.route,
|
|
344
|
-
accepted_event_delta: result.record.landing.accepted_event_delta,
|
|
345
|
-
clean_clone_reproduced: result.record.reproduction.matched,
|
|
346
|
-
run_file: path.join(result.paths.root, "run.json"),
|
|
347
|
-
})}\n`);
|
|
348
|
-
}
|
|
349
266
|
async function doctorCommand(args) {
|
|
350
267
|
const parsed = productOptions(args, ["--profile"], []);
|
|
351
268
|
if (parsed.positional.length > 1)
|
|
@@ -358,7 +275,7 @@ async function doctorCommand(args) {
|
|
|
358
275
|
process.stdout.write(`${JSON.stringify(result.public)}\n`);
|
|
359
276
|
}
|
|
360
277
|
async function productRunCommand(args) {
|
|
361
|
-
const parsed = productOptions(args, ["--target", "--profile", "--output", "--codex-home"], ["--first"
|
|
278
|
+
const parsed = productOptions(args, ["--target", "--profile", "--output", "--codex-home"], ["--first"]);
|
|
362
279
|
if (parsed.positional.length > 1)
|
|
363
280
|
throw new Error("run accepts at most one frontier");
|
|
364
281
|
if (parsed.flags.has("--first") && parsed.values.has("--target")) {
|
|
@@ -375,25 +292,20 @@ async function productRunCommand(args) {
|
|
|
375
292
|
...(requested === undefined ? {} : { requestedTarget: requested }),
|
|
376
293
|
...(outputRoot === undefined ? {} : { outputRoot: path.resolve(outputRoot) }),
|
|
377
294
|
...(codexHome === undefined ? {} : { codexHome: path.resolve(codexHome) }),
|
|
378
|
-
noLand: parsed.flags.has("--no-land"),
|
|
379
295
|
});
|
|
380
|
-
const landing = result.run.record.landing;
|
|
381
296
|
process.stdout.write(`${JSON.stringify({
|
|
382
297
|
ok: true,
|
|
383
298
|
command: "run",
|
|
384
|
-
|
|
299
|
+
effect: "none",
|
|
385
300
|
run_id: result.run.record.run_id,
|
|
386
301
|
target: result.run.record.mission.target,
|
|
387
302
|
candidate_digest: result.run.record.candidate.digest,
|
|
388
303
|
verifier_status: result.run.record.verifier.status,
|
|
389
304
|
observed_tokens: result.run.record.budget.observed_tokens,
|
|
390
|
-
|
|
391
|
-
proposal_id: landing?.proposal_id ?? null,
|
|
392
|
-
route: landing?.route ?? null,
|
|
393
|
-
accepted_event_delta: landing?.accepted_event_delta ?? null,
|
|
305
|
+
submission: null,
|
|
394
306
|
clean_clone_reproduced: result.run.record.reproduction.matched,
|
|
395
307
|
evidence_root: result.evidence_root,
|
|
396
|
-
|
|
308
|
+
source_state: result.source_state,
|
|
397
309
|
run_file: path.join(result.run.paths.root, "run.json"),
|
|
398
310
|
})}\n`);
|
|
399
311
|
}
|
|
@@ -430,9 +342,9 @@ async function latestInspectionFile() {
|
|
|
430
342
|
ranked.sort((left, right) => right.modified - left.modified || left.file.localeCompare(right.file));
|
|
431
343
|
return ranked[0]?.file ?? (() => { throw new Error("no inspectable Canopus product run was found"); })();
|
|
432
344
|
}
|
|
433
|
-
async function
|
|
345
|
+
async function showCommand(value, rest) {
|
|
434
346
|
if (rest.length !== 0)
|
|
435
|
-
throw new Error("
|
|
347
|
+
throw new Error("show accepts at most one run file");
|
|
436
348
|
const file = value === undefined || value === "latest"
|
|
437
349
|
? await latestInspectionFile()
|
|
438
350
|
: path.resolve(value);
|
|
@@ -440,95 +352,52 @@ async function inspectCommand(value, rest) {
|
|
|
440
352
|
const schema = typeof raw === "object" && raw !== null && !Array.isArray(raw)
|
|
441
353
|
? raw.schema
|
|
442
354
|
: undefined;
|
|
443
|
-
const projection = schema === "canopus.
|
|
444
|
-
?
|
|
445
|
-
: schema === "canopus.failure.v0"
|
|
355
|
+
const projection = schema === "canopus.run.v2"
|
|
356
|
+
? projectCurrentRun(parseRetainedRunRecord(raw).record)
|
|
357
|
+
: schema === "canopus.failure.v0" || schema === "canopus.failure.v1"
|
|
446
358
|
? projectFailure(parseFailureRecord(raw))
|
|
447
|
-
:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
process.stdout.write(`${JSON.stringify({ ok: true, command: "inspect", run_file: file, projection, withdrawal })}\n`);
|
|
359
|
+
: (() => {
|
|
360
|
+
throw new Error("current Canopus accepts only canopus.run.v2 and retained failure records; use the exact historical release for older Run schemas");
|
|
361
|
+
})();
|
|
362
|
+
process.stdout.write(`${JSON.stringify({ ok: true, command: "show", run_file: file, projection })}\n`);
|
|
452
363
|
}
|
|
453
364
|
async function replayCommand(file, rest) {
|
|
454
365
|
if (file === undefined || rest.length !== 0)
|
|
455
366
|
throw new Error("replay requires exactly one run file");
|
|
456
367
|
process.stdout.write(`${JSON.stringify(await replayProduct(path.resolve(file)))}\n`);
|
|
457
368
|
}
|
|
458
|
-
async function
|
|
459
|
-
if (file === undefined)
|
|
460
|
-
throw new Error("public-run requires one completed run file");
|
|
461
|
-
const values = options(rest, ["--mission", "--repository", "--output"]);
|
|
462
|
-
const record = parseRunRecord(await jsonFile(file));
|
|
463
|
-
const mission = parseMission(await jsonFile(required(values, "--mission")));
|
|
464
|
-
const projection = projectPublicRun({
|
|
465
|
-
record,
|
|
466
|
-
mission,
|
|
467
|
-
repository: required(values, "--repository"),
|
|
468
|
-
});
|
|
469
|
-
const output = path.resolve(required(values, "--output"));
|
|
470
|
-
await writeFile(output, canonicalJson(projection), { flag: "wx", mode: 0o644 });
|
|
471
|
-
process.stdout.write(`${JSON.stringify({
|
|
472
|
-
ok: true,
|
|
473
|
-
command: "public-run",
|
|
474
|
-
run_id: projection.run_id,
|
|
475
|
-
output,
|
|
476
|
-
projection_root: contentDigest(projection),
|
|
477
|
-
})}\n`);
|
|
478
|
-
}
|
|
479
|
-
async function publishRunCommand(file, rest) {
|
|
369
|
+
async function exportCommand(file, rest) {
|
|
480
370
|
if (file === undefined)
|
|
481
|
-
throw new Error("
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
writeFile(path.join(temporary, "web-import.json"), canonicalJson(bundle.webImport), { flag: "wx", mode: 0o644 }),
|
|
499
|
-
writeFile(path.join(temporary, "root-manifest.json"), canonicalJson(bundle.manifest), { flag: "wx", mode: 0o644 }),
|
|
500
|
-
]);
|
|
501
|
-
await rename(temporary, output);
|
|
502
|
-
}
|
|
503
|
-
catch (error) {
|
|
504
|
-
await rm(temporary, { recursive: true, force: true });
|
|
505
|
-
throw error;
|
|
506
|
-
}
|
|
507
|
-
process.stdout.write(`${JSON.stringify({
|
|
508
|
-
ok: true,
|
|
509
|
-
command: "publish-run",
|
|
510
|
-
run_id: bundle.projection.run_id,
|
|
511
|
-
output,
|
|
512
|
-
projection_root: contentDigest(bundle.projection),
|
|
513
|
-
bundle_root: contentDigest(bundle.manifest),
|
|
514
|
-
authority_effect: "none",
|
|
515
|
-
})}\n`);
|
|
371
|
+
throw new Error("export requires a Run file or latest");
|
|
372
|
+
const parsed = productOptions(rest, ["--output", "--as", "--claim", "--scope-limit"], []);
|
|
373
|
+
if (parsed.positional.length !== 0)
|
|
374
|
+
throw new Error("export accepts one Run file");
|
|
375
|
+
const runFile = file === "latest" ? await latestRunFile() : path.resolve(file);
|
|
376
|
+
const output = parsed.values.get("--output") ??
|
|
377
|
+
path.join(path.dirname(path.dirname(runFile)), `submission-${Date.now()}`);
|
|
378
|
+
const actor = parsed.values.get("--as");
|
|
379
|
+
const correctedClaim = parsed.values.get("--claim");
|
|
380
|
+
const scopeLimit = parsed.values.get("--scope-limit");
|
|
381
|
+
process.stdout.write(`${JSON.stringify(await exportSubmission({
|
|
382
|
+
runFile,
|
|
383
|
+
outputRoot: path.resolve(output),
|
|
384
|
+
...(actor === undefined ? {} : { actor }),
|
|
385
|
+
...(correctedClaim === undefined ? {} : { correctedClaim }),
|
|
386
|
+
...(scopeLimit === undefined ? {} : { scopeLimit }),
|
|
387
|
+
}))}\n`);
|
|
516
388
|
}
|
|
517
|
-
async function
|
|
518
|
-
|
|
389
|
+
async function submitCommand(bundle, rest) {
|
|
390
|
+
if (bundle === undefined)
|
|
391
|
+
throw new Error("submit requires a Submission bundle");
|
|
392
|
+
const parsed = productOptions(rest, ["--vela"], []);
|
|
519
393
|
if (parsed.positional.length > 1)
|
|
520
|
-
throw new Error("
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const runValue = parsed.values.get("--run") ?? "latest";
|
|
525
|
-
const runFile = runValue === "latest" ? await latestRunFile() : path.resolve(runValue);
|
|
526
|
-
const result = await withdrawProduct({
|
|
394
|
+
throw new Error("submit accepts at most one frontier");
|
|
395
|
+
const velaBinary = parsed.values.get("--vela");
|
|
396
|
+
process.stdout.write(`${JSON.stringify(await submitBundle({
|
|
397
|
+
bundle: path.resolve(bundle),
|
|
527
398
|
frontier: path.resolve(parsed.positional[0] ?? "."),
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
});
|
|
531
|
-
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
399
|
+
...(velaBinary === undefined ? {} : { velaBinary }),
|
|
400
|
+
}))}\n`);
|
|
532
401
|
}
|
|
533
402
|
async function main(argv) {
|
|
534
403
|
const [command, file, ...rest] = argv;
|
|
@@ -552,13 +421,12 @@ async function main(argv) {
|
|
|
552
421
|
}
|
|
553
422
|
if (isHelp(file)) {
|
|
554
423
|
process.stdout.write(`${command === "run" ? runUsage()
|
|
555
|
-
: command === "
|
|
424
|
+
: command === "show" ? showUsage()
|
|
556
425
|
: command === "doctor" ? doctorUsage()
|
|
557
426
|
: command === "replay" ? replayUsage()
|
|
558
|
-
: command === "
|
|
559
|
-
: command === "
|
|
560
|
-
:
|
|
561
|
-
: usage()}\n`);
|
|
427
|
+
: command === "export" ? exportUsage()
|
|
428
|
+
: command === "submit" ? submitUsage()
|
|
429
|
+
: usage()}\n`);
|
|
562
430
|
return;
|
|
563
431
|
}
|
|
564
432
|
if (command === "doctor") {
|
|
@@ -569,35 +437,26 @@ async function main(argv) {
|
|
|
569
437
|
await replayCommand(file, rest);
|
|
570
438
|
return;
|
|
571
439
|
}
|
|
572
|
-
if (command === "public-run") {
|
|
573
|
-
await publicRunCommand(file, rest);
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
if (command === "publish-run") {
|
|
577
|
-
await publishRunCommand(file, rest);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
if (command === "withdraw") {
|
|
581
|
-
await withdrawCommand(argv.slice(1));
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
440
|
if (command === "validate") {
|
|
585
441
|
if (file === undefined)
|
|
586
442
|
throw new Error("validate requires a mission file");
|
|
587
443
|
await missionCommand(["validate", file, ...rest]);
|
|
588
444
|
return;
|
|
589
445
|
}
|
|
590
|
-
if (command === "
|
|
591
|
-
await
|
|
446
|
+
if (command === "show") {
|
|
447
|
+
await showCommand(file, rest);
|
|
592
448
|
return;
|
|
593
449
|
}
|
|
594
450
|
if (command === "run") {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
451
|
+
await productRunCommand(argv.slice(1));
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (command === "export") {
|
|
455
|
+
await exportCommand(file, rest);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (command === "submit") {
|
|
459
|
+
await submitCommand(file, rest);
|
|
601
460
|
return;
|
|
602
461
|
}
|
|
603
462
|
throw new Error(`unknown command ${command}`);
|
|
@@ -13,8 +13,7 @@ export type Replayability = (typeof REPLAYABILITY)[number];
|
|
|
13
13
|
export interface MissionRoots {
|
|
14
14
|
git_commit: string;
|
|
15
15
|
git_tree: string;
|
|
16
|
-
|
|
17
|
-
vela_snapshot: string;
|
|
16
|
+
vela_repository: string;
|
|
18
17
|
}
|
|
19
18
|
export interface MissionBudgets {
|
|
20
19
|
max_research_wall_time_ms: number;
|
|
@@ -61,16 +60,6 @@ export interface ProducerProfileSpec {
|
|
|
61
60
|
name: string;
|
|
62
61
|
root: string;
|
|
63
62
|
}
|
|
64
|
-
export interface StrictRuleCount {
|
|
65
|
-
rule: string;
|
|
66
|
-
count: number;
|
|
67
|
-
}
|
|
68
|
-
export interface StrictBaseline {
|
|
69
|
-
status: "pass" | "fail";
|
|
70
|
-
blocker_count: number;
|
|
71
|
-
blockers_root: string;
|
|
72
|
-
rule_counts: StrictRuleCount[];
|
|
73
|
-
}
|
|
74
63
|
export interface LandingSpec {
|
|
75
64
|
expected_routes: LandRoute[];
|
|
76
65
|
max_accepted_delta: number;
|
|
@@ -127,7 +116,6 @@ export interface MissionV1 extends MissionBase {
|
|
|
127
116
|
schema: typeof MISSION_V1_SCHEMA;
|
|
128
117
|
target_packet: TargetPacketSpec;
|
|
129
118
|
profile?: ProducerProfileSpec;
|
|
130
|
-
strict_baseline: StrictBaseline;
|
|
131
119
|
worker: WorkerSpec;
|
|
132
120
|
verifier: ContainerVerifierSpec;
|
|
133
121
|
execution_binding?: ExecutionBindingV1;
|
|
@@ -24,12 +24,11 @@ export const REPLAYABILITY = [
|
|
|
24
24
|
];
|
|
25
25
|
function parseRoots(value) {
|
|
26
26
|
const object = objectAt(value, "mission.roots");
|
|
27
|
-
exactKeys(object, ["git_commit", "git_tree", "
|
|
27
|
+
exactKeys(object, ["git_commit", "git_tree", "vela_repository"], [], "mission.roots");
|
|
28
28
|
return {
|
|
29
29
|
git_commit: gitObjectAt(object.git_commit, "mission.roots.git_commit"),
|
|
30
30
|
git_tree: gitObjectAt(object.git_tree, "mission.roots.git_tree"),
|
|
31
|
-
|
|
32
|
-
vela_snapshot: sha256At(object.vela_snapshot, "mission.roots.vela_snapshot"),
|
|
31
|
+
vela_repository: sha256At(object.vela_repository, "mission.roots.vela_repository"),
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
34
|
function frontierPathAt(value) {
|
|
@@ -118,41 +117,6 @@ function parseTargetPacket(value) {
|
|
|
118
117
|
sha256: sha256At(object.sha256, "mission.target_packet.sha256"),
|
|
119
118
|
};
|
|
120
119
|
}
|
|
121
|
-
function parseStrictBaseline(value) {
|
|
122
|
-
const object = objectAt(value, "mission.strict_baseline");
|
|
123
|
-
exactKeys(object, ["status", "blocker_count", "blockers_root", "rule_counts"], [], "mission.strict_baseline");
|
|
124
|
-
const rule_counts = arrayAt(object.rule_counts, "mission.strict_baseline.rule_counts", { min: 0, max: 64 }, (item, at) => {
|
|
125
|
-
const entry = objectAt(item, at);
|
|
126
|
-
exactKeys(entry, ["rule", "count"], [], at);
|
|
127
|
-
return {
|
|
128
|
-
rule: stringAt(entry.rule, `${at}.rule`, {
|
|
129
|
-
min: 1,
|
|
130
|
-
max: 128,
|
|
131
|
-
pattern: /^[a-z][a-z0-9_]*$/u,
|
|
132
|
-
}),
|
|
133
|
-
count: integerAt(entry.count, `${at}.count`, 1, 1_000_000),
|
|
134
|
-
};
|
|
135
|
-
});
|
|
136
|
-
for (let index = 1; index < rule_counts.length; index += 1) {
|
|
137
|
-
if ((rule_counts[index - 1]?.rule ?? "") >= (rule_counts[index]?.rule ?? "")) {
|
|
138
|
-
throw new ContractError("mission.strict_baseline.rule_counts must be sorted and unique");
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const blocker_count = integerAt(object.blocker_count, "mission.strict_baseline.blocker_count", 0, 1_000_000);
|
|
142
|
-
if (rule_counts.reduce((sum, entry) => sum + entry.count, 0) !== blocker_count) {
|
|
143
|
-
throw new ContractError("mission.strict_baseline.rule_counts must sum to blocker_count");
|
|
144
|
-
}
|
|
145
|
-
const status = enumAt(object.status, "mission.strict_baseline.status", ["pass", "fail"]);
|
|
146
|
-
if ((status === "pass") !== (blocker_count === 0)) {
|
|
147
|
-
throw new ContractError("mission.strict_baseline status must agree with blocker_count");
|
|
148
|
-
}
|
|
149
|
-
return {
|
|
150
|
-
status,
|
|
151
|
-
blocker_count,
|
|
152
|
-
blockers_root: sha256At(object.blockers_root, "mission.strict_baseline.blockers_root"),
|
|
153
|
-
rule_counts,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
120
|
function parseLanding(value) {
|
|
157
121
|
const object = objectAt(value, "mission.landing");
|
|
158
122
|
exactKeys(object, ["expected_routes", "max_accepted_delta"], [], "mission.landing");
|
|
@@ -275,14 +239,13 @@ export function parseMission(value) {
|
|
|
275
239
|
"repair_reason",
|
|
276
240
|
"target_packet",
|
|
277
241
|
"profile",
|
|
278
|
-
"strict_baseline",
|
|
279
242
|
"worker",
|
|
280
243
|
"execution_binding",
|
|
281
244
|
"result_contract",
|
|
282
245
|
]
|
|
283
246
|
: ["parent_candidate", "repair_reason"], "mission");
|
|
284
247
|
if (isV1) {
|
|
285
|
-
for (const required of ["target_packet", "
|
|
248
|
+
for (const required of ["target_packet", "worker"]) {
|
|
286
249
|
if (object[required] === undefined) {
|
|
287
250
|
throw new ContractError(`mission.${required} is required for mission v1`);
|
|
288
251
|
}
|
|
@@ -313,7 +276,7 @@ export function parseMission(value) {
|
|
|
313
276
|
vela_version: stringAt(object.vela_version, "mission.vela_version", {
|
|
314
277
|
min: 5,
|
|
315
278
|
max: 32,
|
|
316
|
-
pattern: /^0\.[0-9]+\.[0-9]
|
|
279
|
+
pattern: /^0\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u,
|
|
317
280
|
}),
|
|
318
281
|
vela_sha256: sha256At(object.vela_sha256, "mission.vela_sha256"),
|
|
319
282
|
frontier: frontierPathAt(object.frontier),
|
|
@@ -376,7 +339,6 @@ export function parseMission(value) {
|
|
|
376
339
|
schema: MISSION_V1_SCHEMA,
|
|
377
340
|
target_packet: targetPacket,
|
|
378
341
|
...(profile === undefined ? {} : { profile }),
|
|
379
|
-
strict_baseline: parseStrictBaseline(object.strict_baseline),
|
|
380
342
|
worker: parseWorker(object.worker),
|
|
381
343
|
verifier: verifier,
|
|
382
344
|
...(executionBinding === undefined ? {} : { execution_binding: executionBinding }),
|
|
@@ -1,25 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
constructor(message: string);
|
|
3
|
-
}
|
|
4
|
-
export type JsonObject = Record<string, unknown>;
|
|
5
|
-
export declare function objectAt(value: unknown, at: string): JsonObject;
|
|
6
|
-
export declare function exactKeys(value: JsonObject, required: readonly string[], optional: readonly string[], at: string): void;
|
|
7
|
-
export declare function stringAt(value: unknown, at: string, options: {
|
|
8
|
-
min?: number;
|
|
9
|
-
max: number;
|
|
10
|
-
pattern?: RegExp;
|
|
11
|
-
}): string;
|
|
12
|
-
export declare function integerAt(value: unknown, at: string, min: number, max: number): number;
|
|
13
|
-
export declare function enumAt<const T extends string>(value: unknown, at: string, allowed: readonly T[]): T;
|
|
14
|
-
export declare function arrayAt<T>(value: unknown, at: string, options: {
|
|
15
|
-
min?: number;
|
|
16
|
-
max: number;
|
|
17
|
-
unique?: boolean;
|
|
18
|
-
}, parse: (item: unknown, at: string) => T): T[];
|
|
19
|
-
export declare const GIT_OBJECT_RE: RegExp;
|
|
20
|
-
export declare const SHA256_RE: RegExp;
|
|
21
|
-
export declare const MISSION_ID_RE: RegExp;
|
|
22
|
-
export declare const AGENT_RE: RegExp;
|
|
23
|
-
export declare function relativePathAt(value: unknown, at: string): string;
|
|
24
|
-
export declare function sha256At(value: unknown, at: string): string;
|
|
25
|
-
export declare function gitObjectAt(value: unknown, at: string): string;
|
|
1
|
+
export { AGENT_RE, ContractError, GIT_OBJECT_RE, MISSION_ID_RE, SHA256_RE, arrayAt, enumAt, exactKeys, gitObjectAt, integerAt, objectAt, relativePathAt, sha256At, stringAt, type JsonObject, } from "@vela-science/protocol";
|