Terminology Guard Exemption Policy
This document describes the surfaces deliberately excluded from the two active terminology drift guards:
tests/contract/test_terminology_guards.py— live-doc scan for deprecated CLI option names and removed command patternstests/architectural/test_no_legacy_terminology.py— repo-wide scan for specific forbidden legacy terms
These exclusions are intentional policy decisions, not workarounds. The rationale for each exempt surface is recorded here so future contributors can distinguish "this surface is correctly out of scope" from "this surface was accidentally missed."
Background
The terminology guards enforce that active, first-party surfaces — source code, doctrine skills, and live documentation — stay aligned with the canonical vocabulary. They scan live surfaces only; surfaces that are historical records or archival snapshots are deliberately out of scope.
Four categories of surfaces are currently exempt from the live-doc component of the guards. Each is described below.
Exempt Surface 1: docs/adr/ — Immutable Architectural Decision Records
What is excluded
All files under docs/adr/ are excluded from:
- the live-doc scan in
_live_doc_scan_targets()intests/contract/test_terminology_guards.py - the legacy-term scan
_EXCLUDED_PATH_FRAGMENTSintests/architectural/test_no_legacy_terminology.py
Why it is exempt
Architectural Decision Records (ADRs) are immutable, byte-invariant snapshots by convention (NFR-001/C-002/C-006). An ADR records the reasoning behind a decision at a specific point in time. Once an ADR is written, its body is never modified — even if the vocabulary it uses has since been superseded. Retroactively altering an ADR body would corrupt the historical record and undermine the purpose of decision documentation.
The docs/adr/ tree was relocated from architecture/ (which was already
outside the scan perimeter) into docs/ during the Common Docs consolidation
(mission doc-quality-hardening). The exemption was carried over so that the
relocation did not introduce spurious guard failures on files that are
intentionally historical.
Scope boundary
The exemption is narrow: only docs/adr/. All other pages under docs/ remain
scanned. This narrowness is pinned by test_docs_adr_exemption_is_narrow in both
guard files, which confirms that live docs pages outside the exempt roots are
still being scanned.
Exempt Surface 2: Unreleased-Only CHANGELOG Scan
What is excluded
Both CHANGELOG.md (at the repository root) and docs/changelog/CHANGELOG.md
are scanned, but only the unreleased section — the portion of the file above
the first versioned heading — is checked for terminology drift. Historical version
sections are not scanned.
Why it is exempt
A CHANGELOG is an append-at-the-top log. Each released version section records what changed at the time of that release, using vocabulary that was canonical at that time. Rewriting historical version sections to conform to vocabulary that became canonical later would make the CHANGELOG historically inaccurate.
The Unreleased section, by contrast, describes work that has not yet shipped
and must reflect current canonical vocabulary.
How it is implemented
The guard implements this boundary via _extract_changelog_unreleased(), which
returns only the content above the first ## [X.Y.Z] heading. Both CHANGELOG
files are explicitly excluded from the docs/**/*.md glob and processed
separately through this extractor, ensuring only the unreleased content is
evaluated.
The docs/changelog/index.md index page is not a CHANGELOG file and is still
scanned as a normal live doc.
Exempt Surface 3: Archived Sub-areas Under docs/plans/
What is excluded
Three subdirectories under docs/plans/ are excluded from the live-doc scan:
docs/plans/engineering-notes/docs/plans/initiatives/docs/plans/notes/
Why it is exempt
These subdirectories contain archival records relocated from the previously
unscanned architecture/ tree during the Common Docs consolidation. Their
content consists of:
engineering-notes/— retained deep-dive notes from earlier development erasinitiatives/— completed initiative records describing work that has already concludednotes/— informal engineering notes from previous development cycles
All three are archival: they document decisions, investigations, and completed
work. Their content uses vocabulary that was current at the time of writing and
is not maintained going forward. Scanning them would produce false positives that
cannot be remediated without rewriting historical context — the same reasoning
that exempts docs/adr/.
Scope boundary
Only the three named subdirectories are exempt. The docs/plans/ root and all
non-archival pages at the top level of docs/plans/ remain live surfaces that
are fully scanned.
Exempt Surface 4: docs/migrations/ — Migration Runbooks
What is excluded
All files under docs/migrations/ are excluded from the live-doc scan.
Why it is exempt
Migration runbooks must name the deprecated flags, commands, and workflows they
help users move away from — --feature, the pre-3.0 main-centric workflow, legacy
env vars, and so on. The whole purpose of a migration doc is to reference the old
vocabulary verbatim so a reader can find-and-replace it. Scanning these pages
would flag the very terms they exist to document, producing false positives that
cannot be remediated without defeating the doc's purpose. Same reasoning as
docs/adr/: the content legitimately carries era-correct vocabulary.
Scope boundary
Only docs/migrations/ is exempt. All other live docs/ pages remain fully
scanned.
Invariant: Exemptions Must Stay Narrow
Each exemption above is explicitly bounded. The guards include non-vacuity and narrowness checks:
test_docs_adr_exemption_is_narrow(in both guard files) confirms that livedocs/pages outside the exempt roots are still being scanned.- The CHANGELOG handling must remain via
_extract_changelog_unreleased()rather than a raw glob that would skip the file entirely. test_grep_guards_do_not_scan_historical_artifactsconfirms that no glob pattern in the guards directly targets anyFORBIDDEN_SCAN_ROOTSroot.
If a future change widens an exemption beyond its stated boundary — for example,
by exempting all of docs/plans/ instead of only the three archival
subdirectories, or by treating all of docs/ as historical — that is a
regression, not maintenance.
Updating This Policy
If a new surface requires an exemption:
- Update
FORBIDDEN_SCAN_ROOTSintests/contract/test_terminology_guards.py. - Update
_EXCLUDED_PATH_FRAGMENTSintests/architectural/test_no_legacy_terminology.pyif the legacy-term scan is also affected. - Update this document to record the rationale and scope boundary for the new exemption.
- Add or update a narrowness test that pins both the exempt surface and the non-exempt remainder, so a future glob change cannot silently widen the carve-out.