fix: stop the tool making claims its own code does not support - #52
Merged
Conversation
Four defects, all the same shape: something asserted a fact that was not
checked against the thing it described.
The README showed hand-written CLI output. Every identifier in it was wrong:
`CHG-OPERATION-REMOVED-1` where change ids are built from
`kind.value.upper()` and every ChangeKind value is snake_case, so a hyphen
there is not producible; `DRIFT-FIELD` where the real literal is
`DRIFT-MISSING-FIELD`. A reader who copied either and grepped for it found
nothing. The examples are now captured from real runs by
`scripts/capture_readme_examples.py`, spliced between markers, with a
`--check` mode wired into CI that fails when the committed README stops
matching what the code produces. Confirmed it catches exactly the original
defect: restoring one hyphenated id fails the check.
Capturing the diff example surfaced the reason nobody noticed. The shared
terminal renderer looked for a `severity` and a `rule_id`; a Change has
neither, so `apiverity diff` printed
[] operation 'DELETE /users/{id}' was removed
-- an empty bracket, and the change id dropped entirely, even though every
Change carries one for exactly this purpose. The renderer now falls back to
the change's direction and id, and omits the bracket rather than printing an
empty one.
Change ids did not have the property ARCHITECTURE.md claimed. Documented as
`CHG-{kind}-{operation-hash}-{index}`, emitted as a flat `CHG-{KIND}-{N}` from
one counter shared across every operation. Measured: a requiredness change on
`GET /zebra` was `CHG-PARAMETER_REQUIREDNESS-1` until an unrelated `/alpha`
endpoint was added, after which the same change became `-2`. An id quoted in a
review then pointed somewhere else. The ordinal is now scoped per (kind,
operation).
Being precise about what was *not* broken, since the doc's wording implied
more: stability under document reordering already held, because `run()`
iterates `sorted()` over operation keys. ARCHITECTURE.md now separates the two
guarantees instead of attributing both to the id format.
The artifact envelope asserted three things it did not check:
- `tool_version` was the literal "0.1.0", so every result bundle, JSON export
and SARIF upload ever written claimed 0.1.0 whatever produced it. Read from
the installed package now, with a test comparing it to pyproject rather than
to a literal so the test cannot go stale itself.
- `protocol_version` was fixed at "openapi-3.x", so a gRPC or AsyncAPI run
wrote an artifact claiming to be OpenAPI. Taken from the loaded contract.
- `redaction` was `{"applied": true, "sensitive_field_count": 10}` on every
artifact unconditionally. `enrich()` performs no redaction at all -- that
was a fabricated claim about a security control, stamped identically onto
outputs with nothing sensitive in them. It now reports honestly that no
redaction was applied here and points at where redaction actually happens.
The test that asserted `redaction["applied"] is True` was pinning the
fabrication in place; it now asserts the truth.
Also corrects ARCHITECTURE.md's "React 18" against a package.json on 19.2.8.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
API Verity — contract reviewOne comment per PR — updated on each push. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four defects, all the same shape: something asserted a fact that was never checked against the thing it described. This is the plan's §2.0 finding, closed.
The README showed output the code cannot produce
CHG-OPERATION-REMOVED-1CHG-OPERATION_REMOVED-…CHG-PARAM-REQUIREDNESS-2CHG-PARAMETER_REQUIREDNESS-…DRIFT-FIELDDRIFT-MISSING-FIELDDRIFT-UNDECLAREDDRIFT-UNDECLARED-FIELDChange ids are built from
kind.value.upper()and everyChangeKindvalue is snake_case, so a hyphen there is not producible. A reader who copied an id out of the README and grepped for it found nothing.Examples are now captured from real runs by
scripts/capture_readme_examples.pyand spliced between markers, with--checkwired into CI. Confirmed non-vacuous: restoring one hyphenated id fails the check with a diff.Capturing it surfaced why nobody noticed
The shared terminal renderer looks for a
severityand arule_id. AChangehas neither, soapiverity diffprinted:An empty bracket, and the change id dropped entirely — even though every Change carries one for exactly this purpose. Now:
Change ids lacked the property the docs promised
Documented as
CHG-{kind}-{operation-hash}-{index}; emitted as a flatCHG-{KIND}-{N}from one counter shared across every operation. Measured:An id quoted in a review, or used to suppress a finding, pointed somewhere else once an unrelated endpoint appeared. The ordinal is now scoped per (kind, operation).
Being precise about what was not broken, because the doc's wording implied more than was wrong: stability under document reordering already held, since
run()iteratessorted()over operation keys. I checked before claiming credit for it — 3 of the 7 new tests pass against the old implementation.ARCHITECTURE.mdnow separates the two guarantees instead of attributing both to the id format.The artifact envelope asserted three unchecked things
tool_versionwas the literal"0.1.0"— every result bundle, JSON export and SARIF upload ever written claimed 0.1.0 whatever produced it. A consumer diffing two bundles would conclude the tool had not changed. Read from the installed package now, and the test compares it topyproject.tomlrather than to a literal, so the test cannot go stale itself.protocol_versionwas fixed at"openapi-3.x"— a gRPC or AsyncAPI run wrote an artifact claiming to be OpenAPI. Nowgrpcfor a.proto, verified.redactionwas{"applied": true, "sensitive_field_count": 10}on every artifact, unconditionally.enrich()performs no redaction at all. That was a fabricated claim about a security control, stamped identically onto outputs with nothing sensitive in them — and it was machine-readable, so tooling consumed it. It now reports that no redaction applied here and points attraffic/redact.py, where redaction genuinely happens.The existing test asserted
redaction["applied"] is True, pinning the fabrication in place. It asserts the truth now.Verification
ruff ✅ · mypy (90 files) ✅ · pytest 81.08% against a 72% floor ✅ · e2e ✅ ·
capture_readme_examples.py --check✅ ·generate_rule_catalog.py --check✅Also corrects
ARCHITECTURE.md's "React 18" against apackage.jsonon 19.2.8.