FIELD NOTES//LOG 02 · PRACTICE
Your agent changed 14 files. Which docs went stale?
The failure mode of AI-assisted development is quiet. Nothing crashes, the tests pass, the diff merges. And somewhere in your docs, a paragraph that used to be true just stopped being true.
Docs are load-bearing now
Coding agents read documentation before they write code. That changed what a stale doc costs. It used to mislead the next engineer, who would notice the smell and double-check the source. Now it steers the next agent session, which will confidently build on whatever the doc claims. A wrong sentence in a feature doc becomes wrong code within the hour.
In agent-speed development, documentation stopped being a courtesy. It is an input.
Staleness is a measurement problem
Most teams treat doc drift like weather: everyone complains, nobody measures. But drift has a precise definition once you write down one fact per file: which doc owns it. codument keeps that fact in a registry, docs/.registry.json, mapping every source file to the feature doc responsible for it.
With ownership recorded, staleness becomes checkable. A source file changed and its owning doc did not: that is not a vibe, it is a finding.
$ npx codument review
2 changed file(s): 1 source, 0 docs
Stale docs (source changed, mapped doc did not)
⚠ auth: docs/features/auth.md (changed: src/auth/session.ts)
Only the owner wakes
File-level checks cause alarm fatigue: touch a big file and every doc that mentions it screams. codument resolves staleness per symbol instead. Each exported symbol's token stream is fingerprinted across two git refs, and names bound inside a declaration are rewritten to positions before hashing. A local rename that preserves meaning moves nothing.
When a documented symbol genuinely moves and its owning doc does not, exactly one feature wakes, and the finding names the symbol:
Symbol drift — resolve each: update the doc, or ack a contract-neutral move
• rotateToken (changed) in auth
contract changed → update docs/features/auth.md at intent altitude
internal only → codument ack src/auth/session.ts::rotateToken(). --reason "..."
The verdict is a pure function of two git refs: same repo state, same output, no model call anywhere on the path.
When no doc is owed: acknowledge, don't paper
Some moves change no contract. The worst response is editing prose to appease a checker, because junk mirror edits rot docs as surely as staleness does. codument's answer is an acknowledgment:
$ codument ack src/auth/session.ts::rotateToken(). --reason "moved intact, contract unchanged"
✓ acknowledged src/auth/session.ts::rotateToken(). (3a992885→388fb915, self)
An ack is bound to the exact fingerprint transition it adjudicated. The next time that symbol moves, the ack expires on its own. There is no ride-forever exemption to accumulate.
The gate only trusts what it can re-run
A drift check keeps docs honest; it says nothing about whether the change itself holds up. For that, codument runs two adversaries across the workflow, and neither one gets to be creative.
The plan adversary contests the plan before code exists. Its objections must be grounded: each one cites a committed doc, a test, or the stated scope. It never blocks; the human adjudicates every objection in chat.
The review adversary attacks a fingerprint-bound bundle of the diff plus the documented invariants it crosses. Its findings only block when a named test is genuinely red on a live re-run. No red test, no block. And because the recorded review binds to both the reviewed sources and the tests its findings name, fixing the code or touching a test invalidates the review, and the gate reopens:
✗ --require-review: 1 confirmed finding(s) unresolved.
• src/auth/session.ts:rotateToken — the per-rotation cap still extends the
session on every refresh; continuous rotation keeps a session alive forever
(test: test/session-ttl.test.ts)
A reviewer's prose is never trusted. A verdict is computed, not generated.
The payoff is retrieval
Here is the part that makes the discipline pay rent every day, not just on the day something drifts. The same registry that catches staleness can be projected the other way: given a feature, hand back the smallest grounded working set for it. The owning doc, its invariants with their test pointers, the primary sources, the declared risk.
$ codument context --feature auth
auth — docs/features/auth.md ~88 tok
Invariants & boundaries
- An expired session must never authorize
- Sessions expire one hour after issue.
primary sources: src/auth/authorize.ts, src/auth/session.ts
risk: security
An agent that starts from this pack reads a fraction of what a whole-repo crawl costs, and everything it reads has been kept true by the gate above. In codument's packaged benchmark the context pack measured 1,746 estimated tokens against 3,068 for whole-file context, an eight-file working set instead of sixteen. It is a fixture benchmark, not your repo, but the direction is the point: docs in, trusted context out.
That loop is the whole argument. A doc you can trust is retrieval infrastructure. A doc you cannot trust gets routed around, and then it is just weight.
Try it on the history you already have
You do not need to adopt anything to see your own number. Two read-only commands replay your committed history against a proposed ownership map and report every feature whose code moved while its doc got no attention:
$ npx codument scan
$ npx codument audit v1.0.0..HEAD
Read the damage report, then decide. Nothing is gated, nothing needs committing; delete the scaffolds and you have adopted nothing.
One honest limit, because honest limits are the house style: codument reports facts and gaps. It does not certify that a change is safe, and it does not try. The judgment stays with you; the instrument just makes sure you are judging the change that actually happened, against docs that are actually true.
More field notes
Keeping AI off the verdict path
Why a safety layer for agent output has to be deterministic all the way down, and what that rules out by design.
The diff is not the deliverable
When an agent writes the code, review stops being a courtesy and starts being the product. What a reviewer actually owes the merge.