@vela-science/canopus 0.5.1 → 0.6.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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 - 2026-07-20
4
+
5
+ - Type completed-run evidence by stage as `worker_observations`,
6
+ `verifier_observations`, and `standing_caveats`, while preserving read
7
+ compatibility for immutable `canopus.run.v0` records.
8
+ - Add `canopus publish-run`, which emits a sanitized public projection, root
9
+ manifest, exact pending-proposal commands, and read-only Observatory import
10
+ descriptor without landing, signing, pushing, deploying, or accepting.
11
+ - Compose against Vela 0.912.0 and its proposal-scoped verifier attachment and
12
+ reproduction surfaces.
13
+
14
+ ## 0.5.2 - 2026-07-20
15
+
16
+ - Compose against Vela 0.911.1 so same-actor retries of `vela work` return the
17
+ exact active session without appending a second lease event.
18
+ - Preserve the 0.911.0 cold-use run and registration as immutable diagnostic
19
+ evidence; any focused retry remains separate and never rewrites that record.
20
+
3
21
  ## 0.5.1 - 2026-07-20
4
22
 
5
23
  - Preserve exact pending-result replay roots instead of recomputing a receipt
package/README.md CHANGED
@@ -38,8 +38,8 @@ Mission → GPT-5.6 → artifact → verifier → Receipt → Defer.
38
38
  **90 seconds — inspect the shipped product:**
39
39
 
40
40
  ```sh
41
- bunx @vela-science/canopus@0.5.1 --version
42
- bunx @vela-science/canopus@0.5.1 profile validate sidon-a24-at-least-7194-gpt56-v3
41
+ bunx @vela-science/canopus@0.6.0 --version
42
+ bunx @vela-science/canopus@0.6.0 profile validate sidon-a24-at-least-7194-gpt56-v3
43
43
  ```
44
44
 
45
45
  **Full workflow — reproduce without rebuilding Canopus:**
@@ -56,22 +56,35 @@ vela reproduce .
56
56
  Run the provenance-backed public package with Bun:
57
57
 
58
58
  ```sh
59
- bunx @vela-science/canopus@0.5.1 --version
59
+ bunx @vela-science/canopus@0.6.0 --version
60
60
  ```
61
61
 
62
62
  Inspect a clean frontier, then run its first ranked producer offer:
63
63
 
64
64
  ```sh
65
- bunx @vela-science/canopus@0.5.1 doctor /path/to/frontier
66
- bunx @vela-science/canopus@0.5.1 run /path/to/frontier --first
67
- bunx @vela-science/canopus@0.5.1 inspect latest
68
- bunx @vela-science/canopus@0.5.1 replay /path/to/run.json
65
+ bunx @vela-science/canopus@0.6.0 doctor /path/to/frontier
66
+ bunx @vela-science/canopus@0.6.0 run /path/to/frontier --first
67
+ bunx @vela-science/canopus@0.6.0 inspect latest
68
+ bunx @vela-science/canopus@0.6.0 replay /path/to/run.json
69
69
  ```
70
70
 
71
+ Export a completed Defer run without publishing or mutating anything:
72
+
73
+ ```sh
74
+ canopus publish-run /path/to/run.json --mission /path/to/mission.json \
75
+ --repository https://github.com/vela-science/<frontier> \
76
+ --output ./public-evidence
77
+ ```
78
+
79
+ The new directory contains `public-run.json`, `root-manifest.json`, exact
80
+ pending-state commands, and a read-only Observatory import descriptor. Run v1
81
+ separates worker observations, verifier observations, and caveats that remain
82
+ standing after verification; historical run v0 records remain inspectable.
83
+
71
84
  Use `--no-land` for a diagnostic mission that cannot change the source frontier:
72
85
 
73
86
  ```sh
74
- bunx @vela-science/canopus@0.5.1 run /path/to/frontier --first --no-land
87
+ bunx @vela-science/canopus@0.6.0 run /path/to/frontier --first --no-land
75
88
  ```
76
89
 
77
90
  `doctor` binds the exact Vela, Codex, Git, frontier, packet, profile, and verifier
@@ -112,7 +125,7 @@ commits, run roots, audit evidence, and nonclaims live in
112
125
 
