| name | docs-drift-guard |
| description | Blocks calling a code change "done" when it renamed, added, removed, or changed a public name, flag, command, default value, count, config key, or behavior but left the docs (README, CHANGELOG, docs/, examples, --help text, code comments/docstrings) still referencing the old surface. Best used reactively after code changes a public name, flag, command, default value, count, config key, or behavior. Use when the user says "rename", "change the flag", "update the API", "add a command", "bump the version", or after any change to a user-facing surface. DO NOT USE for pure internal refactors with no public surface, or for verifying tests (test-code quality is out of proofguard's scope; a test-quality-guard is in `deferred/`, not yet shipped); this guard checks that DOCS match the code after a change. |
docs-drift-guard
"Docs are part of done." A change that renames a flag, adds a command, or
flips a default is not finished the moment the code compiles — it is
finished when every doc that describes the old surface has been found and
updated to describe the new one. This guard blocks the completion claim
until that grep has actually been run.
The failure mode this guard targets is AI-slop documentation: grammatically
perfect JSDoc/README prose that describes what the model thinks the code
does — inferred from the function/flag/command name — rather than what it
actually does after the rename. A renamed flag silently drifts from its own
docs because nothing forced the two to be checked against each other.
When to use — three modes
- Guard-pass (default). Right before saying a change is "done" that
touched a public name, flag, command, default value, count, config key, or
behavior: diff the public surface, grep the whole repo for every OLD
token, and update or explicitly list every doc file that still references
it. This is the mode that fires on "rename", "change the flag", "update
the API", "add a command", "bump the version," or any commit/PR that
touches a user-facing surface.
- Live. While actively making the rename/add/remove: update the doc
reference in the same edit pass as the code change, rather than batching
"fix the docs" as an afterthought at the end. If you touch
cli.js to
rename a flag, touch the README's flag table in the same turn.
- Review. When asked "did the docs get updated?" / "is this in sync?":
audit as a critic — grep for the old token across the whole repo, list
every remaining hit with file and line, and do not silently patch them
unless asked to fix what you find.
What this guard blocks
- Rename/remove/add a public token → grep the WHOLE repo for the OLD
token, update every doc that references it. A "public token" is a CLI
flag, subcommand name, exported function/class name, environment
variable, config key, default value, or a documented count. When one of
these changes, grep the entire repo (not just the file you edited) for
the old literal string and check every hit:
README, CHANGELOG,
docs/, examples/, --help/usage text, and code comments/docstrings.
Fixing the code and leaving the README's flag table saying the old name
is not done — it is a half-finished rename. See
references/stale-token-grep.md for the exact grep commands.
- A new/removed/renamed feature updates its describing doc IN THE SAME
change. If the README (or a
docs/ page) lists available commands,
flags, or config keys, adding/removing one without touching that list in
the same diff is a drift bug the moment it merges, not a follow-up task.
- Never invent doc content you did not verify. Do not write a new
example, a new "supports X" claim, or a new usage snippet describing
behavior you did not actually read from the code or run. A doc update
that "sounds right" but was never checked against the real
implementation is the same failure this guard exists to catch, just
introduced fresh instead of left stale.
- Update counts and version strings the change invalidates. "Supports
5 commands," "3 config options," a hardcoded version number in an
example, or a "supports N flags" sentence must be recomputed, not left at
its pre-change value, whenever the change adds/removes an item from the
set being counted.
- Report doc files touched vs. doc files still stale. Every guard-pass
ends with two explicit lists: the doc files that were updated, and any
doc file that still references the old surface and was NOT updated (with
a stated reason — out of scope, needs a human call, etc.). "I updated the
docs" without naming which files, and confirming no old-token hits
remain elsewhere, is not evidence.
Procedure (guard-pass mode)
- Diff the public surface. Identify exactly what changed: a flag name,
a command name, a function/env/config name, a default value, a count, or
a described behavior. If nothing on this list changed (pure internal
refactor, private/unexported symbol, no behavior change visible to a
caller), this guard has nothing to do — say so and stop (see the control
fixture in
tests/kill-tests/docs-drift-guard/control.md).
- Grep the whole repo for the OLD token, not just the directory you
were editing. Use the commands in
references/stale-token-grep.md —
case-sensitive, whole-repo, including README*, CHANGELOG*, docs/**,
examples/**, and any --help/usage string literal in the source.
- Classify every hit. For each file that still contains the old token:
is it (a) a doc that describes the changed surface and must be updated,
(b) a historical/point-in-time record (an old changelog entry, an ADR, a
dated example) that should stay as written, or (c) genuinely unrelated
(the string coincidentally matches something else)? Use
references/doc-surface-map.md to know which doc artifacts a given kind
of change typically touches, so you're not guessing file-by-file.
- Update category (a) hits in this same change. Edit the README table,
the
--help string, the example file, the docstring — whatever
references the old surface as current/live documentation. Do not defer
this to "a follow-up docs pass."
- Do not invent. For anything you add or reword, confirm it matches
the actual current code (read it or run it) before writing it down —
never phrase a new doc claim from the symbol name alone.
- Recompute any invalidated count/version string touched by the
change (item 4 above).
- Compose the two lists — doc files updated, and doc files that still
reference the old surface and were deliberately left (with why) — before
claiming the change is done.
- Emit the guard footer (see Output) as the last line of the response.
Output
Emit this verbatim as the last line of the response where this guard fires
or is checked:
proofguard:docs-drift-guard — <PASS | FIX-REQUIRED | WAIVED(reason)> · Triggered: <what fired it> · Fixed: <n> · Verified: <exact grep + files updated> · Remaining gap: <doc files still stale, if any>
PASS — either no public surface changed (nothing for this guard to do),
or a public surface changed and the whole-repo grep for the old token
came back clean after doc updates were applied.
FIX-REQUIRED — a public surface changed and at least one doc file still
references the old token/behavior/count and has not yet been updated in
this response.
WAIVED(reason) — a stale doc reference was found and the user explicitly
accepted leaving it for a later pass, with a stated reason (e.g. a
point-in-time historical record that must stay as written).
References
references/doc-surface-map.md — for each kind of change (CLI flag,
command, env var, config key, default value, public function, count or
version string), which doc artifacts typically reference it and must be
checked.
references/stale-token-grep.md — exact, cross-platform commands for
grepping the repo for an old token, what counts as a doc artifact to
check, and the "don't invent docs" rule in detail.
What this guard does NOT do
It does not write net-new tutorials or explanatory docs from scratch, does
not judge documentation prose quality or style, and does not verify that
the build/tests actually pass (that's evidence-before-done). It does not
grade whether a test is a good test (test-code quality is out of
proofguard's scope; a test-quality-guard is in deferred/, not yet
shipped), whether the diff is scoped tightly (clean-diff-guard), or
whether a dependency is real (dep-verify-guard). This guard has exactly
one job: after a public-surface
change, keep the existing docs in sync with the changed code — no more,
no less.