You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Phase: 0′ — Contracts / foundation · Plan task: 0.1 (SchemaPackage), validator/CLI/CI slice · Implementing repo: amicode
Important
Decision surface — what the validator surfaces, and how CI selects + gates each schema.
Problem
Plan task 0.1 (SchemaPackage) is a single monolithic 6pd item that bundles the JSON Schemas, amico-validate, the field-precise error path (S17), the lab.toml validator the extension calls on load, the Julia round-trip, and the CI gate. The schemas can be authored but nothing exercises them: there is no command a partner or dev runs to check a file, and nothing in CI stops a schema-invalid config or a drifted emitter from landing. β shipped no validation layer at all — the extension's onResult path hand-rolls result.toml parsing by regex (/fidelity\s*=.../ + parseFloat, Q62), bypassing any schema, and a malformed lab.toml fails silently mid-solve instead of loudly at validation.
Approach
Treat task 0.1 as a deliberate vertical decomposition (ADR-0003) into three sibling slices that share the schema set and the validate() core: (s-defs) the schema definitions + the shared validate() core + the load-time lab.toml validator; (s-roundtrip) the Julia round-trip that validates Julia-emitted result.toml/manifest.toml; and this slice — the user-facing amico-validate <file> CLI plus the CI fast-tier gate that runs validate() across committed fixtures and configs. amico-validate selects a schema (by file role, or by explicit --schema), and on failure emits a field-precise error naming the offending key and its path (S17). The CI step reds the PR on schema-invalidity or emitter drift (S16).
Approaches Considered
Standalone amico-validate CLI over the shared validate() core + a CI fast-tier step — chosen; one entrypoint reused by CLI, CI, and the extension's load-time lab.toml check.
Validate inline inside amico-run only — rejected: gives no CLI/CI surface and recouples validation to the run path (β's silent-mid-solve failure mode).
CI-only schema check, no user-facing command — rejected: drops S15's validate command and the partner's pre-solve self-serve check (S17).
Scope
In:
amico-validate <file> resolving file→schema and reporting pass/fail, with the exit-code contract below.
A CI fast-tier job validating committed fixtures + committed configs/golden artifacts against the schema set (S16).
A negative-fixture corpus (missing / wrong-type / out-of-range / unknown-key / bad-version) per schema.
Out:
The schema definitions, the validate() core, and the load-time lab.toml validator themselves — sibling slice s-defs; this slice is their CLI + CI surface, not their author. (The extension's load-time lab.toml validation is part of 0.1 per S15 + the task-0.1 body, owned by s-defs — it is not Phase 1.)
Julia round-trip harness — sibling slice s-roundtrip; this CI step consumes its emitted artifacts as fixtures, it does not build the harness.
Editor-side live (keystroke) diagnostics — genuine Phase 1 UX surface; distinct from the 0.1 load-time lab.toml check, which is in s-defs.
Slow-tier Julia smoke / opencode boot — stay nightly; this is fast-tier only.
Auto-fix / migration of invalid files — report only, no rewrite.
Assumptions
This is a deliberate decomposition of monolithic task 0.1; the sibling boundaries above are introduced here, not pre-existing givens. This slice depends on s-defs landing the schema set + validate() so the CLI is a thin wrapper, not a re-implementation.
File→schema resolution keys off filename/role for the fixed-filename schemas (lab.toml, result.toml, manifest.toml); schemas with no fixed filename are selected by explicit --schema.
The CI fast tier already exists (unit + schema + shim per PR, Q33–Q36 default); this adds the schema step, it does not stand up CI from zero.
Open Qs
How many schemas, and is SolveSpec one of them? Sources conflict: the plan task-0.1 body enumerates four (lab.toml, result.toml, manifest.toml, catalog-entry) + "the run-dir contract shape" and omits SolveSpec, whereas PRD line 133, the architecture module table, and the Phase-0′ DoD say five including SolveSpec. AC β.4 — One-lab provisioning slice (bundle + install + healthcheck) #4's enumeration must not silently pick a side: is the fifth schema SolveSpec, or the run-dir-contract shape? Resolve with s-defs before AC β.4 — One-lab provisioning slice (bundle + install + healthcheck) #4 is finalized.
Acceptance Criteria
amico-validate <file> checks a config against its schema and reports pass/fail (S15); on a schema-invalid file it exits 64 and on a valid file it exits 0 (config/schema-error exit contract — Interfaces exit-code map, Q85).
A malformed lab.toml (e.g. wrong-typed or out-of-range hardware field) yields a field-precise error naming the offending key and its path within the file — not a bare valid=false. (S17)
An unknown/misspelled key and a schema_version outside the supported range each produce a distinct, field-precise error. (S14)
The CI fast-tier step validates committed fixtures and configs/golden artifacts against every schema in the resolved set (count/membership per the Open Q) and fails the job if any does not conform. (S16, Phase-0′ DoD)
Schemas with no fixed filename (e.g. catalog-entry, whose producer is Phase 3; and SolveSpec if in scope) are exercised in CI via committed fixtures selected with an explicit --schema — not via file-role resolution. (S16)
File→schema resolution picks the correct schema by filename/role for the fixed-filename schemas, and --schema overrides it for a payload whose role is ambiguous or has no fixed filename. (S15)
A negative fixture per failure class (missing / wrong-type / out-of-range / unknown-key / bad-version) is asserted to fail with an error pointing at the expected field. (S17)
Key Decisions
One validation entrypoint (amico-validate) over the shared validate() core is reused by CLI, CI, and the extension's load-time lab.toml check — no second validator.
The error contract is "names the offending field + path," not merely a boolean — the lab-partner-facing promise (S17), asserted as a behavior.
Schema selection is by file role for fixed-filename schemas, with an explicit --schema override; non-filename schemas (catalog-entry, and SolveSpec if in scope) are reached in CI only via committed fixtures + --schema, never by file-role inference.
Exit-code contract follows the amico-run Interfaces convention: 64 = config/schema error, 0 = valid (Q85 noted that β had no path to 64 for schema failures; this slice establishes it for the validator).
Constraints & Invariants
JSON Schema is the single source of truth (owned by s-defs); this slice adds no parallel validation logic, only the CLI surface + CI gate over validate().
Fast-tier only: no Julia runtime, no opencode boot, no network — cheap enough to run on every PR.
Prior Art / Patterns
SchemaPackage — the shared workspace package (sibling slice s-defs) owning the schema set + validate() + the load-time lab.toml validator; this slice is its CLI + CI surface.
amico-validate — the named CLI from the PRD schema-package decision and the Interfaces list.
amico-run / Executor — the run orchestrator whose Interfaces exit-code convention (64 = config/schema error) this validator follows.
The extension onResult path — β's schema-bypassing result.toml regex parse this validation layer supersedes once consumers adopt it (Q62).
CI fast tier vs slow tier — the established split (fast: unit + schema + shim per PR; slow: Julia smoke + opencode boot nightly); this lands the schema portion of the fast tier.
Source
Phase plan: [[plan-20260603-124231-amicode-phased-build]] §3 Phase 0′, task 0.1 (SchemaPackage) — "Includes amico-validate + the field-precise error path (S17) and the lab.toml validator the extension calls on load"; Phase-0′ DoD ("all five schemas validate in CI fast tier"). Deliberate vertical decomposition of the monolithic 6pd task 0.1 under ADR-0003 (this slice + s-defs + s-roundtrip).
PRD: S14 (versioned schemas), S15 (a validate command checks a config against its schema), S16 (CI enforces conformance of configs + emitted artifacts), S17 (load-time field-precise error). Schema-package decision (line 133–134: schema set incl. SolveSpec; amico-validate + extension diagnostics + CI gate). Testing decision: error "points at the offending field," not valid===false.
Architecture: SchemaPackage module (shared across CLI/ext/CI + Julia round-trip); CI tiering default (Q33–Q36); run-dir contract shape.
Decisions/observations superseded: the extension onResult regex result-parse (Q62) and the exit-code gap where schema failures had no path to 64 (Q85, Interfaces exit-code map).
Related: depends on s-defs (schema definitions + validate() core + load-time lab.toml validator); sibling of s-roundtrip (Julia round-trip), whose emitted artifacts this CI step consumes as fixtures. Supersedes β's absence of any validation layer (β explicitly excluded SchemaPackage + mechanical CI gates) and, specifically, the extension's onResult regex result-parse (Q62).
Testing
Semi-TDD (RED→GREEN): extend the CI fast tier with the schema-validation step and a per-schema positive/negative fixture corpus; negative cases assert field-precise errors and the 64/0 exit contract. No prescribed test names — the TDD loop decides structure/reuse at implementation time.
Notes
This is a deliberate vertical slice of task 0.1, not a pre-established "0.1c." It is correctly sized (the CLI + CI gate are the testable surface of the schema set) — do not merge it into s-defs (definitions + validate() + load-time lab.toml validator) or s-roundtrip (Julia round-trip), and do not split the CLI from the CI gate: they share the same validate() call and the same field-precise-error contract, and the DoD couples them. AC #4's schema count is parked on the Open Q until s-defs resolves the plan-body-vs-PRD/DoD conflict; AC #5 keeps the CI gate runnable for non-filename schemas (catalog-entry's producer is Phase 3) regardless of how that resolves.
Phase: 0′ — Contracts / foundation · Plan task: 0.1 (SchemaPackage), validator/CLI/CI slice · Implementing repo: amicode
Important
Decision surface — what the validator surfaces, and how CI selects + gates each schema.
Problem
Plan task 0.1 (SchemaPackage) is a single monolithic 6pd item that bundles the JSON Schemas,
amico-validate, the field-precise error path (S17), the lab.toml validator the extension calls on load, the Julia round-trip, and the CI gate. The schemas can be authored but nothing exercises them: there is no command a partner or dev runs to check a file, and nothing in CI stops a schema-invalid config or a drifted emitter from landing. β shipped no validation layer at all — the extension'sonResultpath hand-rollsresult.tomlparsing by regex (/fidelity\s*=.../+parseFloat, Q62), bypassing any schema, and a malformedlab.tomlfails silently mid-solve instead of loudly at validation.Approach
Treat task 0.1 as a deliberate vertical decomposition (ADR-0003) into three sibling slices that share the schema set and the
validate()core: (s-defs) the schema definitions + the sharedvalidate()core + the load-timelab.tomlvalidator; (s-roundtrip) the Julia round-trip that validates Julia-emittedresult.toml/manifest.toml; and this slice — the user-facingamico-validate <file>CLI plus the CI fast-tier gate that runsvalidate()across committed fixtures and configs.amico-validateselects a schema (by file role, or by explicit--schema), and on failure emits a field-precise error naming the offending key and its path (S17). The CI step reds the PR on schema-invalidity or emitter drift (S16).Approaches Considered
amico-validateCLI over the sharedvalidate()core + a CI fast-tier step — chosen; one entrypoint reused by CLI, CI, and the extension's load-time lab.toml check.amico-runonly — rejected: gives no CLI/CI surface and recouples validation to the run path (β's silent-mid-solve failure mode).validatecommand and the partner's pre-solve self-serve check (S17).Scope
In:
amico-validate <file>resolving file→schema and reporting pass/fail, with the exit-code contract below.Out:
validate()core, and the load-timelab.tomlvalidator themselves — sibling slice s-defs; this slice is their CLI + CI surface, not their author. (The extension's load-timelab.tomlvalidation is part of 0.1 per S15 + the task-0.1 body, owned by s-defs — it is not Phase 1.)lab.tomlcheck, which is in s-defs.Assumptions
validate()so the CLI is a thin wrapper, not a re-implementation.lab.toml,result.toml,manifest.toml); schemas with no fixed filename are selected by explicit--schema.Open Qs
lab.toml,result.toml,manifest.toml, catalog-entry) + "the run-dir contract shape" and omits SolveSpec, whereas PRD line 133, the architecture module table, and the Phase-0′ DoD say five including SolveSpec. AC β.4 — One-lab provisioning slice (bundle + install + healthcheck) #4's enumeration must not silently pick a side: is the fifth schema SolveSpec, or the run-dir-contract shape? Resolve with s-defs before AC β.4 — One-lab provisioning slice (bundle + install + healthcheck) #4 is finalized.Acceptance Criteria
amico-validate <file>checks a config against its schema and reports pass/fail (S15); on a schema-invalid file it exits64and on a valid file it exits0(config/schema-error exit contract — Interfaces exit-code map, Q85).lab.toml(e.g. wrong-typed or out-of-range hardware field) yields a field-precise error naming the offending key and its path within the file — not a barevalid=false. (S17)schema_versionoutside the supported range each produce a distinct, field-precise error. (S14)--schema— not via file-role resolution. (S16)--schemaoverrides it for a payload whose role is ambiguous or has no fixed filename. (S15)Key Decisions
amico-validate) over the sharedvalidate()core is reused by CLI, CI, and the extension's load-time lab.toml check — no second validator.--schemaoverride; non-filename schemas (catalog-entry, and SolveSpec if in scope) are reached in CI only via committed fixtures +--schema, never by file-role inference.amico-runInterfaces convention:64= config/schema error,0= valid (Q85 noted that β had no path to64for schema failures; this slice establishes it for the validator).Constraints & Invariants
validate().Prior Art / Patterns
validate()+ the load-timelab.tomlvalidator; this slice is its CLI + CI surface.64= config/schema error) this validator follows.result.tomlregex parse this validation layer supersedes once consumers adopt it (Q62).Source
amico-validate+ the field-precise error path (S17) and the lab.toml validator the extension calls on load"; Phase-0′ DoD ("all five schemas validate in CI fast tier"). Deliberate vertical decomposition of the monolithic 6pd task 0.1 under ADR-0003 (this slice + s-defs + s-roundtrip).validatecommand checks a config against its schema), S16 (CI enforces conformance of configs + emitted artifacts), S17 (load-time field-precise error). Schema-package decision (line 133–134: schema set incl. SolveSpec;amico-validate+ extension diagnostics + CI gate). Testing decision: error "points at the offending field," notvalid===false.onResultregex result-parse (Q62) and the exit-code gap where schema failures had no path to64(Q85, Interfaces exit-code map).validate()core + load-time lab.toml validator); sibling of s-roundtrip (Julia round-trip), whose emitted artifacts this CI step consumes as fixtures. Supersedes β's absence of any validation layer (β explicitly excluded SchemaPackage + mechanical CI gates) and, specifically, the extension'sonResultregex result-parse (Q62).Testing
Semi-TDD (RED→GREEN): extend the CI fast tier with the schema-validation step and a per-schema positive/negative fixture corpus; negative cases assert field-precise errors and the
64/0exit contract. No prescribed test names — the TDD loop decides structure/reuse at implementation time.Notes
This is a deliberate vertical slice of task 0.1, not a pre-established "0.1c." It is correctly sized (the CLI + CI gate are the testable surface of the schema set) — do not merge it into s-defs (definitions +
validate()+ load-time lab.toml validator) or s-roundtrip (Julia round-trip), and do not split the CLI from the CI gate: they share the samevalidate()call and the same field-precise-error contract, and the DoD couples them. AC #4's schema count is parked on the Open Q until s-defs resolves the plan-body-vs-PRD/DoD conflict; AC #5 keeps the CI gate runnable for non-filename schemas (catalog-entry's producer is Phase 3) regardless of how that resolves.