diff --git a/packages/amico-run/src/catalog_verb.ts b/packages/amico-run/src/catalog_verb.ts index 0f0c020d..c87d5192 100644 --- a/packages/amico-run/src/catalog_verb.ts +++ b/packages/amico-run/src/catalog_verb.ts @@ -177,6 +177,30 @@ export function catalogIngest(argv: string[]): VerbResult { const id = flagValue(argv, "--id") ?? nextVersionId(records, platform, gate); const warmStart = flagValue(argv, "--warm-start") ?? incumbent?.id ?? ""; + // ── SEAM 5 (amicode #681): the chain's provenance flags ───────────────────── + // The calibrate→pin→re-optimize chain stages this exact command; the + // recording path later VERIFIES the fingerprint these write. Additive — + // absent flags write no keys (pre-chain entries unchanged). + const calibrationRef = flagValue(argv, "--calibration-ref"); + const pinRaw = flagValue(argv, "--pin"); + const pinProblems: string[] = []; + const pinnedGlobals: Record = {}; + if (pinRaw !== undefined) { + for (const pair of pinRaw.split(",")) { + const idx = pair.indexOf("="); + const k = pair.slice(0, idx).trim(); + const v = Number(pair.slice(idx + 1).trim()); + if (idx === -1 || k === "" || !Number.isFinite(v)) { + pinProblems.push(`--pin entries must be name=number (got "${pair.trim()}")`); + } else { + pinnedGlobals[k] = v; + } + } + if (Object.keys(pinnedGlobals).length === 0 && pinProblems.length === 0) { + pinProblems.push("--pin was given but parsed to no globals"); + } + } + if (pinProblems.length > 0) return fail(`invalid --pin: ${pinProblems.join("; ")}`); const tagsRaw = flagValue(argv, "--tags"); const tags = tagsRaw ? tagsRaw @@ -206,6 +230,10 @@ export function catalogIngest(argv: string[]): VerbResult { meta.path = relPath; meta.branch = flagValue(argv, "--branch") ?? "main"; meta.warm_start = warmStart; + // SEAM 5 (#681): the chain's fingerprint — additive metadata (reuse of the + // note schema; warm_start above is the seed lineage this chain relies on). + if (calibrationRef) meta.calibration_ref = calibrationRef; + if (pinRaw !== undefined) meta.pinned_globals = pinnedGlobals; if (tags) meta.tags = tags; meta.date = new Date().toISOString().slice(0, 10); diff --git a/packages/amico-run/src/repertoire.ts b/packages/amico-run/src/repertoire.ts index 3c5bd4cb..7dd37298 100644 --- a/packages/amico-run/src/repertoire.ts +++ b/packages/amico-run/src/repertoire.ts @@ -31,6 +31,14 @@ export interface PulseRecord { warm_start?: string; // lineage: the incumbent id this was warm-started from tags?: string[]; date?: string; // ISO date "YYYY-MM-DD" + // ── SEAM 5 (amicode #681): the calibrate→pin→re-optimize chain's provenance ── + // The chain's re-bank carries its fingerprint — which calibration, which pin, + // which warm-start seed — as ADDITIVE metadata fields (`warm_start` above IS + // the seed). The recording path (extension opencode-plugin/calib_chain.ts) + // VERIFIES these before the chain's executed marker can land. Additive keys: + // old entries simply lack them. + calibration_ref?: string; // which calibration: the chain record / rehearsal artifact ref + pinned_globals?: Record; // which pin: global → calibrated value dir: string; // ABS path to the entry directory } @@ -56,6 +64,19 @@ function dateStr(v: unknown): string | undefined { return undefined; } +/** A `[pinned_globals]`-style inline table: every value a finite number. Returns + * undefined for anything that isn't a clean number table (SEAM 5 #681 — a + * half-parseable pin set is worse than absent). */ +function pinTable(v: unknown): Record | undefined { + if (typeof v !== "object" || v === null || Array.isArray(v)) return undefined; + const out: Record = {}; + for (const [k, val] of Object.entries(v as Record)) { + if (typeof val !== "number" || !Number.isFinite(val)) return undefined; + out[k] = val; + } + return out; +} + function parseRecord(file: string, dir: string): PulseRecord | undefined { let parsed: Record; try { @@ -85,6 +106,9 @@ function parseRecord(file: string, dir: string): PulseRecord | undefined { warm_start: str(parsed.warm_start) ?? str(parsed.warm_started_from), tags: Array.isArray(parsed.tags) ? parsed.tags.filter((t): t is string => typeof t === "string") : undefined, date: dateStr(parsed.date), + // SEAM 5 (#681): the chain provenance — additive, absent on pre-chain entries. + calibration_ref: str(parsed.calibration_ref), + pinned_globals: pinTable(parsed.pinned_globals), }; } diff --git a/packages/amico-run/test/catalog_verb.test.ts b/packages/amico-run/test/catalog_verb.test.ts index 81ea4b0c..04667dd1 100644 --- a/packages/amico-run/test/catalog_verb.test.ts +++ b/packages/amico-run/test/catalog_verb.test.ts @@ -264,4 +264,71 @@ describe("amico catalog ingest (bundle) — the promotion gate", () => { expect(r.code).toBe(64); expect(JSON.parse(r.stdout).error).toMatch(/not found/); }); + + // ── SEAM 5 (amicode #681): the chain's provenance rides the catalog note ───── + // The calibrate→pin→re-optimize chain's re-bank carries its fingerprint — + // which calibration, which pin, which warm-start seed — as ADDITIVE metadata + // fields (the note schema's open growth; the existing warm_start field IS the + // seed). The chain stages this exact command; the recording path (extension + // side, calib_chain.ts) later VERIFIES the fingerprint against these fields. + it("--calibration-ref + --pin + --warm-start write the chain's fingerprint (which calibration, which pin, which seed); loadRepertoire reads all three back", () => { + seedEntry(pulses, "transmon-X-v1", { platform: "transmon", gate: "X", fidelity: 0.98 }); + const newPulse = join(pulses, "..", "chain-pulse.jld2"); + writeFileSync(newPulse, "calibrated-pulse"); + const r = run( + [ + "catalog", "ingest", + "--platform", "transmon", "--kind", "X", + "--artifact", newPulse, "--fidelity", "0.9995", + "--agree", "true", + "--warm-start", "transmon-X-v1", + "--calibration-ref", "/problems/chain/entities/calib_chain.toml", + "--pin", "delta=0.21", + ], + { AMICO_CATALOG_DIR: pulses }, + ); + expect(r.code).toBe(0); + expect(JSON.parse(r.stdout).promoted).toBe(true); + const meta = readToml(join(pulses, "transmon-X-v2", "metadata.toml")); + expect(meta.warm_start).toBe("transmon-X-v1"); // which seed (the existing lineage field) + expect(meta.calibration_ref).toBe("/problems/chain/entities/calib_chain.toml"); // which calibration + expect(meta.pinned_globals).toEqual({ delta: 0.21 }); // which pin + // round-trip: the repertoire loader surfaces the fingerprint (additive fields) + const rec = queryIncumbent(loadRepertoire(pulses), "transmon", "X").incumbent; + expect(rec?.warm_start).toBe("transmon-X-v1"); + expect(rec?.calibration_ref).toBe("/problems/chain/entities/calib_chain.toml"); + expect(rec?.pinned_globals).toEqual({ delta: 0.21 }); + }); + + it("--pin parses multi-global comma lists; a malformed pin value is refused honestly (exit 64, no write)", () => { + const newPulse = join(pulses, "..", "p.jld2"); + writeFileSync(newPulse, "x"); + const r = run( + [ + "catalog", "ingest", + "--platform", "transmon", "--kind", "X", + "--artifact", newPulse, "--fidelity", "0.9999", "--agree", "true", + "--pin", "delta=0.21,omega=4.9", + ], + { AMICO_CATALOG_DIR: pulses }, + ); + expect(r.code).toBe(0); + expect(readToml(join(pulses, "transmon-X-v1", "metadata.toml")).pinned_globals).toEqual({ delta: 0.21, omega: 4.9 }); + + const bad = join(pulses, "..", "p2.jld2"); + writeFileSync(bad, "x"); + const r2 = run( + [ + "catalog", "ingest", + "--platform", "transmon", "--kind", "X", + "--artifact", bad, "--fidelity", "0.99995", "--agree", "true", + "--id", "transmon-X-v2", + "--pin", "delta=not-a-number", + ], + { AMICO_CATALOG_DIR: pulses }, + ); + expect(r2.code).toBe(64); + expect(JSON.parse(r2.stdout).error).toMatch(/--pin/); + expect(existsSync(join(pulses, "transmon-X-v2"))).toBe(false); + }); }); diff --git a/packages/extension/opencode-plugin/amicode_tools.ts b/packages/extension/opencode-plugin/amicode_tools.ts index ffec0063..b44b0c72 100644 --- a/packages/extension/opencode-plugin/amicode_tools.ts +++ b/packages/extension/opencode-plugin/amicode_tools.ts @@ -93,6 +93,11 @@ import { import { guardAndRecordStage, completeStage } from "./score_guard"; import { readRehearsalRecord } from "./rehearsal"; +import { + recordCalibChain, + completeCalibChain, + type ChainLeg, +} from "./calib_chain"; import { SPAWN_MAX_COUNT, SPAWN_MAX_DEPTH, @@ -1208,6 +1213,128 @@ export const AmicodeTools = async (input: unknown) => { ); }, }, + + // SEAM 5 (#681) — the calibrate→pin→re-optimize→re-bank chain: ONE recorded + // verb path composed from existing seams. The recording core (calib_chain.ts) + // owns the logic and is unit-tested; this wrapper is the agent-facing + // surface (args → core → AMICODE_DIFF receipt), never a launch, never a + // promotion (the staged re-bank runs out-of-band, human-gated). + amicode_calib_chain: { + description: + "Record the calibrate→pin→re-optimize→re-bank chain (SEAM 5, #681) — the drift-response " + + "tune-up as ONE recorded verb. TWO calls, one chain: STAGE with the calibration + pin + " + + "seed; COMPLETE with the promoted entry's metadata once the re-bank ran.\n" + + "CALIBRATE (leg=mock): the SEAM 1 MockSoc rehearsal is the calibration data source — " + + "run it first per the run-launch seam (bash, julia --startup-file=no): " + + "julia --startup-file=no --project=/templates/mocksoc-rehearsal " + + "/templates/mocksoc_rehearsal.jl [out_dir], and pass the " + + "rehearsal.toml as rehearsal_ref (validated through the same reader amicode_to_hardware " + + "uses — a dishonest artifact records nothing). leg=hardware is REFUSED: real-board " + + "sessions are an enumerated human gate and this build has no real-board session surface.\n" + + "PIN: pass `pinned` (global → calibrated value, e.g. {delta: 0.21}) — it lands on the " + + "recorded formulation as the existing calibration_pin constraint (the " + + "fix_global_variable! path) + solve.pinned_globals; re-staging replaces the pin.\n" + + "RE-OPTIMIZE: pass warm_start (the bank seed — catalog entry id or pulse ref); the run " + + "stub records it. The re-solve itself launches through the EXISTING solve path (bash " + + "amico-run), warm-started via the load_traj idiom; pass its run_dir when known.\n" + + "RE-BANK: the tool STAGES the exact `amico catalog ingest` command with the chain's " + + "provenance flags (--warm-start/--calibration-ref/--pin — which calibration, which pin, " + + "which seed). Promotion is human-gated like all promotions: run it ONLY after the " + + "researcher signs off (with verification evidence). Then COMPLETE: pass the promoted " + + "entry's metadata.toml path as rebank_metadata_ref — the fingerprint is verified and the " + + "executed_on_mock event lands on the provenance spine (the countable execution record).", + args: { + leg: { + type: ["string", "null"], + description: 'mock (the only recordable leg) | hardware (refused — real-board sessions are an enumerated human gate). Null = mock.', + }, + rehearsal_ref: { + type: ["string", "null"], + description: "The SEAM 1 rehearsal.toml artifact — the mock leg's calibration data source. Null to complete a staged chain.", + }, + pinned: { + type: ["object", "null"], + additionalProperties: { type: "number" }, + description: "The calibrated globals to pin (global → value), e.g. {delta: 0.21} from a 'delta × 1.05' rehearsal mismatch on a 0.2 nominal.", + }, + warm_start: { + type: ["string", "null"], + description: "The bank seed the re-solve warm-starts from (catalog entry id or pulse ref).", + }, + run_dir: { + type: ["string", "null"], + description: "The re-solve's run directory, once launched through the solve path; else null.", + }, + note: { + type: ["string", "null"], + description: "Short free-text note; null for none.", + }, + rebank_metadata_ref: { + type: ["string", "null"], + description: "COMPLETE the chain: the promoted catalog entry's metadata.toml path — verified (read-only) against the chain's fingerprint, then the executed_on_mock event is recorded. Null to stage.", + }, + }, + async execute(a: { + leg?: string | null; + rehearsal_ref?: string | null; + pinned?: Record | null; + warm_start?: string | null; + run_dir?: string | null; + note?: string | null; + rebank_metadata_ref?: string | null; + }) { + const meta = ensureActiveProblem(); + + // COMPLETE — verify the promoted entry's fingerprint + the execution record. + if (given(a.rebank_metadata_ref)) { + const res = completeCalibChain({ slug: meta.slug, rebankMetadataRef: a.rebank_metadata_ref }); + if (!res.ok) { + return `Cannot complete the calibrate→pin→re-optimize chain for "${meta.slug}": ${res.problem}`; + } + const sentinel = sentinelLine(meta.slug, "calib_chain", res.chainEvent.action, res.chainEvent.seq, res.chainEvent.diff); + return ( + `Chain executed on mock for "${meta.slug}"${res.already ? " (re-verified; already complete)" : ""} — the re-bank ` + + `carried the chain's fingerprint (which calibration, which pin, which warm-start ` + + `seed), the rebank leg is recorded on the chain entity, and the executed_on_mock ` + + `event is on the provenance spine. The promotion itself ran out-of-band through the ` + + `human-gated ingest — this record is its receipt, not its author.\n\n${sentinel}` + ); + } + + // STAGE — calibrate + pin + re-optimize legs. + if (!given(a.rehearsal_ref) || !given(a.pinned) || !given(a.warm_start)) { + return ( + `Cannot stage the chain for "${meta.slug}": rehearsal_ref (the SEAM 1 rehearsal ` + + `artifact), pinned (the calibrated globals), and warm_start (the bank seed) are all ` + + `required to stage — or pass rebank_metadata_ref alone to complete a staged chain. ` + + `Nothing was recorded.` + ); + } + const res = recordCalibChain({ + slug: meta.slug, + leg: (a.leg === "hardware" ? "hardware" : "mock") as ChainLeg, + rehearsalRef: a.rehearsal_ref, + pinned: a.pinned, + warmStart: a.warm_start, + runDir: given(a.run_dir) ? a.run_dir : undefined, + note: given(a.note) ? a.note : undefined, + }); + if (!res.ok) { + return `Cannot stage the calibrate→pin→re-optimize chain for "${meta.slug}": ${res.problem}`; + } + const sentinel = sentinelLine(meta.slug, "calib_chain", res.staged.chainEvent.action, res.staged.chainEvent.seq, res.staged.chainEvent.diff); + return ( + `Chain staged for "${meta.slug}" — calibrated via the MockSoc rehearsal (${res.staged.chainRef} ` + + `carries the fingerprint), the pin landed on the formulation (calibration_pin + ` + + `pinned_globals), and the re-optimize leg's warm-start seed is on the run stub.\n\n` + + `Re-bank when the re-solve finishes — the human-gated promotion, run only after the ` + + `researcher signs off:\n ${res.staged.rebankCommand}\n${res.staged.humanGate}\n\n` + + `Then complete the chain: pass the promoted entry's metadata.toml path as ` + + `rebank_metadata_ref (the fingerprint gets verified, and the executed_on_mock event ` + + `lands on the provenance spine).\n\n${sentinel}` + ); + }, + }, } : {}), // end quantum-control domain tools gate // ── Onboarding (spec-20260705-002847 §3) — NOT a problem stage: UNGATED // (no guardAndRecordStage), writes the ops-side onboarding stream, never the diff --git a/packages/extension/opencode-plugin/calib_chain.ts b/packages/extension/opencode-plugin/calib_chain.ts new file mode 100644 index 00000000..b9949aec --- /dev/null +++ b/packages/extension/opencode-plugin/calib_chain.ts @@ -0,0 +1,383 @@ +// ============================================================================ +// SEAM 5 (amicode #681) — the calibrate→pin→re-optimize→re-bank chain, the +// recording core behind the `amicode_calib_chain` tool. +// +// SIBLING-MODULE RULES (same as ./rehearsal — this one DOES import smol-toml, +// the ./rehearsal + ./ledger_client precedent: the plugin runs inside +// opencode's embedded Bun runtime, where the package resolves from the +// extension's node_modules): node: builtins + smol-toml only, no other npm +// packages, never anything from ../src/. +// +// The chain composes EXISTING seams — no new physics, no new tiers; the +// RECORDING PATH is the deliverable (spec SEAM 5): +// 1. calibrate — mock leg: the SEAM 1 rehearsal artifact is the calibration +// data source (read through ./rehearsal — the SAME reader the tool uses; +// a dishonest artifact records NOTHING). Hardware leg: structurally +// refused — real-board sessions are an enumerated human gate, and this +// build has no real-board session surface. `hardwareLegRefusal` is the +// tested refusal path, mirroring the human-gates enumeration. +// 2. pin — the calibrated globals land on the EXISTING formulation surfaces: +// the `calibration_pin` constraint (params = the values; re-staging +// replaces it — a pin is a set point, not an accumulating list) and +// `solve.pinned_globals` (the names) — the fix_global_variable! path. +// 3. re-optimize — the run stub records the warm-start seed (additive +// `warm_start`); the re-solve itself launches through the EXISTING solve +// path (bash amico-run) — this core NEVER launches anything. +// 4. re-bank — the chain stages the `amico catalog ingest` command with the +// provenance flags (which calibration, which pin, which seed) and +// VERIFIES the promoted entry afterwards. Promotion is human-gated like +// all promotions: this core performs NO catalog write (read-only verify); +// the ingest runs out-of-band, only on the researcher's sign-off. +// +// The executed marker: `completeCalibChain` verifies the promoted entry's +// catalog note carries THIS chain's fingerprint, then appends the +// `executed_on_mock` event — the countable execution record +// (`calib_pin_reopt_chain_executed_on_mock == 1` is an event, not a schema). +// ============================================================================ + +import * as fs from "node:fs"; +import * as path from "node:path"; +import { parse as parseToml } from "smol-toml"; +import { + calibChainToml, + entityDiff, + normalizeFormulation, + normalizeSystem, + runStubToml, + updateFormulation, + formulationToml, + validateCalibChainRecord, + type CalibChainRecord, + type Constraint, + type FormulationEntity, + type RunStub, +} from "./entities"; +import { entityHash } from "./hashes"; +import { appendEvent, problemDir, writeEntityFiles } from "./problems"; +import { readRehearsalRecord } from "./rehearsal"; + +/** The chain's calibration leg. Only "mock" is constructible; "hardware" is + * refused by the recording path (see hardwareLegRefusal). */ +export type ChainLeg = "mock" | "hardware"; + +/** The hardware-leg refusal — names the enumerated human gate. Real-board + * sessions are one of the five enumerated human gates the premium tier may + * never route around; this build has no real-board session surface, so the + * hardware calibration leg is structurally impossible and the chain says so + * instead of recording a costume of it. */ +export function hardwareLegRefusal(): string { + return ( + "the hardware calibration leg runs ONLY inside a real-board session — one of the " + + "enumerated human gates (live gateway spend; real-board sessions; opening P4 on real " + + "hardware; defaults-flips with live behavior; promotions of results) — and this build " + + "has no real-board session surface. The chain's calibration leg is the SEAM 1 MockSoc " + + "rehearsal (mock), and that is all it can honestly record. Nothing was recorded." + ); +} + +export interface RecordCalibChainInput { + /** The problem workspace slug (the tool resolves the active problem). */ + slug: string; + leg: ChainLeg; + /** Path to the rehearsal.toml artifact — the mock leg's calibration data + * source (SEAM 1). Validated through the same reader the tool uses. */ + rehearsalRef: string; + /** The calibrated globals to pin (global → value). */ + pinned: Record; + /** The bank seed the re-solve warm-starts from (catalog entry id or pulse ref). */ + warmStart: string; + /** The re-solve's run directory, once launched (optional at stage time). */ + runDir?: string; + note?: string; +} + +export interface StagedChain { + /** The exact `amico catalog ingest` command carrying the chain's provenance — + * the promotion the chain never performs (human-gated like all promotions). */ + rebankCommand: string; + /** The human-gate instruction to relay with the command. */ + humanGate: string; + /** The chain entity's TOML ref (its recorded fingerprint). */ + chainRef: string; + /** The chain entity's event receipt (the wrapper renders the AMICODE_DIFF + * sentinel from it — same idiom as every entity write in the tool pack). */ + chainEvent: { action: "created" | "updated"; seq: number; diff: Record }; +} + +export type RecordCalibChainResult = + | { ok: true; staged: StagedChain } + | { ok: false; problem: string }; + +export interface CompleteCalibChainInput { + slug: string; + /** Path to the promoted catalog entry's metadata.toml — read (never written) + * to verify the re-bank carries this chain's fingerprint. */ + rebankMetadataRef: string; +} + +export type CompleteCalibChainResult = + | { ok: true; executed_on_mock: boolean; already?: boolean; chainEvent: { action: "created" | "updated"; seq: number; diff: Record } } + | { ok: false; problem: string }; + +/** Read an entity's JSON sidecar (the plugin is TOML-writer-only; reads go + * through .json). */ +function readEntityJson(slug: string, kind: string): T | undefined { + const file = path.join(problemDir(slug), "entities", `${kind}.json`); + if (!fs.existsSync(file)) return undefined; + try { + return JSON.parse(fs.readFileSync(file, "utf8")) as T; + } catch { + return undefined; + } +} + +/** Persist an entity: write TOML+JSON sidecar, append a structured-diff event + * with content hash. The parallel of amicode_tools.ts's recordEntity (this + * module cannot import from the plugin entry — single-export constraint). */ +function recordEntity( + slug: string, + kind: string, + entity: Record, + toml: string, + source: { tool: string; stage?: string }, +): { action: "created" | "updated"; seq: number; diff: Record } { + const before = readEntityJson>(slug, kind); + const action: "created" | "updated" = before ? "updated" : "created"; + writeEntityFiles(slug, kind, toml, JSON.stringify(entity, null, 2) + "\n"); + const diff = entityDiff(before, entity); + const seq = appendEvent(slug, { entity: kind, action, diff, hash: entityHash(entity), source }); + return { action, seq, diff }; +} + +/** The staged re-bank command — the chain's provenance flags riding `amico + * catalog ingest` (which calibration, which pin, which warm-start seed). */ +function rebankCommand( + form: FormulationEntity, + platform: string, + chain: CalibChainRecord, + chainRef: string, +): string { + const pin = Object.entries(chain.pinned_globals) + .map(([k, v]) => `${k}=${v}`) + .join(","); + const runSrc = chain.run_dir !== undefined ? `--from-run ${chain.run_dir}` : "--from-run "; + return ( + `amico catalog ingest --platform ${platform} --kind ${form.target} ${runSrc} ` + + `--warm-start ${chain.warm_start} --calibration-ref ${chain.calibration.source} ` + + `--pin ${pin}` + ); +} + +const HUMAN_GATE_NOTE = + "promotion is human-gated like all promotions — run the staged ingest only after the " + + "researcher signs off (and only with verification evidence: --agree true or a run dir " + + "with verification.toml); the chain records the outcome, it never promotes."; + +/** Stage the chain's calibrate + pin + re-optimize legs. Refusals record + * NOTHING (honest refusal, never a costume of progress). */ +export function recordCalibChain(input: RecordCalibChainInput): RecordCalibChainResult { + // leg 1 — calibrate. The hardware leg is structurally refused. + if (input.leg !== "mock") return { ok: false, problem: hardwareLegRefusal() }; + + const rr = readRehearsalRecord(input.rehearsalRef); + if (!rr.ok) { + return { + ok: false, + problem: `the calibration artifact is not an honest rehearsal record — ${rr.problem}. Nothing was recorded.`, + }; + } + + const pinEntries = Object.entries(input.pinned ?? {}); + if (pinEntries.length === 0) { + return { ok: false, problem: "the chain pins at least one calibrated global — pass a non-empty `pinned` set. Nothing was recorded." }; + } + if (typeof input.warmStart !== "string" || input.warmStart.trim() === "") { + return { ok: false, problem: "warm_start (the bank seed) is required — the re-optimize leg warm-starts from the bank. Nothing was recorded." }; + } + + // leg 2 — pin: onto the RECORDED formulation (existing surfaces only). + const formRaw = readEntityJson>(input.slug, "formulation"); + if (!formRaw) { + return { + ok: false, + problem: "no formulation recorded in this problem — the chain pins the calibrated globals onto the recorded formulation (the calibration_pin constraint). Nothing was recorded.", + }; + } + const form = normalizeFormulation(formRaw); + const prior = form.constraints.filter((c) => c.kind !== "calibration_pin"); + const pinConstraint: Constraint = { + kind: "calibration_pin", + params: { ...input.pinned }, + label: `calibrate→pin chain: ${rr.record.mismatch}`, + }; + const mergedForm = updateFormulation(formRaw, { + constraints: [...prior, pinConstraint], + solve: { pinned_globals: pinEntries.map(([k]) => k) }, + }); + + // leg 3 — re-optimize: the run stub records the warm-start seed. + const dir = problemDir(input.slug); + const sysPath = path.join(dir, "entities", "system.toml"); + const formPath = path.join(dir, "entities", "formulation.toml"); + const existingRun = readEntityJson(input.slug, "run") ?? ({} as RunStub); + const runStub: RunStub = { + ...existingRun, + ...(fs.existsSync(sysPath) ? { system_ref: sysPath } : {}), + ...(fs.existsSync(formPath) ? { formulation_ref: formPath } : {}), + warm_start: input.warmStart, + ...(input.runDir !== undefined ? { run_dir: input.runDir } : {}), + }; + + // the chain entity — the fingerprint. + const chain: CalibChainRecord = { + leg: "mock", + calibration: { + source: input.rehearsalRef, + pulse_hash: rr.record.pulse_hash, + mismatch: rr.record.mismatch, + }, + pinned_globals: { ...input.pinned }, + warm_start: input.warmStart, + ...(input.runDir !== undefined ? { run_dir: input.runDir } : {}), + ...(input.note !== undefined ? { note: input.note } : {}), + }; + const chainProblems = validateCalibChainRecord(chain); + if (chainProblems.length > 0) { + return { ok: false, problem: `invalid chain record: ${chainProblems.join("; ")}. Nothing was recorded.` }; + } + + const sysRaw = readEntityJson>(input.slug, "system"); + const platform = sysRaw ? normalizeSystem(sysRaw).platform : ""; + + // Write through the existing entities + the chain — the provenance spine. + recordEntity(input.slug, "formulation", mergedForm as unknown as Record, formulationToml(mergedForm), { + tool: "amicode_calib_chain", + stage: "formulate", + }); + recordEntity(input.slug, "run", runStub as unknown as Record, runStubToml(runStub), { + tool: "amicode_calib_chain", + stage: "solve", + }); + const chainRef = path.join(dir, "entities", "calib_chain.toml"); + const chainEvent = recordEntity( + input.slug, + "calib_chain", + chain as unknown as Record, + calibChainToml(chain), + { tool: "amicode_calib_chain" }, + ); + + return { + ok: true, + staged: { + rebankCommand: rebankCommand(mergedForm, platform, chain, chainRef), + humanGate: HUMAN_GATE_NOTE, + chainRef, + chainEvent: { action: chainEvent.action, seq: chainEvent.seq, diff: chainEvent.diff }, + }, + }; +} + +/** Read the promoted entry's catalog note (smol-toml parse; never written). */ +function readCatalogMetadata(ref: string): Record | { error: string } { + let raw: string; + try { + raw = fs.readFileSync(ref, "utf8"); + } catch (err) { + return { error: `cannot read the promoted entry's metadata at ${ref}: ${err instanceof Error ? err.message : String(err)}` }; + } + try { + return parseToml(raw) as Record; + } catch (err) { + return { error: `cannot parse the promoted entry's metadata at ${ref}: ${err instanceof Error ? err.message : String(err)}` }; + } +} + +function samePin(a: unknown, b: Record): boolean { + if (typeof a !== "object" || a === null || Array.isArray(a)) return false; + const ao = a as Record; + const ak = Object.keys(ao); + const bk = Object.keys(b); + if (ak.length !== bk.length) return false; + return bk.every((k) => typeof ao[k] === "number" && Number.isFinite(ao[k]) && ao[k] === b[k]); +} + +/** Complete the chain: verify the promoted entry's catalog note carries THIS + * chain's fingerprint (which calibration, which pin, which seed), then land + * the re-bank leg + the `executed_on_mock` event — the countable execution + * record. The promotion itself happened out-of-band (the human-gated ingest); + * this core only READS the result. Idempotent: completing an already-completed + * chain re-verifies and never appends a second executed event. */ +export function completeCalibChain(input: CompleteCalibChainInput): CompleteCalibChainResult { + const chain = readEntityJson(input.slug, "calib_chain"); + if (!chain) { + return { + ok: false, + problem: "no chain staged in this problem — stage the calibrate→pin→re-optimize legs first (amicode_calib_chain with the rehearsal artifact + pin + seed). Nothing was recorded.", + }; + } + + const meta = readCatalogMetadata(input.rebankMetadataRef); + if ("error" in meta) { + return { + ok: false, + problem: `${meta.error}. ${HUMAN_GATE_NOTE}`, + }; + } + + // the fingerprint check — the re-bank must carry THIS chain's provenance. + const mismatches: string[] = []; + if (meta.warm_start !== chain.warm_start) { + mismatches.push(`warm_start: note has ${JSON.stringify(meta.warm_start)}, chain pinned ${JSON.stringify(chain.warm_start)}`); + } + if (meta.calibration_ref !== chain.calibration.source) { + mismatches.push(`calibration_ref: note has ${JSON.stringify(meta.calibration_ref)}, chain ran ${JSON.stringify(chain.calibration.source)}`); + } + if (!samePin(meta.pinned_globals, chain.pinned_globals)) { + mismatches.push(`pinned_globals: note has ${JSON.stringify(meta.pinned_globals ?? null)}, chain pinned ${JSON.stringify(chain.pinned_globals)}`); + } + const entryId = typeof meta.id === "string" ? meta.id : ""; + if (entryId.trim() === "") { + mismatches.push("id: the promoted entry's metadata carries no entry id"); + } + if (mismatches.length > 0) { + return { + ok: false, + problem: `the re-bank does not carry this chain's provenance — ${mismatches.join("; ")}. Re-run the staged ingest with the chain's provenance flags. Nothing was recorded.`, + }; + } + + const provenance = { + warm_start: chain.warm_start, + calibration_ref: chain.calibration.source, + pinned_globals: { ...chain.pinned_globals }, + }; + const already = + chain.rebank !== undefined && chain.rebank.catalog_entry === entryId && chain.rebank.provenance.warm_start === provenance.warm_start; + const completed: CalibChainRecord = { ...chain, rebank: { catalog_entry: entryId, provenance } }; + + const chainEvent = recordEntity( + input.slug, + "calib_chain", + completed as unknown as Record, + calibChainToml(completed), + { tool: "amicode_calib_chain" }, + ); + if (!already) { + // THE EXECUTION RECORD — countable in events.jsonl + // (`calib_pin_reopt_chain_executed_on_mock == 1` is this event). + appendEvent(input.slug, { + entity: "calib_chain", + action: "executed_on_mock", + diff: { rebank: { from: chain.rebank ? "present" : null, to: entryId } }, + hash: entityHash(completed), + source: { tool: "amicode_calib_chain" }, + }); + } + return { + ok: true, + executed_on_mock: true, + ...(already ? { already: true } : {}), + chainEvent: { action: chainEvent.action, seq: chainEvent.seq, diff: chainEvent.diff }, + }; +} diff --git a/packages/extension/opencode-plugin/entities.ts b/packages/extension/opencode-plugin/entities.ts index 56dbf309..323ff8ea 100644 --- a/packages/extension/opencode-plugin/entities.ts +++ b/packages/extension/opencode-plugin/entities.ts @@ -279,6 +279,9 @@ export interface RunStub { script_ref?: string; /** Resolved env binding kind (spec C). */ env?: string; + /** SEAM 5 (#681): the bank seed this run warm-started from (catalog entry id + * or pulse ref) — the load_traj idiom's recorded half. Additive. */ + warm_start?: string; /** Free-tier re-rollout verification outcome (spec C) — recorded by * amicode_verify after amico-run's harness writes verification.toml. Spec B's * entity view renders it beside the tier; promotion is gated on agree. */ @@ -408,6 +411,149 @@ export interface CalibrationStub { note?: string; } +// --- SEAM 5 (#681): the calibrate→pin→re-optimize→re-bank chain record ---------- + +/** The chain's fingerprint (spec SEAM 5): what the calibration was, which globals + * got pinned, which bank pulse seeded the re-solve, and — once the human-gated + * re-bank is verified — the promoted entry with the provenance its catalog note + * carries. Composes EXISTING seams; the record is the recording path's spine. + * + * STRUCTURAL HONESTY: `leg` is the literal "mock" — the ONLY constructible leg. + * The hardware leg is a REFUSAL in the recording path (real-board sessions are + * an enumerated human gate), never a record variant, so no caller can label a + * chain hardware-flavored. `promotion` is NOT a field: the serializer DERIVES it + * (pending-human-sign-off while staged; human-gated-rebank-recorded once the + * verified re-bank leg lands) — the record can never claim an approval that + * didn't happen through the human-gated ingest. */ +export interface CalibChainRecord { + leg: "mock"; + /** The calibration leg — the SEAM 1 rehearsal artifact is the mock calibration + * data source (the cross-seam dependency, explicit). */ + calibration: { + /** The rehearsal.toml artifact the calibration ran on. */ + source: string; + /** Content-hash of the pulse the calibration ran (from the artifact). */ + pulse_hash: string; + /** The calibration's mismatch declaration (mock truth vs nominal model). */ + mismatch: string; + }; + /** The pin: global → calibrated value. Lands on the formulation as the + * existing `calibration_pin` constraint (params = these values) and as + * `solve.pinned_globals` (the names) — the fix_global_variable! path. */ + pinned_globals: Record; + /** The bank seed the re-solve warm-started from (catalog entry id or pulse + * ref) — the load_traj idiom's recorded half. */ + warm_start: string; + /** The re-solve's run directory, once launched through the solve path. */ + run_dir?: string; + note?: string; + /** Present ONLY after the human-gated promotion is VERIFIED against the + * promoted entry's catalog note (the fingerprint must match). */ + rebank?: { + catalog_entry: string; + /** The provenance the catalog note carries (checked to MATCH this chain + * before the executed marker can land — see ./calib_chain.ts). */ + provenance: { + warm_start: string; + calibration_ref: string; + pinned_globals: Record; + }; + }; +} + +/** Human-readable problems for a CalibChainRecord; [] = valid. */ +export function validateCalibChainRecord(rec: Partial): string[] { + const problems: string[] = []; + if (rec.leg !== "mock") { + problems.push( + `leg must be "mock" — the hardware leg runs ONLY inside a real-board session (an enumerated human gate) and is never recordable, got ${JSON.stringify(rec.leg)}`, + ); + } + const cal = rec.calibration as CalibChainRecord["calibration"] | undefined; + if (!cal || typeof cal.source !== "string" || cal.source.trim() === "") { + problems.push("calibration.source must be a non-empty path to the calibration artifact"); + } + if (!cal || typeof cal.pulse_hash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(cal.pulse_hash)) { + problems.push(`calibration.pulse_hash must be a sha256 content-hash ("sha256:<64 hex>"), got ${JSON.stringify(cal?.pulse_hash)}`); + } + if (!cal || typeof cal.mismatch !== "string" || cal.mismatch.trim() === "") { + problems.push("calibration.mismatch must be a non-empty declaration of the calibrated mismatch"); + } + const pinProblems = (pin: unknown, field: string): void => { + if (typeof pin !== "object" || pin === null || Array.isArray(pin)) { + problems.push(`${field} must be a table of global → calibrated value`); + return; + } + const entries = Object.entries(pin as Record); + if (entries.length === 0) problems.push(`${field} must pin at least one global`); + for (const [k, v] of entries) { + if (typeof v !== "number" || !Number.isFinite(v)) { + problems.push(`${field}["${k}"] must be a finite number, got ${JSON.stringify(v)}`); + } + } + }; + pinProblems(rec.pinned_globals, "pinned_globals"); + if (typeof rec.warm_start !== "string" || rec.warm_start.trim() === "") { + problems.push("warm_start must be a non-empty bank seed (catalog entry id or pulse ref)"); + } + if (rec.run_dir !== undefined && (typeof rec.run_dir !== "string" || rec.run_dir.trim() === "")) { + problems.push("run_dir must be a non-empty path when given"); + } + if (rec.rebank !== undefined) { + const rb = rec.rebank; + if (typeof rb.catalog_entry !== "string" || rb.catalog_entry.trim() === "") { + problems.push("rebank.catalog_entry must be a non-empty catalog entry id"); + } + const prov = rb.provenance as CalibChainRecord["rebank"]["provenance"] | undefined; + if (!prov || typeof prov.warm_start !== "string" || prov.warm_start.trim() === "") { + problems.push("rebank.provenance.warm_start must be a non-empty seed"); + } + if (!prov || typeof prov.calibration_ref !== "string" || prov.calibration_ref.trim() === "") { + problems.push("rebank.provenance.calibration_ref must be a non-empty calibration ref"); + } + pinProblems(prov?.pinned_globals, "rebank.provenance.pinned_globals"); + } + return problems; +} + +/** Serialize the chain record under [calib_chain]. `leg` is pinned "mock" and + * `promotion` DERIVED (staged → "pending-human-signoff"; verified re-bank → + * "human-gated-rebank-recorded") — neither is caller data, mirroring the + * rehearsal record's pinned `sim = true`. Throws on an invalid record. */ +export function calibChainToml(rec: CalibChainRecord, now?: Date): string { + const problems = validateCalibChainRecord(rec); + if (problems.length > 0) throw new Error(`invalid calib chain: ${problems.join("; ")}`); + const inlineNum = (p: Record): string => { + const entries = Object.entries(p); + return entries.length === 0 ? "{}" : `{ ${entries.map(([k, v]) => `${tomlKey(k)} = ${tomlNumber(v)}`).join(", ")} }`; + }; + const lines = ["[calib_chain]"]; + lines.push(`leg = ${tomlEscape(rec.leg)}`); // pinned — the record has no hardware variant + lines.push(`promotion = ${tomlEscape(rec.rebank ? "human-gated-rebank-recorded" : "pending-human-signoff")}`); + lines.push(`warm_start = ${tomlEscape(rec.warm_start)}`); + if (rec.run_dir !== undefined) lines.push(`run_dir = ${tomlEscape(rec.run_dir)}`); + if (rec.note !== undefined) lines.push(`note = ${tomlEscape(rec.note)}`); + lines.push(`recorded = ${tomlEscape(isoNow(now))}`); + lines.push("", "[calib_chain.calibration]"); + lines.push(`source = ${tomlEscape(rec.calibration.source)}`); + lines.push(`pulse_hash = ${tomlEscape(rec.calibration.pulse_hash)}`); + lines.push(`mismatch = ${tomlEscape(rec.calibration.mismatch)}`); + lines.push("", "[calib_chain.pinned_globals]"); + lines.push(...Object.entries(rec.pinned_globals).map(([k, v]) => `${tomlKey(k)} = ${tomlNumber(v)}`)); + if (rec.rebank !== undefined) { + lines.push("", "[calib_chain.rebank]"); + lines.push(`catalog_entry = ${tomlEscape(rec.rebank.catalog_entry)}`); + lines.push("", "[calib_chain.rebank.provenance]"); + lines.push(`warm_start = ${tomlEscape(rec.rebank.provenance.warm_start)}`); + lines.push(`calibration_ref = ${tomlEscape(rec.rebank.provenance.calibration_ref)}`); + lines.push("", "[calib_chain.rebank.provenance.pinned_globals]"); + lines.push( + ...Object.entries(rec.rebank.provenance.pinned_globals).map(([k, v]) => `${tomlKey(k)} = ${tomlNumber(v)}`), + ); + } + return lines.join("\n") + "\n"; +} + /** Platforms with built-in affordances (Hamiltonian LaTeX, defaults). NOT a * closed validation set anymore (spec A opened `platform` to any string) — this * is the hint list for tool descriptions. PLATFORMS kept as an alias for the @@ -1018,6 +1164,7 @@ export function runStubToml(stub: RunStub, now?: Date): string { if (stub.tier !== undefined) lines.push(`tier = ${tomlEscape(stub.tier)}`); if (stub.script_ref !== undefined) lines.push(`script_ref = ${tomlEscape(stub.script_ref)}`); if (stub.env !== undefined) lines.push(`env = ${tomlEscape(stub.env)}`); + if (stub.warm_start !== undefined) lines.push(`warm_start = ${tomlEscape(stub.warm_start)}`); lines.push(`launched_via = ${tomlEscape("bash amico-run")}`); if (stub.note !== undefined) lines.push(`note = ${tomlEscape(stub.note)}`); lines.push(`recorded = ${tomlEscape(isoNow(now))}`); diff --git a/packages/extension/test/calib_chain.test.ts b/packages/extension/test/calib_chain.test.ts new file mode 100644 index 00000000..8cd9df2c --- /dev/null +++ b/packages/extension/test/calib_chain.test.ts @@ -0,0 +1,357 @@ +// SEAM 5 (amicode #681) — the calibrate→pin→re-optimize→re-bank verb chain. +// +// The chain composes EXISTING seams into ONE recorded path: +// 1. calibrate — the mock leg's calibration data source is the SEAM 1 MockSoc +// rehearsal artifact (test/fixtures/mocksoc/ — the cross-seam dependency is +// explicit and the fixture is shared). The hardware leg is structurally +// impossible outside a real-board session: the code path REFUSES (a unit +// test below) — real-board sessions are an enumerated human gate. +// 2. pin — the formulation's calibration_pin constraint (the +// fix_global_variable! path) + solve.pinned_globals (existing entity +// surfaces, no new kinds). +// 3. re-optimize — warm-started from the bank (the load_traj idiom); the +// re-solve launches through the EXISTING solve path (bash amico-run — the +// recording core never launches anything). +// 4. re-bank — the catalog note carries the chain's fingerprint (which +// calibration, which pin, which warm-start seed) via `amico catalog ingest` +// (packages/amico-run — provenance flags tested in that package's suite). +// Promotion is human-gated like all promotions: the chain stages the +// command and only VERIFIES the promoted entry afterwards. +// +// Layers here (mirroring the SEAM 1 test shape): +// 1. entities.ts — the additive [calib_chain] record (leg PINNED mock — the +// record has no hardware variant to lie with; promotion DERIVED by the +// serializer — never caller data). +// 2. calib_chain.ts — the recording core (recordCalibChain / completeCalibChain): +// reads the rehearsal artifact through the SAME reader the tool uses, +// refuses dishonesty by recording NOTHING, writes through the existing +// entities (formulation calibration_pin + pinned_globals, run warm_start) +// + the chain entity + events. +// The plugin wrapper (amicode_tools.ts amicode_calib_chain) is a thin adapter +// over this core, verified against the real binary (night-build), not in vitest. +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { parse } from "smol-toml"; +import { readRehearsalRecord } from "../opencode-plugin/rehearsal"; +import { + calibChainToml, + validateCalibChainRecord, + formulationToml, + type CalibChainRecord, + type FormulationEntity, +} from "../opencode-plugin/entities"; +import { + createProblem, + problemDir, + writeEntityFiles, +} from "../opencode-plugin/problems"; +import { + recordCalibChain, + completeCalibChain, + hardwareLegRefusal, +} from "../opencode-plugin/calib_chain"; + +const REHEARSAL = join(__dirname, "fixtures", "mocksoc", "rehearsal-success.toml"); + +function rehearsalRecord() { + const rr = readRehearsalRecord(REHEARSAL); + if (!rr.ok) throw new Error(`fixture must parse: ${rr.problem}`); + return rr.record; +} + +/** A staged chain built from the SEAM 1 fixture — the shape the recording core + * records after the calibrate + pin + re-optimize legs. */ +function stagedChain(overrides?: Partial): CalibChainRecord { + const reh = rehearsalRecord(); + return { + leg: "mock", + calibration: { + source: REHEARSAL, + pulse_hash: reh.pulse_hash, + mismatch: reh.mismatch, + }, + pinned_globals: { delta: 0.21 }, + warm_start: "transmon-X-v1", + run_dir: "/runs/devlab/r20260901-000000Z-chain", + ...overrides, + }; +} + +describe("calibChainToml — the chain record under [calib_chain]", () => { + it("round-trips a staged chain: leg PINNED mock, promotion DERIVED pending-human-signoff, calibration + pin + seed", () => { + const doc = parse(calibChainToml(stagedChain())) as any; + expect(doc.calib_chain.leg).toBe("mock"); // pinned by the serializer — the record has no hardware variant + expect(doc.calib_chain.promotion).toBe("pending-human-signoff"); // derived, never caller data + expect(doc.calib_chain.warm_start).toBe("transmon-X-v1"); // which warm-start seed + expect(doc.calib_chain.run_dir).toContain("r20260901"); + expect(doc.calib_chain.calibration.source).toMatch(/rehearsal-success\.toml$/); // which calibration + expect(doc.calib_chain.calibration.pulse_hash).toMatch(/^sha256:[0-9a-f]{64}$/); + expect(doc.calib_chain.calibration.mismatch).toContain("delta × 1.05"); + expect(doc.calib_chain.pinned_globals.delta).toBeCloseTo(0.21); // which pin + expect(doc.calib_chain.rebank).toBeUndefined(); // staged — the re-bank leg is absent until the promotion is verified + expect(Number.isNaN(Date.parse(doc.calib_chain.recorded))).toBe(false); + }); + + it("round-trips the rebank leg and flips the DERIVED promotion to human-gated-rebank-recorded (the record still never claims approval)", () => { + const reh = rehearsalRecord(); + const completed = stagedChain({ + rebank: { + catalog_entry: "transmon-X-v2", + provenance: { + warm_start: "transmon-X-v1", + calibration_ref: REHEARSAL, + pinned_globals: { delta: 0.21 }, + }, + }, + }); + const doc = parse(calibChainToml(completed)) as any; + expect(doc.calib_chain.promotion).toBe("human-gated-rebank-recorded"); + expect(doc.calib_chain.rebank.catalog_entry).toBe("transmon-X-v2"); + expect(doc.calib_chain.rebank.provenance.warm_start).toBe("transmon-X-v1"); + expect(doc.calib_chain.rebank.provenance.calibration_ref).toMatch(/rehearsal-success\.toml$/); + expect(doc.calib_chain.rebank.provenance.pinned_globals.delta).toBeCloseTo(0.21); + expect(reh.outcome).toBe("success"); // the fixture is a passed rehearsal (cross-seam sanity) + }); +}); + +describe("validateCalibChainRecord", () => { + it("accepts the staged shape ([] problems)", () => { + expect(validateCalibChainRecord(stagedChain())).toEqual([]); + }); + + it("refuses a leg other than mock — the hardware leg is not a recordable variant", () => { + const problems = validateCalibChainRecord(stagedChain({ leg: "hardware" as any })); + expect(problems.join(" ")).toMatch(/mock|hardware/i); + }); + + it("refuses an empty pin set, a bad pulse hash, and an empty warm-start seed", () => { + expect(validateCalibChainRecord(stagedChain({ pinned_globals: {} }))[0]).toMatch(/pinned_globals/); + expect( + validateCalibChainRecord( + stagedChain({ calibration: { source: REHEARSAL, pulse_hash: "not-a-hash", mismatch: "delta × 1.05" } }), + )[0], + ).toMatch(/pulse_hash/); + expect(validateCalibChainRecord(stagedChain({ warm_start: "" }))[0]).toMatch(/warm_start/); + }); +}); + +// ── the recording core (opencode-plugin/calib_chain.ts) ───────────────────────── +// The SAME core the amicode_calib_chain tool drives; the slow e2e (test/slow) +// drives it end-to-end against the real solve + rehearsal + catalog ingests. + +const FORM: FormulationEntity = { + trajectory_type: "gate", + time_mode: "fixed", + parameterization: "smooth", + robustness: { kind: "none", params: {} }, + free_phase: false, + leakage: false, + target: "X", + objectives: [], + constraints: [{ kind: "bounds", params: {}, label: "amplitude bound (drive_max)" }], +}; + +/** Fresh problem workspace with a system + formulation pre-recorded (the chain + * pins onto the RECORDED formulation — no formulation, no chain). */ +function freshWorkspace(): string { + const root = mkdtempSync(join(tmpdir(), "calib-chain-")); + process.env.AMICODE_PROBLEMS_DIR = root; + const meta = createProblem("chain test"); + const dir = problemDir(meta.slug); + const sys = { platform: "transmon", components: [{ id: "q1", role: "qubit", levels: 3, params: { omega: 4.8, delta: 0.2 } }], couplings: [], drive: { arch: "per-component" } }; + writeEntityFiles(meta.slug, "system", "x\n", JSON.stringify(sys) + "\n"); + writeEntityFiles(meta.slug, "formulation", formulationToml(FORM), JSON.stringify(FORM) + "\n"); + return meta.slug; +} + +function readEvents(slug: string): Record[] { + const f = join(problemDir(slug), "events.jsonl"); + if (!existsSync(f)) return []; + return readFileSync(f, "utf8").split("\n").filter((l) => l.trim() !== "").map((l) => JSON.parse(l)); +} + +describe("recordCalibChain — the chain's staging (calibrate + pin + re-optimize legs)", () => { + const prevProblems = process.env.AMICODE_PROBLEMS_DIR; + + afterEach(() => { + if (prevProblems === undefined) delete process.env.AMICODE_PROBLEMS_DIR; + else process.env.AMICODE_PROBLEMS_DIR = prevProblems; + }); + + it("stages through the EXISTING entities: formulation gains the calibration_pin constraint + solve.pinned_globals, the run stub gains warm_start, the chain entity + events express the chain", () => { + const slug = freshWorkspace(); + const res = recordCalibChain({ + slug, + leg: "mock", + rehearsalRef: REHEARSAL, + pinned: { delta: 0.21 }, + warmStart: "transmon-X-v1", + runDir: "/runs/devlab/r20260901-000000Z-chain", + }); + if (!res.ok) throw new Error(`expected ok, got: ${res.problem}`); + // leg 2 — the pin rides the EXISTING formulation surfaces (calibration_pin + // constraint with the calibrated VALUES, solve.pinned_globals with the + // NAMES — the fix_global_variable! path's recorded halves). + const form = parse(readFileSync(join(problemDir(slug), "entities", "formulation.toml"), "utf8")) as any; + const pin = form.formulation.constraints.find((c: any) => c.kind === "calibration_pin"); + expect(pin).toBeDefined(); + expect(pin.params.delta).toBeCloseTo(0.21); + expect(form.formulation.solve.pinned_globals).toEqual(["delta"]); + // leg 3 — the re-optimize rides the run stub (warm_start, additive). + const run = parse(readFileSync(join(problemDir(slug), "entities", "run.toml"), "utf8")) as any; + expect(run.run.warm_start).toBe("transmon-X-v1"); + expect(run.run.run_dir).toContain("r20260901"); + // the chain entity — the fingerprint. + const chain = parse(readFileSync(join(problemDir(slug), "entities", "calib_chain.toml"), "utf8")) as any; + expect(chain.calib_chain.warm_start).toBe("transmon-X-v1"); + expect(chain.calib_chain.pinned_globals.delta).toBeCloseTo(0.21); + expect(chain.calib_chain.calibration.pulse_hash).toMatch(/^sha256:[0-9a-f]{64}$/); + expect(chain.calib_chain.promotion).toBe("pending-human-signoff"); + // events express the chain (the provenance spine). + const events = readEvents(slug); + const kinds = events.map((e) => `${e.entity}:${e.action}`); + expect(kinds).toContain("formulation:updated"); + expect(kinds).toContain("run:created"); + expect(kinds).toContain("calib_chain:created"); + }); + + it("re-staging replaces the prior calibration_pin (idempotent pin, not a growing constraint set)", () => { + const slug = freshWorkspace(); + for (const delta of [0.21, 0.205]) { + const res = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta }, warmStart: "transmon-X-v1" }); + if (!res.ok) throw new Error(res.problem); + } + const form = parse(readFileSync(join(problemDir(slug), "entities", "formulation.toml"), "utf8")) as any; + const pins = form.formulation.constraints.filter((c: any) => c.kind === "calibration_pin"); + expect(pins).toHaveLength(1); + expect(pins[0].params.delta).toBeCloseTo(0.205); + }); + + it("the hardware leg is structurally refused — the refusal names the enumerated human gate and records NOTHING", () => { + const slug = freshWorkspace(); + const res = recordCalibChain({ slug, leg: "hardware", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + expect(res.ok).toBe(false); + if (res.ok) return; + expect(res.problem).toMatch(/real-board session/i); // the enumerated human gate + expect(hardwareLegRefusal()).toMatch(/real-board session/i); + // nothing recorded — no entity, no event, and the formulation untouched. + expect(existsSync(join(problemDir(slug), "entities", "calib_chain.toml"))).toBe(false); + expect(readEvents(slug).filter((e) => e.entity === "calib_chain")).toHaveLength(0); + const form = parse(readFileSync(join(problemDir(slug), "entities", "formulation.toml"), "utf8")) as any; + expect(form.formulation.constraints.some((c: any) => c.kind === "calibration_pin")).toBe(false); + }); + + it("refuses a dishonest calibration artifact through the SEAM 1 reader — nothing recorded", () => { + const slug = freshWorkspace(); + const dir = mkdtempSync(join(tmpdir(), "calib-chain-badart-")); + const bad = join(dir, "rehearsal.toml"); + writeFileSync(bad, readFileSync(REHEARSAL, "utf8").replace("sim = true", "sim = false")); + const res = recordCalibChain({ slug, leg: "mock", rehearsalRef: bad, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + expect(res.ok).toBe(false); + if (!res.ok) expect(res.problem).toMatch(/sim/i); + expect(existsSync(join(problemDir(slug), "entities", "calib_chain.toml"))).toBe(false); + rmSync(dir, { recursive: true, force: true }); + }); + + it("refuses honestly when no formulation is recorded (the chain pins onto the recorded formulation)", () => { + const slug = freshWorkspace(); + rmSync(join(problemDir(slug), "entities", "formulation.toml")); + rmSync(join(problemDir(slug), "entities", "formulation.json")); + const res = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + expect(res.ok).toBe(false); + if (!res.ok) expect(res.problem).toMatch(/formulation/i); + }); + + it("stages the human-gated re-bank command with the chain's provenance flags (the promotion the chain never performs)", () => { + const slug = freshWorkspace(); + const res = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + if (!res.ok) throw new Error(res.problem); + expect(res.staged.rebankCommand).toContain("amico catalog ingest"); + expect(res.staged.rebankCommand).toContain("--platform transmon"); // from the recorded system + expect(res.staged.rebankCommand).toContain("--kind X"); // from the recorded formulation target + expect(res.staged.rebankCommand).toContain("--warm-start transmon-X-v1"); // which seed + expect(res.staged.rebankCommand).toContain("--calibration-ref"); // which calibration + expect(res.staged.rebankCommand).toContain("--pin delta=0.21"); // which pin + expect(res.staged.humanGate).toMatch(/sign-off|human/i); // promotion is human-gated like all promotions + }); +}); + +describe("completeCalibChain — the verified re-bank leg (the execution record)", () => { + const prevProblems = process.env.AMICODE_PROBLEMS_DIR; + + afterEach(() => { + if (prevProblems === undefined) delete process.env.AMICODE_PROBLEMS_DIR; + else process.env.AMICODE_PROBLEMS_DIR = prevProblems; + }); + + /** A catalog entry's metadata.toml carrying the chain's fingerprint — the + * shape `amico catalog ingest --warm-start/--calibration-ref/--pin` writes + * (the amico-run suite round-trips those flags; here the plugin side only + * READS it). */ + function fakeCatalogEntry(root: string, id: string, provenance: { warm_start?: string; calibration_ref?: string; pinned_globals?: Record }): string { + const dir = join(root, "pulses", id); + mkdirSync(dir, { recursive: true }); + const lines = ["schema_version = 1", `id = ${JSON.stringify(id)}`, 'platform = "transmon"', 'gate = "X"', "fidelity = 0.9999"]; + if (provenance.warm_start !== undefined) lines.push(`warm_start = ${JSON.stringify(provenance.warm_start)}`); + if (provenance.calibration_ref !== undefined) lines.push(`calibration_ref = ${JSON.stringify(provenance.calibration_ref)}`); + if (provenance.pinned_globals !== undefined) { + const inner = Object.entries(provenance.pinned_globals).map(([k, v]) => `${k} = ${v}`).join(", "); + lines.push(`pinned_globals = { ${inner} }`); + } + writeFileSync(join(dir, "metadata.toml"), lines.join("\n") + "\n"); + return join(dir, "metadata.toml"); + } + + it("refuses a staged chain (no promoted entry to verify) — nothing recorded, promotion stays pending", () => { + const slug = freshWorkspace(); + const stage = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + if (!stage.ok) throw new Error(stage.problem); + const res = completeCalibChain({ slug, rebankMetadataRef: "/nowhere/metadata.toml" }); + expect(res.ok).toBe(false); + if (!res.ok) expect(res.problem).toMatch(/human|sign-off|metadata/i); + expect(readEvents(slug).some((e) => e.action === "executed_on_mock")).toBe(false); + }); + + it("refuses a mismatched fingerprint — the re-bank must carry THIS chain's provenance (which calibration, which pin, which seed)", () => { + const slug = freshWorkspace(); + const stage = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + if (!stage.ok) throw new Error(stage.problem); + const root = mkdtempSync(join(tmpdir(), "calib-chain-cat-")); + // wrong seed in the note + const wrongSeed = fakeCatalogEntry(root, "transmon-X-v2", { warm_start: "other-v9", calibration_ref: REHEARSAL, pinned_globals: { delta: 0.21 } }); + const res1 = completeCalibChain({ slug, rebankMetadataRef: wrongSeed }); + expect(res1.ok).toBe(false); + // wrong pin in the note + const wrongPin = fakeCatalogEntry(root, "transmon-X-v2", { warm_start: "transmon-X-v1", calibration_ref: REHEARSAL, pinned_globals: { delta: 0.5 } }); + const res2 = completeCalibChain({ slug, rebankMetadataRef: wrongPin }); + expect(res2.ok).toBe(false); + // missing calibration ref + const noCal = fakeCatalogEntry(root, "transmon-X-v2", { warm_start: "transmon-X-v1", pinned_globals: { delta: 0.21 } }); + const res3 = completeCalibChain({ slug, rebankMetadataRef: noCal }); + expect(res3.ok).toBe(false); + expect(readEvents(slug).some((e) => e.action === "executed_on_mock")).toBe(false); + rmSync(root, { recursive: true, force: true }); + }); + + it("records the verified re-bank: the executed_on_mock event (the countable execution record) + the fingerprint in the chain entity", () => { + const slug = freshWorkspace(); + const stage = recordCalibChain({ slug, leg: "mock", rehearsalRef: REHEARSAL, pinned: { delta: 0.21 }, warmStart: "transmon-X-v1" }); + if (!stage.ok) throw new Error(stage.problem); + const root = mkdtempSync(join(tmpdir(), "calib-chain-cat-")); + const meta = fakeCatalogEntry(root, "transmon-X-v2", { warm_start: "transmon-X-v1", calibration_ref: REHEARSAL, pinned_globals: { delta: 0.21 } }); + const res = completeCalibChain({ slug, rebankMetadataRef: meta }); + if (!res.ok) throw new Error(res.problem); + expect(res.executed_on_mock).toBe(true); + const events = readEvents(slug); + const executed = events.filter((e) => e.action === "executed_on_mock"); + expect(executed).toHaveLength(1); // calib_pin_reopt_chain_executed_on_mock == 1 + expect(executed[0].entity).toBe("calib_chain"); + const chain = parse(readFileSync(join(problemDir(slug), "entities", "calib_chain.toml"), "utf8")) as any; + expect(chain.calib_chain.promotion).toBe("human-gated-rebank-recorded"); + expect(chain.calib_chain.rebank.catalog_entry).toBe("transmon-X-v2"); + expect(chain.calib_chain.rebank.provenance.pinned_globals.delta).toBeCloseTo(0.21); + rmSync(root, { recursive: true, force: true }); + }); +}); diff --git a/packages/extension/test/calib_chain_imports.test.ts b/packages/extension/test/calib_chain_imports.test.ts new file mode 100644 index 00000000..da66af4e --- /dev/null +++ b/packages/extension/test/calib_chain_imports.test.ts @@ -0,0 +1,62 @@ +// SEAM 5 (amicode #681) — the chain's structural invariants, made mechanical +// (the mocksoc_imports.test.ts pattern): +// +// `chain_promotion_never_a_plugin_write == 1` (AC: the chain's promotion is +// human-gated like all promotions). The recording path (calib_chain.ts — +// the same core the amicode_calib_chain tool drives) must have NO catalog +// discovery and NO direct filesystem write: it can never find the catalog on +// its own (so it can never write an entry), and every workspace write goes +// through the provenance-spine helpers (writeEntityFiles/appendEvent), whose +// only writer surface is the problem workspace. The promotion happens +// out-of-band via the human-gated `amico catalog ingest`; the chain only +// READS the promoted entry afterwards (an explicit metadata path). +// +// `chain_hardware_leg_refusal_is_the_only_path == 1` (AC: the hardware leg is +// structurally impossible outside a real-board session). The record type has +// exactly one leg variant ("mock" — entities.ts pins it), and the recording +// path's only other leg is the REFUSAL that names the enumerated human gate. +import { describe, it, expect } from "vitest"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const CORE = join(__dirname, "..", "opencode-plugin", "calib_chain.ts"); +const ENTITIES = join(__dirname, "..", "opencode-plugin", "entities.ts"); + +describe("chain recording path — the promotion invariant (structural scan)", () => { + const src = readFileSync(CORE, "utf8"); + + it("never discovers the catalog — no AMICO_CATALOG_DIR, no catalogPulsesDir (the promotion runs out-of-band, human-gated)", () => { + expect(src).not.toMatch(/AMICO_CATALOG_DIR/); + expect(src).not.toMatch(/catalogPulsesDir/); + expect(src).not.toMatch(/armonissima/); + }); + + it("performs no direct filesystem WRITE — every workspace write rides the provenance-spine helpers", () => { + // writeEntityFiles / appendEvent (problems.ts) are the ONLY write surface; + // a direct fs write here would bypass the diff/hash/event spine. + const offenders = src + .split("\n") + .map((l, i) => [i + 1, l] as const) + .filter(([, l]) => /fs\.(write|append|mkdir|rename|copy|rm|unlink)Sync/.test(l)); + expect(offenders, `direct fs writes in the chain core: ${JSON.stringify(offenders)}`).toEqual([]); + }); + + it("reads the promoted entry only through the caller-given metadata path (read-only verify)", () => { + // The single catalog touch: completeCalibChain's read of the explicit + // rebankMetadataRef. readFileSync appears once, in readCatalogMetadata. + const reads = src.split("\n").filter((l) => /fs\.readFileSync/.test(l)); + expect(reads.length).toBe(2); // readEntityJson + readCatalogMetadata — both read-only + expect(src).toMatch(/rebankMetadataRef/); + }); +}); + +describe("chain record type — the leg invariant (structural scan)", () => { + it("the record has exactly one leg variant: mock (the hardware leg is a refusal, never a record variant)", () => { + const entities = readFileSync(ENTITIES, "utf8"); + expect(entities).toMatch(/leg: "mock"/); + // the validator refuses anything else — the structural refusal + expect(entities).toMatch(/leg must be "mock"/); + // and the refusal path names the enumerated human gate + expect(readFileSync(CORE, "utf8")).toMatch(/real-board session/); + }); +}); diff --git a/packages/extension/test/slow/calib_chain.test.ts b/packages/extension/test/slow/calib_chain.test.ts new file mode 100644 index 00000000..b7f99ac2 --- /dev/null +++ b/packages/extension/test/slow/calib_chain.test.ts @@ -0,0 +1,259 @@ +// SEAM 5 (amicode #681) — the calibrate→pin→re-optimize→re-bank chain, executed +// END-TO-END on mock. Env-gated exactly like the SEAM 1 slow lane (Julia is NOT +// a vitest prerequisite — the fast suite runs without it): +// +// AMICO_TEST_JULIA_PROJECT the provisioned solve env (Piccolo ~1.19) — +// produces the real pulses via amico-run +// AMICO_TEST_REHEARSAL_PROJECT the rehearsal env (templates/mocksoc-rehearsal/ +// — Strumento 0.3 + Intonato 0.4 + Piccolo 2.1; +// instantiate once) +// AMICO_TEST_JULIA_BIN optional julia override (default: PATH's julia) +// +// The chain, leg by leg — every leg through its ESTABLISHED invocation: +// 1. solve A (the template, an under-converged cold start at max_iter=15 — +// the bank's incumbent-to-be), via amico-run. +// 2. BANK A: `amico catalog ingest` into a temp catalog (the test STANDS IN +// for the researcher's sign-off — promotions are human-gated like all +// promotions; nothing here relaxes that). +// 3. CALIBRATE: the SEAM 1 MockSoc rehearsal runs banked pulse A through the +// actual Strumento transport path — its "delta × 1.05" mismatch is the +// calibration data → the pin δ=0.21 (the agent's derivation, recorded). +// 4. PIN + seed: recordCalibChain stages the chain (the calibration_pin +// constraint lands on the formulation; the run stub carries the seed). +// 5. RE-OPTIMIZE: a warm-started re-solve (the load_traj idiom, seeded from +// the BANK's copy of pulse A; the pinned δ=0.21 in the FILL IN block) via +// amico-run — the existing solve path, no new tier. +// 6. RE-BANK: the EXACT command the chain staged, run through the real +// `amico catalog ingest` (again the human-gate stand-in) — the promoted +// entry's catalog note carries the fingerprint (which calibration, which +// pin, which seed). +// 7. COMPLETE: completeCalibChain verifies the fingerprint and appends the +// `executed_on_mock` event — `calib_pin_reopt_chain_executed_on_mock == 1` +// is an EXECUTION RECORD (this run of this test is that record's proof). +import { describe, it, expect, beforeAll, afterAll } from "vitest"; +import { execFileSync } from "node:child_process"; +import { mkdtempSync, rmSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { parse } from "smol-toml"; + +import { readRehearsalRecord } from "../../opencode-plugin/rehearsal"; +import { formulationToml, type FormulationEntity } from "../../opencode-plugin/entities"; +import { createProblem, problemDir, writeEntityFiles } from "../../opencode-plugin/problems"; +import { recordCalibChain, completeCalibChain } from "../../opencode-plugin/calib_chain"; + +const SOLVE_PROJECT = process.env.AMICO_TEST_JULIA_PROJECT; +const REHEARSAL_PROJECT = process.env.AMICO_TEST_REHEARSAL_PROJECT; +const JULIA = process.env.AMICO_TEST_JULIA_BIN ?? "julia"; +const AMICO_RUN_PKG = join(__dirname, "..", "..", "..", "amico-run"); +const RUN_BIN = join(AMICO_RUN_PKG, "dist", "amico-run.js"); // β.1 bundle (solve launch) +const AMICO_BIN = join(AMICO_RUN_PKG, "dist", "amico.js"); // the verb router (catalog ingest) +const TEMPLATE = join(__dirname, "..", "..", "templates", "solve_template.jl"); +const REHEARSAL_SCRIPT = join(__dirname, "..", "..", "templates", "mocksoc_rehearsal.jl"); + +/** Generate a solve script from the vetted template by editing ONLY the FILL IN + * block + the init lines — the sanctioned edit surfaces (no new physics, no + * new tier; the template is the vetted artifact). */ +function solveScript(root: string, name: string, edits: [string, string][]): string { + let src = readFileSync(TEMPLATE, "utf8"); + for (const [from, to] of edits) { + if (!src.includes(from)) throw new Error(`template edit anchor missing: ${from}`); + src = src.replace(from, to); + } + const p = join(root, name); + writeFileSync(p, src); + return p; +} + +describe.skipIf(!(SOLVE_PROJECT && REHEARSAL_PROJECT))( + "slow: the calibrate→pin→re-optimize chain on mock (SEAM 5 — executed end-to-end)", + () => { + const prevProblemsDir = process.env.AMICODE_PROBLEMS_DIR; + let root: string; + let slug: string; + + beforeAll(() => { + execFileSync("node", [join(AMICO_RUN_PKG, "esbuild.config.mjs")], { cwd: AMICO_RUN_PKG }); + }); + + afterAll(() => { + if (prevProblemsDir === undefined) delete process.env.AMICODE_PROBLEMS_DIR; + else process.env.AMICODE_PROBLEMS_DIR = prevProblemsDir; + if (root && !process.env.AMICO_DEBUG_KEEP_DIR) rmSync(root, { recursive: true, force: true }); + }); + + it( + "calibrate (rehearsal) → pin → re-optimize (warm-started) → re-bank (provenanced) → executed_on_mock", + { timeout: 1_800_000 }, + async () => { + root = mkdtempSync(join(tmpdir(), "calib-chain-e2e-")); + const problemsRoot = join(root, "problems"); + const catalogRoot = join(root, "catalog", "pulses"); + const runsRoot = join(root, "runs"); + process.env.AMICODE_PROBLEMS_DIR = problemsRoot; + + // ── leg 0 — solve A: the bank's incumbent-to-be (deliberately + // under-converged cold start, so the warm-started re-solve can beat it). + const scriptA = solveScript(root, "solve_A.jl", [["max_iter = 60", "max_iter = 15"]]); + const outA = execFileSync( + "node", + [RUN_BIN, scriptA, "--runs-root", runsRoot, "--project", SOLVE_PROJECT!, "--lab", "devlab"], + { encoding: "utf8", timeout: 900_000 }, + ); + expect(outA).toMatch(/AMICODE_FINISHED status=completed/); + const runDirA = outA.match(/AMICODE_FINISHED .*runDir=(.+)/)![1].trim(); + const pulseA = join(runDirA, "pulse.jld2"); + const resultA = parse(readFileSync(join(runDirA, "result.toml"), "utf8")) as any; + expect(existsSync(pulseA)).toBe(true); + + // ── BANK A — the day-one bank (the test stands in for the researcher's + // sign-off; the human gate is the point, not an obstacle). + const ingestEnv = { ...process.env, AMICO_CATALOG_DIR: catalogRoot }; + const bankA = execFileSync( + "node", + [AMICO_BIN, "catalog", "ingest", "--platform", "transmon", "--kind", "X", "--from-run", runDirA, "--agree", "true"], + { encoding: "utf8", env: ingestEnv, timeout: 60_000 }, + ); + expect(JSON.parse(bankA).promoted).toBe(true); + const seedId = JSON.parse(bankA).id; // transmon-X-v1 + + // ── leg 1 — CALIBRATE: the SEAM 1 rehearsal is the calibration data source. + const rehearsalDir = join(root, "rehearsal"); + const rehOut = execFileSync( + JULIA, + ["--startup-file=no", `--project=${REHEARSAL_PROJECT}`, REHEARSAL_SCRIPT, pulseA, join(runDirA, "result.toml"), rehearsalDir], + { encoding: "utf8", timeout: 900_000 }, + ); + expect(rehOut).toMatch(/REHEARSAL outcome=success/); + const rehearsalArtifact = join(rehearsalDir, "rehearsal.toml"); + const rr = readRehearsalRecord(rehearsalArtifact); + expect(rr.ok).toBe(true); + if (!rr.ok) throw new Error(rr.problem); + expect(rr.record.mismatch).toMatch(/delta × 1\.05/); // the mock truth — the calibration's evidence + + // ── leg 2+3 — PIN + seed: stage the chain (the recording path). + slug = createProblem("calib-chain-e2e").slug; + const dir = problemDir(slug); + const sys = { + platform: "transmon", + components: [{ id: "q1", role: "qubit", levels: 3, params: { omega: 4.8, delta: 0.2 } }], + couplings: [], + drive: { arch: "per-component" }, + }; + writeEntityFiles(slug, "system", "x\n", JSON.stringify(sys) + "\n"); + const form: FormulationEntity = { + trajectory_type: "gate", + time_mode: "fixed", + parameterization: "smooth", + robustness: { kind: "none", params: {} }, + free_phase: false, + leakage: false, + target: "X", + objectives: [], + constraints: [{ kind: "bounds", params: {}, label: "amplitude bound (drive_max)" }], + }; + writeEntityFiles(slug, "formulation", formulationToml(form), JSON.stringify(form) + "\n"); + + const stage1 = recordCalibChain({ + slug, + leg: "mock", + rehearsalRef: rehearsalArtifact, + pinned: { delta: 0.21 }, // 0.2 nominal × the rehearsal's declared 1.05 mismatch + warmStart: seedId, + }); + expect(stage1.ok).toBe(true); + if (!stage1.ok) throw new Error(stage1.problem); + + // ── leg 3 — RE-OPTIMIZE: the warm-started re-solve (the load_traj idiom, + // seeded from the BANK's copy of pulse A; the pin made real: δ=0.21). + const bankedSeed = join(catalogRoot, seedId, "pulse.jld2"); + expect(existsSync(bankedSeed)).toBe(true); + const scriptB = solveScript(root, "solve_B.jl", [ + ["δ = 0.2", "δ = 0.21"], + [ + "initial = 0.1 * randn(sys.n_drives, N)\nqtraj = UnitaryTrajectory(sys, ZeroOrderPulse(initial, times), op)", + `warm = load_traj("${bankedSeed}") # the banked pulse, re-wrapped for THIS problem: +qtraj = UnitaryTrajectory(sys, ZeroOrderPulse(warm), op)`, + ], + ]); + const outB = execFileSync( + "node", + [RUN_BIN, scriptB, "--runs-root", runsRoot, "--project", SOLVE_PROJECT!, "--lab", "devlab"], + { encoding: "utf8", timeout: 900_000 }, + ); + expect(outB).toMatch(/AMICODE_FINISHED status=completed/); + const runDirB = outB.match(/AMICODE_FINISHED .*runDir=(.+)/)![1].trim(); + const resultB = parse(readFileSync(join(runDirB, "result.toml"), "utf8")) as any; + expect(resultB.fidelity).toBeGreaterThan(resultA.fidelity); // the warm-started re-solve improved on the bank + + // re-stage with the re-solve's run dir — the chain's staged re-bank command goes concrete. + const stage2 = recordCalibChain({ + slug, + leg: "mock", + rehearsalRef: rehearsalArtifact, + pinned: { delta: 0.21 }, + warmStart: seedId, + runDir: runDirB, + }); + expect(stage2.ok).toBe(true); + if (!stage2.ok) throw new Error(stage2.problem); + expect(stage2.staged.rebankCommand).toContain(`--from-run ${runDirB}`); + expect(stage2.staged.rebankCommand).toContain(`--calibration-ref ${rehearsalArtifact}`); + expect(stage2.staged.rebankCommand).toContain("--pin delta=0.21"); + expect(stage2.staged.rebankCommand).toContain(`--warm-start ${seedId}`); + + // ── leg 4 — RE-BANK: the EXACT staged command, run through the real + // catalog ingest (the human-gate stand-in again). The promoted entry's + // note must carry the chain's fingerprint. + const stagedArgs = stage2.staged.rebankCommand.split(/\s+/).slice(3); // "amico catalog ingest …" → args after the verb + const bankB = execFileSync( + "node", + [AMICO_BIN, "catalog", "ingest", ...stagedArgs, "--agree", "true"], + { encoding: "utf8", env: ingestEnv, timeout: 60_000 }, + ); + const banked = JSON.parse(bankB); + expect(banked.promoted).toBe(true); // beats the incumbent — the Version rule + const rebankId = banked.id; // transmon-X-v2 + const metaFile = join(catalogRoot, rebankId, "metadata.toml"); + const meta = parse(readFileSync(metaFile, "utf8")) as any; + expect(meta.warm_start).toBe(seedId); // which seed + expect(meta.calibration_ref).toBe(rehearsalArtifact); // which calibration + expect(meta.pinned_globals).toEqual({ delta: 0.21 }); // which pin + + // ── COMPLETE: verify the fingerprint, land the execution record. + const done = completeCalibChain({ slug, rebankMetadataRef: metaFile }); + expect(done.ok).toBe(true); + if (!done.ok) throw new Error(done.problem); + expect(done.executed_on_mock).toBe(true); + + // ── the assertions — entities + events express the chain, and the + // execution record is COUNTABLE (== 1, not a schema). + const events = readFileSync(join(dir, "events.jsonl"), "utf8") + .split("\n") + .filter((l) => l.trim() !== "") + .map((l) => JSON.parse(l)); + const executed = events.filter((e) => e.entity === "calib_chain" && e.action === "executed_on_mock"); + expect(executed).toHaveLength(1); // calib_pin_reopt_chain_executed_on_mock == 1 + const kinds = events.map((e) => `${e.entity}:${e.action}`); + expect(kinds).toContain("formulation:updated"); // the pin (existing entity) + expect(kinds).toContain("run:updated"); // the warm-start seed (existing entity) + expect(kinds).toContain("calib_chain:updated"); + + const formAfter = parse(readFileSync(join(dir, "entities", "formulation.toml"), "utf8")) as any; + const pin = formAfter.formulation.constraints.find((c: any) => c.kind === "calibration_pin"); + expect(pin.params.delta).toBeCloseTo(0.21); + expect(formAfter.formulation.solve.pinned_globals).toEqual(["delta"]); + + const runAfter = parse(readFileSync(join(dir, "entities", "run.toml"), "utf8")) as any; + expect(runAfter.run.warm_start).toBe(seedId); + expect(runAfter.run.run_dir).toBe(runDirB); + + const chain = parse(readFileSync(join(dir, "entities", "calib_chain.toml"), "utf8")) as any; + expect(chain.calib_chain.promotion).toBe("human-gated-rebank-recorded"); + expect(chain.calib_chain.rebank.catalog_entry).toBe(rebankId); + expect(chain.calib_chain.rebank.provenance.pinned_globals.delta).toBeCloseTo(0.21); + expect(chain.calib_chain.calibration.source).toBe(rehearsalArtifact); + }, + ); + }, +);