diff --git a/.agents/skills/code-review/SKILL.md b/.agents/skills/code-review/SKILL.md index 1594097a..b4687084 100644 --- a/.agents/skills/code-review/SKILL.md +++ b/.agents/skills/code-review/SKILL.md @@ -25,7 +25,7 @@ them here would let the copy drift: | Source | What it holds | |---|---| | `context/design-principles.md` | The "why" — functional-first, polymorphism over conditionals, correctness by construction, layering, §7 testing doctrine | -| `context/repo-map.md` | The "where", plus **numbered gotchas** — read the ones your diff touches | +| `context/repo-map.md` | The "where", plus a **numbered gotcha digest** (the full text is `context/gotchas.md`) — read the long form of the ones your diff touches | | `prolog-sessions/kb.pl` | Executable knowledge: `invariant/2`, `doctrine/2`, `forbidden/2`, `decision/3`, and prior `work_done/3` | | `AGENTS.md` | Working rules: bug-first tests, `Option`/`Result`/`Box` at the edges, history reconciled only by merge, a new conventional commit by default (amend only an unpushed HEAD, for a small fix), and nothing that needs a force push | | `.agents/skills/wave/agent-rules.md`, "GitHub" | The reviewer's rule: what to read before your first comment, how to answer each existing review, and what every review you post must state. Read it before reviewing a PR | diff --git a/.agents/skills/wave/agent-rules.md b/.agents/skills/wave/agent-rules.md index 444059f8..16840d3b 100644 --- a/.agents/skills/wave/agent-rules.md +++ b/.agents/skills/wave/agent-rules.md @@ -341,7 +341,8 @@ out on purpose: ## Files you must not write `.beads/**` (never commit `issues.jsonl`, never `git checkout` it), -`prolog-sessions/kb.pl`, `context/repo-map.md`: `AGENTS.md`, "Who owns what". +`prolog-sessions/kb.pl`, `context/repo-map.md`, `context/gotchas.md`, +`context/file-inventory.md`: `AGENTS.md`, "Who owns what". Also `AGENTS.md`, unless your brief grants you a named section. Report proposed text for any of these in your hand-back. diff --git a/AGENTS.md b/AGENTS.md index b5c5e18a..845b1507 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,8 +160,9 @@ badly: | `.beads/` (incl. `issues.jsonl`) | bd owns it. See "Never hand-edit" below. | | `prolog-sessions/kb.pl` | Written by `scripts/kb` only. See `context/code/kb-tool.md`. | | `context/repo-map.md` | Every agent wants to add a gotcha; every wave would conflict. | +| `context/gotchas.md`, `context/file-inventory.md` | The long forms the map digests; same conflict, same owner. | -Wave agents **read** all three freely (`bd show`, `bd ready`, grep `kb.pl`) and +Wave agents **read** all of them freely (`bd show`, `bd ready`, grep `kb.pl`) and **write** none of them. They report proposed repo-map lines and `kb.pl` facts as *text* in their hand-back, and the orchestrator applies them. Repo-map lines are batched at the end of the wave, after the review, because they conflict. diff --git a/context/code/doc-site.md b/context/code/doc-site.md index 09a9eb01..5a364b4c 100644 --- a/context/code/doc-site.md +++ b/context/code/doc-site.md @@ -18,7 +18,7 @@ Published, in four sections: | Section | Contents | Why | |---|---|---| -| Start here | `docs/design-notes.md`, `context/design-principles.md`, `context/repo-map.md` | What the project is for, the doctrine, and the single best explanation of how it is built. | +| Start here | `docs/design-notes.md`, `context/design-principles.md`, `context/repo-map.md`, `context/gotchas.md`, `context/file-inventory.md` | What the project is for, the doctrine, and the single best explanation of how it is built. The map is a digest; the last two are its long forms, published so a `gotcha N` citation and the per-file listing have somewhere to land. | | Decision records | `context/adr/*.md` | An ADR is written for an outside reader by construction — it states the options that were rejected, which is the part that is worth reading and the part that is nowhere else. | | The arguments, by area | `context/code/*.md` | This is the reasoning that used to live in code comments and was moved out under the two-line cap (design-principles §6). It is the most valuable prose in the repository and it is addressed to exactly the reader a documentation site has. | | Test evidence | `context/test-evidence/*.md` | One entry per test whose narrative is longer than its code. | diff --git a/context/file-inventory.md b/context/file-inventory.md index 6ba97b8b..aa56a4f2 100644 --- a/context/file-inventory.md +++ b/context/file-inventory.md @@ -342,7 +342,9 @@ context/adr/001-concurrent-edits.md Concurrent edits between clients: record-le context/cloud-agents.md Cloud-session environment: tracker sync, bd pitfalls, what is blocked context/design-principles.md Architectural principles & testing doctrine context/plan.md Show HN launch plan -context/repo-map.md This file +context/repo-map.md The map: crates, how-to-find-things, the gotcha digest, a file map +context/gotchas.md The long form of every numbered gotcha (the digest is in repo-map.md) +context/file-inventory.md This file: the per-file listing the repo map summarises docs/design-notes.md Product vision & non-goals ``` diff --git a/scripts/repo-stats b/scripts/repo-stats index 6444d2a8..f96ab557 100755 --- a/scripts/repo-stats +++ b/scripts/repo-stats @@ -189,12 +189,9 @@ def read_rows(path): def gotchas(text): - """(number, lines, chars) for each numbered item of repo-map's Gotchas section.""" - out, cur, inside = [], None, False + """(number, lines, chars) for each numbered item of context/gotchas.md.""" + out, cur, inside = [], None, True for line in text.split("\n"): - if line.startswith("## "): - inside = line.startswith("## Gotchas") - continue if inside and line.startswith("---"): inside = False if not inside: @@ -214,13 +211,13 @@ def doc_sizes(repo, sha): "context").split("\n") if p.endswith(".md")] show = lambda p: git(repo, "show", f"{sha}:{p}") lines = {p: len(show(p).splitlines()) for p in sorted(files)} - gs = gotchas(show("context/repo-map.md")) if "context/repo-map.md" in files else [] + gs = gotchas(show("context/gotchas.md")) if "context/gotchas.md" in files else [] longest = max(gs, key=lambda g: g[2], default=None) evidence = {p: sum(1 for l in show(p).split("\n") if re.match(r"^#{3,4} ", l)) for p in sorted(files) if p.startswith("context/test-evidence/")} return { "context_lines": lines, - "repo_map": {"gotchas": len(gs), "longest": longest and + "gotchas": {"count": len(gs), "longest": longest and {"number": longest[0], "lines": longest[1], "chars": longest[2]}}, "test_evidence": {"entries": sum(evidence.values()), "per_file": evidence}, } @@ -270,9 +267,9 @@ def text(r, top): out += ["", TITLES[t]] + table(r["tables"][t]) out += ["", "Doc sizes (lines)"] out += [f" {n:>6} {path}" for path, n in r["docs"]["context_lines"].items()] - rm, te = r["docs"]["repo_map"], r["docs"]["test_evidence"] + rm, te = r["docs"]["gotchas"], r["docs"]["test_evidence"] lg = rm["longest"] - out.append(f" repo-map gotchas: {rm['gotchas']}" + ( + out.append(f" gotchas: {rm['count']}" + ( f"; longest is {lg['number']} ({lg['lines']} lines, {lg['chars']} chars)" if lg else "")) out.append(f" test-evidence entries: {te['entries']}") diff --git a/scripts/repo-stats-test.sh b/scripts/repo-stats-test.sh index 2e138dbd..65fbe5e2 100755 --- a/scripts/repo-stats-test.sh +++ b/scripts/repo-stats-test.sh @@ -76,10 +76,9 @@ put context/code/x.md 8 x3 mkdir -p "$repo/context/test-evidence" printf '### t_one\ntext\n#### t_two\n## not an entry\n### t_three\n' \ > "$repo/context/test-evidence/y.md" -cat > "$repo/context/repo-map.md" <<'EOF' -# Map - -## Gotchas (read before editing) +printf '# Map\n' > "$repo/context/repo-map.md" +cat > "$repo/context/gotchas.md" <<'EOF' +# Gotchas 1. **One.** short. 2. **Two.** a much longer gotcha, with plenty of words in it to be the longest one @@ -136,25 +135,25 @@ if run "$work/stats" text; then row "docs/*.md is other docs" by-area "other docs" '["2","0","0.000"]' row "context/code" by-area "context/code" '["8","0","0.000"]' row "context/test-evidence" by-area "context/test-evidence" '["5","0","0.000"]' - row "repo-map is its own area" by-area "repo-map" '["13","0","0.000"]' - row "other context" by-area "other context" '["2","0","0.000"]' + row "repo-map is its own area" by-area "repo-map" '["1","0","0.000"]' + row "other context" by-area "other context" '["13","0","0.000"]' row "kb.pl" by-area "kb.pl" '["5","0","0.000"]' row "scripts/CI takes .github, and a rename is a delete and an add" \ by-area "scripts/CI" '["15","7","0.467"]' row "web and harness, and its deletion ratio" by-area "web and harness" '["14","9","0.643"]' row "a lock file, .beads/ and site/ are generated" by-area "generated" '["14","0","0.000"]' row "the pre-window README counts nowhere" by-area "other" '["4","0","0.000"]' - row "prose is the context areas, other docs and agent docs" by-kind prose '["43","6","0.140"]' + row "prose is the context areas, other docs and agent docs" by-kind prose '["42","6","0.143"]' row "code is rust, scripts/CI and web" by-kind code '["82","45","0.549"]' - row "prose to code is prose over code" by-kind ProseToCode '["0.524","0.133",""]' + row "prose to code is prose over code" by-kind ProseToCode '["0.512","0.133",""]' is "weeks are columns, first-seen first" '.tables["area-by-week"][0][1:]' '["2026-W24","2026-W23"]' row "an area is split by ISO week" area-by-week "web and harness" '["3","11"]' is "every day's churn.csv total equals code-maat's abs-churn" \ '[.tables["by-day"][1:][]|.[1]==.[2]]|all' 'true' - row "a day's total is every file changed that day" by-day 2026-06-04 '["72","72"]' - is "gotchas end with their section" '.docs.repo_map.gotchas' '3' + row "a day's total is every file changed that day" by-day 2026-06-04 '["71","71"]' + is "gotchas end with their section" '.docs.gotchas.count' '3' is "the longest gotcha is measured over its lines" \ - '.docs.repo_map.longest|[.number,.lines]' '[2,2]' + '.docs.gotchas.longest|[.number,.lines]' '[2,2]' is "test-evidence entries are ### and #### headings" '.docs.test_evidence.entries' '3' is "coupling finds the 15 pairs of six files, and web/app.js with scripts/foo.sh" \ '.coupling|length' '16'