docs: require contract change routing#2960
Conversation
|
Read the diff against The static test only checks documentation strings, not behaviordef test_contributing_requires_contract_routing_for_contract_affecting_prs():
text = CONTRIBUTING.read_text(encoding="utf-8")
required_terms = [
"contract-affecting PR",
"Contract Routing",
"Contract Change",
"release batch",
]
missing = [term for term in required_terms if term not in text]
assert missing == []This pins specific copy in That's the well-known shape of a static-content regression test, and it's not new in this repo — but for a process contract, this is weaker than the equivalent test for a runtime contract. A runtime contract test fails when the behavior changes. This test fails only when the literal string That gap is fine if the PR description is honest that this is advisory coverage, not enforcement. The current framing in "Tests must move with docs" is hard to enforce without toolingThe new section in
In practice, the way a PR "silently redefines a contract" is by editing an assertion (e.g.
The PR explicitly excludes both from scope, which is fine, but it means the rule lives entirely as social contract. That's an honest trade-off given the small scope; just worth being clear that without enforcement, this is a norm dressed as a contract. The next contributor to invert a test will not be stopped by any check — only by a reviewer noticing. A cheap step that would actually catch the failure mode: a Smaller things
Bigger questionIssue #2959 frames the problem as "CI turns green while product direction silently shifts." This PR's response is "add prose in two docs and a test that pins the prose." That doesn't actually close the failure mode the issue describes — it just makes the rule citeable. If the goal is closing the gap, this should probably be labeled "phase 1: write down the rule" with a follow-up tracked for "phase 2: enforce at release time." If the goal is just documenting the norm, then the issue's framing is over-promising what this PR will deliver, and the issue should be updated to match. That's a maintainer call, not a blocker on the diff. Diff itself is small, safe, and well-tested for what it pins. |
|
Follow-up pushed in What changed:
Verification:
Scope boundary:
|
Thinking Path
Fixes #2959.
Contract Routing
Task type: contributor-process guardrail
Touched areas:
CONTRIBUTING.mddocs/CONTRACTS.mdtests/test_contract_review_gate.pyCHANGELOG.mdRelevant public docs:
AGENTS.mdCONTRIBUTING.mddocs/CONTRACTS.mdScope boundaries:
Evidence needed before claiming done:
Contract Routing,Contract Change, contract tests, corresponding docs, and release-batch callouts.What Changed
Contract-affecting PRssection toCONTRIBUTING.md.Contract changessection todocs/CONTRACTS.md.Contract Routing, and intentional contract changes requireContract Change.tests/test_contract_review_gate.pyto pin the process terms.Why It Matters
Contracts should prevent accidental product-direction changes, not just document them after the fact. When a PR changes product semantics or the tests that encode them, reviewers need an explicit signal that the PR is changing a contract rather than merely fixing a local bug.
Verification
python3 -m pytest tests/test_contract_review_gate.py -q-> failed on missingContract Routing,Contract Change,contract tests, corresponding-docs language, and release-batch callout.python3 -m pytest tests/test_contract_review_gate.py tests/test_canonical_session_resolution_rfc.py -q->4 passedgit diff --checkRisks / Follow-ups
Model Used
OpenAI GPT-5 via Codex app agent. Tool use: local repo inspection, GitHub CLI, pytest, git worktree, and git push/PR creation.