docs: require contract change routing

This commit is contained in:
Frank Song
2026-05-26 10:06:50 +08:00
parent 48a2e79224
commit 8f152a005e
4 changed files with 75 additions and 0 deletions

View File

@@ -3,6 +3,10 @@
## [Unreleased]
### Changed
- Contributor guidance now requires explicit `Contract Routing` for contract-affecting PRs and `Contract Change` when a PR intentionally changes an existing product, runtime, or review contract. Contract tests must move with the corresponding docs instead of silently redefining behavior by themselves.
## [v0.51.137] — 2026-05-25 — Release DI (stage-batch19 — 6-PR medium-risk batch)
### Added

View File

@@ -20,6 +20,21 @@ Use those documents as review guardrails: keep the change scoped, preserve the
no-build-step architecture, update docs/changelog when behavior changes, include
UI evidence for UI changes, and add tests for behavior changes where practical.
### Contract-affecting PRs
A contract-affecting PR is any change that updates a public contract document,
an RFC, a contributor guide, a product-semantics test, or behavior that those
documents already describe. These PRs need an explicit `Contract Routing` section
in the PR body that names the touched contract family and the evidence used.
If the PR intentionally changes an existing contract, add a `Contract Change`
section that states the old rule, the new rule, and why the change is justified.
Do not silently redefine product behavior by changing tests alone; update the
corresponding docs in the same PR.
A release batch should call out included contract-affecting PRs separately
from ordinary fixes, even when the code diff is small and CI is green.
## Two Paths to a Strong Pull Request
### Path 1: Small, Focused Changes

View File

@@ -102,6 +102,26 @@ Evidence needed before claiming done:
For small, obvious fixes, keep this short. The goal is to avoid routing mistakes,
not to create process overhead.
## Contract changes
Changing contract documents, RFC guidance, or contract tests changes review
expectations for future contributors. A PR that intentionally changes an
existing contract should include a `Contract Change` section in its PR body with:
- the previous contract,
- the new contract,
- the affected docs and tests,
- the compatibility or migration reason.
Contract tests and corresponding docs must move together. Tests that encode
product semantics must not silently redefine the contract by asserting the
opposite behavior without updating the public docs and naming the change in the
PR body.
Release batches should list included contract-affecting PRs explicitly so
reviewers can distinguish ordinary green-CI fixes from changes that update the
project's product or runtime guardrails.
## PR preparation checklist
Before opening or updating a PR, verify `CONTRIBUTING.md` against the actual PR
@@ -118,6 +138,8 @@ Required checks:
- UI/UX changes include before/after evidence and responsive-state coverage.
- Runtime/streaming changes name the state layer or invariant being changed and
list the regression or manual invariant check.
- Contract-affecting PRs include `Contract Routing`; intentional contract
changes also include `Contract Change`.
- Onboarding/setup validation used isolated `HERMES_HOME` and
`HERMES_WEBUI_STATE_DIR`, unless the human operator explicitly requested real
state.

View File

@@ -0,0 +1,34 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
CONTRIBUTING = ROOT / "CONTRIBUTING.md"
CONTRACTS = ROOT / "docs" / "CONTRACTS.md"
def 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 == []
def test_contracts_requires_docs_tests_and_pr_body_to_move_together():
text = CONTRACTS.read_text(encoding="utf-8")
required_terms = [
"Contract Change",
"contract tests",
"corresponding docs",
"must not silently redefine",
]
missing = [term for term in required_terms if term not in text]
assert missing == []