@eir-labs/coltrane 0.5.1 → 0.7.2

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 (115) hide show
  1. package/README.md +23 -0
  2. package/agents/bill.json +59 -0
  3. package/agents/deploy-agent.json +68 -0
  4. package/agents/deploy-scout.json +40 -0
  5. package/agents/john.json +42 -0
  6. package/agents/miles.json +44 -0
  7. package/charts/software-delivery-v1.json +9 -0
  8. package/charts/software-delivery-v2.json +39 -0
  9. package/dist/src/bifrost_invoker.js +5 -3
  10. package/dist/src/bifrost_invoker.js.map +1 -1
  11. package/dist/src/canonical_form.d.ts +23 -0
  12. package/dist/src/canonical_form.js +53 -0
  13. package/dist/src/canonical_form.js.map +1 -1
  14. package/dist/src/chart.d.ts +254 -0
  15. package/dist/src/chart.js +897 -0
  16. package/dist/src/chart.js.map +1 -0
  17. package/dist/src/claude_invoker.d.ts +20 -3
  18. package/dist/src/claude_invoker.js +30 -5
  19. package/dist/src/claude_invoker.js.map +1 -1
  20. package/dist/src/cli.d.ts +19 -4
  21. package/dist/src/cli.js +132 -9
  22. package/dist/src/cli.js.map +1 -1
  23. package/dist/src/composition.d.ts +24 -0
  24. package/dist/src/composition.js +50 -5
  25. package/dist/src/composition.js.map +1 -1
  26. package/dist/src/conduct_daemon.d.ts +59 -0
  27. package/dist/src/conduct_daemon.js +178 -0
  28. package/dist/src/conduct_daemon.js.map +1 -0
  29. package/dist/src/genome_schema.d.ts +1476 -146
  30. package/dist/src/genome_schema.js +438 -32
  31. package/dist/src/genome_schema.js.map +1 -1
  32. package/dist/src/genome_store.d.ts +79 -0
  33. package/dist/src/genome_store.js +503 -0
  34. package/dist/src/genome_store.js.map +1 -0
  35. package/dist/src/gig_tracker.d.ts +11 -1
  36. package/dist/src/gig_tracker.js +5 -0
  37. package/dist/src/gig_tracker.js.map +1 -1
  38. package/dist/src/hosted_tools.d.ts +23 -0
  39. package/dist/src/hosted_tools.js +170 -0
  40. package/dist/src/hosted_tools.js.map +1 -0
  41. package/dist/src/index.d.ts +4 -0
  42. package/dist/src/index.js +4 -0
  43. package/dist/src/index.js.map +1 -1
  44. package/dist/src/ledger.d.ts +22 -0
  45. package/dist/src/ledger.js +4 -0
  46. package/dist/src/ledger.js.map +1 -1
  47. package/dist/src/loader.d.ts +9 -1
  48. package/dist/src/loader.js +105 -5
  49. package/dist/src/loader.js.map +1 -1
  50. package/dist/src/mcp.js +52 -5
  51. package/dist/src/mcp.js.map +1 -1
  52. package/dist/src/output_mirror.d.ts +70 -0
  53. package/dist/src/output_mirror.js +381 -0
  54. package/dist/src/output_mirror.js.map +1 -0
  55. package/dist/src/outputs.d.ts +77 -1
  56. package/dist/src/outputs.js +179 -37
  57. package/dist/src/outputs.js.map +1 -1
  58. package/dist/src/play_worker.d.ts +24 -0
  59. package/dist/src/play_worker.js +49 -0
  60. package/dist/src/play_worker.js.map +1 -0
  61. package/dist/src/registry.d.ts +2 -0
  62. package/dist/src/registry.js +63 -33
  63. package/dist/src/registry.js.map +1 -1
  64. package/dist/src/reuse.d.ts +56 -0
  65. package/dist/src/reuse.js +0 -0
  66. package/dist/src/reuse.js.map +1 -1
  67. package/dist/src/runtime.d.ts +91 -2
  68. package/dist/src/runtime.js +236 -18
  69. package/dist/src/runtime.js.map +1 -1
  70. package/dist/src/seal_drill.d.ts +32 -0
  71. package/dist/src/seal_drill.js +138 -0
  72. package/dist/src/seal_drill.js.map +1 -0
  73. package/dist/src/server.d.ts +39 -1
  74. package/dist/src/server.js +760 -68
  75. package/dist/src/server.js.map +1 -1
  76. package/dist/src/skill_subprocess.js +12 -4
  77. package/dist/src/skill_subprocess.js.map +1 -1
  78. package/dist/src/supabase_genome.d.ts +28 -0
  79. package/dist/src/supabase_genome.js +49 -0
  80. package/dist/src/supabase_genome.js.map +1 -0
  81. package/dist/src/tool_surface.d.ts +5 -0
  82. package/dist/src/tool_surface.js +15 -0
  83. package/dist/src/tool_surface.js.map +1 -0
  84. package/dist/src/version.d.ts +1 -1
  85. package/dist/src/version.js +1 -1
  86. package/dist/src/worker.d.ts +182 -0
  87. package/dist/src/worker.js +609 -0
  88. package/dist/src/worker.js.map +1 -0
  89. package/domain_types/branch-state.json +21 -0
  90. package/domain_types/change-context.json +39 -0
  91. package/domain_types/change-decision.json +36 -0
  92. package/domain_types/change-plan.json +47 -0
  93. package/domain_types/change-request.json +24 -0
  94. package/domain_types/change-set.json +46 -0
  95. package/domain_types/change-verdict.json +26 -0
  96. package/domain_types/deploy-verdict.json +23 -0
  97. package/domain_types/design-brief.json +37 -0
  98. package/domain_types/design-concept.json +36 -0
  99. package/domain_types/design-definition.json +37 -0
  100. package/domain_types/design-question.json +23 -0
  101. package/domain_types/design-verdict.json +27 -0
  102. package/domain_types/preview-deployment.json +32 -0
  103. package/institutions/quartet.json +344 -0
  104. package/package.json +21 -3
  105. package/skills/vercel-api/fixtures/error.json +10 -0
  106. package/skills/vercel-api/fixtures/ready.json +10 -0
  107. package/skills/vercel-api/fixtures/unsettled.json +10 -0
  108. package/skills/vercel-api/meta.json +10 -0
  109. package/skills/vercel-api/skill.mjs +63 -0
  110. package/standards/preview-deploy-v1.json +89 -0
  111. package/standards/product-design-v1.json +122 -0
  112. package/standards/promote-v1.json +41 -0
  113. package/standards/software-change-v1.json +147 -0
  114. package/venues/ci-deploy-room-v1.json +28 -0
  115. package/venues/empty-room-v1.json +19 -0
