Maintainer-only. Use to audit THIS KIT's OWN feature estate against its path map, "run the topology-drift loop", "feature inventory drift". NOT for a consumer/adopter repo, NOT for a target project (/kit:feature-map), NOT for regenerating the registry, NOT for whole-doc prose drift (doc-drift), NOT for one known-missing feature.
Install
npx skillscat add dwarvesf/dwarves-kit/topology-drift Install via the SkillsCat registry.
Topology drift
Maintainer-only, dwarves-kit repo development only: this skill audits the KIT'S OWNdocs/FEATURES.md/docs/workflow-paths.md pair, which only exists in this repo. It
is not something a consumer/adopter repo would ever have a reason to invoke. To
inventory the features of a project the kit is POINTED AT (a migration source, a
codebase you want documented), use /kit:feature-map instead -- seedocs/patterns/audit-loop.md for how the two relate.
Scope and triggers
Dwarves-kit repo dev only. Also fires on "is the workflow path map still complete", "does every feature appear in workflow-paths", or after a batch of merges that added/removed commands, agents, skills, or hooks. An audit-loop instance (docs/patterns/audit-loop.md), sibling to /kit:feature-map, which is the tool for auditing a target project instead of this repo's own registry.
Cross-checks the generated docs/FEATURES.md registry against the docs/workflow-paths.md path index both directions, then re-places only the DELTA features on the topology diagrams. REFUSES to run while FEATURES.md is stale (regenerate first). This schema is dwarves-kit-specific: a consumer/adopter repo has nothing to check against here. The registry itself is regenerated by lib/registry/feature-registry.sh, pinned by test-meta, never by this skill. A known line to add for one known-missing feature does not need this skill; just add it.
Overview
Audit the live feature estate (every command, agent, skill, hook) against the workflow path map and ship fixes as a PR. This is the feature-inventory instance of docs/patterns/audit-loop.md: the generated registry docs/FEATURES.md is the machine truth; docs/workflow-paths.md section 5 is the hand-derived path index that drifts when features land or leave. Tier 1 is pure shell; Tier 2 spends model time only on the delta.
The four slots (per the audit-loop pattern)
| Slot | This instance |
|---|---|
| Item set | every row of docs/FEATURES.md plus every line of docs/workflow-paths.md section 5 (both sides enumerate; the diff is the queue) |
| Contract | (a) FEATURES.md is fresh (regenerating changes nothing); (b) every registry row has exactly one path-index line and vice versa, all four kinds; (c) trigger classes agree between the two (secondary, listed not auto-fixed) |
| Evidence class | Tier 1: the repo itself via the generator diff + sed/comm name extraction. Tier 2: a model re-reads only the delta features' definitions to place them on the topology |
| Apply mechanics | FIX on an isolated branch; new features get a path-index line AND a placement on the section 2/3 diagrams; removed features get their line deleted; PR body lists every verdict; UNSURE never auto-resolved |
Process
Freshness gate, REFUSE if stale. Regenerate to a temp file and compare:
bash lib/registry/feature-registry.sh generate /tmp/feat-check.md cmp -s /tmp/feat-check.md docs/FEATURES.md || echo STALESTALE means the committed registry itself lags the tree (test-meta is already RED). STOP and tell the operator: run
bash lib/registry/feature-registry.sh generate, commit, then re-run this skill. Auditing the path map against a stale registry produces false verdicts.Branch first. All edits ride an isolated branch, per the pattern.
Tier 1, mechanical cross-check, zero model cost. Extract names from both files and diff both directions per kind (BSD sed: keep
/as the delimiter;|cannot be both delimiter and literal):W=docs/workflow-paths.md; F=docs/FEATURES.md sed -n '/^## Commands/,/^## Agents/p' $F | sed -nE 's/^\| `\/kit:([a-z0-9-]+)`.*/\1/p' | sort > f-cmd sed -n '/^### Commands/,/^### Agents/p' $W | sed -nE 's/^\| `\[[^]]+\] \/kit:([a-z0-9-]+).*/\1/p' | sort > w-cmd sed -n '/^## Agents/,/^## Skills/p' $F | sed -nE 's/^\| `([a-z0-9-]+)`.*/\1/p' | sort > f-agt sed -n '/^### Agents/,/^### Skills/p' $W | sed -nE 's/^\| `\[D\] ([a-z0-9-]+).*/\1/p' | sort > w-agt sed -n '/^## Skills/,/^## Hooks/p' $F | sed -nE 's/^\| `([a-z0-9-]+)`.*/\1/p' | sort > f-skl sed -n '/^### Skills/,/^### Hooks/p' $W | sed -nE 's/^\| `\[[HI]\] ([a-z0-9-]+).*/\1/p' | sort > w-skl sed -n '/^## Hooks/,$p' $F | sed -nE 's/^\| `([a-z0-9._-]+)\.sh`.*/\1/p' | sort > f-hks sed -n '/^### Hooks/,/^## 6/p' $W | sed -nE 's/^\| `\[E\] [^>]*-> *([a-z0-9._-]+).*/\1/p' | sort -u > w-hks for k in cmd agt skl hks; do comm -3 f-$k w-$k; doneEmpty
comm -3output for all four kinds = presence parity holds. Any name in column 1 (only in FEATURES) is a NEW/unmapped feature; column 2 (only in the path index) is a REMOVED/ghost feature. Each is a finding with the name as evidence. Secondary pass, same evidence class: compare trigger classes for matched names; a disagreement (e.g.skill-reviewfrontmatter-derived[I]vs the index's hand-judged[H]) is a listed UNSURE for the operator, never auto-flipped, because either side may be the wrong one.Tier 2, delta only, model-read. ONLY when step 3 produced deltas: dispatch ONE
kit:audit-scanner(the shared read-only scanner, preferred: it physically cannot write; fall back to a general-purpose subagent only where the kit agent roster is unavailable, e.g. a frozen plugin snapshot) with the delta list. Its scope, exactly: read each delta feature's definition file and return, per delta, the section 5 path-index line to add/remove (matching the existing line grammar:entry -> ... -> terminal, trigger mark from the registry) and the feature's real attach point on the section 2 flow-topology and section 3 system-topology diagrams, with the definition evidence quoted. It must invent no edge the feature's definition does not show (regeneration rule 5 of workflow-paths.md). Apply its returned placements HERE, on the branch (the scanner proposes, this skill applies). Zero deltas = zero dispatch; report CLEAN and stop.Verdict each finding with the audit-loop grammar: OK / FIX / REMOVE / UNSURE / DANGER. A ghost line whose feature file is gone is REMOVE with the deletion commit as evidence. A trigger-class disagreement is UNSURE.
Verify. Re-run steps 1 and 3: freshness green,
comm -3empty all four kinds. Runbash tests/test-meta.sh: green, or the run is not done.Ship. Commit, push, open a PR whose body lists every verdict with evidence and every UNSURE for the operator. Nothing to change: no branch, report CLEAN with the four counts.
Cadence
Run after any merge batch that touched commands/, agents/, skills/, or hooks/ (the test-meta freshness pin going RED is the loudest trigger), or on a schedule per the audit-loop driver ladder.
Red flags
- Auditing against a stale FEATURES.md: the step 1 refusal exists for exactly this.
- Dispatching Tier 2 with an empty delta: pure spend, the cheap-first split exists to prevent it.
- Auto-flipping a trigger-class disagreement: either side may be wrong; it is the operator's call.
- Rewriting whole topology diagrams for one delta feature: place the delta, leave the rest.
Cadence
This instance has a declared cadence in the ## Cadence table of docs/patterns/audit-loop.md.
Record a finished pass with bin/audit ran topology-drift "<one line>", including a CLEAN one, sobin/audit due stops naming it. The kit ships no scheduler: due is what a human or a job reads.