epiphany/spikes/editor-toolkit/round2-candidatekit
Levi Neuwirth ad4f6ed4f3 Pin-13 schema amendment 3: the provider invariant moves into the type
Appends to 775d7ba, which is left untouched.

That amendment put the non-empty check in a constructor and in Deserialize,
and left `Inherited { provider: String }` public. So the struct-literal path
bypassed both -- and the very first caller took it: C1's adapter rows were
written as `IntegrationOwnership::Inherited { provider: "...".to_string() }`,
never touching the constructor that was supposed to be guarding them. A
checked constructor sitting beside a public field is a suggestion. The field
is the API.

Provider is now a newtype whose inner String is private, so every route in
-- Provider::new, Deserialize -- runs the same check, and an empty provider
cannot be constructed on any path outside this module. The compiler proved
it during the change: converting the field turned my own struct-literal
test sites into type errors, which is exactly the class of site that had
been slipping through. I also compiled a deliberate bypass from outside the
module to confirm it is rejected rather than assume it:

    error[E0308]: mismatched types
      provider: String::new(),
                ^^^^^^^^^^^^^ expected `Provider`, found `String`

and reverted that probe byte-identically.

Two new tests beyond the constructor and wire cases already present. One
pins the serialization consequence a type error cannot express: every
Provider that exists has been checked, so no serialized row can carry an
empty one. The other round-trips a whole adapter row and asserts the
provider survives intact, since the shape a real report carries this in is
the row, not the enum alone.

C1's two construction sites are converted to the checked constructor. No
report values change -- both candidates already named real providers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RSX4zSLgKvtiXaPjnMqLGz
2026-07-30 20:39:32 -04:00
..
src Pin-13 schema amendment 3: the provider invariant moves into the type 2026-07-30 20:39:32 -04:00
tests Packet 2B apparatus: the neutral candidatekit and the check-5 oracle 2026-07-30 15:49:07 -04:00
Cargo.toml Packet 2B apparatus: the neutral candidatekit and the check-5 oracle 2026-07-30 15:49:07 -04:00