docs(11.1-07): complete the fail-closed checkers plan

This commit is contained in:
Jakub Zych
2026-10-01 08:59:26 +02:00
parent ce5dcec7e4
commit 16be02c6f1
3 changed files with 230 additions and 16 deletions

View File

@@ -544,7 +544,7 @@ Plans:
4. Every Go example in a `docs/` page is compiled and run by `go test ./...` (Go code in ingested module READMEs is identifier-checked, not compiled — D-18). An identifier checker and an internal link/anchor checker also run there and fail on stale names or broken links.
5. A "Coming from WinterCMS" concept map and an `acme/blog` porting walkthrough exist, and the walkthrough's code is verified under criterion 4.
**Plans:** 6/7 plans executed
**Plans:** 7/7 plans executed
Plans:
**Wave 1**
@@ -566,7 +566,7 @@ Plans:
- [x] 11.1-06-PLAN.md — Unit tests last: planted-violation fixtures, internal/docsite coverage, SC1-SC5 acceptance, final gate, validated VALIDATION.md
**Wave 7** *(gap closure, blocked on Wave 6 completion)*
- [ ] 11.1-07-PLAN.md — Checkers fail closed: AST fence discovery (nested and README src= refused, captions only on verified fences, Go-lexer aliases need src=), go test roots and go/build membership for src= targets, `go doc -c`, env/flag/go run/bin command forms; planted fixtures and unit tests for every hole
- [x] 11.1-07-PLAN.md — Checkers fail closed: AST fence discovery (nested and README src= refused, captions only on verified fences, Go-lexer aliases need src=), go test roots and go/build membership for src= targets, `go doc -c`, env/flag/go run/bin command forms; planted fixtures and unit tests for every hole
### Phase 11.2: Ready to share: summercms.io website and newsletter plugin (INSERTED)
@@ -677,7 +677,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 9. Backend admin authentication and schema pipeline | 12/12 | In Progress| |
| 10. Admin Vue SPA | 5/5 | Complete | 2026-09-27 |
| 11. Jobs, realtime and search infrastructure | 8/8 | In Progress| |
| 11.1. SummerCMS documentation for humans and AI agents | 6/7 | In Progress| |
| 11.1. SummerCMS documentation for humans and AI agents | 7/7 | In Progress| |
| 11.2. Ready to share: summercms.io website and newsletter plugin | 0/TBD | Not started | - |
| 12. Płytarium API — Collections and Albums | 0/TBD | Not started | - |
| 13. Płytarium API — wishlist, notifications, CSV, credentials, public routes | 0/TBD | Not started | - |

View File

@@ -2,18 +2,18 @@
gsd_state_version: "1.0"
milestone: v1.0
current_phase: "11.1"
current_phase_name: summercms-documentation-for-humans-and-ai-agents
status: executing
stopped_at: Completed 11.1-06-PLAN.md
last_updated: "2026-09-30T23:52:47.764Z"
last_activity: 2026-09-30
current_phase_name: SummerCMS documentation for humans and AI agents (INSERTED)
status: verifying
stopped_at: Completed 11.1-07-PLAN.md
last_updated: "2026-10-01T06:58:29.387Z"
last_activity: 2026-10-01
last_activity_desc: Phase 11.1 execution started
state_head: 209e44cfd7d44e1f2081f10f0321b38e77e50d46
state_head: ce5dcec7e4e0733b07676b36abb26188d7150501
progress:
total_phases: 19
completed_phases: 9
total_plans: 93
completed_plans: 92
completed_plans: 93
milestone_name: milestone
---
@@ -28,10 +28,10 @@ See: .planning/PROJECT.md (updated 2026-09-16)
## Current Position
Phase: 11.1 (summercms-documentation-for-humans-and-ai-agents) — READY TO EXECUTE
Plan: 6 of 6
Status: Ready to execute
Last activity: 2026-09-30 — Phase 11.1 execution started
Phase: 11.1 (SummerCMS documentation for humans and AI agents (INSERTED)) — EXECUTING
Plan: 7 of 7
Status: Phase complete — ready for verification
Last activity: 2026-10-01 — Phase 11.1 execution started
Progress: [██████░░░░] 60%
@@ -147,6 +147,7 @@ Progress: [██████░░░░] 60%
| Phase 11.1 P04 | 47min | 3 tasks | 68 files |
| Phase 11.1 P05 | 18min | 3 tasks | 37 files |
| Phase 11.1 P06 | 29min | 3 tasks | 168 files |
| Phase 11.1 P07 | 33 min | 5 tasks | 64 files |
## Accumulated Context
@@ -409,6 +410,10 @@ Recent decisions affecting current work:
- [Phase 11.1]: 11.1-06: violation cases are overlays on testdata/clean with a want.txt naming the one problem each plant must produce
- [Phase 11.1]: 11.1-06: check-phase11.1.sh --named requires every named test to PASS; module TestDocs* and output Examples are derived from source
- [Phase 11.1]: 11.1-06: CRLF and BOM docs pages stay refused, with a message naming the encoding
- [Phase 11.1]: A src= fence that is not a top-level block of a docs page is refused and docs:sync does not rewrite it.
- [Phase 11.1]: Module README src= fences are refused and never captioned; Go fences without src= in a README stay legal.
- [Phase 11.1]: The identifier fallback runs go doc -c, so a span must match the declaration's case.
- [Phase 11.1]: Shell command words follow cobra stripFlags and include env prefixes, go run ./cmd/summer and bin/{app}.
### Pending Todos
@@ -439,6 +444,6 @@ Items acknowledged and carried forward from previous milestone close:
## Session Continuity
Last session: 2026-09-30T22:17:57.872Z
Stopped at: Completed 11.1-06-PLAN.md
Last session: 2026-10-01T06:53:41.688Z
Stopped at: Completed 11.1-07-PLAN.md
Resume file: None

View File

@@ -0,0 +1,209 @@
---
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`.