@vela-science/canopus 0.7.0 → 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.
Files changed (94) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +67 -145
  3. package/capsules/erdos1056-k15/bin/linux-arm64/{10428801-10429000 → 10429201-10429400}/verifier +0 -0
  4. package/capsules/erdos1056-k15/bin/linux-x86_64/{10428801-10429000 → 10429201-10429400}/verifier +0 -0
  5. package/compatibility.json +25 -0
  6. package/dist/src/{receipt/map.d.ts → candidate/finalize.d.ts} +2 -9
  7. package/dist/src/candidate/finalize.js +71 -0
  8. package/dist/src/cli.js +89 -195
  9. package/dist/src/contracts/mission.d.ts +1 -13
  10. package/dist/src/contracts/mission.js +4 -42
  11. package/dist/src/contracts/validation.d.ts +1 -25
  12. package/dist/src/contracts/validation.js +1 -95
  13. package/dist/src/engines/codex-tools-native.js +2 -2
  14. package/dist/src/index.d.ts +5 -34
  15. package/dist/src/index.js +4 -34
  16. package/dist/src/mission/prepare.d.ts +10 -1
  17. package/dist/src/mission/prepare.js +29 -30
  18. package/dist/src/product/coverage.d.ts +17 -0
  19. package/dist/src/product/coverage.js +137 -0
  20. package/dist/src/product/doctor.d.ts +1 -2
  21. package/dist/src/product/doctor.js +29 -8
  22. package/dist/src/product/profile.js +8 -2
  23. package/dist/src/product/replay.js +11 -12
  24. package/dist/src/product/run.d.ts +5 -9
  25. package/dist/src/product/run.js +17 -81
  26. package/dist/src/product/submission.d.ts +40 -0
  27. package/dist/src/product/submission.js +217 -0
  28. package/dist/src/product/submit.d.ts +22 -0
  29. package/dist/src/product/submit.js +264 -0
  30. package/dist/src/product/version.d.ts +2 -2
  31. package/dist/src/product/version.js +27 -4
  32. package/dist/src/projection/current-run.d.ts +12 -0
  33. package/dist/src/projection/current-run.js +94 -0
  34. package/dist/src/projection/failure.d.ts +17 -7
  35. package/dist/src/projection/failure.js +43 -12
  36. package/dist/src/projection/retained-mission.d.ts +6 -0
  37. package/dist/src/projection/retained-mission.js +41 -0
  38. package/dist/src/projection/retained-run.d.ts +7 -0
  39. package/dist/src/projection/retained-run.js +50 -0
  40. package/dist/src/run.d.ts +43 -34
  41. package/dist/src/run.js +34 -397
  42. package/dist/src/util/canonical.d.ts +1 -5
  43. package/dist/src/util/canonical.js +1 -53
  44. package/dist/src/vela/cli.d.ts +7 -42
  45. package/dist/src/vela/cli.js +102 -475
  46. package/dist/src/vela/types.d.ts +3 -19
  47. package/dist/src/verifier/run.js +1 -1
  48. package/dist/src/workspace/prepare.d.ts +1 -1
  49. package/dist/src/workspace/prepare.js +15 -15
  50. package/docs/EVALUATION.md +142 -0
  51. package/docs/MISSIONS.md +42 -80
  52. package/docs/RUN_RECORD.md +77 -99
  53. package/docs/adr/0010-nonmutating-runs-and-explicit-submission.md +191 -0
  54. package/missions/erdos1056-k15-next/mission.draft.json +10 -8
  55. package/package.json +18 -15
  56. package/profiles/{erdos1056-k15-10428801-10429000.json → erdos1056-k15-10429201-10429400.json} +10 -10
  57. package/schemas/failure.v1.json +17 -0
  58. package/schemas/mission.v0.json +3 -4
  59. package/schemas/mission.v1.json +7 -28
  60. package/schemas/{run.v1.json → run.v2.json} +58 -116
  61. package/schemas/submission-bundle.v1.json +63 -0
  62. package/toolchain.lock.json +31 -0
  63. package/capsules/formal-erdos-505-test-dim-one/verifier +0 -105
  64. package/capsules/quantum-10-1-4/verifier.py +0 -152
  65. package/capsules/sidon-a24/bin/linux-arm64/verifier +0 -0
  66. package/capsules/sidon-a24/bin/linux-x86_64/verifier +0 -0
  67. package/dist/src/engines/codex-exec.d.ts +0 -17
  68. package/dist/src/engines/codex-exec.js +0 -136
  69. package/dist/src/engines/codex-tool-free.d.ts +0 -26
  70. package/dist/src/engines/codex-tool-free.js +0 -213
  71. package/dist/src/projection/diagnostic.d.ts +0 -12
  72. package/dist/src/projection/diagnostic.js +0 -61
  73. package/dist/src/projection/public-run.d.ts +0 -59
  74. package/dist/src/projection/public-run.js +0 -106
  75. package/dist/src/projection/publication.d.ts +0 -36
  76. package/dist/src/projection/publication.js +0 -47
  77. package/dist/src/projection/run.d.ts +0 -95
  78. package/dist/src/projection/run.js +0 -173
  79. package/dist/src/receipt/map.js +0 -168
  80. package/dist/src/repair/plan.d.ts +0 -2
  81. package/dist/src/repair/plan.js +0 -22
  82. package/dist/src/roles.d.ts +0 -2
  83. package/dist/src/roles.js +0 -9
  84. package/missions/formal-erdos-505-test-dim-one-gpt56/mission.draft.json +0 -40
  85. package/missions/quantum-10-1-4-retry/mission.draft.json +0 -40
  86. package/missions/sidon-a24-at-least-7194-gpt56/mission.draft.json +0 -42
  87. package/missions/sidon-a24-at-least-7194-gpt56-v2/mission.draft.json +0 -42
  88. package/missions/sidon-a24-at-least-7194-gpt56-v3/mission.draft.json +0 -42
  89. package/profiles/formal-erdos-505-test-dim-one-gpt56.json +0 -35
  90. package/profiles/quantum-10-1-4-stabilizer-retry.json +0 -35
  91. package/profiles/sidon-a24-at-least-7194-gpt56-v2.json +0 -35
  92. package/profiles/sidon-a24-at-least-7194-gpt56-v3.json +0 -35
  93. package/profiles/sidon-a24-at-least-7194-gpt56.json +0 -35
  94. package/schemas/canopus.public-run.v1.json +0 -116
