Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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, with the current static coverage documented as advisory rather than a GitHub policy gate.

## [v0.51.137] — 2026-05-25 — Release DI (stage-batch19 — 6-PR medium-risk batch)

### Added
Expand Down
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ 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.
See [`docs/CONTRACTS.md#contract-routing`](docs/CONTRACTS.md#contract-routing)
for the short routing shape and [`docs/CONTRACTS.md#contract-changes`](docs/CONTRACTS.md#contract-changes)
for intentional contract changes.

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
Expand Down
29 changes: 29 additions & 0 deletions docs/CONTRACTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,33 @@ 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.

The static tests for this guidance are advisory coverage. They pin contributor
wording so the rule stays visible. This advisory coverage is not an automated
policy gate; static coverage is not an automated policy gate and does not enforce
PR-body content on GitHub. A future release-time or CI check could
surface contract-affecting diffs whose PR body lacks `Contract Routing`, but this
document only defines the review expectation.

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
Expand All @@ -118,6 +145,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.
Expand Down
49 changes: 49 additions & 0 deletions tests/test_contract_review_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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 == []


def test_contract_guidance_names_static_coverage_as_advisory_not_enforcement():
text = CONTRACTS.read_text(encoding="utf-8")

required_terms = [
"advisory",
"not an automated policy gate",
"does not enforce",
"PR-body content",
"release-time",
]

missing = [term for term in required_terms if term not in text]
assert missing == []
Loading