113
126
  ## Development
114
127
 
115
- Requires Bun 1.3.12, Vela 0.911.0, Codex CLI 0.144.6, and Docker. The built
128
+ Requires Bun 1.3.12, Vela 0.912.0, Codex CLI 0.144.6, and Docker. The built
116
129
  package also runs under Node 22 or 24; unsupported odd-numbered Node releases
117
130
  are rejected rather than silently treated as supported.
118
131
 
package/dist/src/cli.js CHANGED
@@ -3,7 +3,7 @@ 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 { readdir, stat, writeFile } from "node:fs/promises";
6
+ import { mkdir, mkdtemp, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
7
7
  import { parseMission } from "./contracts/mission.js";
8
8
  import { CodexExecEngine } from "./engines/codex-exec.js";
9
9
  import { CodexToolsNativeEngine } from "./engines/codex-tools-native.js";
@@ -12,6 +12,7 @@ import { parseDiagnosticRunRecord, projectDiagnosticRun } from "./projection/dia
12
12
  import { parseFailureRecord, projectFailure } from "./projection/failure.js";
13
13
  import { parseRunRecord, projectRun } from "./projection/run.js";
14
14
  import { projectPublicRun } from "./projection/public-run.js";
15
+ import { buildPublicationBundle } from "./projection/publication.js";
15
16
  import { doctorProduct } from "./product/doctor.js";
16
17
  import { replayProduct } from "./product/replay.js";
17
18
  import { runProduct } from "./product/run.js";
@@ -35,6 +36,8 @@ Primary workflow:
35
36
  canopus inspect [run.json | latest]
36
37
  canopus public-run <run.json> --mission <mission.json> \
37
38
  --repository <public-url> --output <file>
39
+ canopus publish-run <run.json> --mission <mission.json> \
40
+ --repository <public-url> --output <new-directory>
38
41
  canopus replay <run.json>
39
42
  canopus withdraw [frontier] [--run <run.json|latest>] --reason <text>
40
43
 
@@ -104,6 +107,15 @@ Generates one canonical, sanitized canopus.public-run.v1 projection from a
104
107
  submission-ready completed run. Raw worker logs, homes, credentials, private
105
108
  paths, and unrestricted transcripts are never copied.`;
106
109
  }
110
+ function publishRunUsage() {
111
+ return `Usage:
112
+ canopus publish-run <run.json> --mission <mission.json> \\
113
+ --repository <public-url> --output <new-directory>
114
+
115
+ Creates a sanitized public projection, root manifest, proposal-scoped pending
116
+ commands, and a read-only Vela Observatory import descriptor. It never lands,
117
+ signs, accepts, pushes, or deploys.`;
118
+ }
107
119
  function withdrawUsage() {
108
120
  return `Usage:
109
121
  canopus withdraw [frontier] [--run <run.json|latest>] --reason <text>
@@ -464,6 +476,44 @@ async function publicRunCommand(file, rest) {
464
476
  projection_root: contentDigest(projection),
465
477
  })}\n`);
466
478
  }
479
+ async function publishRunCommand(file, rest) {
480
+ if (file === undefined)
481
+ throw new Error("publish-run requires one completed run file");
482
+ const values = options(rest, ["--mission", "--repository", "--output"]);
483
+ const record = parseRunRecord(await jsonFile(file));
484
+ const mission = parseMission(await jsonFile(required(values, "--mission")));
485
+ const bundle = buildPublicationBundle({
486
+ record,
487
+ mission,
488
+ repository: required(values, "--repository"),
489
+ });
490
+ const output = path.resolve(required(values, "--output"));
491
+ const parent = path.dirname(output);
492
+ await mkdir(parent, { recursive: true, mode: 0o755 });
493
+ const temporary = await mkdtemp(path.join(parent, `.${path.basename(output)}.tmp-`));
494
+ try {
495
+ await Promise.all([
496
+ writeFile(path.join(temporary, "public-run.json"), canonicalJson(bundle.projection), { flag: "wx", mode: 0o644 }),
497
+ writeFile(path.join(temporary, "pending-commands.json"), canonicalJson(bundle.pendingCommands), { flag: "wx", mode: 0o644 }),
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`);
516
+ }
467
517
  async function withdrawCommand(args) {
468
518
  const parsed = productOptions(args, ["--run", "--reason"], []);
469
519
  if (parsed.positional.length > 1)
@@ -506,8 +556,9 @@ async function main(argv) {
506
556
  : command === "doctor" ? doctorUsage()
507
557
  : command === "replay" ? replayUsage()
508
558
  : command === "public-run" ? publicRunUsage()
509
- : command === "withdraw" ? withdrawUsage()
510
- : usage()}\n`);
559
+ : command === "publish-run" ? publishRunUsage()
560
+ : command === "withdraw" ? withdrawUsage()
561
+ : usage()}\n`);
511
562
  return;
