Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions packages/amico-run/esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import { build } from "esbuild";
import { chmodSync } from "node:fs";

await build({
entryPoints: ["src/cli.ts"],
const common = {
bundle: true,
platform: "node",
target: "node20",
// ESM, not CJS: the package is "type": "module", so node executes dist/amico-run.js
// ESM, not CJS: the package is "type": "module", so node executes the bundles
// as ESM — a CJS bundle would die on `require is not defined in ES module scope`.
format: "esm",
outfile: "dist/amico-run.js",
banner: { js: "#!/usr/bin/env node" },
sourcemap: true,
logLevel: "info",
};

await build({
...common,
entryPoints: ["src/cli.ts"],
outfile: "dist/amico-run.js",
banner: { js: "#!/usr/bin/env node" },
});
chmodSync("dist/amico-run.js", 0o755);

// Harness-reframe prototype demo (amicode#109, slice B4): bundles the harness
// driver + its deterministic fake experimenter leaf so `demo:harness` runs one
// iteration end-to-end with NO LLM and NO Julia. It shells out to the sibling
// dist/amico-run.js built above.
await build({
...common,
entryPoints: ["harness-demo/run_demo.ts"],
outfile: "dist/harness-demo.js",
banner: { js: "#!/usr/bin/env node" },
});
chmodSync("dist/harness-demo.js", 0o755);
124 changes: 124 additions & 0 deletions packages/amico-run/harness-demo/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Deterministic fixtures for the harness-reframe prototype (amicode#109, B4).
// Shared by the runnable demo (run_demo.ts) and the test
// (test/experiment_iteration.test.ts). The whole point: the experimenter leaf
// and the re-rollout harness are FAKES, so the CONTROL FLOW is exercised with NO
// model and NO Julia — proving the iteration runs without an LLM orchestrator.
import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { maskedHash } from "../src/baseline.js";
import type { ExperimenterDispatch } from "../src/harness/index.js";

/** The exemplar the (fake) experimenter leaf splices — a minimal Piccolo script
* with the template convention's default fill-point markers. */
export const EXEMPLAR_SCRIPT =
`using Piccolo\n` +
`using JLD2, TOML\n` +
`# ── FILL IN ──────\n` +
`T = 10.0\n` +
`# ─────────────────\n` +
`# (a real leaf would build + serialize system_verify.jld2 here)\n` +
`solve()\n`;

export interface FakeEnv {
juliaBin: string;
verifyHarness: string;
authoringFile: string;
/** Env for the amico-run CLI child (authoring path + verify runner). */
env: Record<string, string>;
/** The deterministic experimenter leaf — a plain function, NOT an LLM. */
dispatchExperimenter: ExperimenterDispatch;
exemplarId: string;
}

function writeExec(dir: string, name: string, body: string): string {
const p = join(dir, name);
writeFileSync(p, `#!/usr/bin/env node\n${body}\n`);
chmodSync(p, 0o755);
return p;
}

/**
* Build a deterministic environment for one harness iteration:
* - a fake `julia` that writes result.toml into the run dir and exits 0;
* - a fake re-rollout harness that writes verification.toml with the requested
* `agree` (stands in for the VETTED Julia harness — the trust anchor);
* - the authoring.json the CLI gate + verify read;
* - a matching tier-2 exemplars index so the composed launch gate passes.
* The returned `dispatchExperimenter` authors the exemplar with an inside-fill-
* point edit — a pure function so the loop has no model in it.
*/
export function setupFakeIterationEnv(dir: string, opts: { agree: boolean } = { agree: true }): FakeEnv {
mkdirSync(dir, { recursive: true });
const exemplarId = "demo-cz";

const juliaBin = writeExec(
dir,
"fake-julia",
`const fs=require('fs');\n` +
`fs.writeFileSync('result.toml','schema_version = "1"\\nfidelity = 0.9995\\niterations = 42\\n');\n` +
`console.log('AMICODE_ITER iter=1 f=0.5');\n` +
`console.log('DONE f=0.9995');`,
);

// Run by the CLI as `node <harness> <runDir> <tol>` (AMICO_VERIFY_RUNNER=node),
// so argv[2] is the run dir.
const verifyHarness = writeExec(
dir,
"fake-verify.js",
`const fs=require('fs'),p=require('path');\n` +
`const runDir=process.argv[2];\n` +
`fs.writeFileSync(p.join(runDir,'verification.toml'),\n` +
` 'schema_version = "1"\\nagree = ${opts.agree}\\nfidelity_rerolled = 0.9994\\n' +\n` +
` 'fidelity_reported = 0.9995\\ntolerance = 0.01\\nintegrator = "fake"\\n');`,
);

// exemplars index — baseline hash of the UNEDITED exemplar (masked outside its fill points).
const exemplarsIndex = join(dir, "exemplars-index.json");
writeFileSync(
exemplarsIndex,
JSON.stringify({
schema_version: 1,
exemplars: [
{
id: exemplarId,
platform: "rydberg",
kind: "gate_synthesis",
size: 2,
path: `${exemplarId}/script.jl`,
packages: ["Piccolo", "JLD2", "TOML"],
baseline_hash: maskedHash(EXEMPLAR_SCRIPT),
},
],
}),
);

const authoringFile = join(dir, "authoring.json");
writeFileSync(
authoringFile,
JSON.stringify({
schema_version: 1,
allowlist: ["Piccolo", "Legato"],
support_set: ["JLD2", "CairoMakie", "TOML", "Printf"],
exemplars: exemplarsIndex,
verify_harness: verifyHarness,
verify_tolerance: 0.01,
}),
);

// The deterministic experimenter leaf. In production this is
// `opencode run --agent experimenter` (headless, flat); here it is a function.
const dispatchExperimenter: ExperimenterDispatch = async (_target, ctx) => {
const scriptPath = join(ctx.workdir, "solve.jl");
writeFileSync(scriptPath, EXEMPLAR_SCRIPT.replace("T = 10.0", "T = 25.0"));
return { scriptPath, note: "spliced T=25.0 into demo-cz (fake leaf, no LLM)" };
};

return {
juliaBin,
verifyHarness,
authoringFile,
env: { AMICO_AUTHORING_FILE: authoringFile, AMICO_VERIFY_RUNNER: "node" },
dispatchExperimenter,
exemplarId,
};
}
93 changes: 93 additions & 0 deletions packages/amico-run/harness-demo/run_demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Runnable demo of the harness-reframe prototype (amicode#109, slice B4).
//
// pnpm --filter @amicode/amico-run build
// pnpm --filter @amicode/amico-run demo:harness
//
// Runs ONE experiment iteration driven entirely by code + data (an iteration
// score) — NO LLM in the control-flow loop and NO Julia. The experimenter leaf
// and the re-rollout harness are deterministic fakes; what is exercised is the
// deterministic control flow that replaces the 1117-line orchestrator prompt:
// select target → dispatch one flat leaf → launch via amico-run → tier-2
// re-rollout verify → record + gate promotion on `agree`.
import { existsSync, mkdtempSync, readFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { parseIterationScore, runExperimentIteration } from "../src/harness/index.js";
import { setupFakeIterationEnv } from "./fixtures.js";

async function main(): Promise<void> {
const here = dirname(fileURLToPath(import.meta.url)); // dist/ after bundling
const amicoRunBundle = resolve(here, "amico-run.js");
if (!existsSync(amicoRunBundle)) {
console.error(`[demo] missing ${amicoRunBundle} — run: pnpm --filter @amicode/amico-run build`);
process.exit(1);
}

// 1) The shipped harness score (data) parses — the flow lives as data.
const shipped = resolve(here, "..", "..", "extension", "scores", "experiment-iteration", "ITERATION.toml");
if (existsSync(shipped)) {
const r = parseIterationScore(readFileSync(shipped, "utf8"));
console.log(
r.ok
? `[demo] shipped ITERATION.toml parses → ${r.score.target.platform}/${r.score.target.gate} tier=${r.score.target.tier}, promote_on=${r.score.verify.promote_on}`
: `[demo] shipped score error: ${r.error}`,
);
}

// 2) Run one iteration against a demo-tuned score (exemplar matches the fakes).
const work = mkdtempSync(join(tmpdir(), "harness-demo-"));
const fake = setupFakeIterationEnv(join(work, "fixtures"));
const parsed = parseIterationScore(
[
`schema_version = 1`,
`id = "experiment-iteration-demo"`,
`[target]`,
`platform = "rydberg"`,
`gate = "CZ"`,
`kind = "gate_synthesis"`,
`size = 2`,
`tier = "composed"`,
`exemplar_id = "${fake.exemplarId}"`,
`env = { kind = "provisioned" }`,
`[verify]`,
`promote_on = "agree"`,
].join("\n"),
);
if (!parsed.ok) {
console.error(`[demo] score error: ${parsed.error}`);
process.exit(1);
}

console.log("\n[demo] ── running one iteration (control flow = code, one flat leaf) ──");
const iterDir = join(work, "iter");
const outcome = await runExperimentIteration(parsed.score, {
dispatchExperimenter: fake.dispatchExperimenter, // ← the ONLY model seam (here: a fake)
workdir: iterDir,
runsRoot: join(work, "runs"),
amicoRunBundle,
juliaBin: fake.juliaBin,
env: fake.env,
logger: (l) => console.log(l),
});

console.log("\n[demo] ── outcome ──");
console.log(JSON.stringify(outcome, null, 2));
console.log(`\n[demo] iteration.toml (${join(iterDir, "iteration.toml")}):`);
console.log(readFileSync(join(iterDir, "iteration.toml"), "utf8"));

const ok =
outcome.dispatched === 1 && outcome.status === "completed" && outcome.verified === true && outcome.promoted === true;
if (!ok) {
console.error("[demo] UNEXPECTED outcome — the prototype did not behave as designed");
process.exit(1);
}
console.log(
"[demo] PASS — one iteration ran: exactly one flat experimenter leaf, tier-2 re-rollout agreed, promotion gated on agree. No LLM in the control-flow loop.",
);
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
3 changes: 2 additions & 1 deletion packages/amico-run/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"build": "node esbuild.config.mjs",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests --exclude '**/slow/**'",
"test:slow": "vitest run test/slow"
"test:slow": "vitest run test/slow",
"demo:harness": "node esbuild.config.mjs && node dist/harness-demo.js"
},
"dependencies": {
"@amicode/schema": "workspace:*",
Expand Down
19 changes: 13 additions & 6 deletions packages/amico-run/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LocalExecutor } from "./local_executor.js";
import { ConfigError, type Finished, type SubmitOpts } from "./types.js";
import { readAuthoring } from "./authoring.js";
import { runGate } from "./gate.js";
import { runVerification } from "./verify.js";
import { isVerifiedTier, runVerification } from "./verify.js";
import { trySubcommand } from "./subcommands.js";

function readTomlSafe(fp: string): Record<string, unknown> | undefined {
Expand Down Expand Up @@ -173,11 +173,18 @@ export async function main(argv: string[]): Promise<number> {
console.error(`amico-run: FINISHED missing in ${handle.runDir} (write fault)`);
return 64;
}
// spec C: free-tier re-rollout verification runs AFTER FINISHED, BEFORE the
// AMICODE_FINISHED line — so consumers see a settled verification state. The
// harness (or the fallback) always writes verification.toml; the promote gate
// keys off agree==true.
if (opts.spec?.tier === "free") {
// spec C + spec-20260708-112732 §4.3: re-rollout verification runs AFTER
// FINISHED, BEFORE the AMICODE_FINISHED line — so consumers see a settled
// verification state. The harness (or the fallback) always writes
// verification.toml; the promote gate keys off agree==true.
//
// TIERS VERIFIED: "free" (author-first, the original tier-3 trust anchor) AND
// "composed" (tier-2). The depth-1 redesign extends the gate to tier-2 because
// splicing params into an exemplar is exactly where a subtle mangle survives
// the masked-baseline check — a wrong fill can still re-roll to a different
// pulse. "vetted" (tier-1) skips it (the template is the trust anchor). Keep
// this set in sync with SolveSpec.tier (schema enum: vetted|composed|free).
if (opts.spec && isVerifiedTier(opts.spec.tier)) {
const { config: authoring } = readAuthoring();
await runVerification(handle.runDir, opts.spec, authoring);
const verified = readTomlSafe(join(handle.runDir, "verification.toml"));
Expand Down
Loading
Loading