AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Documentation Drift Audit

skill-arasz-ai-badger-documentation-drift-audit · by Arasz

Use when auditing docs for drift vs code ('audit and fix documentation drift'): inventory claims with path:line, verify each against real files (scaffolders, manifests, hooks), classify verifiably-false vs design-position vs ambiguous vs historical, fix only the false, and report A/B/C. Also for post-merge doc-gap audits and user-facing doc compaction rewrites.

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-arasz-ai-badger-documentation-drift-audit

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-arasz-ai-badger-documentation-drift-audit)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
17d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Documentation Drift Audit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Documentation drift audit

Audit documentation against the actual tree — scaffolder behavior, manifests, hook registration, config schemas — fix only what is verifiably false, and hand decision-grade findings back to the orchestrator. The point is to separate "the doc is wrong" from "the doc records a design position" before touching anything.

When to use

  • A task says "audit and fix documentation drift" about a feature area.
  • A doc claims something about what code does, scaffolds, ships, or fires

(script names, hook events, manifest entries, activation conditions, file layout).

  • A research record or extension doc needs its claims checked against real behavior.
  • A feature just merged (e.g. a new backend/CLI verb behind an existing interface)

and a follow-up audit must check CLAUDE.md/.hermes.md + user docs against the merged code — the "Phase 5" doc-gap audit. See the post-merge section below.

  • A user-facing doc (root README, packaged README) needs a compaction/rewrite

pass — "clean this up, use proper markdown, compact it and redirect to the detailed files". See the compaction section below; it is a rewrite, not a correction, but the verification discipline is the same.

Method

  1. Inventory the claims first. Grep the doc surface for the topic's vocabulary

(script names, config keys, manifest entries, hook events, paths). List every candidate claim with path:line before editing anything.

  1. Verify each claim against actual file content. Read the code that would make

the claim true: the scaffolder's copy logic, the manifest, the plugin's register(), the extension's requires. Where a claim is about scaffolded output, check a real scaffolded project (or re-scaffold a throwaway) and ls the delivered tree. Never edit on the strength of the doc's own wording, and never trust your memory of what the code does — re-read it.

  1. Classify every finding into exactly one bucket:
  • Verifiably false → fix directly, smallest edit that makes the sentence true.
  • Design position ("Claude-only by design", "replaced by native features") →

report only. Changing it is a decision, not a correction.

  • Ambiguous statement (loose counts, vague referents) → report only; don't guess.
  • Historical record (changelog entries, dated research records) → never

rewrite; they record what was true when written.

  1. Edit only the false claims, quoting reality from verified evidence: name the

exact files/scripts, the actual mechanism, and the measured outcome.

  1. Check generated mirrors. If the repo keeps a committed mirror of its own

source (e.g. a .ai-badger/ tree mirroring features/), a source edit makes the mirror stale and trips the freshness gate. If constraints forbid touching the mirror, flag it in the report so the orchestrator re-scaffolds.

  1. Report A/B/C — the shape that worked:
  • A — drift found: path:line + stale claim + reality (report only, no edits).
  • B — edits made: file + before/after summary.
  • C — decision gaps: items needing a human (exemption/reason strings now known

to rest on false premises, future-state designs, shipping-inert artifacts, gate/mirror consequences).

  1. Re-verify after editing: git diff shows exactly the intended change; grep

tests/ for assertions on removed strings; every sentence you wrote is backed by verified evidence (a real scaffolded tree, a register() list, a manifest).

Post-merge feature audits (the "Phase 5" pattern)

For audits that follow a merged feature (worktree-isolated, docs-only, no push):

  1. Verify the checkout is actually on the claimed tree first. The premise

("repo is now on merge X") is often stale — local main may sit behind origin/main. Check git log --oneline -1 against git log --oneline -1 origin/main; if behind, git merge --ff-only origin/main aligns the checkout without creating a commit or pushing, so it stays inside a "don't commit, don't push" constraint. Diagnose discrepancies with git branch -a --contains and git merge-base HEAD origin/main. Worktree variant: git worktree add origin/main, confirm the target merge is an ancestor (git merge-base --is-ancestor HEAD), work ONLY there.

