Skip to content

0.1a — @amicode/schema: single source of truth for the five config/artifact schemas (closes #15-core) - #28

Merged
jack-champagne merged 3 commits into
mainfrom
rchari/0.1a-schema-package
Jun 29, 2026
Merged

0.1a — @amicode/schema: single source of truth for the five config/artifact schemas (closes #15-core)#28
jack-champagne merged 3 commits into
mainfrom
rchari/0.1a-schema-package

Conversation

@Rchari1

@Rchari1 Rchari1 commented Jun 27, 2026

Copy link
Copy Markdown
Member

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-backed validate() 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

  • Five versioned schemas (each carries schema_version, an enum = the supported-version SET): manifest.toml, result.toml, lab.toml, SolveSpec, catalog-entry.
  • FINISHED — a sub-shape of the run-dir contract ({status, exit_code}, no own schema_version).
  • Encoded to match the exact shapes emitted today (formalize, don't fork): manifest [julia] table; lab.toml matches β.4's shipped lab.toml.example ([lab].name + [transmon] omega/delta/levels/drive_max); result fidelity ∈ [0, 1.0001].
  • validate(obj, kind) / validateFile(path, kind){ok, errors} with field-precise errors (JSON-pointer path + offending key).
  • amico-run's validators now delegate here (export names + {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 demo result.toml stamp schema_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-invalid result.toml instead of silently dropping fidelity/promote.

Two adversarial reviews (design + code) folded in

  • Design review (pre-impl): M1 lockfile committed; params kept lenient; out-of-range range added (fidelity, lab); enum not const; emitters patched.
  • Code review (post-impl): lab shape fidelity-to-example; S1 fidelity 1+ε no longer false-rejects a converged run; S2 unquoted-datetime tolerance; S3 version-enum drift guard; S4 readers log swallowed errors; S5/S6 catalog-entry/solvespec negatives; distinct wrong-type vs out-of-range assertions.

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/*.json from Julia. 0.1a lands the schemas + the TS validator + the emitter schema_version stamping it depends on.

Tests

@amicode/schema 24, 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 in packages/schema/test/fixtures/valid/ (also consumed by 0.1c/0.1d).

🤖 Generated with Claude Code

Rchari1 and others added 2 commits June 27, 2026 00:24
…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 jack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.tomlrun.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.jsonrun.schema.json (file + $id .../schema/run/v1 + title; SchemaKind "manifest""run" in src/index.ts)
  • packages/schema/test/fixtures/valid/manifest.tomlrun.toml
  • packages/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.ts
  • packages/extension/CONTRACT.md, packages/extension/AGENTS.md
  • packages/extension/demo/run/manifest.tomlrun.toml
  • the tests still referencing the old name

2. closes #15closes #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",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in de031b1 — renamed to run.schema.json ($id .../schema/run/v1), the on-disk file to run.toml, and the SchemaKind manifestrun. 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.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 #15closes #15-core; the env-contract is a 0.1a-follow.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@Rchari1 Rchari1 changed the title 0.1a — @amicode/schema: single source of truth for all five config/artifact schemas (closes #15) 0.1a — @amicode/schema: single source of truth for the five config/artifact schemas (closes #15-core) Jun 27, 2026
@Rchari1

Rchari1 commented Jun 27, 2026

Copy link
Copy Markdown
Member Author

Pushed de031b1 addressing both: (1) the manifest.toml → run.toml rename across the whole run-dir contract (schema + writer + readers + docs + demo + fixtures + tests — full touchpoint list), and (2) retitled to closes #15-core with the env-contract (requires/provides cross-check) left to the 0.1a-follow. Bonus: bounded delta_GHz + added the lab range/minLength negatives (your #29 nits, since that schema lives here). schema 25 / amico-run 47 / extension 49(+1 skip) green. Re-requesting.

@Rchari1
Rchari1 requested a review from jack-champagne June 27, 2026 23:35
Rchari1 added a commit that referenced this pull request Jun 28, 2026
…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>
Rchari1 added a commit that referenced this pull request Jun 28, 2026
…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>
Rchari1 added a commit that referenced this pull request Jun 28, 2026
…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 jack-champagne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants