0.1a — @amicode/schema: single source of truth for the five config/artifact schemas (closes #15-core) - #28
Conversation
…all five config/artifact schemas (closes #15) Stands up the shared workspace SchemaPackage. JSON Schema files (draft-07, shared verbatim with the Julia round-trip in 0.1d) are the contract; one ajv-backed validate() is consumed by the extension, amico-run, the (0.1c) CLI, and CI. Schemas (each carries schema_version, an enum = the supported-version SET): - manifest.toml, result.toml, lab.toml, SolveSpec, catalog-entry (the five) - FINISHED — a SUB-SHAPE of the run-dir contract (no own schema_version) Encoded to match the EXACT shapes amico-run emits today (formalize, don't fork): manifest [julia] table, FINISHED {status, exit_code}, result fidelity∈[0,1]. validate(obj, kind) / validateFile(path, kind) return {ok, errors} with field-precise errors (JSON-pointer path + offending key). amico-run's hand-rolled validateManifest/Finished/Result now DELEGATE here (export names + shape preserved so the extension is untouched); re-introducing a local schema is guarded as a regression. result.toml migration (the one hazard): the schema now requires schema_version, so BOTH Julia emitters (solve_template.jl + test/slow/solve_common.jl) and the bundled demo result.toml stamp `schema_version = "1"` in this same commit. Pre-0.1a run dirs (dev-machine history) lose fidelity display until re-solved — documented, accepted. Tests: valid golden corpus (the shared corpus for 0.1c/0.1d) + field-precise negative matrix (missing / wrong-type / unknown-key / out-of-range / bad-version) + schema_version policy + FINISHED sub-shape + formalize-don't-fork migration + bundled-demo conformance. ajv bundles cleanly into the extension dist + CLI; CI lockfile regenerated so --frozen-lockfile stays green. Addresses design-review must-fixes M1–M5 (M6/0.1d-scope deferred to 0.1d). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e, fidelity epsilon, datetime + drift guards, reader logging Address the adversarial code review of 0.1a: - lab.schema.json now formalizes the EXACT shape β.4 ships in lab.toml.example ([lab].name + [transmon] omega_GHz/delta_GHz/levels/drive_max_GHz), not an invented [qubit] shape (contract-fidelity: formalize, don't fork). - S1: result/catalog fidelity max relaxed to 1.0001 — a converged rollout can emit 1+ε, which the schema previously false-rejected (would break the round-trip). - S2: validateFile normalizes TOML Date → ISO string, so an UNQUOTED datetime (smol-toml → Date; a Julia TOML.print of a DateTime) validates like a quoted one. - S3: test asserts every schema's schema_version.enum stays in sync with SUPPORTED_SCHEMA_VERSIONS (no drift seam in the anti-drift package). - S4: both reader gates (run_dir_reader, file_watcher) now LOG a present-but- invalid result.toml instead of silently dropping fidelity + skipping promote. - S5/S6 + N2/N3/N4: field-precise negative cases for catalog-entry + solvespec; wrong-type vs out-of-range asserted distinctly; unrecognized-version over all five; FINISHED exit_code path. N6: trimmed enum message, dropped dead const branch. AC6 (the Julia emit→validate round-trip in CI) is DEFERRED to 0.1d — that slice (issue #18) exists precisely for the cross-language round-trip; 0.1a lands the schemas + the TS validator + emitter schema_version stamping it depends on. schema 24 / amico-run 47 / extension 50 tests green; ajv bundles; lockfile committed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jack-champagne
left a comment
There was a problem hiding this comment.
Schema substance is solid — manifest matches the shape amico-run actually emits, normalizeDates handles the unquoted-Julia-datetime seam, and the fidelity 1.0001 tolerance + enum-version are the right calls. Two changes before this merges, because this PR is the freeze: it stamps schema_version = "1" and every consumer (extension, CLI, CI, the 0.1d Julia round-trip) will hardcode these names and shapes.
1. Rename the run-dir header manifest.toml → run.toml here, not later.
manifest.toml collides with Julia's Manifest.toml (the Pkg lockfile). Cognitively, every Julia dev reads manifest.toml as the lockfile; and on case-insensitive filesystems — the macOS labs (the EC2 Mac host we're standing up, darwin dev boxes) — manifest.toml and Manifest.toml alias to the same file the moment a Julia env and a run-dir ever co-locate or something globs for it. It's latent today (a run-dir holds no Project.toml/Manifest.toml), but the env-contract work puts the real Julia Manifest into this same contract (lab.toml's "provides" = the depot's package set), so two "manifests" stop being hypothetical.
Renaming after v1 freezes is a breaking contract migration; doing it in this PR is free. β run-dirs are ephemeral dev artifacts, so a clean cutover (no dual-read shim) is fine. run.toml joins the existing run-dir family (run.log, result.toml) and the contract sentence stays clean: "run.toml first, FINISHED last."
Touchpoints (the writer isn't in this PR yet, so the rename is broader than the current diff):
packages/schema/schemas/manifest.schema.json→run.schema.json(file +$id .../schema/run/v1+ title;SchemaKind"manifest"→"run"insrc/index.ts)packages/schema/test/fixtures/valid/manifest.toml→run.tomlpackages/amico-run/src/run_dir.ts— the writer:atomicWriteFile(runDir, 'manifest.toml', …)packages/extension/src/file_watcher.ts,src/run_dir_reader.ts,src/demo_replay.tspackages/extension/CONTRACT.md,packages/extension/AGENTS.mdpackages/extension/demo/run/manifest.toml→run.toml- the tests still referencing the old name
2. closes #15 → closes #15-core; split the env-contract to a 0.1a-follow.
#15's ACs now include the execution-environment contract: SolveSpec declares what a solve requires (packages, load mechanism, julia patch), lab.toml declares what a lab provides, and validate() cross-checks requires ⊆ provides. That was added after the #24 Piccolissimo binary recheck — #24's template validated fine against a source Pkg.develop env and is non-functional on the shipped binary (using Piccolo/Piccolissimo/CairoMakie all fail; JLD2.save crashes the run) precisely because nothing declares provides-vs-requires.
This PR's SolveSpec is the minimal forward shape (no requires), lab.toml has no provides, and there's no cross-check — which is a fine scope call (it lands the core and unblocks #16/#17/#18 fast), but it doesn't meet those ACs. So this closes #15-core; I'll open a 0.1a-follow for the env-contract — it mainly serves the cloud track, which only soft-depends on this.
Otherwise good — the validation core barely needs touching.
| @@ -0,0 +1,28 @@ | |||
| { | |||
| "$schema": "http://json-schema.org/draft-07/schema#", | |||
| "$id": "https://amico.harmoniqs.co/schema/manifest/v1", | |||
There was a problem hiding this comment.
This is the freeze point — rename to run.schema.json / $id .../schema/run/v1, and the on-disk file to run.toml. manifest.toml collides with Julia's Manifest.toml (Pkg lockfile): cognitively, and as a case-insensitive-FS aliasing hazard on the macOS labs. Free now, a breaking migration once v1 freezes. Full touchpoint list in the summary.
There was a problem hiding this comment.
Done in de031b1 — renamed to run.schema.json ($id .../schema/run/v1), the on-disk file to run.toml, and the SchemaKind manifest→run. Followed the full touchpoint list: the writer (amico-run run_dir.ts), the extension readers (file_watcher.ts, run_dir_reader.ts, demo_replay.ts), CONTRACT.md/AGENTS.md, demo/run/run.toml, fixtures, and all tests. Kept the writeManifest/validateManifest function names (internal API; only the file + kind changed). The ci.yml/validate.jl refs in #30/#31 follow in lockstep when those rebase. Clean cutover, no dual-read shim (β run-dirs ephemeral).
| "$schema": "http://json-schema.org/draft-07/schema#", | ||
| "$id": "https://amico.harmoniqs.co/schema/solvespec/v1", | ||
| "title": "amico SolveSpec", | ||
| "description": "FORWARD-LOOKING. The resolved solve specification a future amico-run would assemble and validate before dispatch. amico-run is argv-only today and emits no SolveSpec, so this schema is authored from the PRD shape and exercised via a committed fixture + `--schema solvespec` only (no emitter to round-trip yet). Its assembler/validate() call is a later slice, NOT 0.1a.", |
There was a problem hiding this comment.
Minimal forward shape is right for #15-core, but #15's ACs now require a requires block here (packages / load mechanism / julia patch), a provides block in lab.toml, and a requires ⊆ provides cross-check — the #24-prevention from the binary recheck. So drop closes #15 → closes #15-core; the env-contract is a 0.1a-follow.
There was a problem hiding this comment.
Agreed — retitled to closes #15-core. SolveSpec stays the minimal forward shape here (no requires), lab.toml has no provides, no cross-check; the env-contract (requires ⊆ provides, the #24-binary-prevention) is the 0.1a-follow you're opening. Also bounded delta_GHz (was the one unbounded [transmon] field — caught your #29 nit here since the schema lives in this PR).
…toml (freeze) + bound delta_GHz Address Jack's #28 review (the freeze PR): 1. Rename the run-dir header `manifest.toml` → `run.toml` now, while it's free. `manifest.toml` collides with Julia's `Manifest.toml` (Pkg lockfile) — cognitively, and as a case-insensitive-FS aliasing hazard on the macOS labs once a Julia env and a run-dir ever co-locate. Renaming after v1 freezes would be a breaking migration; β run-dirs are ephemeral so this is a clean cutover (no dual-read shim). Touches: - schema: run.schema.json (+ $id .../schema/run/v1) and the SchemaKind "manifest"→"run" - the writer: amico-run/src/run_dir.ts (atomicWriteFile … 'run.toml') - readers: extension file_watcher.ts, run_dir_reader.ts, demo_replay.ts - CONTRACT.md, AGENTS.md, demo/run/run.toml, fixtures, and all affected tests (writeManifest/validateManifest function NAMES kept — internal API; only the on-disk file + the schema kind change.) 2. Bound `delta_GHz` in lab.schema.json (was unbounded — garbage/sign-flipped anharmonicity passed; |δ| physical ~0.1–0.5 GHz, bounded to [-2,2]). Added the lab range/minLength negatives (omega_GHz≤100, drive_max_GHz≤10, lab.name minLength) the negative matrix had skipped. schema 25 / amico-run 47 / extension 49 (+1 packaging skip) green. The env-contract (SolveSpec `requires` / lab `provides` / requires⊆provides cross-check) is the 0.1a-follow Jack is opening — this PR closes #15-core. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pushed de031b1 addressing both: (1) the |
…h/Schuster (rebased on #28 rename) Address Jack's #29 nits: - Loop the parity assertion over a CORPUS (valid + missing/wrong-type/out-of-range/ unknown-key/absent+unrecognized-version) asserting checkLabToml === @amicode/schema validateFile on each — was a single input (#16 "over the corpus"). - Add the range-bound negatives the matrix skipped: omega_GHz≤100, drive_max_GHz≤10, delta_GHz (now bounded in #28), and lab.name minLength — each field-precise. - Add a Schuster-profile valid fixture (negative-δ convention, 4 levels) alongside demo-lab — the PRD demo forcing-function + second real-shaped profile. Rebased onto #28's manifest.toml→run.toml rename (lab files don't reference the run-dir header, so clean). extension 64 (+1 packaging skip) green. Non-blocking (Jack): the toast/channel seam has no VS Code host test (no host in CI) and lab.toml has no `provides` — both are Phase-1 prerequisites (provides ties to the 0.1a-follow env-contract), noted for that work, not this slice. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…all five, wrong-type fixture, rename lockstep Address Jack's #30 review (rebased on #28's run.toml rename): - bin now points at a COMMITTED launcher (packages/schema/launcher/amico-validate, mirrors amico-run) instead of the un-built dist/amico-validate.js — so the `amico-validate` bin links on a clean install (was "Failed to create bin … ENOENT"; dist is built by `pnpm build`, absent at install time). CI now exercises the LINKED bin (`pnpm --filter amicode-v2 exec amico-validate --help`) so a broken entry reds. - CI gate validates ALL FIVE: added solvespec + catalog-entry via --schema (AC5 / DoD). - Self-contained wrong-type fixture (invalid/result-wrongtype.toml) + a cli.test case — the class matrix no longer relies on an in-test mutation (AC7). - Rename lockstep: index.ts kindForFilename + cli.ts usage + ci.yml gate + cli.test KINDS + invalid/run.toml all follow #28's manifest.toml→run.toml / "manifest"→"run". schema 34 / amico-run 47 / extension 64 (+1 skip) green; linked bin + gate verified locally. (The bigger real-emit→validate lane Jack flagged lands in #31, the round-trip slice.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nd-to-end (rebased on #28 rename) Address Jack's #31 review: - REAL producer lane (not just fixtures): scripts/producer_roundtrip.sh runs amico-run on a minimal non-Piccolo emitter (julia/emit_fixture.jl) so it produces a live run-dir (run.toml + FINISHED from the orchestrator, result.toml from the Julia emitter), then validates the FRESHLY-EMITTED artifacts with validate.jl. CI runs it (fast tier; the real Piccolo solve stays the slow/nightly extension). Scoped to what each side actually emits — the orchestrator writes run.toml/FINISHED, the Julia producer writes result.toml. - AC6 exercised, not asserted: scripts/ac6_drift_check.sh perturbs the SHARED schema, REBUILDS TS (it bakes schemas at build time — the gap Jack found), then asserts BOTH the TS bin AND validate.jl reject a previously-valid fixture, then reverts. Proven locally; wired into the schema-roundtrip CI job. runtests.jl's AC6 testset notes the build-vs- runtime asymmetry. - Rename lockstep: validate.jl + runtests.jl manifest.toml→run.toml, "manifest"→"run", run.schema.json; resolved the ci.yml conflict keeping #30's all-five gate + this job. schema 34 / amico-run 47 / extension 64 (+1 skip) / julia 22 green; producer + AC6 scripts pass locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jack-champagne
left a comment
There was a problem hiding this comment.
Rename complete across all 23 touchpoints — verified at the head: run.schema.json ($id .../schema/run/v1, self-documents the why), no orphaned manifest.* (all 404), writer (run_dir.ts) + readers + CONTRACT.md/AGENTS.md + demo/fixtures/tests all moved, SchemaKind manifest→run. Title now closes #15-core; the env-contract (requires⊆provides) is correctly deferred to the 0.1a-follow; and you bounded delta_GHz (the #29 nit). I synced the architecture spec's run-dir-contract section to run.toml on our side. Good to merge — this lands the wk-3 freeze (SchemaPackage v0 + the run-dir contract).
Phase 0′ keystone. Stands up the shared workspace
@amicode/schema— JSON Schema files (draft-07, shared verbatim with the Julia round-trip in 0.1d) as the single source of truth, behind one ajv-backedvalidate()consumed by the extension, amico-run, the (0.1c) CLI, and CI. Do not merge (dependency root for 0.1b/0.1c/0.1d).What's here
schema_version, anenum= the supported-version SET):manifest.toml,result.toml,lab.toml,SolveSpec,catalog-entry.{status, exit_code}, no ownschema_version).[julia]table;lab.tomlmatches β.4's shippedlab.toml.example([lab].name+[transmon]omega/delta/levels/drive_max);resultfidelity ∈ [0, 1.0001].validate(obj, kind)/validateFile(path, kind)→{ok, errors}with field-precise errors (JSON-pointer path + offending key).{ok,errors}preserved → extension untouched); re-introducing a local schema is guarded as a regression.The result.toml migration (the one hazard, handled atomically)
The schema now requires
schema_version, so both Julia emitters (solve_template.jl+test/slow/solve_common.jl) and the bundled demoresult.tomlstampschema_version = "1"in this same change. Pre-0.1a run dirs (dev-machine history) lose fidelity display until re-solved — documented; readers now log a present-but-invalidresult.tomlinstead of silently dropping fidelity/promote.Two adversarial reviews (design + code) folded in
enumnotconst; emitters patched.AC6 deferred to 0.1d (stated explicitly)
The Julia emit→validate round-trip in CI is issue #18 (0.1d) — that slice reads these same
schemas/*.jsonfrom Julia. 0.1a lands the schemas + the TS validator + the emitterschema_versionstamping it depends on.Tests
@amicode/schema24, amico-run 47, extension 50 — green. ajv bundles cleanly into the extension dist (verified) + the amico-run CLI stays lean (reader-side only). Shared valid corpus inpackages/schema/test/fixtures/valid/(also consumed by 0.1c/0.1d).🤖 Generated with Claude Code