feat: immutable editions - #9357
Conversation
A frozen edition carries a read-forever guarantee, so its encoding set must never change again. Enforcement so far was a single inline assertion pinning core2026.07.0 -- not the edition the default writer targets -- leaving three of five frozen core editions unpinned, and living in the same mutable tree as the declarations it guarded. Generate one TOML record per frozen edition, holding the identifier, the recorded min_vortex_version, and the full computed encoding set. A test keeps the records in step with EDITION_DECLARATIONS and rejects a record with no frozen edition behind it, so deleting or unfreezing a declaration fails too. Update mode never removes a file, so unfreezing cannot be laundered through the generator. Two CI checks close the loop. The generated-files job regenerates the records and fails if git is dirty, alongside the existing flatbuffers and proto generation. A new job rejects any diff that modifies, deletes, or renames a record, and any newly added edition that is not newer than its family's newest recorded edition. required_vortex_release is deliberately left out of the records: it is backfilled from compat-fixture evidence after an edition freezes, so pinning it would put that backfill in conflict with the append-only rule. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
Record it in a table of its own rather than beside each encoding. It is the one fact in a record that is not fixed at freeze time -- it is backfilled from compat-fixture evidence as that evidence appears -- so giving it its own table makes a backfill purely an added line. The append-only check parses both revisions of a modified record and permits exactly that transition: the table may gain entries, but everything else must be byte-identical and a release that was already recorded may never change or be dropped. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
Editions are drafts until a min_vortex_version is recorded, and a draft is
free to change, so recording only frozen editions left the drafts invisible.
Generate a record for every declared edition instead. A draft's record may
change, move, or go away with the draft; freezing turns the record into a
read-forever contract that never changes again.
The CI check reads frozen-ness from the record at the base revision, so a diff
cannot unfreeze an edition and edit it in the same change, and the generator
refuses to unfreeze a record it finds on disk.
Encoding ids in a declaration may now be paired with the release that first
read them -- `&("vortex.alp", "0.36.0")` -- which flows into
EditionInclusion::required_vortex_release and into the records. Each core
edition's members are recorded as requiring the release current when that
edition froze, checked against the published release timeline: 0.36.0
(2025-05-28), 0.40.0 (2025-06-26), 0.54.0 (2025-10-20), 0.84.0 (2026-08-07),
and 0.65.0 (2026-03-25) for core2026.07.0, whose only member vortex.variant
first shipped there. These are upper bounds under each edition's own immutable
min_vortex_version, so the check permits refining them as compat-fixture
evidence narrows them, but never dropping one.
Renamed the module and script from `frozen` to `records`, since they now cover
drafts too.
Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
The exporter belongs with the repo's other generated files, so move it to `cargo run -p xtask -- generate-editions`, alongside generate-fbs and generate-proto, and run it from the same generated-files CI job that already checks git is clean afterwards. The `#[cfg(test)]` module and its UPDATE_EDITION_RECORDS environment variable are gone; the two rules git history cannot see -- a record may not be deleted, and a frozen edition may not return to draft -- now fail the exporter itself. Drop the per-encoding release from the records. An edition declares the release it froze in, so repeating it on all 23 of core2025.05.0's members said nothing that the edition did not already say. Declarations return to plain encoding lists, EditionInclusion::required_vortex_release goes back to being unset until there is per-encoding evidence to record, and the append-only check simplifies to rejecting any change at all to a frozen record. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
|
Thoughts on using CODEOWNERS for these files? |
Merging this PR will not alter performance
Comparing Footnotes
|
Families version independently, so a flat directory mixed two unrelated chronologies and left the reader to spot the family from a filename prefix. Group the records as `vortex/editions/<family>/<edition>.toml`, mirroring the declarations in `vortex/src/editions`. The exporter creates a directory per family and treats a record under the wrong one as a stray, since that is what it is. The append-only check requires a newly added record's directory to match the family its name declares, so a record cannot be filed under a family whose chronology it does not extend. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
|
what do you want to enforce with codeowners? We can maybe require +2 for changes to these? |
|
also before we do this we should make sure editions have all the objects we care about |
Currently there is no way to ensure editions persist apart from code review.
This pr add a CI check and also creates useful output that can be used to code-gen other docs