Generate the minor ledger's metadata from the schema #135

Merged
natsukium merged 1 commit from protocol/schema-first-ledger into main 2026-10-13 22:27:08 +09:00
Owner

Closes #129.

Why

Each wire addition was stated by hand in several Rust places: an ArmMeta row that a test compared with the (felis.v1.arm) option by parsing the schema text, an exhaustive since_minor() arm per closed-enum value, an ADDED_FIELDS or GatedField entry per field, WireCodec::ARM_FIELDS, and MINOR_LEDGER. A non-Rust peer could read arm minors from the descriptor but not those of fields or enum values.

What

  • felis.proto now carries every addition's minor:
    • fields, arms included, use (felis.v1.field_since) = { minor, skippable } (ArmRouting.since is gone, so an arm is dated like any field). A field is gated unless it is marked skippable, so a forgotten flag refuses the send rather than letting an older peer silently skip it;
    • closed-enum values use (felis.v1.value_since).
  • tools/proto/schema_meta.py reads the buf build descriptor and generates src/schema_meta.rs:
    • every wrapper's arm table and arm field numbers;
    • since_minor for each frame-reachable enum;
    • the gated-field minors and one test-only table of every dated identifier for the ledger test.
  • The script also checks the schema's shape rules (a wrapper holds only its arms, a family numbers its arms in order, no oneof member, arm or payload, can be skippable).
  • just proto runs the script after buf generate, and a schema-meta pre-commit hook fails on a stale copy.
  • Removed: the proto text parser and its tests, and MINOR_LEDGER (the doc test now counts rows itself).
  • The send gate's composition (the MinorGated impls and the GatedField presence tests) stays hand-written.
  • An annotation left out reads as minor 0. The ledger row catches it: the reverse check matches the Family::Variant / Enum::VALUE / Message.field identifiers exactly and fails on one the schema does not date at that minor. A test also requires every enum carrying an added value to be one the gate reads. Forgetting both the annotation and the ledger row goes uncaught, as it does today.
  • Updated docs: docs/reference/ipc.md (the arm table, the minor ledger), testing.md, workspace.md, the explanation pages, the extend-ipc skill, and tools/README.md.

Verification

  • just check passes.
  • Deliberately breaking the schema makes the expected check fail:
    • an annotated value on an enum the gate does not read;
    • an arm whose field_since is dropped;
    • a skippable arm;
    • a skippable oneof member.
Closes #129. ## Why Each wire addition was stated by hand in several Rust places: an `ArmMeta` row that a test compared with the `(felis.v1.arm)` option by parsing the schema text, an exhaustive `since_minor()` arm per closed-enum value, an `ADDED_FIELDS` or `GatedField` entry per field, `WireCodec::ARM_FIELDS`, and `MINOR_LEDGER`. A non-Rust peer could read arm minors from the descriptor but not those of fields or enum values. ## What - `felis.proto` now carries every addition's minor: - fields, arms included, use `(felis.v1.field_since) = { minor, skippable }` (`ArmRouting.since` is gone, so an arm is dated like any field). A field is gated unless it is marked `skippable`, so a forgotten flag refuses the send rather than letting an older peer silently skip it; - closed-enum values use `(felis.v1.value_since)`. - `tools/proto/schema_meta.py` reads the `buf build` descriptor and generates `src/schema_meta.rs`: - every wrapper's arm table and arm field numbers; - `since_minor` for each frame-reachable enum; - the gated-field minors and one test-only table of every dated identifier for the ledger test. - The script also checks the schema's shape rules (a wrapper holds only its arms, a family numbers its arms in order, no `oneof` member, arm or payload, can be skippable). - `just proto` runs the script after `buf generate`, and a `schema-meta` pre-commit hook fails on a stale copy. - Removed: the proto text parser and its tests, and `MINOR_LEDGER` (the doc test now counts rows itself). - The send gate's composition (the `MinorGated` impls and the `GatedField` presence tests) stays hand-written. - An annotation left out reads as minor 0. The ledger row catches it: the reverse check matches the `Family::Variant` / `Enum::VALUE` / `Message.field` identifiers exactly and fails on one the schema does not date at that minor. A test also requires every enum carrying an added value to be one the gate reads. Forgetting both the annotation and the ledger row goes uncaught, as it does today. - Updated docs: `docs/reference/ipc.md` (the arm table, the minor ledger), `testing.md`, `workspace.md`, the explanation pages, the `extend-ipc` skill, and `tools/README.md`. ## Verification - `just check` passes. - Deliberately breaking the schema makes the expected check fail: - an annotated value on an enum the gate does not read; - an arm whose `field_since` is dropped; - a skippable arm; - a skippable `oneof` member.
protocol, docs, skills: generate the minor ledger's metadata from the schema
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 8s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 17s
windows / windows docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m12s
windows / cargo nextest (Windows) (pull_request) Successful in 4m25s
windows / frontend smoke (Windows) (pull_request) Successful in 1m1s
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
5008b73cce
Each wire addition had to be stated by hand in several Rust places:
an `ArmMeta` row that a test compared with the `(felis.v1.arm)` option
by parsing the schema text, an exhaustive `since_minor()` arm per
closed-enum value, an `ADDED_FIELDS` or `GatedField` entry per field,
`WireCodec::ARM_FIELDS`, and `MINOR_LEDGER`'s description string. A
non-Rust peer could read the arm minors from the descriptor but not a
field's or an enum value's.

