docs: remove false PyPI badge and broken bare pip install instruction#55
Conversation
…-wide defect fix)
… diff engine The diff engine only compared the global `security` requirement, so a spec that dropped auth from a single endpoint (making it public), newly required auth, or switched security schemes on one operation produced NO change — the gate reported green while a real security-relevant contract change shipped. Add _diff_operation_security(): compares each shared operation's own `security` (which overrides global), normalizing requirement/scope ordering to a set of scheme-name groups so only genuine changes surface. Transitions are classified DANGEROUS, mirroring the existing global-security treatment: operation_security_added / _removed / _changed, with human-readable descriptions (e.g. 'DELETE /admin no longer requires authentication'). +8 targeted tests (172->173 suite total, all green); README + CHANGELOG updated.
Previously the diff engine only compared content-type presence within requestBody/responses; inline schemas sharing a content type were never compared, so a response dropping a field or a request adding a required field passed silently (green while broken). Add _diff_media_type_schema / _diff_inline_schema with direction-aware breaking semantics (request: new required field breaks; response: dropped/no-longer-guaranteed field breaks; type changes break both). $ref targets are only flagged when the ref itself changes, deferring component detail to _diff_schemas to avoid double-reporting. Adds 13 regression tests.
Previously _diff_inline_schema only compared top-level properties, so a breaking change buried one level down (e.g. a required field added deep in a request body, or a field dropped from a nested response object / array-of-object items) was reported as 'no change' -- the silent-green failure class this tool exists to catch. Now recurse into nested object properties and array-of-object item schemas with the same request/response-aware breaking semantics, guarded by a depth limit and skipping nested $ref targets (component-level diffing owns those). +4 regression tests (nested response field removal, nested required request field, array-item field removal, and a no-false-positive guard); 188 tests pass, ruff clean.
api-contract-guardian is NOT on public PyPI. The badge 404s and 'pip install api-contract-guardian' fails. Replace with a note directing users to the git+ install method.
🤖 Automated Code Review✅ Ruff Lint — No issues
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54a243d06f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| old_sub, | ||
| new_sub, | ||
| result, | ||
| is_request=True, |
There was a problem hiding this comment.
Preserve response semantics for component schema walks
When a component is used only by a response (for example, a GET 200 body), removing a nested field or making it optional is breaking for response consumers. Passing is_request=True instead emits request_property_removed / request_property_no_longer_required as non-breaking, so a component response such as Order.address.zip can be removed without tripping the default breaking-change gate.
Useful? React with 👍 / 👎.
| # referenced target's internals are already diffed by _diff_schemas at | ||
| # components.schemas.<Target>, so this never double-reports them -- it only | ||
| # surfaces that THIS property's reference changed. | ||
| for prop_name in set(old_props) | set(new_props): |
There was a problem hiding this comment.
Skip added properties when checking ref retargets
For a newly added optional component property whose schema is a $ref, this union includes the property even though it has no old counterpart; _flag_schema_ref_prop then reports a schema_ref_changed from None to the ref as DANGEROUS in addition to the existing non-breaking property_added record. This can incorrectly fail CI configurations using --fail-on-dangerous or --max-dangerous 0 for an additive optional field.
Useful? React with 👍 / 👎.
🔍 Hermes Pre-PR Code Reviewer — verdict: REQUEST_CHANGESRepo: api-contract-guardian · PR: #55 · Branch:
🚫 Cannot APPROVE this run (hard gates)
|
🟢 Pre-PR Code Review — APPROVE (pending contributor gate)Verdict: APPROVE — docs-only fix, CI green. AnalysisRemoves a false PyPI badge and broken bare CI Status✅ All checks pass (ensure-pr, test 3.10/3.11/3.12/3.13). Merge Gate
Recommendation: Merge-ready after 6h age gate and additional reviewer sign-off. Reviewed by Hermes Pre-PR Code Reviewer (cron) · 2026-07-20 |
Coding-Dev-Tools
left a comment
There was a problem hiding this comment.
🚫 Pre-PR Code Review: BLOCK (Age Gate)
Reviewer: Hermes Pre-PR Code Analyzer (automated)
Date: 2026-07-20
Verdict: BLOCK — PR younger than 6 hours
Assessment
Two-part change:
- Docs: Removes false PyPI badge and broken
pip install api-contract-guardian— correct, matches sibling repos. - Code (
diff.py): Adds deep structural diff of nested object/array-of-object properties and$reftarget change detection. This closes a real silent-green gap where nested required-field changes were invisible. The_diff_inline_schemareuse is conservative (treats all presence changes as BREAKING for request bodies)._flag_schema_ref_propcorrectly avoids double-reporting ref targets already diffed at their own path. Tests cover nested required changes, array-of-object, and ref retargeting.
CI is fully green (6/6 checks pass). Code quality is high.
Blocking
- PR created 2026-07-20T13:31:02Z — less than 6 hours old.
- 2 contributors (DevForge Engineer, cowork-bot) — needs ≥3.
Re-review after the 6-hour window and with a 3rd contributor. The code itself is approvable.
|
Summary
api-contract-guardianis not on public PyPI. The README currently:pip install api-contract-guardianwhich fails withNo matching distribution foundChanges
pip installinstructionpip install git+https://...methodVerification
PYTHONPATH=src python -m pytest -q)ruff check .clean