You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tooling: root doc-reachability at the repo-root CLAUDE.md, enforce specs + notes, add specs index
Follow-ups to the `docs-reachable` check, per review:
- **Root is now the repo-root `CLAUDE.md`** (the real entry point Claude Code loads first, which `@import`s AGENTS.md), not AGENTS.md directly.
- **`docs/specs` and `docs/notes` are no longer exempt.** Everything under `docs/` is enforced: scratch dirs must still be discoverable while they exist. Dropped the ephemeral-dir carve-out.
- **New `docs/specs/index.md`** lists every spec (root + `later/`) as a dated checklist (`[x]` = shipped), linked from `AGENTS.md` § File structure. This connects all 34 specs. Done/not-done is best-effort from each spec's top + git; a few are uncertain (see the worktree report).
Net effect: 230 docs reachable, 23 orphans remaining (4 subsystem CLAUDE.md, 13 guides, 6 notes) for connecting in a later pass. Enabling notes surfaced only 6 real orphans: the other ~12 were already linked from their colocated CLAUDE.md/DETAILS.md, which the graph counts.
|`claude-md-length.go`| Warn-only push-tier scanner: warns when a `CLAUDE.md` exceeds 600 words (`DETAILS.md` is the unlimited pull tier, not scanned). Allowlist with the same shrink-wrap semantics as file-length. See § CLAUDE.md length. |
20
20
|`claude-md-length-allowlist.json`| Allowlist for claude-md-length: `{ "files": { "path": wordCount } }`. Same ratchet/consent rules as file-length. |
21
-
|`docs_graph.go`| Shared doc-discoverability graph: reachability from `AGENTS.md` over references between docs. Powers both the `docs-reachable` check and the `--docs-graph` renderer. See § Docs reachable.|
22
-
|`docs-reachable.go`| Errors (not warn-only) when any `CLAUDE.md` / `DETAILS.md` / `docs/` file can't be reached from `AGENTS.md`. Allowlist with the same shrink-wrap/consent semantics as file-length. See § Docs reachable.|
21
+
|`docs_graph.go`| Shared doc-discoverability graph: reachability from the repo-root `CLAUDE.md` over references between docs. Powers both the `docs-reachable` check and the `--docs-graph` renderer. See § Docs reachable. |
22
+
|`docs-reachable.go`| Errors (not warn-only) when any `CLAUDE.md` / `DETAILS.md` / `docs/` file can't be reached from the root `CLAUDE.md`. Allowlist with the same shrink-wrap/consent semantics as file-length. See § Docs reachable. |
23
23
|`docs-reachable-allowlist.json`| Allowlist for docs-reachable: `{ "files": { "path": reason } }` of docs intentionally unreachable. Goal is empty. Shrink-wraps gone/now-reachable entries; adding one needs David's OK. |
24
24
|`e2e-durations.go`| E2E test duration flagger (warn-only): parses the Playwright JSON reports after each E2E run and flags tests over the 2 s budget. Embedded in both E2E checks, not a registry check. See § E2E test duration flagger. |
25
25
|`e2e-duration-allowlist.json`| Per-platform (`macos` / `linux`) allowlist for the duration flagger: `{ "<spec>::<describe chain>::<title>": reason }`. Entries need a reason; new entries need David's OK. |
@@ -191,24 +191,26 @@ change. Adding or raising an entry needs David's OK (`.claude/rules/file-length-
191
191
## Docs reachable
192
192
193
193
`docs-reachable` (`IsFast`, an **error** not a warn: the doc tree must stay connected) enforces that every `CLAUDE.md`,
194
-
`DETAILS.md`, and `docs/` file is discoverable from the single root `AGENTS.md` by link-walking, so a reader entering
195
-
there can find every doc. `docs_graph.go` builds the graph (shared with the `--docs-graph` renderer in
194
+
`DETAILS.md`, and `docs/` file is discoverable from the repo-root `CLAUDE.md` by link-walking, so a reader entering at
195
+
the real entry point can find every doc. `docs_graph.go` builds the graph (shared with the `--docs-graph` renderer in
196
196
`../docs_graph_render.go`); `docs-reachable.go` is the check shell + allowlist.
197
197
198
198
How reachability is decided (`BuildDocGraph`):
199
199
200
-
-**One root, `AGENTS.md`.** A doc is reached when a doc already reached from the root references it. BFS, so each doc
201
-
is placed under its closest-to-root reference (a cycle just hits an already-reached node and stops).
200
+
-**One root, the repo-root `CLAUDE.md`.** It's the true entry point: Claude Code loads it first, and it `@import`s
201
+
`AGENTS.md` + the core docs. A doc is reached when a doc already reached from the root references it. BFS, so each doc
202
+
is placed under its closest-to-root reference (a cycle just hits an already-reached node and stops). The root itself
203
+
is never an orphan.
202
204
-**A reference is any mention, syntax-agnostic:** Markdown link, `@import`, backtick path, or bare path token are all
203
205
equal. We watch intent, not form. Matching is generous (relative-to-source, repo-root-relative, and ≥2-segment path
204
206
suffix), because over-connecting only hides a would-be orphan, while a false orphan would be a noisy CI failure.
205
207
-**The CLAUDE.md asymmetry:** a `DETAILS.md` or `docs/` file must be named, but a `CLAUDE.md` also counts as reached
206
208
when a reachable doc mentions its _directory_ (`architecture.md` lists most subsystems as `` `some/dir/` ``, and
207
209
Claude Code auto-injects a `CLAUDE.md` from its directory regardless). Such edges are tagged `ViaDir`; the renderer
208
210
shows "(dir reference)".
209
-
-**Ephemeral dirs are excluded** from the enforced candidate set: `docs/specs` and `docs/notes` self-declare in their
210
-
READMEs as temporary scratch "wiped periodically", so requiring each to be linked fights their purpose
211
-
(`ephemeralDocDirs`). The repo-root `CLAUDE.md`(the loader shim that only `@import`s the entry docs) is excluded too.
211
+
-**Everything under `docs/` is enforced, including `docs/specs` and `docs/notes`.** Those dirs are periodically-wiped
212
+
scratch, but they must still be discoverable while they exist: specs hang off `docs/specs/index.md`, and a note is
213
+
expected to be linked from the colocated `CLAUDE.md`/ `DETAILS.md` whose work it informs.
212
214
213
215
`docs-reachable-allowlist.json` maps a doc path → the reason it's intentionally unreachable. The goal is an empty list:
214
216
connect docs rather than exempt them. Shrink-wrap drops entries whose file is gone or which became reachable; adding or
@@ -283,16 +285,16 @@ RUSTSEC ignores — that's a quarterly task in `docs/maintenance.md`.
"$comment": "Docs intentionally NOT reachable from AGENTS.md, each mapped to its reason. The goal is an empty list: connect docs instead of exempting them. The docs-reachable check shrink-wraps stale entries (file gone or now reachable) on local runs; adding or keeping an entry needs David's explicit consent (see .claude/rules/file-length-allowlist.md).",
2
+
"$comment": "Docs intentionally NOT reachable from the repo-root CLAUDE.md, each mapped to its reason. The goal is an empty list: connect docs instead of exempting them. The docs-reachable check shrink-wraps stale entries (file gone or now reachable) on local runs; adding or keeping an entry needs David's explicit consent (see .claude/rules/file-length-allowlist.md).",
0 commit comments