# Find Rule Surface Drift

> Detect drift on the agent-rules surface — oversized always-loaded files, dormant load-on-demand docs, missing-but-referenced docs, unreferenced docs, and broken links from the human onboarding entry point. SUSPECT skill governing the placement convention defined in ADR 0005 (agent-rules-design).

- Skill: `khurrummahmood/find-rule-surface-drift` (Agent Skill, multi-file: 14 files)
- Install (CLI): `npx skillmds@latest add khurrummahmood/find-rule-surface-drift`
- Raw SKILL.md: https://api.skillmd.com/api/skills/khurrummahmood/find-rule-surface-drift/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: KhurrumMahmood (https://skillmd.com/u/khurrummahmood)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/khurrummahmood/find-rule-surface-drift

---


# /find-rule-surface-drift

This skill is host-language-neutral: it audits the agent-rules and
documentation surface, not application source syntax. Its Python scripts are
the installed implementation, not a claim that the host project is Python.

You are the orchestrator for a SUSPECT skill that audits the agent-rules
surface against ADR 0005's tiered-storage convention.

## Scope

- Default root: `.claude/`.
- Default `CLAUDE.md` path: `<root>/CLAUDE.md`.
- Default docs dir: `<root>/docs/` (top-level `.md` files only — nested
  package docs like `subsystems/<name>.md` are out of scope for this
  skill).
- Default ONBOARDING.md path: `<project-root>/ONBOARDING.md` (the human
  entry point; pass `--onboarding-md` to override or point at a missing
  path to skip the onboarding bands).
- Output: `reports/find-rule-surface-drift/<scan-id>/`.
- No code or doc edits; detection only.

## How success is judged

- The run creates a fresh scan dir under
  `reports/find-rule-surface-drift/<scan-id>/` with `detections.jsonl`,
  `report.md`, and `findings.json`.
- Each command's exit code is honored; stop on non-zero and report the
  failing command instead of rendering stale detections.
- Handoff identifiers are valid: every `findings.json` record uses one of
  the `pattern` names in Findings and carries `file` / `lineno` evidence.
- No silent drops: the JSONL record count matches
  `findings.summary.findings_total` and the `findings` array length.
- Detector edits are not trusted until the Replay fixtures commands pass
  for `fixtures/exercise-all/` and `fixtures/exercise-onboarding/`.

## Pipeline

```bash
set -euo pipefail
SCAN_ID="scan-$(date -u +%Y%m%d-%H%M%S)"
REPORT_DIR="reports/find-rule-surface-drift/$SCAN_ID"
mkdir -p "$REPORT_DIR"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/detect.py \
  --output "$REPORT_DIR/detections.jsonl"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/report.py \
  --detections "$REPORT_DIR/detections.jsonl" \
  --output-md "$REPORT_DIR/report.md" \
  --output-json "$REPORT_DIR/findings.json" \
  --target ".claude/"
```

## Findings

- `oversized_root`: `.claude/CLAUDE.md` exceeds the soft size budget
  (default 30,000 chars, per ADR 0005). Demote content to load-on-demand
  docs; don't subdivide at root.
- `oversized_doc`: a `.claude/docs/*.md` exceeds the per-doc soft
  budget (default 50,000 chars). Decide whether it's one topic or two —
  legitimate inventories may warrant a higher threshold or an explicit
  exemption.
- `dormant_doc`: a file exists under `.claude/docs/` but has no row in
  CLAUDE.md's Supplementary Documentation table. Either add a trigger
  row or remove the doc — load-on-demand docs need an explicit "Read
  when…" entry to be reachable.
- `missing_doc`: a row in the Supplementary Documentation table
  references a file that does not exist on disk. Either fix the row or
  create the doc.
- `unreferenced_doc`: a doc is registered in the table but appears in
  no other artifact under `.claude/`. May be legitimately reachable
  only via its trigger; the recommendation reads "confirm or remove."
- `missing_link`: ONBOARDING.md links to a path that does not exist on
  disk. Treat as a real defect — broken links in the human entry point
  block onboarding directly. Either fix the link target or remove the
  link.
- `dormant_in_onboarding`: a doc registered in CLAUDE.md's
  Supplementary Documentation table is **not** linked from
  ONBOARDING.md. **Info-level only.** Most agent-targeted docs (oracle,
  model-tiering, deployment, sub-agents, etc.) legitimately stay
  unmentioned in human onboarding. Use this band when triaging
  newly-registered docs to decide whether the human path should
  reference them — never as a blocking signal.

## Calibration