@@ -0,0 +1,381 @@
1
+ // Two-tier output persistence + retrieval — the reliable local mirror MCP traverses.
2
+ //
3
+ // The bug this closes: a CLI-dispatched gig sealed outputs to disk, but the payloads were not
4
+ // reliably retrievable through the MCP surface. This module makes every sealed output land in a
5
+ // content-addressed local store under `.coltrane/` (gitignored) that MCP reads seamlessly with
6
+ // NO remote configured, and — only when an append credential is present — ALSO drains the same
7
+ // record to a remote row + artifact store.
8
+ //
9
+ // Two tiers, by design:
10
+ // • TIER 1 — a compact, queryable METADATA row, ALWAYS. id, gig_id, agent, phase, primitive,
11
+ // domain_type, content_sha, a short preview, a storage_ref, cost/tokens, created_at. This
12
+ // alone supports high-level traversal (`output_query`/`output_trace`) without loading a
13
+ // single payload.
14
+ // • TIER 2 — the full PAYLOAD, as a content-addressed artifact, fetched only on the deeper
15
+ // second pass (`readPayload`, or `output_query { include_data:true }`).
16
+ //
17
+ // OSS stays pure: with no drain credential in the environment, ONLY the local tier runs and no
18
+ // new npm dependency is touched (the remote row goes over `fetch`; the optional Postgres path is
19
+ // a guarded dynamic import that is never reached unless a PG connection string is set).
20
+ import * as fs from "node:fs";
21
+ import * as path from "node:path";
22
+ const ARTIFACT_SUBDIR = path.join("outputs", "artifacts");
23
+ const META_SUBDIR = path.join("outputs", "meta");
24
+ // Where the local mirror lives. `COLTRANE_MIRROR_DIR` overrides (tests, sandboxes); otherwise
25
+ // `<genomeRoot>/.coltrane` — beside the ledger, gitignored, so a CLI and an MCP server rooted at
26
+ // the same repo share one store and MCP retrieval traverses exactly what the CLI sealed.
27
+ export function defaultMirrorDir(root) {
28
+ const override = process.env["COLTRANE_MIRROR_DIR"];
29
+ if (override && override.length > 0)
30
+ return override;
31
+ return path.join(root ?? process.cwd(), ".coltrane");
32
+ }
33
+ function ensureDir(dir) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ function appendJsonl(file, row) {
37
+ ensureDir(path.dirname(file));
38
+ fs.appendFileSync(file, JSON.stringify(row) + "\n", "utf8");
39
+ }
40
+ // A short, deterministic summary of the payload for the Tier-1 row. Never throws.
41
+ export function outputPreview(data) {
42
+ try {
43
+ const s = JSON.stringify(data);
44
+ return s.length <= 200 ? s : s.slice(0, 197) + "...";
45
+ }
46
+ catch {
47
+ return "";
48
+ }
49
+ }
50
+ const makePreview = outputPreview;
51
+ /** The repo-relative artifact path for a content_sha — the Tier-1 row's local `storage_ref`. */
52
+ export function mirrorStorageRef(content_sha) {
53
+ return path.join(ARTIFACT_SUBDIR, `${content_sha.replace(/[^0-9a-zA-Z._-]/g, "_")}.json`);
54
+ }
55
+ function metaOf(rec, storage_ref) {
56
+ return {
57
+ id: rec.id,
58
+ gig_id: rec.gig_id,
59
+ agent_slug: rec.agent_slug,
60
+ from_role: rec.from_role,
61
+ phase: rec.phase,
62
+ primitive: rec.primitive,
63
+ core_type: rec.core_type,
64
+ domain_type: rec.domain_type,
65
+ domain_type_version: rec.domain_type_version,
66
+ domain: rec.domain,
67
+ content_sha: rec.content_sha,
68
+ input_refs: rec.input_refs,
69
+ input_shas: rec.input_shas,
70
+ cost_usd: rec.cost_usd,
71
+ tokens_used: rec.tokens_used,
72
+ duration_ms: rec.duration_ms,
73
+ model: rec.model,
74
+ model_tier: rec.model_tier,
75
+ created_at: rec.created_at,
76
+ preview: makePreview(rec.data),
77
+ storage_ref,
78
+ };
79
+ }
80
+ function readJsonlRows(file) {
81
+ if (!fs.existsSync(file))
82
+ return [];
83
+ const rows = [];
84
+ for (const line of fs.readFileSync(file, "utf8").split("\n")) {
85
+ const t = line.trim();
86
+ if (!t)
87
+ continue;
88
+ try {
89
+ rows.push(JSON.parse(t));
90
+ }
91
+ catch {
92
+ // Forgiving read (a torn append should not take the whole traversal offline). The
93
+ // store's own `integrity()` is the surface that REPORTS damage; here we keep serving.
94
+ }
95
+ }
96
+ return rows;
97
+ }
98
+ export function createOutputMirror(mirrorRoot) {
99
+ const artifactsDir = path.join(mirrorRoot, ARTIFACT_SUBDIR);
100
+ const metaDir = path.join(mirrorRoot, META_SUBDIR);
101
+ function artifactPath(content_sha) {
102
+ // Content-addressed: a filename-safe form of the sha. Two byte-identical payloads dedupe.
103
+ const safe = content_sha.replace(/[^0-9a-zA-Z._-]/g, "_");
104
+ return path.join(artifactsDir, `${safe}.json`);
105
+ }
106
+ const storageRef = mirrorStorageRef;
107
+ function writeArtifact(rec) {
108
+ const file = artifactPath(rec.content_sha);
109
+ // Content-addressed → if it already exists, the bytes are identical; skip the rewrite.
110
+ if (fs.existsSync(file))
111
+ return;
112
+ ensureDir(path.dirname(file));
113
+ fs.writeFileSync(file, JSON.stringify({ content_sha: rec.content_sha, id: rec.id, data: rec.data }), "utf8");
114
+ }
115
+ function metaFile(gig_id) {
116
+ return path.join(metaDir, `${gig_id}.jsonl`);
117
+ }
118
+ return {
119
+ root: mirrorRoot,
120
+ persist(rec) {
121
+ const ref = storageRef(rec.content_sha);
122
+ // TIER 2 first, so the Tier-1 row never points at an artifact that is not there yet.
123
+ writeArtifact(rec);
124
+ // TIER 1 — the always-on compact row.
125
+ appendJsonl(metaFile(rec.gig_id), metaOf(rec, ref));
126
+ // REMOTE, credential-gated. Fire-and-forget: a finished gig is not failed because a
127
+ // remote append could not be reached. OSS with no credential never enters this path.
128
+ if (remoteConfigured()) {
129
+ void drainRemote(rec).catch((e) => {
130
+ if (process.env["COLTRANE_DRAIN_DEBUG"]) {
131
+ console.warn(`[output_mirror] remote drain failed: ${e instanceof Error ? e.message : String(e)}`);
132
+ }
133
+ });
134
+ }
135
+ },
136
+ queryMeta(filter) {
137
+ // A FRESH read every call — this is what makes a long-lived MCP server see a gig sealed by
138
+ // a separate CLI process. No `fullyHydrated`-style latch lives here on purpose.
139
+ if (!fs.existsSync(metaDir))
140
+ return [];
141
+ const gigId = filter?.gig_id;
142
+ const files = gigId
143
+ ? [metaFile(gigId)]
144
+ : fs.readdirSync(metaDir).filter((f) => f.endsWith(".jsonl")).map((f) => path.join(metaDir, f));
145
+ const out = [];
146
+ for (const file of files)
147
+ out.push(...readJsonlRows(file));
148
+ return out;
149
+ },
150
+ readPayload(sel) {
151
+ let content_sha = sel.content_sha;
152
+ let meta;
153
+ if (!content_sha && sel.id) {
154
+ // Resolve id → content_sha via the Tier-1 rows (fresh scan).
155
+ meta = this.queryMeta().find((m) => m.id === sel.id);
156
+ content_sha = meta?.content_sha;
157
+ }
158
+ else if (content_sha) {
159
+ meta = this.queryMeta().find((m) => m.content_sha === content_sha);
160
+ }
161
+ if (!content_sha)
162
+ return undefined;
163
+ const file = artifactPath(content_sha);
164
+ if (fs.existsSync(file)) {
165
+ try {
166
+ const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
167
+ return { meta, data: parsed.data };
168
+ }
169
+ catch {
170
+ return { meta };
171
+ }
172
+ }
173
+ // Local miss — the artifact may live only in the remote store (a mirror pulled from a peer).
174
+ // Best-effort remote fetch when configured; otherwise nothing to return.
175
+ return meta ? { meta } : undefined;
176
+ },
177
+ };
178
+ }
179
+ // ── REMOTE TIER — append-only, credential-gated. Never a service_role key (see the TODO). ──────
180
+ //
181
+ // Two credential shapes are accepted, whichever is present drives the write:
182
+ // (a) COLTRANE_DRAIN_KEY — a per-consumer ISSUED, scoped append key. The Tier-1 row is POSTed
183
+ // to PostgREST (`coltrane_outputs`) and the Tier-2 payload uploaded to Storage, both with
184
+ // this key. Uses `fetch` only — no new npm dependency.
185
+ // (b) COLTRANE_DRAIN_PG — a Postgres connection string for a scoped append role. The row is
186
+ // written over a direct `pg` connection (a guarded dynamic import; `pg` is NOT a declared
187
+ // dependency, so this path is unreachable — and harmless — unless the operator both sets
188
+ // the env AND installs the driver).
189
+ //
190
+ // COLTRANE_DRAIN_URL is the PostgREST + Storage project base URL (deployment-supplied, no host
191
+ // baked in here) for the (a) REST paths. COLTRANE_DRAIN_BUCKET names the Storage bucket
192
+ // (default "coltrane-artifacts").
193
+ function remoteConfigured() {
194
+ return Boolean(process.env["COLTRANE_DRAIN_KEY"] || process.env["COLTRANE_DRAIN_PG"]);
195
+ }
196
+ function drainBody(rec) {
197
+ const body = {
198
+ id: rec.id,
199
+ gig_id: rec.gig_id,
200
+ agent_slug: rec.agent_slug,
201
+ phase: rec.phase,
202
+ primitive: rec.primitive,
203
+ core_type: rec.core_type,
204
+ domain_type: rec.domain_type,
205
+ domain_type_version: rec.domain_type_version,
206
+ domain: rec.domain,
207
+ content_sha: rec.content_sha,
208
+ data: rec.data,
209
+ input_shas: rec.input_shas,
210
+ cost_usd: rec.cost_usd,
211
+ tokens_used: rec.tokens_used,
212
+ duration_ms: rec.duration_ms,
213
+ created_at: rec.created_at,
214
+ };
215
+ return body;
216
+ }
217
+ async function drainRemote(rec) {
218
+ const key = process.env["COLTRANE_DRAIN_KEY"];
219
+ if (key) {
220
+ await drainViaPostgrest(rec, key);
221
+ return;
222
+ }
223
+ const pgConn = process.env["COLTRANE_DRAIN_PG"];
224
+ if (pgConn) {
225
+ await drainViaPg(rec, pgConn);
226
+ return;
227
+ }
228
+ }
229
+ async function drainViaPostgrest(rec, key) {
230
+ const base = (process.env["COLTRANE_DRAIN_URL"] ?? "").replace(/\/$/, "");
231
+ if (!base)
232
+ throw new Error("COLTRANE_DRAIN_KEY is set but COLTRANE_DRAIN_URL (project base) is missing");
233
+ // TIER 1 — the metadata+data row into `coltrane_outputs` (columns already exist in the schema).
234
+ const rowRes = await fetch(`${base}/rest/v1/coltrane_outputs`, {
235
+ method: "POST",
236
+ headers: {
237
+ apikey: key,
238
+ Authorization: `Bearer ${key}`,
239
+ "Content-Type": "application/json",
240
+ Prefer: "resolution=merge-duplicates,return=minimal",
241
+ },
242
+ body: JSON.stringify(drainBody(rec)),
243
+ });
244
+ if (!rowRes.ok)
245
+ throw new Error(`coltrane_outputs POST ${rowRes.status}`);
246
+ // TIER 2 — the payload artifact into Storage, content-addressed by sha (idempotent upsert).
247
+ const bucket = process.env["COLTRANE_DRAIN_BUCKET"] ?? "coltrane-artifacts";
248
+ const objectPath = `${rec.gig_id}/${rec.content_sha}.json`;
249
+ const artRes = await fetch(`${base}/storage/v1/object/${bucket}/${objectPath}`, {
250
+ method: "POST",
251
+ headers: {
252
+ apikey: key,
253
+ Authorization: `Bearer ${key}`,
254
+ "Content-Type": "application/json",
255
+ "x-upsert": "true",
256
+ },
257
+ body: JSON.stringify({ content_sha: rec.content_sha, id: rec.id, data: rec.data }),
258
+ });
259
+ // A duplicate object (already uploaded for this sha) is success, not failure.
260
+ if (!artRes.ok && artRes.status !== 409)
261
+ throw new Error(`storage POST ${artRes.status}`);
262
+ }
263
+ async function drainViaPg(rec, conn) {
264
+ // Guarded dynamic import — `pg` is intentionally NOT a declared dependency, so the string is
265
+ // indirected to keep tsc from resolving it, and any failure to load surfaces as a drain error
266
+ // (fire-and-forget at the call site) rather than a hard crash.
267
+ const moduleName = "pg";
268
+ let pg;
269
+ try {
270
+ pg = await import(moduleName);
271
+ }
272
+ catch {
273
+ throw new Error("COLTRANE_DRAIN_PG is set but the 'pg' driver is not installed — install it in the consuming " +
274
+ "deployment, or use COLTRANE_DRAIN_KEY (PostgREST) instead. OSS ships no pg dependency.");
275
+ }
276
+ const Client = pg.Client;
277
+ if (!Client)
278
+ throw new Error("'pg' loaded but exposes no Client");
279
+ const client = new Client({ connectionString: conn });
280
+ await client.connect();
281
+ try {
282
+ const b = drainBody(rec);
283
+ await client.query(`insert into coltrane_outputs
284
+ (id, gig_id, agent_slug, phase, primitive, domain_type, domain_type_version, domain, content_sha, data, input_shas, cost_usd, tokens_used, duration_ms, created_at)
285
+ values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
286
+ on conflict (id) do nothing`, [
287
+ b["id"], b["gig_id"], b["agent_slug"], b["phase"], b["primitive"], b["domain_type"],
288
+ b["domain_type_version"], b["domain"], b["content_sha"], JSON.stringify(b["data"]),
289
+ b["input_shas"], b["cost_usd"], b["tokens_used"], b["duration_ms"], b["created_at"],
290
+ ]);
291
+ }
292
+ finally {
293
+ await client.end();
294
+ }
295
+ }
296
+ /** The sink row, derived entirely from the run's own record (engine "complete" → sink "completed"). */
297
+ export function gigHeaderBody(rec) {
298
+ const started = rec.started_at ? Date.parse(rec.started_at) : NaN;
299
+ const finished = rec.finished_at ? Date.parse(rec.finished_at) : NaN;
300
+ const duration = Number.isFinite(started) && Number.isFinite(finished) ? finished - started : null;
301
+ const tokens = rec.usage && (rec.usage.input_tokens !== undefined || rec.usage.output_tokens !== undefined)
302
+ ? (rec.usage.input_tokens ?? 0) + (rec.usage.output_tokens ?? 0)
303
+ : null;
304
+ const manifest = {};
305
+ if (rec.outputs_count !== undefined)
306
+ manifest["output_count"] = rec.outputs_count;
307
+ if (rec.error !== undefined)
308
+ manifest["error"] = rec.error;
309
+ return {
310
+ id: rec.gig_id,
311
+ standard_slug: rec.standard_slug,
312
+ status: rec.status === "complete" ? "completed" : rec.status,
313
+ genome_hash: rec.genome_hash ?? null,
314
+ run_fingerprint: rec.run_fingerprint ?? null,
315
+ started_at: rec.started_at ?? null,
316
+ completed_at: rec.finished_at ?? null,
317
+ total_cost_usd: rec.usage?.total_cost_usd ?? null,
318
+ total_tokens: tokens,
319
+ total_duration_ms: duration,
320
+ manifest,
321
+ };
322
+ }
323
+ /** Drain the header. Silent no-op when no drain credential is configured. */
324
+ export async function drainGigHeader(rec) {
325
+ if (!remoteConfigured())
326
+ return;
327
+ const key = process.env["COLTRANE_DRAIN_KEY"];
328
+ if (key) {
329
+ const base = (process.env["COLTRANE_DRAIN_URL"] ?? "").replace(/\/$/, "");
330
+ if (!base)
331
+ throw new Error("COLTRANE_DRAIN_KEY is set but COLTRANE_DRAIN_URL (drain service base) is missing");
332
+ const res = await fetch(`${base}/rest/v1/coltrane_gigs`, {
333
+ method: "POST",
334
+ headers: {
335
+ apikey: key,
336
+ Authorization: `Bearer ${key}`,
337
+ "Content-Type": "application/json",
338
+ Prefer: "resolution=merge-duplicates,return=minimal",
339
+ },
340
+ body: JSON.stringify(gigHeaderBody(rec)),
341
+ });
342
+ if (!res.ok)
343
+ throw new Error(`coltrane_gigs POST ${res.status}`);
344
+ return;
345
+ }
346
+ const pgConn = process.env["COLTRANE_DRAIN_PG"];
347
+ if (pgConn) {
348
+ const moduleName = "pg";
349
+ const pg = (await import(moduleName));
350
+ if (!pg.Client)
351
+ throw new Error("'pg' loaded but exposes no Client");
352
+ const client = new pg.Client({ connectionString: pgConn });
353
+ await client.connect();
354
+ try {
355
+ const b = gigHeaderBody(rec);
356
+ await client.query(`insert into coltrane_gigs (id, standard_slug, status, genome_hash, run_fingerprint, started_at, completed_at, total_cost_usd, total_tokens, total_duration_ms, manifest)
357
+ values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
358
+ on conflict (id) do update set
359
+ standard_slug = excluded.standard_slug, status = excluded.status,
360
+ genome_hash = excluded.genome_hash, run_fingerprint = excluded.run_fingerprint,
361
+ started_at = excluded.started_at, completed_at = excluded.completed_at,
362
+ total_cost_usd = excluded.total_cost_usd, total_tokens = excluded.total_tokens,
363
+ total_duration_ms = excluded.total_duration_ms, manifest = excluded.manifest`, [
364
+ b["id"], b["standard_slug"], b["status"], b["genome_hash"], b["run_fingerprint"],
365
+ b["started_at"], b["completed_at"], b["total_cost_usd"], b["total_tokens"],
366
+ b["total_duration_ms"], JSON.stringify(b["manifest"]),
367
+ ]);
368
+ }
369
+ finally {
370
+ await client.end();
371
+ }
372
+ }
373
+ }
374
+ // TODO(scoped-credential): the remote tier expects an APPEND-ONLY credential — either a
375
+ // per-consumer issued key (COLTRANE_DRAIN_KEY) whose grant is exactly "insert a coltrane_outputs
376
+ // row + upload an artifact object" and nothing else, or a Postgres role (COLTRANE_DRAIN_PG)
377
+ // scoped to INSERT on coltrane_outputs only. A service_role key MUST NOT be used here. Issuing
378
+ // that scoped credential (a Supabase RLS insert policy for the key's role, and a Storage bucket
379
+ // policy allowing upsert to the artifacts bucket) is deployment work that lives outside this OSS
380
+ // repo; this module only consumes whichever env credential is present.
381
+ //# sourceMappingURL=output_mirror.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output_mirror.js","sourceRoot":"","sources":["../../src/output_mirror.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Registry } from "./registry.js";
2
+ import type { OutputMirror } from "./output_mirror.js";
2
3
  export declare const REF_RELATIONS: readonly ["derived_from", "validates", "challenges", "refines", "triggers", "contains"];
