Skip to content

fix: stop the tool making claims its own code does not support - #52

Merged
webdevsamran merged 1 commit into
mainfrom
fix/readme-truth-and-provenance
Sep 7, 2026
Merged

fix: stop the tool making claims its own code does not support#52
webdevsamran merged 1 commit into
mainfrom
fix/readme-truth-and-provenance

Conversation

@webdevsamran

Copy link
Copy Markdown
Owner

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

README claimed Code emits
CHG-OPERATION-REMOVED-1 CHG-OPERATION_REMOVED-…
CHG-PARAM-REQUIREDNESS-2 CHG-PARAMETER_REQUIREDNESS-…
DRIFT-FIELD DRIFT-MISSING-FIELD
DRIFT-UNDECLARED DRIFT-UNDECLARED-FIELD

Change ids are built from kind.value.upper() and every ChangeKind value 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.py and spliced between markers, with --check wired 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 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. Now:

[meta] CHG-OPERATION_REMOVED-92658ed2-1  operation 'DELETE /users/{id}' was removed

Change ids lacked the property the docs promised

Documented as CHG-{kind}-{operation-hash}-{index}; emitted as a flat CHG-{KIND}-{N} from one counter shared across every operation. Measured:

GET /zebra alone     : CHG-PARAMETER_REQUIREDNESS-1
after adding /alpha  : CHG-PARAMETER_REQUIREDNESS-2     ← same change, new id

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() iterates sorted() over operation keys. I checked before claiming credit for it — 3 of the 7 new tests pass against the old implementation. ARCHITECTURE.md now separates the two guarantees instead of attributing both to the id format.

The artifact envelope asserted three unchecked things

  • tool_version was 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 to pyproject.toml rather than to a literal, so the test cannot go stale itself.
  • protocol_version was fixed at "openapi-3.x" — a gRPC or AsyncAPI run wrote an artifact claiming to be OpenAPI. Now grpc for a .proto, verified.
  • 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 — and it was machine-readable, so tooling consumed it. It now reports that no redaction applied here and points at traffic/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 a package.json on 19.2.8.

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.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

API Verity — contract review

One comment per PR — updated on each push.

@webdevsamran
webdevsamran merged commit ec5d1bf into main Sep 7, 2026
8 checks passed
@webdevsamran
webdevsamran deleted the fix/readme-truth-and-provenance branch September 7, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant