Skip to content

fix(wire): tolerate coherence finding codes this build has never heard of - #102

Merged
rennehan merged 3 commits into
mainfrom
feat/open-finding-code
Aug 5, 2026
Merged

fix(wire): tolerate coherence finding codes this build has never heard of#102
rennehan merged 3 commits into
mainfrom
feat/open-finding-code

Conversation

@rennehan

@rennehan rennehan commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes the CLI half of the open-finding-code contract.

The break

Finding.code is an open set server-side — codes are added additively as new coherence rules ship. The vendored spec closed it into a generated enum:

pub enum Code { UnsatisfiedInput, DanglingWire, TypeMismatch }

No catch-all, no #[serde(other)]. The first validate response carrying a code this build has not heard of fails to deserialize entirely — not the one unfamiliar finding, the whole response. An installed CLI that is merely out of date becomes one that cannot read a validate response at all, and every additive server-side rule becomes a coordinated release.

The fix

The server now publishes code as a plain string with the known values in its description, so regenerating drops the enum altogether.

That is stronger than adding an Unknown arm: there is no closed type left to fall out of, and the unrecognized code survives as the string the server sent rather than collapsing into a variant with no name in it. A user told orphan_node can search for orphan_node; a user told Unknown cannot.

Consequences in src/:

  • partition::key loses the serde_json::to_value round-trip it used to recover the enum's wire spelling — f.code is already that string.
  • validate::code_str's three-arm match is deleted; human and JSON output print whatever the server said.

severity deliberately stays closed. It is a two-valued verdict the CLI branches on to pick an exit code, so a third value is a real breaking change that should fail loud rather than fall through to "not an error". Pinned by a test.

Regeneration scope

openapi.json was re-vendored and wire/ regenerated from it, so this also picks up the project and branch lifecycle routes and the decisions read surface that landed on the server since the last vendor. No src/ change was needed for those — they are additive.

Tests

Three new tests in src/cmd/validate.rs: an unknown code deserializes, an unknown code is rendered verbatim, and an unknown severity is still rejected. cargo test green (485 tests), cargo clippy -D warnings clean, cargo fmt --check clean.

🤖 Generated with Claude Code

…d of

The server publishes `Finding.code` as an open set — codes are added
additively as new coherence rules ship. The vendored spec closed it into a
generated enum with three variants and no fallback arm, so the first validate
response carrying an unfamiliar code failed to deserialize *entirely*: not
the one unknown finding, the whole response. An installed CLI that was merely
out of date became one that could not read a validate response at all, and
every additive server-side rule became a coordinated release.

The spec now types `code` as a plain string with the known values in its
description, so regenerating drops the enum altogether. That is a stronger
fix than a `#[serde(other)] Unknown` arm: there is no closed type left to
fall out of, and the unrecognized code survives as the string the server sent
rather than collapsing to a variant with no name in it. `partition`'s key
function loses the serde round-trip it used to recover the enum's wire
spelling, and `validate`'s `code_str` match goes with it — the human and JSON
output now print whatever the server said.

`severity` deliberately stays closed. It is a two-valued verdict the CLI
branches on to choose an exit code, so a third value is a real breaking
change that should fail loud rather than fall through to "not an error".
Pinned by a test.

Re-vendored `openapi.json` and regenerated `wire/` from it, which also picks
up the project and branch lifecycle routes and the decisions read surface
that had landed on the server since the last vendor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rennehan rennehan added the bug Something isn't working label Aug 5, 2026
@rennehan rennehan self-assigned this Aug 5, 2026
@rennehan rennehan added the bug Something isn't working label Aug 5, 2026
rennehan and others added 2 commits August 5, 2026 10:09
…fmt's

`cargo fmt` (no `-p`) reformats the workspace, and `wire/` is a member — so
it rewrote all 87 generated files and the regenerate-and-diff guard failed on
every one of them. CI formats the hand-written crate only
(`cargo fmt -p hydrate -- --check`) for exactly this reason: the committed
wire client must be byte-identical to what `scripts/regen-wire.sh` produces,
or the guard cannot tell a real spec drift from a formatting preference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Additive: `DecisionOut` gains the nullable acceptance criterion, so the
generated `decision_out.rs` gains an `Option<String>`. No hand-written code
references it — the CLI does not call the decisions routes — but the
regenerate-and-diff guard compares the committed crate against the vendored
spec, so the two have to move together.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rennehan
rennehan merged commit c1ce842 into main Aug 5, 2026
3 checks passed
@rennehan
rennehan deleted the feat/open-finding-code branch August 5, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant