ADR-02: Schema evolution SLA¶
Status: accepted (2026-05-28) Blocks: all of workstream B (dag-ml-data schema additions). Land BEFORE B1-B6 wire-shape changes.
Context¶
CoordinatorDataPlanEnvelope is currently v1 with refusal-on-mismatch (unsupported_versions_are_refused). The roadmap adds MetadataSchema, AugmentationMetadata, signal_type, multi-target, GroupSpec, FoldSpec, per-source shape contracts. Without a migration policy, any of these promotes silently into a v2 that orphans existing bundles.
Decision¶
Schema evolution follows a three-phase SLA per wire-shape change:
Land additively first — every new field is
Option<T>for one release, populated by writers but not required by readers. Readers in v1 ignore unknown fields per JSON schemaadditionalProperties. CI gate:scripts/validate_contracts.pychecks that the field is optional, has a documented default, and the C ABI version constant is unchanged.Promote with a major envelope version — when the field becomes required, bump
schema_versionand ship a one-cycle dual-read window:Rust reader accepts v1 AND v2 envelopes for one release;
bundles produced under v1 stay prediction-readable for two releases (long enough for users to either re-train or accept a
--allow-legacyflag);validate-bundleCLI surfaces “deprecated envelope v1” with the target removal version.
Drop the previous version after the two-release window. The CHANGELOG entry references this ADR + the bug-tracker issue that scheduled the removal.
Concretely for the B workstream¶
All of B1–B6 (MetadataSchema, AugmentationMetadata, signal_type, multi-target, shape contracts, GroupSpec / FoldSpec) land as optional v1 fields, all in one merged window to minimize migration churn. The promotion to required fields is a separate ADR-superseder authored only after the bridge has consumed them for one release.
Consequences¶
Any ADR-02-touching PR has a checklist that requires updating: (a) the schema JSON, (b) the C ABI version macros (only if breaking), (c) the cross-repo conformance pack, (d)
STATUS.md, (e) the CHANGELOG, (f) one negative test for the v1 reader receiving a v2-only field.scripts/validate_contracts.pylearns to diff JSON schemas between releases and refuse silentrequiredadditions without a corresponding ADR-superseder..n4abundles carry the envelope version they were built under; loaders fall back to v1 prediction path when the version is < current.
Supersedes / superseded by¶
This ADR governs envelope v1 → v2 (and beyond). Per-version supersession ADRs (e.g. ADR-02b for the actual v2 cutover) reference this one.