3
4
  export type RefRelation = (typeof REF_RELATIONS)[number];
4
5
  export interface OutputRecord {
@@ -96,6 +97,61 @@ export interface OutputWrite {
96
97
  cache_key: string;
97
98
  } | undefined;
98
99
  }
100
+ /** The infix that separates a performance root from a movement id. Carries dots on BOTH sides so
101
+ * it cannot occur in a bare uuid, and `.m` alone cannot be mistaken for it. */
102
+ export declare const MOVEMENT_ID_INFIX = ".m.";
103
+ /** A movement's gig id, from the performance's id and the movement's. */
104
+ export declare function composeMovementGigId(gig_id: string, movement_id: string): string;
105
+ /**
106
+ * The performance a gig id belongs to. A plain gig id is its own root.
107
+ *
108
+ * Split at the FIRST infix, not the last: `composeChart`'s R1 admits `[A-Za-z0-9._-]+` for a
109
+ * movement_id, so a movement may itself contain `.m.` — and only a first-occurrence split puts
110
+ * two siblings of one performance under the same root.
111
+ */
112
+ export declare function performanceRoot(gig_id: string): string;
113
+ /** Which movement a gig id names, or undefined when it names none (a plain gig, or a
114
+ * degenerate chart, whose one movement runs under the performance's own id). */
115
+ export declare function movementOfGigId(gig_id: string): string | undefined;
116
+ /** Which way `trace` walks. `upstream` (the default) is the ancestor closure. */
117
+ export type TraceDirection = "upstream" | "downstream" | "both";
118
+ /**
119
+ * Where a traced record LIVED. Present only when there is something to say: a record sealed under
120
+ * a plain gig id, reached from a seed in that same gig, carries none of these — which is what
121
+ * keeps a single-standard gig's trace byte-identical to what it was before charts existed.
122
+ */
123
+ export interface TraceLabels {
124
+ /** The movement whose gig sealed this record. Absent when its gig id names no movement. */
125
+ movement?: string | undefined;
126
+ /** The performance this record's gig belongs to. Absent when its gig id names no movement. */
127
+ performance_gig_id?: string | undefined;
128
+ /** Set when this node's gig_id differs from the seed's — the walk CROSSED a boundary to reach
129
+ * it. Crossing is never silent: a consumer reads it off the node. */
130
+ crossed?: true | undefined;
131
+ /** Never set. The discriminant against `TraceMissingNode`. */
132
+ missing?: undefined;
133
+ }
134
+ /** A record the walk resolved, labelled with where it lived. */
135
+ export type TraceRecordNode = OutputRecord & TraceLabels;
136
+ /**
137
+ * A reference the chain makes and this store cannot resolve — the upstream movement drained
138
+ * remotely and was never local, or a row was lost.
139
+ *
140
+ * It is a NAMED terminal, never a dropped edge. Silently skipping it is the #248 defect exactly:
141
+ * the engine would report a SHORTER CHAIN as if it were the whole chain. The `content_sha` comes
142
+ * from the referring record's `input_shas` — engine-stamped at seal time, which is why the hole
143
+ * can be named rather than guessed at. It is `""` only when the reference carries no sha at all
144
+ * (a hand-authored `output_refs` edge, which records no hash).
145
+ */
146
+ export interface TraceMissingNode {
147
+ /** The output id the chain referenced. */
148
+ id: string;
149
+ content_sha: string;
150
+ missing: true;
151
+ /** The record that referenced it — so an operator knows where the hole is. */
152
+ referenced_by: string;
153
+ }
154
+ export type TraceNode = TraceRecordNode | TraceMissingNode;
99
155
  export interface OutputRef {
100
156
  id: string;
101
157
  from_output_id: string;
@@ -155,9 +211,28 @@ export interface OutputStore {
155
211
  all(): readonly OutputRecord[];
156
212
  addRef(from_output_id: string, to_output_id: string, relation: RefRelation, primitive: string): OutputRef;
157
213
  refs(): readonly OutputRef[];
214
+ /**
215
+ * E6: walk the provenance graph from a seed record. Returns the reachable closure, cycle-safe,
216
+ * EXCLUDING the seed itself.
217
+ *
218
+ * `direction` — `upstream` (the default) follows `input_refs` plus `derived_from`/`refines`
219
+ * edges to the ancestors; `downstream` follows the reverse of `input_refs` to the descendants;
220
+ * `both` is their union, each node once.
221
+ *
222
+ * `max_depth` caps the walk at N hops from the seed. `0` returns nothing.
223
+ *
224
+ * SCOPE — the PERFORMANCE, not one gig and not the whole store. A movement's gig id is
225
+ * `<performance>.m.<movement>`, so the walk follows an edge into any gig of the same
226
+ * performance and LABELS the node with where it lived (`TraceLabels`). It refuses an edge into
227
+ * an unrelated gig: a hand-authored reference between two performances is out of family, and
228
+ * surfacing it would be the cross-gig leak PR #85 closed.
229
+ *
230
+ * A reference this store cannot resolve is returned as a `TraceMissingNode`, never dropped.
231
+ */
158
232
  trace(id: string, opts?: {
159
233
  max_depth?: number;
160
- }): OutputRecord[];
234
+ direction?: TraceDirection;
235
+ }): TraceNode[];
161
236
  findings(): Finding[];
162
237
  coreTypeOf(typeSlug: string): string | null;
163
238
  /**
@@ -194,6 +269,7 @@ export interface OutputStore {
194
269
  }
195
270
  export interface OutputStoreOptions {
196
271
  persistDir?: string | undefined;
272
+ mirror?: OutputMirror | undefined;
197
273
  }
198
274
  export declare function defaultOutputsPersistDir(): string;
199
275
  export declare function createOutputStore(registry: Registry, options?: OutputStoreOptions): OutputStore;