512
563
  }
513
564
  if (command === "doctor") {
@@ -522,6 +573,10 @@ async function main(argv) {
522
573
  await publicRunCommand(file, rest);
523
574
  return;
524
575
  }
576
+ if (command === "publish-run") {
577
+ await publishRunCommand(file, rest);
578
+ return;
579
+ }
525
580
  if (command === "withdraw") {
526
581
  await withdrawCommand(argv.slice(1));
527
582
  return;
@@ -9,6 +9,7 @@ export * from "./activity/store.js";
9
9
  export * from "./candidate/validate.js";
10
10
  export * from "./util/canonical.js";
11
11
  export * from "./projection/public-run.js";
12
+ export * from "./projection/publication.js";
12
13
  export * from "./util/command.js";
13
14
  export * from "./util/files.js";
14
15
  export * from "./roles.js";
package/dist/src/index.js CHANGED
@@ -9,6 +9,7 @@ export * from "./activity/store.js";
9
9
  export * from "./candidate/validate.js";
10
10
  export * from "./util/canonical.js";
11
11
  export * from "./projection/public-run.js";
12
+ export * from "./projection/publication.js";
12
13
  export * from "./util/command.js";
13
14
  export * from "./util/files.js";
14
15
  export * from "./roles.js";
@@ -120,8 +120,8 @@ export async function doctorProduct(options) {
120
120
  runtimeIdentity({ name: "vela", cwd: frontier, home: runtime, runner }),
121
121
  runtimeIdentity({ name: "git", cwd: frontier, home: runtime, runner }),
122
122
  ]);
123
- if (vela.version !== "vela 0.911.0") {
124
- throw new Error(`Canopus ${CANOPUS_VERSION} requires vela 0.911.0, observed ${vela.version}`);
123
+ if (vela.version !== "vela 0.912.0") {
124
+ throw new Error(`Canopus ${CANOPUS_VERSION} requires vela 0.912.0, observed ${vela.version}`);
125
125
  }
126
126
  const [status, offer, gitStatus] = await Promise.all([
127
127
  jsonCommand({ runner, argv: [vela.binary, "status", ".", "--json"], cwd: frontier, home: runtime, label: "vela status" }),
@@ -0,0 +1,36 @@
1
+ import type { Mission } from "../contracts/mission.js";
2
+ import type { RunRecord } from "./run.js";
3
+ import { projectPublicRun } from "./public-run.js";
4
+ export interface PublicationBundle {
5
+ projection: ReturnType<typeof projectPublicRun>;
6
+ pendingCommands: {
7
+ schema: "canopus.pending-commands.v1";
8
+ authority: "none";
9
+ proposal_id: string;
10
+ commands: Array<{
11
+ purpose: string;
12
+ authority: string;
13
+ command: string;
14
+ }>;
15
+ };
16
+ webImport: {
17
+ schema: "vela-web.canopus-import.v1";
18
+ authority: "read_only";
19
+ run_id: string;
20
+ projection_path: "public-run.json";
21
+ projection_root: string;
22
+ route: "defer";
23
+ accepted_state_delta: 0;
24
+ };
25
+ manifest: {
26
+ schema: "canopus.publication-manifest.v1";
27
+ authority: "none";
28
+ run_id: string;
29
+ files: Record<string, string>;
30
+ };
31
+ }
32
+ export declare function buildPublicationBundle(options: {
33
+ record: RunRecord;
34
+ mission: Mission;
35
+ repository: string;
36
+ }): PublicationBundle;
@@ -0,0 +1,47 @@
1
+ import { contentDigest } from "../util/canonical.js";
2
+ import { projectPublicRun } from "./public-run.js";
3
+ export function buildPublicationBundle(options) {
4
+ const projection = projectPublicRun(options);
5
+ const pendingCommands = {
6
+ schema: "canopus.pending-commands.v1",
7
+ authority: "none",
8
+ proposal_id: projection.policy.proposal_id,
9
+ commands: [
10
+ {
11
+ purpose: "reproduce_pending_artifact",
12
+ authority: "read_only",
13
+ command: `vela reproduce . --proposal ${projection.policy.proposal_id} --json`,
14
+ },
15
+ {
16
+ purpose: "inspect_review_material",
17
+ authority: "read_only",
18
+ command: `vela review show . ${projection.policy.proposal_id} --json`,
19
+ },
20
+ {
21
+ purpose: "retain_independent_verifier_evidence",
22
+ authority: "evidence_only",
23
+ command: `vela verify attach . <attachment.json> --proposal ${projection.policy.proposal_id} --as verifier:<actor> --json`,
24
+ },
25
+ ],
26
+ };
27
+ const webImport = {
28
+ schema: "vela-web.canopus-import.v1",
29
+ authority: "read_only",
30
+ run_id: projection.run_id,
31
+ projection_path: "public-run.json",
32
+ projection_root: contentDigest(projection),
33
+ route: "defer",
34
+ accepted_state_delta: 0,
35
+ };
36
+ const manifest = {
37
+ schema: "canopus.publication-manifest.v1",
38
+ authority: "none",
39
+ run_id: projection.run_id,
40
+ files: {
41
+ "pending-commands.json": contentDigest(pendingCommands),
42
+ "public-run.json": contentDigest(projection),
43
+ "web-import.json": contentDigest(webImport),
44
+ },
45
+ };
46
+ return { projection, pendingCommands, webImport, manifest };
47
+ }
@@ -1,8 +1,9 @@
1
1
  import type { MissionRoots } from "../contracts/mission.js";
2
- export declare const RUN_RECORD_SCHEMA: "canopus.run.v0";
2
+ export declare const RUN_RECORD_SCHEMA: "canopus.run.v1";
3
+ export declare const LEGACY_RUN_RECORD_SCHEMA: "canopus.run.v0";
3
4
  export declare const RUN_PROJECTION_SCHEMA: "canopus.run-projection.v0";
4
5
  export interface RunRecord {
5
- schema: typeof RUN_RECORD_SCHEMA;
6
+ schema: typeof RUN_RECORD_SCHEMA | typeof LEGACY_RUN_RECORD_SCHEMA;
6
7
  run_id: string;
7
8
  status: "completed";
8
9
  authority: "non_authoritative";
@@ -25,6 +26,11 @@ export interface RunRecord {
25
26
  }>;
26
27
  caveats: string[];
27
28
  };
29
+ observations?: {
30
+ worker_observations: string[];
31
+ verifier_observations: string[];
32
+ standing_caveats: string[];
33
+ };
28
34
  verifier: {
29
35
  status: "passed" | "failed" | "error";
30
36
  sandbox: "macos_sandbox" | "container_network_denied";
@@ -1,5 +1,6 @@
1
1
  import { arrayAt, enumAt, exactKeys, gitObjectAt, integerAt, objectAt, relativePathAt, sha256At, stringAt, } from "../contracts/validation.js";
2
- export const RUN_RECORD_SCHEMA = "canopus.run.v0";
2
+ export const RUN_RECORD_SCHEMA = "canopus.run.v1";
3
+ export const LEGACY_RUN_RECORD_SCHEMA = "canopus.run.v0";
3
4
  export const RUN_PROJECTION_SCHEMA = "canopus.run-projection.v0";
4
5
  function literal(value, expected, at) {
5
6
  if (value !== expected)
@@ -24,10 +25,12 @@ function nullableCount(value, at) {
24
25
  }
25
26
  export function parseRunRecord(value) {
26
27
  const record = objectAt(value, "run");
28
+ const schema = enumAt(record.schema, "run.schema", [RUN_RECORD_SCHEMA, LEGACY_RUN_RECORD_SCHEMA]);
27
29
  exactKeys(record, [
28
30
  "schema", "run_id", "status", "authority", "external_gate_credit", "mission",
29
31
  "candidate", "verifier", "landing", "final_roots", "reproduction", "budget",
30
- ], [], "run");
32
+ ...(schema === RUN_RECORD_SCHEMA ? ["observations"] : []),
33
+ ], schema === LEGACY_RUN_RECORD_SCHEMA ? ["observations"] : [], "run");
31
34
  const mission = objectAt(record.mission, "run.mission");
32
35
  exactKeys(mission, ["id", "target", "digest", "starting_roots"], [], "run.mission");
33
36
  const candidate = objectAt(record.candidate, "run.candidate");
@@ -48,8 +51,18 @@ export function parseRunRecord(value) {
48
51
  "research_elapsed_ms", "research_processes", "research_output_bytes", "prompt_bytes",
49
52
  "artifact_bytes", "attempts", "observed_tokens",
50
53
  ], [], "run.budget");
54
+ const observations = record.observations === undefined ? undefined : (() => {
55
+ const stages = objectAt(record.observations, "run.observations");
56
+ exactKeys(stages, ["worker_observations", "verifier_observations", "standing_caveats"], [], "run.observations");
57
+ const strings = (value, at) => arrayAt(value, at, { max: 16 }, (item, itemAt) => stringAt(item, itemAt, { min: 1, max: 4096 }));
58
+ return {
59
+ worker_observations: strings(stages.worker_observations, "run.observations.worker_observations"),
60
+ verifier_observations: strings(stages.verifier_observations, "run.observations.verifier_observations"),
61
+ standing_caveats: strings(stages.standing_caveats, "run.observations.standing_caveats"),
62
+ };
63
+ })();
51
64
  return {
52
- schema: literal(record.schema, RUN_RECORD_SCHEMA, "run.schema"),
65
+ schema,
53
66
  run_id: stringAt(record.run_id, "run.run_id", { min: 5, max: 128 }),
54
67
  status: literal(record.status, "completed", "run.status"),
55
68
  authority: literal(record.authority, "non_authoritative", "run.authority"),
@@ -76,6 +89,7 @@ export function parseRunRecord(value) {
76
89
  }),
77
90
  caveats: arrayAt(candidate.caveats, "run.candidate.caveats", { max: 10 }, (item, at) => stringAt(item, at, { min: 1, max: 4096 })),
78
91
  },
92
+ ...(observations === undefined ? {} : { observations }),
79
93
  verifier: {
80
94
  status: enumAt(verifier.status, "run.verifier.status", ["passed", "failed", "error"]),
81
95
  sandbox: enumAt(verifier.sandbox, "run.verifier.sandbox", ["macos_sandbox", "container_network_denied"]),
package/dist/src/run.js CHANGED
@@ -576,6 +576,14 @@ export async function runCanopus(options) {
576
576
  artifacts: candidate.artifacts,
577
577
  caveats: candidate.caveats,
578
578
  },
579
+ observations: {
580
+ worker_observations: candidate.observations,
581
+ verifier_observations: [
582
+ `Frozen verifier passed in ${verifier.sandbox}.`,
583
+ `Verifier stdout ${verifier.record.stdout_digest}; stderr ${verifier.record.stderr_digest}.`,
584
+ ],
585
+ standing_caveats: candidate.caveats,
586
+ },
579
587
  verifier: {
580
588
  status: verifier.status,
581
589
  sandbox: verifier.sandbox,
@@ -432,7 +432,7 @@ export class VelaClient {
432
432
  if (replay.source_hash !== undefined) {
433
433
  assertEqual(normalizeSha256(replay.source_hash, "vela check.replay.source_hash"), checkCurrent, "Vela source snapshot");
434
434
  }
435
- const proof = version === "0.900.0" || version === "0.900.1" || version === "0.900.2" || version === "0.901.0" || version === "0.910.0" || version === "0.911.0"
435
+ const proof = version === "0.900.0" || version === "0.900.1" || version === "0.900.2" || version === "0.901.0" || version === "0.910.0" || version === "0.911.0" || version === "0.911.1" || version === "0.912.0"
436
436
  ? {
437
437
  ok: true,
438
438
  command: "status_root_projection",
@@ -9,8 +9,8 @@ A completed run writes these local records beneath its run root:
9
9
  - `worker-final.json`: the exact final worker response;
10
10
  - `worker-stderr.bin`: the bounded raw worker stderr stream;
11
11
  - `engine-result.json`: the parsed worker outcome and usage;
12
- - `run.json`: the compact run record, exact roots, landing result, costs, and
13
- clean-clone reproduction result;
12
+ - `run.json`: the compact run record, exact roots, landing result, costs,
13
+ clean-clone reproduction result, and stage-typed observations;
14
14
  - `evidence-manifest.json`: content roots for the worker, run, candidate,
15
15
  artifacts, verifier result, Receipt when present, and final frontier roots;
16
16
  - `projection.json`: a read-only view for another consumer;
@@ -30,25 +30,36 @@ so in its schema and can be rebuilt with `canopus inspect run.json`. Deleting
30
30
  the run-record files must not change Vela replay, a policy route, or accepted
31
31
  state.
32
32
 
33
- For a public evidence surface, generate the strict sanitized projection only
34
- after the successful run has reached Defer with zero accepted-state delta and
35
- matched clean-clone replay:
33
+ Completed runs now use `canopus.run.v1`. Its `observations` object separates
34
+ three claims that must not be collapsed:
35
+
36
+ - `worker_observations`: what the model reported or attempted;
37
+ - `verifier_observations`: what the frozen mechanical verifier established;
38
+ - `standing_caveats`: limitations that remain true after verification.
39
+
40
+ Immutable `canopus.run.v0` records remain readable and replayable. Canopus does
41
+ not rewrite them to manufacture the new evidence categories.
42
+
43
+ For a public evidence surface, generate the publication bundle only after the
44
+ successful run has reached Defer with zero accepted-state delta and matched
45
+ clean-clone replay:
36
46
 
37
47
  ```bash
38
- canopus public-run /local/run/run.json \
48
+ canopus publish-run /local/run/run.json \
39
49
  --mission /local/run/mission/mission.json \
40
50
  --repository https://github.com/vela-science/formal-conjectures-frontier \
41
- --output canopus.public-run.v1.json
51
+ --output ./public-evidence
42
52
  ```
43
53
 
44
- `canopus.public-run.v1` contains only mission and model identity, a bounded
45
- activity summary, claim and caveats, artifact/verifier/Receipt roots, route,
46
- accepted delta, usage, source/final commits, and clean-clone reproduction
47
- commands. Those public commands target the mission's exact allowed artifact
48
- paths; they do not substitute frontier-wide accepted-state replay for
49
- verification of a pending artifact. It cannot export a failed or admitted run.
50
- Never publish the raw run
51
- directory, isolated homes, authentication, private paths, or unrestricted logs.
54
+ The new directory contains the `canopus.public-run.v1` projection, an exact
55
+ root manifest, read-only Observatory import data, and commands to reproduce or
56
+ inspect the pending proposal and retain additional verifier evidence. The
57
+ commands do not accept, publish, push, deploy, or cross a human authority
58
+ boundary. The public projection contains only mission and model identity, a
59
+ bounded activity summary, claim and caveats, artifact/verifier/Receipt roots,
60
+ route, accepted delta, usage, source/final commits, and reproduction commands.
61
+ It cannot export a failed or admitted run. Never publish the raw run directory,
62
+ isolated homes, authentication, private paths, or unrestricted logs.
52
63
 
53
64
  The run root also contains isolated checkouts and content-addressed artifacts.
54
65
  The landing clone uses a disposable attached branch so Vela can publish exact
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vela-science/canopus",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "A bounded, replaceable research harness over released Vela interfaces",
5
5
  "type": "module",
6
6
  "private": false,
@@ -0,0 +1,220 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://vela.science/schemas/canopus/run.v1.json",
4
+ "title": "Canopus completed run v1",
5
+ "description": "A non-authoritative completed-run record with worker observations, mechanical verifier observations, and caveats that remain standing after verification.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schema",
10
+ "run_id",
11
+ "status",
12
+ "authority",
13
+ "external_gate_credit",
14
+ "mission",
15
+ "candidate",
16
+ "observations",
17
+ "verifier",
18
+ "landing",
19
+ "final_roots",
20
+ "reproduction",
21
+ "budget"
22
+ ],
23
+ "properties": {
24
+ "schema": { "const": "canopus.run.v1" },
25
+ "run_id": { "type": "string", "minLength": 5, "maxLength": 128 },
26
+ "status": { "const": "completed" },
27
+ "authority": { "const": "non_authoritative" },
28
+ "external_gate_credit": { "const": false },
29
+ "mission": {
30
+ "type": "object",
31
+ "additionalProperties": false,
32
+ "required": ["id", "target", "digest", "starting_roots"],
33
+ "properties": {
34
+ "id": { "type": "string", "minLength": 1, "maxLength": 134 },
35
+ "target": { "type": "string", "minLength": 1, "maxLength": 256 },
36
+ "digest": { "$ref": "#/$defs/sha256" },
37
+ "starting_roots": { "$ref": "#/$defs/roots" }
38
+ }
39
+ },
40
+ "candidate": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "required": ["digest", "status", "claim", "artifacts", "caveats"],
44
+ "properties": {
45
+ "digest": { "$ref": "#/$defs/sha256" },
46
+ "status": { "enum": ["success", "null", "failed"] },
47
+ "claim": { "type": "string", "minLength": 1, "maxLength": 8192 },
48
+ "artifacts": {
49
+ "type": "array",
50
+ "maxItems": 10,
51
+ "items": {
52
+ "type": "object",
53
+ "additionalProperties": false,
54
+ "required": ["path", "kind", "digest", "bytes"],
55
+ "properties": {
56
+ "path": { "$ref": "#/$defs/relativePath" },
57
+ "kind": { "type": "string", "minLength": 1, "maxLength": 128 },
58
+ "digest": { "$ref": "#/$defs/sha256" },
59
+ "bytes": { "type": "integer", "minimum": 0, "maximum": 1073741824 }
60
+ }
61
+ }
62
+ },
63
+ "caveats": { "$ref": "#/$defs/caveats" }
64
+ }
65
+ },
66
+ "observations": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["worker_observations", "verifier_observations", "standing_caveats"],
70
+ "properties": {
71
+ "worker_observations": { "$ref": "#/$defs/observations" },
72
+ "verifier_observations": { "$ref": "#/$defs/observations" },
73
+ "standing_caveats": { "$ref": "#/$defs/observations" }
74
+ }
75
+ },
76
+ "verifier": {
77
+ "type": "object",
78
+ "additionalProperties": false,
79
+ "required": ["status", "sandbox", "record"],
80
+ "properties": {
81
+ "status": { "enum": ["passed", "failed", "error"] },
82
+ "sandbox": { "enum": ["macos_sandbox", "container_network_denied"] },
83
+ "record": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": [
87
+ "argv",
88
+ "executable_digest",
89
+ "exit_code",
90
+ "stdout_digest",
91
+ "stderr_digest",
92
+ "duration_ms"
93
+ ],
94
+ "properties": {
95
+ "argv": {
96
+ "type": "array",
97
+ "minItems": 1,
98
+ "maxItems": 64,
99
+ "items": { "type": "string", "maxLength": 4096 }
100
+ },
101
+ "executable_digest": { "$ref": "#/$defs/sha256" },
102
+ "exit_code": { "type": "integer", "minimum": -1, "maximum": 255 },
103
+ "stdout_digest": { "$ref": "#/$defs/sha256" },
104
+ "stderr_digest": { "$ref": "#/$defs/sha256" },
105
+ "duration_ms": { "type": "integer", "minimum": 0, "maximum": 3600000 }
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "landing": {
111
+ "type": "object",
112
+ "additionalProperties": false,
113
+ "required": [
114
+ "operation_id",
115
+ "receipt_root",
116
+ "proposal_id",
117
+ "route",
118
+ "original_route",
119
+ "accepted_event_delta",
120
+ "publication_state"
121
+ ],
122
+ "properties": {
123
+ "operation_id": { "type": "string", "minLength": 1, "maxLength": 256 },
124
+ "receipt_root": { "$ref": "#/$defs/sha256" },
125
+ "proposal_id": { "type": "string", "minLength": 1, "maxLength": 256 },
126
+ "route": { "enum": ["permit", "defer", "exact_retry"] },
127
+ "original_route": {
128
+ "oneOf": [
129
+ { "enum": ["permit", "defer"] },
130
+ { "type": "null" }
131
+ ]
132
+ },
133
+ "accepted_event_delta": {
134
+ "oneOf": [
135
+ { "type": "integer", "minimum": 0 },
136
+ { "type": "null" }
137
+ ]
138
+ },
139
+ "publication_state": { "type": "string", "minLength": 1, "maxLength": 4096 }
140
+ }
141
+ },
142
+ "final_roots": { "$ref": "#/$defs/roots" },
143
+ "reproduction": {
144
+ "type": "object",
145
+ "additionalProperties": false,
146
+ "required": ["matched", "roots", "verifier_status", "stdout_digest", "stderr_digest"],
147
+ "properties": {
148
+ "matched": { "const": true },
149
+ "roots": { "$ref": "#/$defs/roots" },
150
+ "verifier_status": { "enum": ["passed", "failed", "error"] },
151
+ "stdout_digest": { "$ref": "#/$defs/sha256" },
152
+ "stderr_digest": { "$ref": "#/$defs/sha256" }
153
+ }
154
+ },
155
+ "budget": {
156
+ "type": "object",
157
+ "additionalProperties": false,
158
+ "required": [
159
+ "research_elapsed_ms",
160
+ "research_processes",
161
+ "research_output_bytes",
162
+ "prompt_bytes",
163
+ "artifact_bytes",
164
+ "attempts",
165
+ "observed_tokens"
166
+ ],
167
+ "properties": {
168
+ "research_elapsed_ms": { "$ref": "#/$defs/nonnegativeInteger" },
169
+ "research_processes": { "$ref": "#/$defs/nonnegativeInteger" },
170
+ "research_output_bytes": { "$ref": "#/$defs/nonnegativeInteger" },
171
+ "prompt_bytes": { "$ref": "#/$defs/nonnegativeInteger" },
172
+ "artifact_bytes": { "$ref": "#/$defs/nonnegativeInteger" },
173
+ "attempts": { "$ref": "#/$defs/nonnegativeInteger" },
174
+ "observed_tokens": { "$ref": "#/$defs/nonnegativeInteger" }
175
+ }
176
+ }
177
+ },
178
+ "$defs": {
179
+ "sha256": {
180
+ "type": "string",
181
+ "pattern": "^sha256:[0-9a-f]{64}$"
182
+ },
183
+ "gitObject": {
184
+ "type": "string",
185
+ "pattern": "^[0-9a-f]{40,64}$"
186
+ },
187
+ "relativePath": {
188
+ "type": "string",
189
+ "minLength": 1,
190
+ "maxLength": 4096,
191
+ "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
192
+ },
193
+ "roots": {
194
+ "type": "object",
195
+ "additionalProperties": false,
196
+ "required": ["git_commit", "git_tree", "vela_event_log", "vela_snapshot"],
197
+ "properties": {
198
+ "git_commit": { "$ref": "#/$defs/gitObject" },
199
+ "git_tree": { "$ref": "#/$defs/gitObject" },
200
+ "vela_event_log": { "$ref": "#/$defs/sha256" },
201
+ "vela_snapshot": { "$ref": "#/$defs/sha256" }
202
+ }
203
+ },
204
+ "observations": {
205
+ "type": "array",
206
+ "maxItems": 16,
207
+ "items": { "type": "string", "minLength": 1, "maxLength": 4096 }
208
+ },
209
+ "caveats": {
210
+ "type": "array",
211
+ "maxItems": 10,
212
+ "items": { "type": "string", "minLength": 1, "maxLength": 4096 }
213
+ },
214
+ "nonnegativeInteger": {
215
+ "type": "integer",
216
+ "minimum": 0,
217
+ "maximum": 9007199254740991
218
+ }
219
+ }
220
+ }