A locally-modified tracking file can block the fast-forward — and the merge may touch the same file. Repos with a committed state/tracking file (e.g. .ai-badger/state.json) often carry an uncommitted orchestrator update exactly when an audit runs. Check first whether the merge modifies it at all: git diff --stat -- . If it does not, git stash push -- → ff → git stash pop is safe. If it does, expect a pop conflict and reconstruct rather than take a side: the stashed version was authored against the pre-merge base, so it can lack entries the merge added (e.g. the merge's own completed-task entry) while the merge lacks the local tracking delta. Take the merged version as base and re-apply the local change's semantic delta (prepend the new entry, update next/pointer fields), then verify with git diff -- that the delta is exactly the intended local change. Do the surgery by JSON parse/modify/dump, not text retyping; entries may be keyed taskId instead of id — match on the identifying value, not the key. Return the file to plain unstaged-modification state with git add && git restore --staged . If you dropped the stash prematurely, nothing is lost — the drop only removes the ref, and the content stays reachable via git show : (the sha is printed by git stash drop).

  1. Ground truth = the merged code, read first. Extract the exact user-facing

strings from the implementation before judging any doc: CLI verbs + option names, settings-table keys, error-message prefixes, MCP tool [Description] text. Docs must match these verbatim — check sync.provider-style key spelling, prompt channel (stderr prompt / stdin read / empty-aborts exit 1), redaction behavior, and default values against the code, not against memory or the PR description.

  1. Grep gates with intentional-residue classification. Run

grep -rn "" --include="*.md" --include="*.cs" . (and one for the old CLI verb). Classify EVERY hit before touching anything:

  • Intentional: internal class XML docs, subcommand help descriptions, and

phrasing already paired with the new alternative ("S3-compatible or Azure Blob"). Also all of docs/plans/ (pre-implementation), docs/work/ (dated records), docs/adr/ (frozen) — they record what was true when written; a plan quoting the old error string is correct history, not drift.

  • Drift: old-phrasing-as-the-only-option in current-surface docs (root

README, docs/reference/, docs/explanation/, SECURITY, src/*/README.md). Only current-surface hits are fixable; a passing gate means zero remaining current-surface hits.

Before fixing pre-existing drift, check for a pending fix. An open PR may already cover the same stale counts/omissions (common after a feature merge — e.g. a "docs: post-#N audit" PR sitting open while the next feature merged). gh pr view --json title,state,files and gh pr diff tell you what it touches. If it covers the drift, do NOT duplicate the edits — report the drift as covered-by-PR- instead, and note the merge hazard: a PR that touches both the docs and the tracking file will conflict on the latter once the feature merge lands, so it needs a rebase.

  1. Generated instruction copies. Root CLAUDE.md/.hermes.md are generated

from .ai-badger/ sources: diff root vs source and confirm the only difference is the managed-by header — use a plain diff and expect a 2-line prepend (comment + blank line); a tail -n +N-style offset comparison misaligns and raises a false alarm. Real drift is fixed in the source, never the copy; and respect the project's compaction policy — provider-neutral existing wording ("optional cloud sync") needs no expansion.

Not every mirror difference is drift — learn the expected transformations before flagging. In ai-badger: the scaffolded .ai-badger/hooks/hooks.json is path-rewritten by design (plugin-root ${CLAUDE_PLUGIN_ROOT}/features/... commands become ${CLAUDE_PROJECT_DIR}/.ai-badger/... fallback command shapes); the plugin skills/ tree ships a frontmatter-only SKILL.md stub plus a full-content SKILL.full.md; and the scaffolder rewrites commands into if-exists/elif/else shapes. Diff against the shape first, then diff only the content fields that should be byte-identical.

  1. Fix discipline + commit. Smallest edit that makes the sentence true (word or

sentence swap — no restructure, no new sections); conventional message (docs(sync): fix stale wording after merge); re-check git status shows only doc files.

  1. Decision gaps are reported, not fixed. Anything a user would hit that the

docs don't state — unsupported auth modes, resources that must pre-exist (e.g. a container the CLI doesn't create), missing dev-testing story, error tables covering only some prefixes — goes in the report as needs-decision, because writing it down either changes product behavior or is a product call.

> Compaction passes: read references/compaction-rewrite-passes.md when doing compaction/rewrite passes on READMEs or user-facing docs.

> ADR-vs-code drift: read references/adr-vs-code-drift.md when auditing ADR-vs-code drift (contract points vs factual points).

Classification pitfalls

  • A doc claim that **matches its own manifest/extension.json/requires entry is

not drift** even if it seems odd — the code and doc may agree while the real problem is the activation condition (e.g. one extension gates on agents=claude, a sibling gates on stacks=hermes). Report the asymmetry as a decision gap; don't "fix" the doc.

  • Count claims ("ships three hook scripts") are usually loose summaries — verify the

real count; if the referent is ambiguous, list in A, don't edit.

  • Verify counts against code, not against sibling docs. Docs drift from each

other as well as from code ("seven are optIn" in one doc, eight in the other, while code declares eight). The declaration (e.g. a frontmatter key, a manifest) is the source of truth; when a count is unambiguous against it, fix the pre-existing wrong doc too, but report it as pre-existing so the maintainer knows it was not merge-caused.

  • Date a doc claim before blaming the merge: `git log -S "" --

` shows when a line was last written. A table last touched at 0.51.0 that omits a 0.78.0 server is pre-existing drift the merge merely failed to fix — still fix it if unambiguous, but report the provenance.

  • At-a-glance table rows that link to #anchors require the section to exist.

Adding a row without its section breaks link-checking gates (e.g. docs_guard.py scans every markdown link). Add row + section together, or make the row a plain name.

  • "NOT scaffolded when agent X is present" is a common false claim: scaffolds

usually copy whole directories; only config.exclude-style patterns filter. Verify by listing a real scaffolded project's delivered tree.

  • After you fix a source doc, dated research records that quote the old text will

quote text that no longer exists. That is correct — do not retro-edit the record.

  • Doc-adjacent files can be LIVE test inputs, not archive. .feature/spec files

under docs/ (e.g. docs/work/**/*.feature) may be wired into the test project — Reqnroll/SpecFlow list them via ` in the test csproj. A stale-but-live spec is NOT a docs edit: rewriting its scenario text can break step bindings, and the steps themselves may be no-op bindings "verified by ToolInventoryTests" that still enumerate the old surface. Check the test project's feature-file globs before treating any .feature` as historical; report stale live specs as decision gaps (fix requires coordinated test-code + spec edits, which a docs-only commit cannot do).

  • Verify removal claims against surviving code paths. A task summary like "env

vars no longer read" is often only partially true — one variable can survive via a dedicated provider (e.g. EnvEncryptionKeyProvider still wired in the composition root). Grep for the actual mechanism (GetEnvironmentVariable, provider registrations, Sources.Clear()) and document the exact survivor set instead of deleting every env-var mention.

  • Respect scope constraints literally ("edit only files under features/ or docs/",

"don't touch tooling/validate.py", "don't commit") and surface their consequences (stale mirror, failing gate) in the report instead of violating them.

  • A doc can contradict itself: prose vs compact block. A reference page often

carries both a prose description AND a compact verb/option block (a fenced code block listing CLI verbs, a summary table). The prose may be current while the compact block is stale — or vice versa. Observed 2026-08-05: the prose of docs/reference/agent-memory-server.md documented watch registered [{project-id}] and watch remove {project-id|*} (matching code), but the fenced verb block a page later omitted both. Grep the compact block against the code declaration (the CLI command tree, the option table) independently of the prose — a block that matches the prose but not the code is still drift.

  • Enumeration lists drift as a family, not one file. A stale skill-name list ("the

twelve operational skills", a tree sketch, an available-by-name sentence) usually lives in several docs written together — one omission in the codebase leaves N stale copies, and an audit pointed at two files (#303 fixed README + skills.md) can miss the siblings (framework-architecture.md, getting-started.md and the README tree sketch all still listed 12 of 14 default skills). After fixing the first copy, grep the whole doc surface for the enumeration's vocabulary, and verify the count against the declaration itself (each skill's scope: frontmatter), never against a sibling doc.

  • Tracking-file next pointers go stale while the task is still open. `.ai-badger/

state.json's next` was written after PR #303 had already merged yet still listed it as pending, alongside a follow-up that had shipped in the meantime. When an audit touches a tracking file, verify each "pending" item against git log/state before keeping it — a pointer that names finished work sends the next task on a ghost errand.

Verification

  • Diff contains exactly the intended change.
  • No tests assert the removed strings.
  • Real-world evidence supports every sentence you wrote.
  • A subset test run that fails while the full suite passes is usually order-dependent

registration (module-level registries like trackerlib.SESSIONSOURCES populated by earlier tests), not a regression from your edit — confirm against the full suite before chasing it.

Gotchas

  • "Verifiably-false" verdicts need path:line evidence — a claim you cannot pin to a real file is "ambiguous", not "false".
  • Never hand-edit generated files: scaffolders and manifests regenerate them; classify them with the doc-surface map instead.

References

  • references/readme-compaction-recipe.md — worked example of the README (read when planning a README compaction)

compaction (the project, 2026-08-06, 561 → 158 lines): ground-truth extraction list, redirect mapping, content-regression grep, the SDK-version stale-fact miss the reviewer caught, and the merge-race recovery (PR merged mid-review → cherry-pick orphaned commit onto a fresh branch from origin/main → follow-up PR).

  • references/ai-badger-drift-audit-map.md — verified

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.