`--max-root-chars` and `--max-doc-chars` are soft budgets. ADR 0005
sets the root soft budget at ~30K — high enough that legitimate
project context fits, low enough to push back when always-loaded
content drifts past the practical signal-density ceiling. The per-doc
ceiling defaults to ~50K; legitimate inventory docs (subsystem maps,
full catalogues) can exceed this and should either raise the threshold
project-wide or carry a documented exemption.

## Replay fixtures

Run fixture output outside each fixture root so report artifacts do not
pollute the next `unreferenced_doc` check:

```bash
set -euo pipefail
FIXTURE_ROOT=".claude/skills/find-rule-surface-drift/fixtures/exercise-all"
FIXTURE_OUT="reports/find-rule-surface-drift/_fixture-runs/exercise-all"
mkdir -p "$FIXTURE_OUT"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/detect.py \
  --root "$FIXTURE_ROOT" \
  --project-root "$FIXTURE_ROOT" \
  --onboarding-md "$FIXTURE_ROOT/NO_ONBOARDING.md" \
  --max-root-chars 200 \
  --max-doc-chars 200 \
  --output "$FIXTURE_OUT/detections.jsonl"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/report.py \
  --detections "$FIXTURE_OUT/detections.jsonl" \
  --output-md "$FIXTURE_OUT/report.md" \
  --output-json "$FIXTURE_OUT/findings.json" \
  --target "$FIXTURE_ROOT"

FIXTURE_ROOT=".claude/skills/find-rule-surface-drift/fixtures/exercise-onboarding"
FIXTURE_OUT="reports/find-rule-surface-drift/_fixture-runs/exercise-onboarding"
mkdir -p "$FIXTURE_OUT"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/detect.py \
  --root "$FIXTURE_ROOT" \
  --project-root "$FIXTURE_ROOT" \
  --onboarding-md "$FIXTURE_ROOT/ONBOARDING.md" \
  --output "$FIXTURE_OUT/detections.jsonl"
.venv/bin/python .claude/skills/find-rule-surface-drift/scripts/report.py \
  --detections "$FIXTURE_OUT/detections.jsonl" \
  --output-md "$FIXTURE_OUT/report.md" \
  --output-json "$FIXTURE_OUT/findings.json" \
  --target "$FIXTURE_ROOT"
```

Expected buckets: `exercise-all` emits one each of `oversized_root`,
`oversized_doc`, `dormant_doc`, `missing_doc`, and `unreferenced_doc`;
`exercise-onboarding` emits one each of `missing_link` and
`dormant_in_onboarding`.

## When things go sideways

| Case | Signal | Response |
|---|---|---|
| Target absent | `--root`, `--claude-md`, `--docs-subdir`, or `--onboarding-md` points at a missing surface. | Let the detector's zero-finding output stand if it exits 0; name the absent target in the report. |
| Zero findings | `detections.jsonl` is empty and `report.md` says `Findings: 0`. | Treat as a clean scan only after confirming the intended root and onboarding path were used. |
| Script non-zero exit | Any command exits non-zero. | Stop the pipeline, paste the command and stderr, and do not run `report.py` against stale detections. |

## Next Skills

- `/fix-workflow` for executing a single migration (e.g. demote one
  oversized section, register one dormant doc, prune one unreferenced
  doc).
- `/decide` if a finding reveals a tradeoff the ADR doesn't yet cover
  (e.g. "we keep accepting `oversized_doc` for `architecture.md` —
  raise the per-doc budget formally").
- `/prevent-regression` if a particular drift recurs often enough to
  justify a pre-commit check (the planned `oversized_root` hard
  guardrail in ADR 0005's Verification section).

## Notes for the orchestrator

- This is a Stage 1 skeleton. Cross-tool sync drift between
  `.claude/CLAUDE.md` and `.augment/rules/imported/*` is **not** yet
  detected — it requires content-level comparison heavier than a
  filename check. Add as a follow-up band when an actual drift
  incident motivates the cost.
- `find_unreferenced` excludes `worktrees/` and `__pycache__/` from
  its grep scan. Mirrored CLAUDE.md files inside agent worktrees would
  otherwise mask every doc as "referenced."
- Replay fixtures live under `fixtures/exercise-all/` and
  `fixtures/exercise-onboarding/`; keep their output outside the fixture
  roots.
- The `unreferenced_doc` band uses `grep -l` across `.claude/`. Docs
  that are reached only via the supplementary table's trigger (and
  never named elsewhere) will fire here legitimately; treat the
  finding as "confirm reachability," not "delete on sight."

