--- phase: 11.1-summercms-documentation-for-humans-and-ai-agents plan: 02 subsystem: docs tags: [docs, checkers, goldmark, chroma, theme, search, docs-serve, gate] requires: - phase: 11.1-01 provides: "internal/docsite (Check, Build, Pages, slugIDs, headingIDs, snippet checks), summer docs:build and docs:sync" - phase: 11-08 provides: "stable module READMEs for the identifier checker" provides: - "docsite.Commands and Options.Commands (nil is a problem, never a silent skip)" - "docsite.Serve, docsite.Handler, docsite.DefaultServeAddr" - "checkers: identifier, link, command, forbidden, snippet (go fence without src=), callout, heading" - "chroma/v2 NodeRenderer mapping tokens onto tok-kw, tok-key, tok-str, tok-com, tok-num, tok-prompt" - "UI-SPEC theme: header, sidebar, TOC, pager, footer, search dialog, icons, 404, site.css, site.js, search.js, theme-init.js, vendored fonts" - "summer docs:serve (--root --src --base-url --addr --allow-remote) and cmd/summer docsCommands()" - "scripts/check-phase11.1.sh with --preconditions --deps --docs --forbidden --claude --self-test --go --all" - "CLAUDE.md D-13 rule naming the checkers, D-17 config-key note; wristband default todo" affects: [11.1-03, 11.1-04, 11.1-05, 11.1-06, 11.2] tech-stack: added: - "github.com/alecthomas/chroma/v2 v2.27.0 (direct, D-15)" - "github.com/dlclark/regexp2/v2 v2.2.1 (indirect, via chroma)" patterns: - "Every checker reads one parse per page (parseRaw: renderer parser and slug IDs, no page context) so anchors match the rendered IDs" - "Command sets are collected from the real constructors; a test keeps them in step with the generated app main" - "Forbidden names are scanned in page sources before render and in every text output after render" - "Theme markers are exact UI-SPEC strings asserted by TestBuildSiteMarkers; no inline script, style or on* attribute" key-files: created: - internal/docsite/check_identifiers.go - internal/docsite/check_links.go - internal/docsite/check_commands.go - internal/docsite/check_forbidden.go - internal/docsite/check_policy.go - internal/docsite/highlight.go - internal/docsite/serve.go - internal/docsite/checks_test.go - internal/docsite/theme_test.go - internal/docsite/theme/templates/header.html - internal/docsite/theme/templates/sidebar.html - internal/docsite/theme/templates/toc.html - internal/docsite/theme/templates/pager.html - internal/docsite/theme/templates/footer.html - internal/docsite/theme/templates/search.html - internal/docsite/theme/templates/icons.html - internal/docsite/theme/templates/404.html - internal/docsite/theme/assets/site.js - internal/docsite/theme/assets/search.js - internal/docsite/theme/assets/theme-init.js - internal/docsite/theme/assets/LICENSE-lucide.txt - internal/docsite/theme/assets/fonts/ (8 woff2 files, LICENSE-dm-sans.txt, LICENSE-dm-mono.txt) - scripts/check-phase11.1.sh - .planning/todos/pending/wristband-neutral-resource-default.md modified: - internal/docsite/docsite.go - internal/docsite/load.go - internal/docsite/render.go - internal/docsite/emit.go - internal/docsite/docsite_test.go - internal/docsite/theme/templates/page.html - internal/docsite/theme/assets/site.css - cmd/summer/docs.go - cmd/summer/docs_test.go - cmd/summer/main.go - cmd/summer/main_test.go - go.mod - go.sum - README.md - CLAUDE.md key-decisions: - "The identifier index resolves members promoted through types embedded in the same package; go doc does not resolve promotion, so it stays only as the fallback for anything else" - "docsCommands() calls the constructors on backpack.New(&compass.Config{}) with nil plugins; they only capture the app, and nothing runs" - "The forbidden-name output scan runs after a clean render; the page-source scan reports first with source file and line" - "Callout types are checked in docs pages and module READMEs; the heading rule and the go-fence src= rule apply to docs/ pages only (D-18)" - "Link rule for other relative repo paths applies to guide pages only; module READMEs are read on the git host first" - "The drawer target is a div#sidebar wrapping the nav, and the search index URL sits on #search-results, so the UI-SPEC markers stay exact" - "A pager target on the index page carries no section line" patterns-established: - "Checker problem lines follow the UI-SPEC CLI table: file:line: rule: message" - "Gate self-tests copy docs/, modules/, go.mod and go.sum into a scratch root and plant one violation per rule" requirements-completed: [DOCS-02, DOCS-04, DOCS-05, DOCS-08] estimate_ref: "tokens 140000, tasks 3, confidence low" actuals: tokens: 46000 tasks: 3 commits: 4 plan_head_before: 9dcc10177609f22ac535d4dd9972d55f7037e6b8 plan_head_after: dd11bdb0c7443b69cb1df3df4574fa6a8024cdb8 coverage: - id: D1 description: "A stale pkg.Ident span in a docs page, module README or the root README fails go test, docs:build and the gate" requirement: DOCS-05 verification: - kind: unit ref: "internal/docsite/checks_test.go#TestIdentifierChecker" status: pass - kind: unit ref: "cmd/summer/docs_test.go#TestDocsTree" status: pass - kind: other ref: "scripts/check-phase11.1.sh --self-test (bonfire.NoSuchThing plant); go run ./cmd/summer docs:build --check --src with lighthouse.NoSuchThing" status: pass human_judgment: false - id: D2 description: "Broken relative links and anchors fail with link: problems computed from the renderer's heading IDs" requirement: DOCS-05 verification: - kind: unit ref: "internal/docsite/checks_test.go#TestLinkChecker" status: pass human_judgment: false - id: D3 description: "summer and ./bin/ command names are checked against sets collected from the real constructors and example bonfire.Command literals" requirement: DOCS-05 verification: - kind: unit ref: "internal/docsite/checks_test.go#TestCommandChecker" status: pass - kind: unit ref: "cmd/summer/docs_test.go#TestDocsCommandNames" status: pass - kind: unit ref: "cmd/summer/docs_test.go#TestDocsCommandsMirrorGeneratedMain" status: pass human_judgment: false - id: D4 description: "Consuming-application names fail in sources and outputs without echoing the match" requirement: DOCS-05 verification: - kind: unit ref: "internal/docsite/checks_test.go#TestForbiddenChecker" status: pass - kind: other ref: "scripts/check-phase11.1.sh --forbidden and --self-test" status: pass human_judgment: false - id: D5 description: "Go fences in docs/ pages need src=; unknown callouts and non-plain docs/ headings fail" requirement: DOCS-04 verification: - kind: unit ref: "internal/docsite/checks_test.go#TestFencePolicy" status: pass human_judgment: false - id: D6 description: "The built site has the UI-SPEC shell, chroma highlighting, 404 page, pager edge cases and no inline script/style/handler" requirement: DOCS-02 verification: - kind: unit ref: "internal/docsite/theme_test.go#TestBuildSiteMarkers" status: pass - kind: unit ref: "cmd/summer/docs_test.go#TestDocsBuildRealTree" status: pass human_judgment: false - id: D7 description: "docs:serve serves on loopback, refuses non-loopback without --allow-remote, returns 404.html with 404 and never a dot-file" requirement: DOCS-02 verification: - kind: unit ref: "internal/docsite/theme_test.go#TestServeHandler" status: pass - kind: unit ref: "internal/docsite/theme_test.go#TestServeRefusesNonLoopback" status: pass - kind: other ref: "manual smoke: summer docs:serve on 127.0.0.1, edit rebuilds, a planted problem keeps the previous build" status: pass human_judgment: false - id: D8 description: "CLAUDE.md records D-13, names the checkers and notes deferred config-key checking" requirement: DOCS-08 verification: - kind: other ref: "scripts/check-phase11.1.sh --claude" status: pass human_judgment: false - id: D9 description: "Search rows, arrow keys and Enter; no theme flash in all three modes; contrast at 1280/1024/375px; no-JS layout" verification: [] human_judgment: true rationale: "Backstop truths in the plan: manual UAT via summer docs:serve (no JS runner without Node). Headless Chromium screenshots at 1400px and 800px in light and dark looked right, but that is not the UAT." duration: 30min completed: 2026-09-30 status: complete --- # Phase 11.1 Plan 02: Docs accuracy gates, theme and docs:serve Summary **Every D-11/D-12 rule now fails `go test` and `docs:build`: stale identifiers, broken links and anchors, unknown commands, consuming-application names, go fences without `src=`, unknown callouts and non-plain headings. The site has the full UI-SPEC WinterCMS-style theme with chroma/v2 highlighting, client-side search, a three-way theme toggle and `summer docs:serve`, and `scripts/check-phase11.1.sh` checks all of it.** ## Performance - **Duration:** about 30 min - **Started:** 2026-09-30T19:29Z - **Completed:** 2026-09-30T19:59Z - **Tasks:** 3 - **Files modified:** 53 (38 without fonts and licences) ## Accomplishments - `check_identifiers.go` uses `go/parser` to index every package under `modules/`, sub-packages included. It records funcs, types, consts, vars, methods (generic receivers stripped), fields, embedded types and interface methods, and resolves promoted members. On the real tree it checks 1,268 module spans across 24 pages and the root README with 0 misses. - Links and anchors are checked against the heading IDs the renderer produces. Command names come from `toolCommands()` and the constructors the generated main calls (plus `lagoon.KeyGenerateCommand`, `centrifugo.Commands` and `flare.Commands`). Example `bonfire.Command` literals under `docs/examples` and `examples` are parsed, never imported. - Consuming-application names are rejected in page sources and in every text output. The problem line never repeats the matched word. - Theme: header (wordmark, search trigger with ``, theme toggle, Menu), grouped sidebar with API items in DM Mono, TOC column and `toc-inline` (only with 2 or more H2/H3), eyebrow/lead/page actions, callouts, heading permalinks, pager (first page Next only, last page Previous only, section line only across sections), footer with llms links, `404.html`, and 15 inline Lucide icons. DM Sans and DM Mono are vendored with their licences. Nothing loads from a third-party origin. - `highlight.go` maps chroma tokens onto the UI-SPEC classes. Shell fences get `tok-prompt` for `$ ` (excluded from copy) and `tok-kw` for the command word. - `search.js` loads `search-index.json` on first open. It uses AND-token matching ranked title over heading over text, shows up to 20 rows built with `createElement`/`textContent` and `` elements, and implements every UI-SPEC state message and live-region count. - `summer docs:serve` builds into a temporary directory, serves on `127.0.0.1:8088` by default and refuses any non-loopback address without `--allow-remote`. It returns `404.html` with status 404, never serves dot-files, and rebuilds on change while keeping the last good build. - The gate self-test plants 9 violations (identifier, missing README, drifted snippet, frontmatter typo, broken anchor, unknown command, forbidden name, go fence without `src=`, `[!DANGER]`) and each one is refused under its own rule. ## Task Commits 1. **Task 1: Identifier checker tracer through go test, docs:build and the gate:** `f460529` (feat) 2. **Task 2: Links, commands, forbidden names, fence policy:** `5d4c1e3` (feat). The docs-rules change was committed separately as `d89e18b` (docs: CLAUDE.md and the wristband todo) 3. **Task 3: Theme, chroma, search, dark mode, docs:serve:** `dd11bdb` (feat) **Plan metadata:** the docs(11.1-02) commit that adds this file ## Files Created/Modified See `key-files` in the frontmatter. The main ones: - `internal/docsite/check_*.go`: the five checker files - `internal/docsite/highlight.go`: the fence NodeRenderer and chroma mapping. It moved out of render.go - `internal/docsite/render.go`: heading permalinks, the callout transformer and renderer, `parseRaw` - `internal/docsite/emit.go`: the page view (eyebrow, TOC, pager, edit and Markdown links) and `404.html` - `internal/docsite/serve.go`: `Serve`, `Handler` and the loopback check - `cmd/summer/docs.go`: `docsCommands()` and `docs:serve` ## Decisions Made See `key-decisions` in the frontmatter. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] `go doc` does not resolve promoted members** - **Found during:** Task 1 - **Issue:** The plan relied on the `go doc` fallback to accept members promoted through embedding. `go doc ./modules/x Bus.ID` exits 1 for a field or method promoted from an embedded type. - **Fix:** The index records the embedded types of each type and follows them within the package. `go doc` remains the fallback for any other miss. - **Files modified:** internal/docsite/check_identifiers.go, internal/docsite/checks_test.go - **Commit:** f460529 **2. [Rule 3 - Blocking] The exact UI-SPEC markers conflicted with the attributes they needed** - **Found during:** Task 3 - **Issue:** `aria-controls="sidebar"` needs an element with `id="sidebar"`, `search.js` needs the index URL, and the toggle shared an `icon-button` class. Putting those attributes on the nav, the dialog and the toggle broke the exact markers `