Skip to content
Merged
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
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ jobs:
# the non-filename schemas (AC5: all five) via --schema
$V packages/schema/test/fixtures/valid/solvespec.toml --schema solvespec
$V packages/schema/test/fixtures/valid/catalog-entry.toml --schema catalog-entry
schema-roundtrip:
# 0.1d: the Julia round-trip against the SAME packages/schema/schemas/*.json the
# TS side uses (cross-language anti-drift). Fast tier — JSONSchema only, NO Piccolo
# solve. Three lanes: (1) golden + negative fixtures, (2) a REAL producer lane
# (amico-run emits a run-dir → validate it — exercises the producer, not just
# fixtures), (3) AC6 drift check (perturb the shared schema → BOTH TS and Julia flip).
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- uses: julia-actions/setup-julia@v2
with: { version: '1.12' }
- run: pnpm install --frozen-lockfile
- run: pnpm -r run build # amico-run + the validate launcher's bundle
- run: julia --project=packages/schema/julia -e 'using Pkg; Pkg.instantiate()'
- name: round-trip (golden + negative fixtures)
run: julia --project=packages/schema/julia packages/schema/julia/runtests.jl
- name: producer lane — amico-run emits a run-dir, Julia validates the emitted output
run: bash packages/schema/scripts/producer_roundtrip.sh
- name: AC6 anti-drift — perturbing the shared schema flips BOTH TS and Julia
run: bash packages/schema/scripts/ac6_drift_check.sh
boot-smoke:
strategy:
matrix:
Expand Down
196 changes: 196 additions & 0 deletions packages/schema/julia/Manifest.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions packages/schema/julia/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
JSONSchema = "1"
julia = "1.10"
14 changes: 14 additions & 0 deletions packages/schema/julia/emit_fixture.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env julia
# Minimal NON-Piccolo emitter for the producer round-trip lane (0.1d). amico-run
# runs this with cwd = the run dir and writes run.toml (first) + FINISHED (last);
# this writes a schema-conforming result.toml. The point is to exercise the real
# PRODUCER seam (amico-run + a Julia emitter → a live run-dir) in the fast tier,
# without a heavy Piccolo solve (the real solve is the slow/nightly extension).
# Uses only the TOML stdlib so it runs in any Julia env.
import TOML
println("AMICODE_ITER iter=1 f=1.000000e-03 inf_pr=1.0e-9 inf_du=1.0e-6"); flush(stdout)
open("result.toml.tmp", "w") do io
TOML.print(io, Dict("schema_version" => "1", "fidelity" => 0.9999, "iterations" => 1))
end
mv("result.toml.tmp", "result.toml"; force = true)
println("DONE fidelity=0.9999"); flush(stdout)
69 changes: 69 additions & 0 deletions packages/schema/julia/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env julia
# 0.1d Julia round-trip test (fast tier — golden + negative fixtures, no solve).
# Proves the Julia validator honors the SAME shared schemas the TS side uses, and
# that mutating those single-source files would flip Julia too (anti-drift, #18 AC6).
# julia --project=packages/schema/julia packages/schema/julia/runtests.jl
# A top-level @testset throws on failure → nonzero exit → reds CI.
using Test
include(joinpath(@__DIR__, "validate.jl"))
using .AmicoValidate: validate_file, SCHEMA_DIR

const FIX = normpath(joinpath(@__DIR__, "..", "test", "fixtures"))
const KINDS = ["run", "result", "lab", "solvespec", "catalog-entry", "finished"]

@testset "0.1d Julia round-trip against the shared schemas" begin
@testset "valid golden corpus conforms" begin
for k in KINDS
@test validate_file(joinpath(FIX, "valid", "$k.toml"), k) === nothing
end
end

@testset "invalid corpus → field-precise errors" begin
# each negative names the offending key/path (the lab-partner promise, S16)
@test occursin("run_id", validate_file(joinpath(FIX, "invalid", "run.toml"), "run"))
@test occursin("schema_version", validate_file(joinpath(FIX, "invalid", "result.toml"), "result"))
@test occursin("/transmon/levels", validate_file(joinpath(FIX, "invalid", "lab.toml"), "lab"))
@test occursin("pulse_path", validate_file(joinpath(FIX, "invalid", "catalog-entry.toml"), "catalog-entry"))
@test occursin("/status", validate_file(joinpath(FIX, "invalid", "finished.toml"), "finished"))
@test validate_file(joinpath(FIX, "invalid", "solvespec.toml"), "solvespec") !== nothing
end

@testset "schema_version policy" begin
mktempdir() do d
absent = joinpath(d, "r.toml"); write(absent, "fidelity = 0.99\niterations = 60\n")
@test occursin("schema_version", validate_file(absent, "result"))
bad = joinpath(d, "b.toml"); write(bad, "schema_version = \"9\"\nfidelity = 0.99\niterations = 60\n")
@test occursin("unrecognized version", validate_file(bad, "result"))
end
end

@testset "unquoted TOML datetime is tolerated (S2)" begin
mktempdir() do d
f = joinpath(d, "run.toml")
write(f, "schema_version = \"1\"\nrun_id=\"r\"\nscript_path=\"/s\"\nlab=\"d\"\nlab_id=\"d\"\n" *
"created_at=2026-06-15T00:00:00Z\norchestrator_version=\"0.1.0\"\n[julia]\nbinary=\"julia\"\n")
@test validate_file(f, "run") === nothing
end
end

@testset "the real bundled demo run dir (emitted golden) validates" begin
demo = normpath(joinpath(@__DIR__, "..", "..", "extension", "demo", "run"))
@test validate_file(joinpath(demo, "run.toml"), "run") === nothing
@test validate_file(joinpath(demo, "result.toml"), "result") === nothing
@test validate_file(joinpath(demo, "FINISHED"), "finished") === nothing
end

@testset "single source of truth (anti-drift, #18 AC6)" begin
# The Julia validator reads the SAME files the TS validator imports — the
# package's schemas/ dir — not a copy. Julia reads them at RUNTIME; the TS
# side BAKES them into dist/ at BUILD time (import … with {type:"json"}), so
# the cross-language flip only holds after a TS rebuild — the ci.yml
# `ac6_drift_check.sh` step exercises that end-to-end (perturb → rebuild TS →
# assert BOTH flip). This testset proves the no-copy single source structurally.
@test basename(SCHEMA_DIR) == "schemas"
@test isfile(joinpath(SCHEMA_DIR, "run.schema.json"))
@test normpath(SCHEMA_DIR) == normpath(joinpath(@__DIR__, "..", "schemas"))
# No transcribed schema copy lives in the Julia tree.
@test isempty(filter(f -> endswith(f, ".schema.json"), readdir(@__DIR__)))
end
end
Loading
Loading