--- phase: 11.1-summercms-documentation-for-humans-and-ai-agents plan: 07 subsystem: docs tags: [docsite, goldmark, go-doc, chroma, snippets] requires: - phase: 11.1-06 provides: planted-violation corpus, docs:build --check, and the phase 11.1 gate provides: - AST fence discovery shared by the snippet, policy, and command checkers - Refusal of nested src= fences and of src= fences in module READMEs - Proof that a .go src= target is in the default build and reached from a Test or an Example with output - Case-sensitive go doc fallback and cobra-style command words affects: [11.1 verification, README src= follow-up] actuals: tokens: 22900 tasks: 5 commits: 6 plan_head_before: d9f187ae39d174d813309a7e9adc8ddc3cc7fe10 plan_head_after: ce5dcec7e4e0733b07676b36abb26188d7150501 tech-stack: added: [] patterns: - "Checkers walk the goldmark AST from newMarkdown, the same parse the renderer uses" - "build.ImportDir on build.Default decides which .go files go test ./... compiles" - "commandWord mirrors cobra stripFlags for a root whose only bool flag is --help/-h" key-files: created: - internal/docsite/fences.go - internal/docsite/fences_test.go modified: - internal/docsite/snippet.go - internal/docsite/check_policy.go - internal/docsite/check_commands.go - internal/docsite/check_identifiers.go - internal/docsite/render.go - cmd/summer/phase11_1_acceptance_test.go - scripts/check-phase11.1.sh key-decisions: - "A src= fence that is not a top-level block of a docs page is refused, and docs:sync does not rewrite it." - "Module README src= fences are refused and never captioned; a Go fence without src= in a README stays legal." - "The identifier fallback runs go doc -c, so a span must match the declaration's case." - "Shell command words follow cobra stripFlags and include env prefixes, go run ./cmd/summer, and bin/{app}." patterns-established: - "Pattern: fence discovery is collectFences over the renderer's AST, not a line scan." - "Pattern: captions are emitted only for top-level src= fences of docs/ pages." requirements-completed: [DOCS-04, DOCS-05] coverage: - id: D1 description: Nested src= fences (callout, blockquote, list item) are refused and are not rewritten by docs:sync. requirement: DOCS-04 verification: - kind: unit ref: internal/docsite TestPlantedViolations/snippet-callout-drift TestCollectFences TestSyncParsedFences status: pass human_judgment: false - id: D2 description: Go-lexer fences without src= are refused at any depth, and module README src= fences are refused and not captioned. requirement: DOCS-04 verification: - kind: unit ref: internal/docsite TestGoLang TestNestedFenceChecks TestFenceCaptionsOnlyVerified status: pass human_judgment: false - id: D3 description: A .go src= target must be in the default build and reached from a Test or an Example with output; go doc -c and commandWord cover the name-form holes. requirement: DOCS-05 verification: - kind: unit ref: internal/docsite TestSnippetRootsAndBuild TestIdentifierGoDocCaseSensitive TestCommandWord status: pass human_judgment: false - id: D4 description: The acceptance scanner sees blockquoted and aliased fences, and the phase gate plants each hole. requirement: DOCS-04 verification: - kind: integration ref: go test ./cmd/summer -run '^(TestPhase11_1Acceptance|TestAcceptanceFenceScanner)$' and scripts/check-phase11.1.sh --all status: pass human_judgment: false duration: 33 min completed: 2026-10-01 status: complete --- # Phase 11.1 Plan 07: Fail-closed docs checkers Summary **Docs checkers walk the goldmark AST, refuse nested and module-README `src=` fences, and accept a Go `src=` target only when `go test ./...` compiles and runs it.** ## Performance - **Duration:** 33 min - **Started:** 2026-10-01T06:19:48Z - **Completed:** 2026-10-01T06:53:36Z - **Tasks:** 5 - **Files modified:** 64 ## Accomplishments - `collectFences` finds every fenced code block the renderer parses, including fences inside callouts, blockquotes, and list items. A `src=` fence that is not a top-level block of a docs page fails Check, docs:build, and docs:sync, and sync writes nothing. - Captions are limited to top-level `src=` fences of docs/ pages. A module README `src=` fence is refused with `readmeSrcMessage` and is not extracted. A Go fence without `src=` in a README stays legal. - A `.go` `src=` target must sit in the default build (`build.ImportDir` on `build.Default`, plus `testdata` and `_`-prefixed directories) and inside a `Test` function or an Example with `// Output:`, or a function one of them calls. `go doc -c` makes the identifier fallback case-sensitive. `commandWord` parses env prefixes, cobra-style flags, `go run ./cmd/summer`, and `bin/{app}`. - Eighteen planted fixtures and branch tests pin those holes. `internal/docsite` coverage is 94.1%. `scripts/check-phase11.1.sh --all` printed `phase11.1 all passed`. ## Task Commits Each task was committed atomically: 1. **Task 1: AST fence discovery, nested src= refused, captions only on verified fences** - `5b7e37f` (fix) 2. **Task 2: Go-lexer policy, README src= refusal, shell fences from the AST** - `73c72af` (fix) 3. **Task 3: Proof of execution, go doc -c, command words** - `efc3161` (fix) 4. **Task 4: Planted fixtures and unit tests** - `9ba5530` (test) 5. **Task 5: Acceptance scanner and gate plants** - `550fa06` (test) 6. **Task 5 planning: VALIDATION rows and README todo** - `ce5dcec` (docs) **Plan metadata:** committed after this file. ## Files Created/Modified - `internal/docsite/fences.go` - AST fence collection shared by check and sync. - `internal/docsite/snippet.go` - nested and README refusals, build membership, test-graph roots. - `internal/docsite/check_policy.go` - Go-lexer fences at every depth; unknown callouts from remaining blockquotes. - `internal/docsite/check_commands.go` - shell fences from the AST; `commandWord`. - `internal/docsite/check_identifiers.go` - `go doc -c`. - `internal/docsite/render.go` - captions only on verified top-level docs fences; `openFence` rejects indent above 3 spaces. - `internal/docsite/highlight.go` - `goLang` via the chroma Go lexer. - `cmd/summer/phase11_1_acceptance_test.go` - independent `scanDocFences` and caption cross-check. - `scripts/check-phase11.1.sh` - self-test plants and the new test names. - `docs/console/utilities.md`, `README.md` - the top-level, alias, callout, and README rules. - `internal/docsite/testdata/violations/` - 18 new plants (81 directories total). ## Decisions Made - Nested `src=` fences are refused instead of extracted, because docs:sync cannot rewrite a line that still carries its container marker. - Module README code blocks stay rendered as written. A `src=` there would claim a check that does not run, so it is refused, and the caption transformer skips README pages. - Reachability roots are the cmd/go `Test` name rule plus `go/doc` Examples that have output. An Example without `// Output:` is not a root. - `commandWord` treats `--help` and `-h` as bool flags and consumes the next token for every other `--name` or two-character `-x`, matching cobra's `stripFlags`. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Drift fixture was a nested src= fence** - **Found during:** Task 1 (AST fence discovery) - **Issue:** `TestSyncRewritesDrift` planted a `src=` fence inside a list item. The new nested rule correctly refused it, so the test no longer reported drift. - **Fix:** Removed the list marker. The drifted fence is a two-space-indented top-level fence. The expected problem line moved from 13 to 11. Indent-preserving sync assertions still hold. - **Files modified:** `internal/docsite/docsite_test.go` - **Commit:** `5b7e37f` **Total deviations:** 1 auto-fixed (Rule 1). **Impact:** the drift test still pins body mismatch; nested fences are covered by the new plants instead of that fixture. Tasks 2 and 3 needed no source fix on the real tree. `go run ./cmd/summer docs:build --check` printed `docs:build: no problems found` after each. No existing unit-test tree relied on an Example without output as a root. ### Tracking `state.advance-plan` at close-out read `Plan: 1 of 7` (phase begin had reset the counter) and stepped it to `2 of 7`. The position was set back to `Plan: 7 of 7` before the last-plan advance, which waits until this summary exists. DOCS-04 and DOCS-05 are listed in `requirements-completed` from the plan frontmatter. They were not ticked in REQUIREMENTS.md; re-verification does that. ## Mutation checks Recorded from scratch edits that were restored and not committed: - Removing the nested branch of `checkFences` turned `TestPlantedViolations/snippet-callout-drift` red (the test panicked in `fenceBody` because a nested fence has no top-level line span). - Dropping `-c` from `goDoc` turned `TestPlantedViolations/identifier-wrong-case` red (zero problems; the wrong-case span passed). - Treating every Example as a root turned `TestPlantedViolations/snippet-example-no-output-helper` red (zero problems; the helper became reachable). - Renaming `TestCommandWord` in a scratch copy made `scripts/check-phase11.1.sh --named` exit 1 with `refuse: named tests did not pass ... TestCommandWord`. The rename was restored. ## Follow-up The identifier index still reads build-ignored files. That hole is outside this plan and was not changed. ## Authentication Gates None. ## Known Stubs None. ## Threat Flags None. The checkers stay inside the plan's threat register (T-11.1-20 through T-11.1-25). No new endpoint, credential path, or dependency. `git diff d9f187ae39d174d813309a7e9adc8ddc3cc7fe10 HEAD -- go.mod go.sum` is empty. ## Self-Check: PASSED - FOUND: internal/docsite/fences.go - FOUND: internal/docsite/fences_test.go - FOUND: cmd/summer/phase11_1_acceptance_test.go - FOUND: scripts/check-phase11.1.sh - FOUND: .planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-VALIDATION.md - FOUND: 5b7e37f - FOUND: 73c72af - FOUND: efc3161 - FOUND: 9ba5530 - FOUND: 550fa06 - FOUND: ce5dcec - `go test ./internal/docsite ./cmd/summer -count=1` passed after Tasks 3 and 4. - `go test ./internal/docsite` coverage 94.1% (above 85%). - `scripts/check-phase11.1.sh --all` printed `phase11.1 all passed`.