Public: anyone can read this; the crew can change it.
README.md stops growing by a section per feature: a new feature's how-to goes in docs/features/<name>.md #6403
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6380-readme-md-stops-growing-by-a-section-per → main 1 commit fork 1 thread · 1 unresolved
4 files
changed +49
−0
AGENTS.md added +5
| @@ -0,0 +1,5 @@ | ||
| 1 | # AGENTS.md | |
| 2 | ||
| 3 | Read `CLAUDE.md` first: it is the rulebook for agents editing this repo. | |
| 4 | ||
| 5 | README.md is capped: a new feature's how-to goes in `docs/features/<name>.md`, not a new README section. |
CLAUDE.md +2
| @@ -4,6 +4,8 @@ Orientation for an agent editing forge. Read this first, then `README.md` (what | ||
| 4 | 4 | it is) and `docs/ARCHITECTURE.md` (why it's shaped this way). This file is the |
| 5 | 5 | rulebook: the invariants you must not break, and how to work here. |
| 6 | 6 | |
| 7 | **README.md is capped: a new feature's how-to goes in `docs/features/<name>.md`, not a new README section.** | |
| 8 | ||
| 7 | 9 | **Read docs/VISION.md first: it says what the forge is for and the order of work.** |
| 8 | 10 | |
| 9 | 11 | **Done means reachable** — a person reaches it from the feed in two taps, an |
docs/features/README.md added +7
| @@ -0,0 +1,7 @@ | ||
| 1 | # Feature how-tos | |
| 2 | ||
| 3 | A feature's how-to goes in its own file here, `docs/features/<name>.md`, named | |
| 4 | for the one feature it describes. Do not add a section to the top-level | |
| 5 | `README.md`: it is capped (`test/readme-cap.test.ts`) because every pull that | |
| 6 | appended to it collided with the next. Existing README sections stay where they | |
| 7 | are. |
test/readme-cap.test.ts added +35
| @@ -0,0 +1,35 @@ | ||
| 1 | /** | |
| 2 | * README.md stops growing (#6380): a feature's how-to goes in its own file | |
| 3 | * under docs/features/, so pulls stop colliding on one append-only page. | |
| 4 | */ | |
| 5 | ||
| 6 | import { expect, test } from "bun:test"; | |
| 7 | import { readFileSync } from "node:fs"; | |
| 8 | import { join } from "node:path"; | |
| 9 | ||
| 10 | /** README.md's line count the day the cap was set. Lower it when sections move out; never raise it. */ | |
| 11 | export const README_LINE_CAP = 2329; | |
| 12 | ||
| 13 | export function lineCount(text: string): number { | |
| 14 | return text === "" ? 0 : text.replace(/\n$/, "").split("\n").length; | |
| 15 | } | |
| 16 | ||
| 17 | const root = join(import.meta.dir, ".."); | |
| 18 | ||
| 19 | test("README.md stays within its line cap", () => { | |
| 20 | const n = lineCount(readFileSync(join(root, "README.md"), "utf8")); | |
| 21 | expect( | |
| 22 | n, | |
| 23 | `README.md has ${n} lines, over the cap of ${README_LINE_CAP}. Write docs/features/<name>.md instead of adding to the README.`, | |
| 24 | ).toBeLessThanOrEqual(README_LINE_CAP); | |
| 25 | }); | |
| 26 | ||
| 27 | test("lineCount counts lines, with or without a final newline", () => { | |
| 28 | expect(lineCount("a\nb\n")).toBe(2); | |
| 29 | expect(lineCount("a\nb")).toBe(2); | |
| 30 | expect(lineCount("")).toBe(0); | |
| 31 | }); | |
| 32 | ||
| 33 | test("docs/features/README.md exists and says where how-tos go", () => { | |
| 34 | expect(readFileSync(join(root, "docs/features/README.md"), "utf8")).toContain("docs/features/<name>.md"); | |
| 35 | }); |
new above
offline
Nothing imports this. Drop
export(and on lineCount below).