The schema now carries every addition's minor: `since` in the arm
option as before, `(felis.v1.field_since)` on a field (with
`skippable` for one an older peer may skip; gated is the default, so a
forgotten flag refuses rather than silently skips), and
`(felis.v1.value_since)` on a closed-enum value. tools/proto/
schema_meta.py reads the `buf build` descriptor and generates
src/schema_meta.rs: every wrapper's arm table and arm field numbers,
each frame-reachable enum's `since_minor`, and the added-field lists.
The schema shape rules that the text-parsing tests held (wrapper
carries only its arms, family arm numbering, no skippable oneof
member) are now generation errors. `MINOR_LEDGER` duplicated the doc
table's first column and goes; the doc test counts rows directly.

The send gate's composition stays hand-written. The generated
metadata replaces declarations, not the decision of which values a
family's `requires()` folds in.

Generating `ArmMeta` reverses the recorded choice to keep two
statements of each routing row. Both statements came from one author
with one intent, so the comparison caught copying slips, never a
wrong row, and generation removes the copy.

An annotation that is left out reads as minor 0. The ledger row that
every addition needs catches it: the reverse check fails on an
identifier the row names at a minor the schema does not give it, and
the enum values it checks now come from the generated table, which
covers every frame-reachable closed enum. An annotated value on an enum
the send gate does not read would reach an older peer unchecked, so a
test requires every enum carrying one to be in the gate's list.

Assisted-by: Claude Code:Opus 5.5
natsukium force-pushed protocol/schema-first-ledger from 5008b73cce
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 8s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 17s
windows / windows docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m12s
windows / cargo nextest (Windows) (pull_request) Successful in 4m25s
windows / frontend smoke (Windows) (pull_request) Successful in 1m1s
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
to d5a33321ad
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 8s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 17s
windows / windows docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m11s
windows / cargo nextest (Windows) (pull_request) Successful in 4m5s
windows / frontend smoke (Windows) (pull_request) Successful in 42s
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
2026-10-13 12:23:58 +09:00
Compare
natsukium force-pushed protocol/schema-first-ledger from d5a33321ad
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 8s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 17s
windows / windows docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m11s
windows / cargo nextest (Windows) (pull_request) Successful in 4m5s
windows / frontend smoke (Windows) (pull_request) Successful in 42s
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
to cb7a6589f0
All checks were successful
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Successful in 3m16s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 2m17s
pr / nix flake check (pull_request) Successful in 2m25s
pr / cargo build / clippy / test / deny (pull_request) Successful in 4m36s
pr / wire schema is compatible with the base (pull_request) Successful in 2m23s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 1m7s
windows / cargo clippy (Windows cross) (pull_request) Successful in 1m19s
windows / detect relevant changes (pull_request) Successful in 2m12s
windows / windows docs-only no-op (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 2m16s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 2m12s
windows / cargo nextest (Windows) (pull_request) Successful in 4m49s
windows / frontend smoke (Windows) (pull_request) Successful in 2m35s
2026-10-13 13:01:57 +09:00
Compare
natsukium deleted branch protocol/schema-first-ledger 2026-10-13 22:27:08 +09:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
felis-terminal/felis!135
No description provided.