Skip to content

[Codegen#71] interface-001: compare the serde envelope, not label(), and census ALL against the enum declaration #71

Closed

Description

@kreneskyp

Two follow-ups from the PR #69 review chain. Neither blocked the merge; both are
cheap and both remove a duplicated source of truth.

1. label() duplicates what serde already produces

GenerationTerminalState carries #[serde(rename_all = "kebab-case")]
(src/oracle.rs:84) and AttestationResult carries snake_case (:305). Both
label() implementations return exactly those strings today, so nothing is
wrong right now — but it is a second source of truth for the wire vocabulary.

interface-001-AC-3 and AC-4 claim the contract describes "the envelope the
generator emits". The generator emits the serde form; the test compares the
label() form. A #[serde(rename = "io_failed")] on one variant would drift
the emitted JSON from the contract with the suite still green.

Fix is one line per test — serde_json::to_value(state) instead of label(),
the same technique already used for pins and required in that file. It makes
the "envelope the generator emits" wording literally true and removes both a
duplicated vocabulary and a new public method.

Orthogonal to item 2 — it does not remove the need for ALL.

2. A source census would close the ALL completeness gap

GenerationTerminalState::ALL and AttestationResult::ALL are hand-maintained
arrays. label()'s exhaustive match forces a compile error on a new variant,
but nothing then carries that variant into ALL, so a variant named in label()
and omitted from ALL still passes every assertion. This is documented honestly
in three places rather than claimed away.

The alternatives were worked and none closes it on stable without a new
dependency:

  • std::mem::variant_count::<T>() — nightly-only (#![feature(variant_count)])
  • strum::EnumCount/EnumIter — closes it properly, but adds a proc-macro
    dependency to deny.toml's surface
  • exhaustiveness runs one direction only: a match is checked against the
    variant set; a list is never checked for completeness against it, and the
    type system has no inverse
  • the index round-trip (const fn index() + from_index()) does not close it —
    add TimedOut, name it => 6, leave ALL at six, and every assertion stays
    bounded by ALL.len() while from_index(6) is None
  • discriminant arithmetic (#[repr(u8)], ALL.len() == LAST as usize + 1) just
    relocates the hand-written constant

What would catch it: a source census over the enum declaration in
src/oracle.rs — count the variant identifiers between the braces and assert the
count equals ALL.len(). That is exactly the tripwire strength this repo already
ships three times and already documents honestly as a floor rather than a proof.

Activity

  1. changed the title [-]interface-001: compare the serde envelope, not label(), and census ALL against the enum declaration[/-] [+][Codegen#71] interface-001: compare the serde envelope, not label(), and census ALL against the enum declaration[/+] on Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions