diff --git a/HARNESS.md b/HARNESS.md index adda5d4..a2c8276 100644 --- a/HARNESS.md +++ b/HARNESS.md @@ -111,8 +111,10 @@ plus one line in `cmd/atelier/wire.go`. `verify.sh` fails on a feature importing feature package without a `doc.go` — the first because sibling imports make an agent's read set compound, the second because a four-line `doc.go` turns orientation into a fifteen-line read (ADR-0027). -**Documentation is gated too.** Every package carries a package comment, every exported identifier a doc -comment, and a decision cited in code (`// Path shape: ADR-0008.`) must name an ADR that exists. The point +**Documentation is gated too.** Every package carries a package comment, and a decision cited in code +(`// Path shape: ADR-0008.`) must name an ADR that exists. Doc comments on exported identifiers are +warned rather than failed — presence is checkable, usefulness is not, and a hard gate there would buy +`// Load loads.` The point is a codebase still navigable by `go doc` and `git log` alone, years from now, with no agent available — `verify.sh` enforces presence, and only you can enforce that the comment says something. @@ -140,7 +142,8 @@ that describe it, in the same change.** - `verify.sh` fails when `CLAUDE.md`, `scripts/` or `.claude/` changes without `HARNESS.md` changing. This file is the current description of the machine, not a snapshot of its design. - `verify.sh` fails when a `.go` file changes without `docs/state.md` changing, and when `cmd/` or - `internal/` code changes without a `_test.go` changing — behaviour ships with a test. + `internal/` code changes without a `_test.go` changing — behaviour ships with a test. A comment-only or + `gofmt`-only diff is exempt: it ships no behaviour, and failing it would only teach you `--no-verify`. - The gate is not optional. `scripts/hooks/pre-commit` runs it on every commit; enable once per clone with `git config core.hooksPath scripts/hooks`. `--no-verify` bypasses it, and the commit body should say why. diff --git a/docs/conventions.md b/docs/conventions.md index ff20f98..6f5ba6f 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -47,11 +47,14 @@ wants splitting. ## Documentation Written for a maintainer working alone, years from now, with no agent to explain anything. `verify.sh` -enforces presence; only a human can enforce that it says something. +fails on a missing package comment and on a citation naming an ADR that does not exist; a missing doc +comment on an exported identifier is a warning, because no gate can tell `// Load loads.` from a useful +sentence, and a gate whose cheapest satisfaction is noise buys noise. - **Every package has a package comment.** What it owns, what it does not, and which packages may import it. For `internal/ext/*` that is the four-line `doc.go` shape in `extensions.md`. -- **Every exported identifier has a doc comment.** The exported surface of a 2000-line core is small, and +- **Every exported identifier has a doc comment** (warned, not gated). The exported surface of a + 2000-line core is small, and `go doc ./...` is the only navigation tool that still works when nothing else does. A comment that restates the name (`// Load loads.`) is worse than none: say what it returns on absence, what it costs, what it assumes. diff --git a/docs/roadmap.md b/docs/roadmap.md index 3436201..0104448 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -70,4 +70,3 @@ Bengali tokenisation for search is the genuinely novel problem here — solve it and deliberately, not as a side effect of adding search. The low-bandwidth, low-carbon ethos is coherent with Gemini output, PWA offline, and no-JS defaults; let that coherence break ties when two designs are otherwise equal. - diff --git a/docs/state.md b/docs/state.md index 2b35786..cd89a5c 100644 --- a/docs/state.md +++ b/docs/state.md @@ -1,6 +1,6 @@ # State -**Verified against:** `54c14a2` on 2026-07-30 — update this line every change. +**Verified against:** `1c19727` on 2026-07-30 — update this line every change. If this file disagrees with the code, the code is right and this file is a bug. ## Inventory diff --git a/scripts/verify.sh b/scripts/verify.sh index dca5a46..57bd4a7 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -51,7 +51,21 @@ if [ -d .git ] && command -v git >/dev/null 2>&1; then fi if echo "$changed" | grep -qE '^(cmd|internal)/.*\.go$' && ! echo "$changed" | grep -qE '_test\.go$'; then - bad "cmd/ or internal/ .go changed but no _test.go did — behaviour ships with a test (conventions.md)" + # A comment-only or gofmt-only diff ships no behaviour, so it owes no test. Compare the added and + # removed lines with comments, blanks and indentation stripped: equal sets mean nothing happened. + gochanged=$(echo "$changed" | grep -E '^(cmd|internal)/.*\.go$') + godiff=$(git diff HEAD -- $gochanged 2>/dev/null) + # strip the marker, comments, blanks, and *all* whitespace runs — gofmt realignment then compares + # equal, while any real edit still differs. + strip() { grep -E "^[$1]" | grep -vE '^(\+\+\+|---)' | sed "s/^[$1]//" | + grep -vE '^[[:space:]]*(//|/\*|\*/|\* )' | tr -s ' \t' ' ' | + sed 's/^ //; s/ $//' | grep -v '^$' | sort; } + newgo=$(git ls-files --others --exclude-standard -- $gochanged 2>/dev/null) + if [ -z "$newgo" ] && [ "$(echo "$godiff" | strip '+')" = "$(echo "$godiff" | strip '-')" ]; then + pass "code/test coupling (comment- or format-only)" + else + bad "cmd/ or internal/ .go changed but no _test.go did — behaviour ships with a test (conventions.md)" + fi else pass "code/test coupling" fi @@ -267,7 +281,7 @@ undocumented=$(echo "$gofiles" | grep -v '_test\.go$' | xargs awk ' /^(func|type|var|const) [A-Z]/ { if (prev !~ /^\/\//) printf "%s:%d ", FILENAME, FNR } { prev = $0 }' 2>/dev/null) if [ -n "$undocumented" ]; then - bad "exported identifier without a doc comment: $undocumented" + note "exported identifier without a doc comment: $undocumented" else pass "exported identifiers documented" fi