package/dist/src/cli.js CHANGED
@@ -3,45 +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 { mkdir, mkdtemp, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
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 { parseDiagnosticRunRecord, projectDiagnosticRun } from "./projection/diagnostic.js";
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";
15
+ import { exportSubmission } from "./product/submission.js";
16
+ import { submitBundle } from "./product/submit.js";
19
17
  import { CANOPUS_VERSION } from "./product/version.js";
20
18
  import { listProductProfiles, packProductProfile, validateProductProfile, } from "./product/profile-bundle.js";
21
19
  import { loadProductProfile } from "./product/profile.js";
22
- import { runCanopus } from "./run.js";
23
20
  import { readBoundedRegularFile } from "./util/files.js";
24
- import { canonicalJson, contentDigest } from "./util/canonical.js";
25
- import { VelaClient } from "./vela/cli.js";
26
21
  function usage() {
27
22
  return `Canopus — bounded Vela research harness
28
23
 
29
24
  Primary workflow:
30
- canopus --version
31
25
  canopus doctor [frontier] [--profile <name>]
32
- canopus run [frontier] [--first | --target <id>] [--profile <name>] \\
33
- [--output <dir>] [--no-land]
34
- canopus inspect [run.json | latest]
35
- canopus public-run <run.json> --mission <mission.json> \
36
- --repository <public-url> --output <file>
37
- canopus publish-run <run.json> --mission <mission.json> \
38
- --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]
39
28
  canopus replay <run.json>
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>]
40
32
 
41
33
  Mission v1 prepare/validate remains available under advanced help.
42
34
 
43
- Canopus may land a Receipt v1 as an agent after verifier success. It cannot
44
- sign, accept, or make a human scientific decision.`;
35
+ Run and export never mutate Vela. submit explicitly registers an authenticated
36
+ Submission as pending review. Canopus cannot verify, decide, or change Standing.`;
45
37
  }
46
38
  function missionUsage() {
47
39
  return `Usage:
@@ -66,19 +58,19 @@ remain replay-only; new tool-using missions require a validated version 2 profil
66
58
  function runUsage() {
67
59
  return `Usage:
68
60
  canopus run [frontier] [--first | --target <id>] [--profile <name>] \\
69
- [--output <dir>] [--no-land]
61
+ [--output <dir>]
70
62
 
71
63
  Discovers and binds Vela, Codex, Git, Docker, the exact frontier roots, and the
72
- registered verifier profile. --no-land runs the worker and verifier in disposable
73
- clones and leaves the source frontier unchanged.`;
64
+ registered verifier profile. Runs the worker and verifier in disposable clones
65
+ and always leaves the source frontier unchanged.`;
74
66
  }
75
- function inspectUsage() {
67
+ function showUsage() {
76
68
  return `Usage:
77
- canopus inspect [run.json | failure.json | latest]
69
+ canopus show [run.json | failure.json | latest]
78
70
 
79
- Projects the newest completed or safely stopped non-authoritative run record
80
- without mutating Vela. A failed run never implies that landing was unchanged;
81
- inspect reports whether retained landing-recovery evidence is required.`;
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.`;
82
74
  }
83
75
  function doctorUsage() {
84
76
  return `Usage:
@@ -95,23 +87,23 @@ function replayUsage() {
95
87
  Re-runs the frozen verifier over the content-addressed candidate without a
96
88
  model call, Vela mutation, network, or authority action.`;
97
89
  }
98
- function publicRunUsage() {
90
+ function exportUsage() {
99
91
  return `Usage:
100
- canopus public-run <run.json> --mission <mission.json> \\
101
- --repository <public-url> --output <file>
92
+ canopus export <run.json | latest> [--output <new-directory>] [--as <agent:id>] \\
93
+ [--claim <corrected-bounded-claim> --scope-limit <limit>]
102
94
 
103
- Generates one canonical, sanitized canopus.public-run.v1 projection from a
104
- submission-ready completed run. Raw worker logs, homes, credentials, private
105
- paths, and unrestricted transcripts are never copied.`;
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.`;
106
99
  }
107
- function publishRunUsage() {
100
+ function submitUsage() {
108
101
  return `Usage:
109
- canopus publish-run <run.json> --mission <mission.json> \\
110
- --repository <public-url> --output <new-directory>
102
+ canopus submit <submission-bundle> [frontier] [--vela <binary>]
111
103
 
112
- Creates a sanitized public projection, root manifest, proposal-scoped pending
113
- commands, and a read-only Vela Observatory import descriptor. It never lands,
114
- signs, accepts, pushes, or deploys.`;
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.`;
115
107
  }
116
108
  function isHelp(value) {
117
109
  return value === "--help" || value === "-h" || value === "help";
@@ -168,9 +160,6 @@ function required(values, key) {
168
160
  throw new Error(`${key} is required`);
169
161
  return value;
170
162
  }
171
- function authHome(values) {
172
- return path.resolve(values.get("--codex-home") ?? process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex"));
173
- }
174
163
  function packagedOutputSchema() {
175
164
  return fileURLToPath(new URL("../../schemas/engine-output.v0.json", import.meta.url));
176
165
  }
@@ -274,67 +263,6 @@ async function profileCommand(args) {
274
263
  }
275
264
  throw new Error(`unknown profile command ${subcommand}`);
276
265
  }
277
- async function runMission(file, rest) {
278
- const values = options(rest, [
279
- "--source",
280
- "--run-root",
281
- "--vela",
282
- "--docker",
283
- "--codex",
284
- "--codex-version",
285
- "--codex-sha256",
286
- "--model",
287
- "--codex-home",
288
- ]);
289
- const mission = parseMission(await jsonFile(file));
290
- const sourceRepo = path.resolve(required(values, "--source"));
291
- const runRoot = path.resolve(required(values, "--run-root"));
292
- const velaBinary = path.resolve(required(values, "--vela"));
293
- const outputSchema = mission.schema === "canopus.mission.v1"
294
- ? path.join(path.dirname(path.resolve(file)), "contract", "engine-output.v0.json")
295
- : packagedOutputSchema();
296
- const vela = new VelaClient({
297
- binary: velaBinary,
298
- expectedVersion: mission.vela_version,
299
- expectedSha256: mission.vela_sha256,
300
- home: path.join(runRoot, "vela-home"),
301
- });
302
- const engine = mission.schema === "canopus.mission.v1"
303
- ? new CodexToolsNativeEngine({
304
- binary: path.resolve(required(values, "--codex")),
305
- authHome: authHome(values),
306
- outputSchema,
307
- permissionProfile: path.join(path.dirname(path.resolve(file)), mission.worker.permission_profile_path),
308
- })
309
- : new CodexExecEngine({
310
- binary: path.resolve(required(values, "--codex")),
311
- expectedSha256: required(values, "--codex-sha256"),
312
- expectedVersion: required(values, "--codex-version"),
313
- model: required(values, "--model"),
314
- authHome: authHome(values),
315
- outputSchema,
316
- });
317
- const result = await runCanopus({
318
- mission,
319
- sourceRepo,
320
- runRoot,
321
- vela,
322
- engine,
323
- bundleRoot: path.dirname(path.resolve(file)),
324
- dockerBinary: values.get("--docker") ?? "docker",
325
- });
326
- process.stdout.write(`${JSON.stringify({
327
- ok: true,
328
- command: "run",
329
- run_id: result.record.run_id,
330
- candidate_digest: result.record.candidate.digest,
331
- receipt_root: result.record.landing.receipt_root,
332
- route: result.record.landing.route,
333
- accepted_event_delta: result.record.landing.accepted_event_delta,
334
- clean_clone_reproduced: result.record.reproduction.matched,
335
- run_file: path.join(result.paths.root, "run.json"),
336
- })}\n`);
337
- }
338
266
  async function doctorCommand(args) {
339
267
  const parsed = productOptions(args, ["--profile"], []);
340
268
  if (parsed.positional.length > 1)
@@ -347,7 +275,7 @@ async function doctorCommand(args) {
347
275
  process.stdout.write(`${JSON.stringify(result.public)}\n`);
348
276
  }
349
277
  async function productRunCommand(args) {
350
- const parsed = productOptions(args, ["--target", "--profile", "--output", "--codex-home"], ["--first", "--no-land"]);
278
+ const parsed = productOptions(args, ["--target", "--profile", "--output", "--codex-home"], ["--first"]);
351
279
  if (parsed.positional.length > 1)
352
280
  throw new Error("run accepts at most one frontier");
353
281
  if (parsed.flags.has("--first") && parsed.values.has("--target")) {
@@ -364,25 +292,20 @@ async function productRunCommand(args) {
364
292
  ...(requested === undefined ? {} : { requestedTarget: requested }),
365
293
  ...(outputRoot === undefined ? {} : { outputRoot: path.resolve(outputRoot) }),
366
294
  ...(codexHome === undefined ? {} : { codexHome: path.resolve(codexHome) }),
367
- noLand: parsed.flags.has("--no-land"),
368
295
  });
369
- const landing = result.run.record.landing;
370
296
  process.stdout.write(`${JSON.stringify({
371
297
  ok: true,
372
298
  command: "run",
373
- mode: landing === null ? "no_land" : "land",
299
+ effect: "none",
374
300
  run_id: result.run.record.run_id,
375
301
  target: result.run.record.mission.target,
376
302
  candidate_digest: result.run.record.candidate.digest,
377
303
  verifier_status: result.run.record.verifier.status,
378
304
  observed_tokens: result.run.record.budget.observed_tokens,
379
- receipt_root: landing?.receipt_root ?? null,
380
- proposal_id: landing?.proposal_id ?? null,
381
- route: landing?.route ?? null,
382
- accepted_event_delta: landing?.accepted_event_delta ?? null,
305
+ submission: null,
383
306
  clean_clone_reproduced: result.run.record.reproduction.matched,
384
307
  evidence_root: result.evidence_root,
385
- source_publication: result.source_publication,
308
+ source_state: result.source_state,
386
309
  run_file: path.join(result.run.paths.root, "run.json"),
387
310
  })}\n`);
388
311
  }
@@ -419,9 +342,9 @@ async function latestInspectionFile() {
419
342
  ranked.sort((left, right) => right.modified - left.modified || left.file.localeCompare(right.file));
420
343
  return ranked[0]?.file ?? (() => { throw new Error("no inspectable Canopus product run was found"); })();
421
344
  }
422
- async function inspectCommand(value, rest) {
345
+ async function showCommand(value, rest) {
423
346
  if (rest.length !== 0)
424
- throw new Error("inspect accepts at most one run file");
347
+ throw new Error("show accepts at most one run file");
425
348
  const file = value === undefined || value === "latest"
426
349
  ? await latestInspectionFile()
427
350
  : path.resolve(value);
@@ -429,76 +352,52 @@ async function inspectCommand(value, rest) {
429
352
  const schema = typeof raw === "object" && raw !== null && !Array.isArray(raw)
430
353
  ? raw.schema
431
354
  : undefined;
432
- const projection = schema === "canopus.diagnostic-run.v1"
433
- ? projectDiagnosticRun(parseDiagnosticRunRecord(raw))
434
- : 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"
435
358
  ? projectFailure(parseFailureRecord(raw))
436
- : projectRun(parseRunRecord(raw));
437
- process.stdout.write(`${JSON.stringify({ ok: true, command: "inspect", run_file: file, projection })}\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`);
438
363
  }
439
364
  async function replayCommand(file, rest) {
440
365
  if (file === undefined || rest.length !== 0)
441
366
  throw new Error("replay requires exactly one run file");
442
367
  process.stdout.write(`${JSON.stringify(await replayProduct(path.resolve(file)))}\n`);
443
368
  }
444
- async function publicRunCommand(file, rest) {
369
+ async function exportCommand(file, rest) {
445
370
  if (file === undefined)
446
- throw new Error("public-run requires one completed run file");
447
- const values = options(rest, ["--mission", "--repository", "--output"]);
448
- const record = parseRunRecord(await jsonFile(file));
449
- const mission = parseMission(await jsonFile(required(values, "--mission")));
450
- const projection = projectPublicRun({
451
- record,
452
- mission,
453
- repository: required(values, "--repository"),
454
- });
455
- const output = path.resolve(required(values, "--output"));
456
- await writeFile(output, canonicalJson(projection), { flag: "wx", mode: 0o644 });
457
- process.stdout.write(`${JSON.stringify({
458
- ok: true,
459
- command: "public-run",
460
- run_id: projection.run_id,
461
- output,
462
- projection_root: contentDigest(projection),
463
- })}\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`);
464
388
  }
465
- async function publishRunCommand(file, rest) {
466
- if (file === undefined)
467
- throw new Error("publish-run requires one completed run file");
468
- const values = options(rest, ["--mission", "--repository", "--output"]);
469
- const record = parseRunRecord(await jsonFile(file));
470
- const mission = parseMission(await jsonFile(required(values, "--mission")));
471
- const bundle = buildPublicationBundle({
472
- record,
473
- mission,
474
- repository: required(values, "--repository"),
475
- });
476
- const output = path.resolve(required(values, "--output"));
477
- const parent = path.dirname(output);
478
- await mkdir(parent, { recursive: true, mode: 0o755 });
479
- const temporary = await mkdtemp(path.join(parent, `.${path.basename(output)}.tmp-`));
480
- try {
481
- await Promise.all([
482
- writeFile(path.join(temporary, "public-run.json"), canonicalJson(bundle.projection), { flag: "wx", mode: 0o644 }),
483
- writeFile(path.join(temporary, "pending-commands.json"), canonicalJson(bundle.pendingCommands), { flag: "wx", mode: 0o644 }),
484
- writeFile(path.join(temporary, "web-import.json"), canonicalJson(bundle.webImport), { flag: "wx", mode: 0o644 }),
485
- writeFile(path.join(temporary, "root-manifest.json"), canonicalJson(bundle.manifest), { flag: "wx", mode: 0o644 }),
486
- ]);
487
- await rename(temporary, output);
488
- }
489
- catch (error) {
490
- await rm(temporary, { recursive: true, force: true });
491
- throw error;
492
- }
493
- process.stdout.write(`${JSON.stringify({
494
- ok: true,
495
- command: "publish-run",
496
- run_id: bundle.projection.run_id,
497
- output,
498
- projection_root: contentDigest(bundle.projection),
499
- bundle_root: contentDigest(bundle.manifest),
500
- authority_effect: "none",
501
- })}\n`);
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"], []);
393
+ if (parsed.positional.length > 1)
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),
398
+ frontier: path.resolve(parsed.positional[0] ?? "."),
399
+ ...(velaBinary === undefined ? {} : { velaBinary }),
400
+ }))}\n`);
502
401
  }
503
402
  async function main(argv) {
504
403
  const [command, file, ...rest] = argv;
@@ -522,11 +421,11 @@ async function main(argv) {
522
421
  }
523
422
  if (isHelp(file)) {
524
423
  process.stdout.write(`${command === "run" ? runUsage()
525
- : command === "inspect" ? inspectUsage()
424
+ : command === "show" ? showUsage()
526
425
  : command === "doctor" ? doctorUsage()
527
426
  : command === "replay" ? replayUsage()
528
- : command === "public-run" ? publicRunUsage()
529
- : command === "publish-run" ? publishRunUsage()
427
+ : command === "export" ? exportUsage()
428
+ : command === "submit" ? submitUsage()
530
429
  : usage()}\n`);
531
430
  return;
532
431
  }
@@ -538,31 +437,26 @@ async function main(argv) {
538
437
  await replayCommand(file, rest);
539
438
  return;
540
439
  }
541
- if (command === "public-run") {
542
- await publicRunCommand(file, rest);
543
- return;
544
- }
545
- if (command === "publish-run") {
546
- await publishRunCommand(file, rest);
547
- return;
548
- }
549
440
  if (command === "validate") {
550
441
  if (file === undefined)
551
442
  throw new Error("validate requires a mission file");
552
443
  await missionCommand(["validate", file, ...rest]);
553
444
  return;
554
445
  }
555
- if (command === "inspect") {
556
- await inspectCommand(file, rest);
446
+ if (command === "show") {
447
+ await showCommand(file, rest);
557
448
  return;
558
449
  }
559
450
  if (command === "run") {
560
- if (file !== undefined && (file.endsWith(".json") || rest.includes("--source"))) {
561
- await runMission(file, rest);
562
- }
563
- else {
564
- await productRunCommand(argv.slice(1));
565
- }
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);
566
460
  return;
567
461
  }
568
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
- vela_event_log: string;
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", "vela_event_log", "vela_snapshot"], [], "mission.roots");
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
- vela_event_log: sha256At(object.vela_event_log, "mission.roots.vela_event_log"),
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", "strict_baseline", "worker"]) {
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]+$/u,
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 declare class ContractError extends Error {
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";