From 9033d81721d1a0fa77fd9ce234119948aa3d0996 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Wed, 30 Sep 2026 19:39:50 +0200 Subject: [PATCH] docs(11.1): record plan-count checkpoint decisions, DOCS requirements and pattern map --- .planning/REQUIREMENTS.md | 25 +++- .planning/ROADMAP.md | 2 +- .../11.1-CONTEXT.md | 6 + .../11.1-PATTERNS.md | 135 ++++++++++++++++++ 4 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 .planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-PATTERNS.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 71df1e5..45b1c71 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -123,6 +123,17 @@ Requirements for v1 (the Płytarium port). Each maps to roadmap phases. "User" b - [x] **QA-04**: The first vertical slice (GET /_fonoteka/api/v1/genres) passes the parity diff end to end before further kernel abstraction - [ ] **QA-05**: Cutover: the parity harness is green on all 154 routes and vue-fonoteka-app and fonoteka-mcp run unchanged against the Go backend +### Documentation (DOCS) + +- [ ] **DOCS-01**: `docs/` holds Markdown pages with strict YAML frontmatter (title, description, section, order), grouped into the Winter-mirroring sections, and every framework module under `modules/` is reachable from the sidebar through an API reference page ingested from its README +- [ ] **DOCS-02**: `summer docs:build` writes a self-contained static site (sidebar, on-page TOC, prev/next, edit-this-page link, client-side search, light/dark/system theme) and `summer docs:serve` previews it on loopback; no Node toolchain, and the only new dependency is `alecthomas/chroma/v2` for syntax highlighting (approved at the 11.1 plan-count checkpoint) +- [ ] **DOCS-03**: The build emits `llms.txt`, `llms-full.txt` and a clean `.md` beside every `.html` page, and a test asserts all three match the page tree +- [ ] **DOCS-04**: Every Go fence in the docs references compiled source by `src=`; a test fails on a missing or drifted snippet, and referenced Examples carry `// Output:` and run under `go test ./...` +- [ ] **DOCS-05**: `go test ./...` runs checkers that fail on stale identifiers (docs pages and module READMEs), broken internal links and anchors, unknown `summer`/runtime CLI command names and forbidden consuming-application names +- [ ] **DOCS-06**: A "Coming from WinterCMS" page maps Winter concepts to SummerCMS equivalents, and every SummerCMS identifier on it is checker-verified +- [ ] **DOCS-07**: An `acme/blog` porting walkthrough covers models, migrations, routes, an admin controller and a console command; its code is a real in-root package under `docs/examples/blog`, verified by DOCS-04 +- [ ] **DOCS-08**: CLAUDE.md's Documentation section records that API, config or CLI changes update both the module README and the affected docs pages, and names the automated checkers + ## v2 Requirements Deferred to a later milestone. Tracked but not in the current roadmap. @@ -232,12 +243,20 @@ Which phases cover which requirements. Updated during roadmap creation. | QA-03 | Phase 2 | Complete | | QA-04 | Phase 3 | Complete | | QA-05 | Phase 15 | Pending | +| DOCS-01 | Phase 11.1 | Pending | +| DOCS-02 | Phase 11.1 | Pending | +| DOCS-03 | Phase 11.1 | Pending | +| DOCS-04 | Phase 11.1 | Pending | +| DOCS-05 | Phase 11.1 | Pending | +| DOCS-06 | Phase 11.1 | Pending | +| DOCS-07 | Phase 11.1 | Pending | +| DOCS-08 | Phase 11.1 | Pending | **Coverage:** -- v1 requirements: 77 total -- Mapped to phases: 77 +- v1 requirements: 85 total +- Mapped to phases: 85 - Unmapped: 0 ✓ --- *Requirements defined: 2026-09-16* -*Last updated: 2026-09-28 after adding ADMIN-07 (Phase 10.1 runtime admin extension point); previously 2026-09-16 after roadmap revision (15 phases, split former Phase 13 into Phase 11 jobs/realtime/search infrastructure and Phase 14 domain jobs/integrations, reordered before the API phases; 100% coverage)* +*Last updated: 2026-09-30 after adding DOCS-01..08 (Phase 11.1 documentation); previously 2026-09-28 after adding ADMIN-07 (Phase 10.1 runtime admin extension point); previously 2026-09-16 after roadmap revision (15 phases, split former Phase 13 into Phase 11 jobs/realtime/search infrastructure and Phase 14 domain jobs/integrations, reordered before the API phases; 100% coverage)* diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 3479c1d..02b7fd8 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -530,7 +530,7 @@ Plans: ### Phase 11.1: SummerCMS documentation for humans and AI agents (INSERTED) **Goal:** SummerCMS has a WinterCMS-style documentation set that serves both humans and AI agents. The Markdown source lives in `summercms.go/docs/` and a `summer` CLI command builds it into a static site with sidebar navigation, search, `llms.txt`/`llms-full.txt` and a raw `.md` per page. Every code example compiles and is tested, and a "Coming from WinterCMS" map plus an `acme/blog` porting walkthrough cover the migration path. It documents the framework as it stands after Phase 11 and never names a consuming application. -**Requirements**: TBD +**Requirements**: DOCS-01, DOCS-02, DOCS-03, DOCS-04, DOCS-05, DOCS-06, DOCS-07, DOCS-08 **Depends on:** Phase 11 **Repos:** summercms.go **Success Criteria** (what must be TRUE): diff --git a/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-CONTEXT.md b/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-CONTEXT.md index 62095ca..4c0cf23 100644 --- a/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-CONTEXT.md +++ b/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-CONTEXT.md @@ -51,6 +51,12 @@ Not in this phase: ### Claude's Discretion - Exact page list within each section, URL scheme, theme styling (reuse the admin SPA's design tokens if convenient), search index format, and the generator's package location (for example `modules/` or `internal/docs`, following the existing naming convention). +### Plan-count checkpoint (2026-09-30) +- **D-14:** Six plans, per RESEARCH.md Q8: tracer (generator core to every output), site UX and accuracy gates, framework content A, framework content B, the `acme/blog` walkthrough, and unit tests last. +- **D-15:** Syntax highlighting uses `github.com/alecthomas/chroma/v2`, approved by the user at this checkpoint (overrides the research's stdlib-only recommendation). It is called from a small custom goldmark `NodeRenderer`; `yuin/goldmark-highlighting` stays rejected. This is the only new dependency; `go.mod` gains chroma/v2 and its transitive `dlclark/regexp2`, and the phase gate asserts no other module is added. +- **D-16:** The walkthrough code is an in-root package under `docs/examples/blog`, covered by root `go test ./...`, plus a scaffold-layout test. +- **D-17:** Raw pages sit beside their HTML pages (`/x/page.html` and `/x/page.md`). Config-key checking is deferred and noted in CLAUDE.md. The wristband default that names the consuming application is logged as a follow-up todo; its API does not change in this phase. + diff --git a/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-PATTERNS.md b/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-PATTERNS.md new file mode 100644 index 0000000..46ab8c6 --- /dev/null +++ b/.planning/phases/11.1-summercms-documentation-for-humans-and-ai-agents/11.1-PATTERNS.md @@ -0,0 +1,135 @@ +# Phase 11.1: SummerCMS documentation for humans and AI agents - Pattern Map + +**Mapped:** 2026-09-30 +**Files analyzed:** 14 file groups +**Analogs found:** 11 / 14 + +All analog paths below are git-tracked in `summercms.go`. There is no `docs/` tree and no `example_test.go` anywhere in `modules/` yet (verified). Phase 11 modules exist: `conga`, `lighthouse`, `flare`, `beachcomber`, `tide`. + +## File Classification + +| New/Modified File | Role | Data Flow | Closest Analog | Match Quality | +|---|---|---|---|---| +| `internal/docsite/*.go` (load, frontmatter, site.yaml, walker, render, emit) | service (generator) | file-I/O, transform | `internal/build/build.go`, `internal/build/manifest.go`, `internal/build/scaffold.go` | role-match | +| `internal/docsite` site.yaml / frontmatter strict decode | utility | transform | `modules/tide/manifest.go:85-104` | exact | +| `internal/docsite/theme/*` (embedded HTML/CSS/JS assets) | config/assets | file-I/O | `internal/build/scaffold.go:20-23` (`//go:embed stubs/*.tmpl`) | role-match | +| `internal/docsite` checkers (identifiers, links, CLI names, forbidden names, src= sync) | test utility | batch | `cmd/summer/main_test.go` (go/parser use, `TestToolCommandNames`) | partial | +| `internal/docsite/*_test.go` | test | file-I/O | `internal/build/build_test.go` (t.TempDir fixtures) | exact | +| `cmd/summer/docs.go` (`docs:build`, `docs:sync`, `docs:serve`) | controller (CLI) | request-response | `cmd/summer/main.go:52-92` | exact | +| `cmd/summer/main.go` (register in `toolCommands()`) | config | - | `cmd/summer/main.go:27-50` | exact | +| `cmd/summer/main_test.go` (extend `TestToolCommandNames`) | test | - | itself, lines 17-54 | exact | +| `modules//example_test.go` (bonfire first, then party, backpack, compass, festival, phrasebook, towel, lagoon, wire, surf, postcard, bouncer, fetchguard, cabana, conga, lighthouse, flare, beachcomber, tide) | test (Example funcs) | - | `modules/bonfire/call_test.go` (fixture shape only) | partial, no Example* exists | +| `docs/examples/blog/**` (plugin, models, YAML, controller, console cmd, lang, tests) | example plugin | CRUD | `examples/hello/plugins/greeter/`, `examples/hello/hello_test.go` | role-match | +| `scripts/check-phase11.1.sh` | gate script | batch | `scripts/check-phase11.sh` + `scripts/check-phase10.2.sh` | exact | +| `.gitignore` (add `/site/`) | config | - | `.gitignore` "# Go" block | exact | +| `CLAUDE.md` Documentation section (D-13 bullet) | docs rule | - | `CLAUDE.md` Documentation section | exact | +| `docs/**/*.md`, `docs/site.yaml` | content | - | `modules/*/README.md` (tone/structure) | no code analog | + +## Pattern Assignments + +### `cmd/summer/docs.go` (CLI, request-response) + +**Analog:** `cmd/summer/main.go` lines 52-92. Commands are plain `bonfire.Command` values returned by a `xxxCommand()` func; flags via `bonfire.Flag`, `Bare: true` for booleans; errors returned, output via `out.Printf`. +```go +func makePluginCommand() bonfire.Command { + return bonfire.Command{ + Name: "make:plugin", + Description: "Scaffold a compiling plugin module from a vendor.plugin id", + Args: []bonfire.Arg{{Name: "id", Description: "Plugin ID in vendor.plugin form", Required: true}}, + Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { + dir, err := os.Getwd() + if err != nil { + return err + } + created, err := build.MakePlugin(ctx, dir, id) + ... + out.Printf("created %s\n", created) + return nil + }, + } +} +``` +Bool flag parsing (for `docs:sync --check` etc.), `cmd/summer/runtime.go:67-87`: +```go +if v, ok := in.Flag("once"); ok { + if once, _ := strconv.ParseBool(v); once { ... } +} +``` +Value flags (`--out`, `--addr`): `in.Flag("out")`; repeatable via `Repeatable: true` + `in.Flags(name)` (`modules/conga/commands.go:33-41`). +Keep logic in `internal/docsite` (like `build.App(ctx, dir, out)`); the command only resolves cwd/flags and delegates. + +**Registration:** append `docsBuildCommand(), docsSyncCommand(), docsServeCommand()` to the slice in `toolCommands()` (`cmd/summer/main.go:27-50`). + +### `cmd/summer/main_test.go` (extend) +Add `"docs:build", "docs:sync", "docs:serve"` to the want list at line 22 and `--out` etc. to `helpWants` (lines 28-37). The CLI-name checker should derive the command set from `toolCommands()` plus each module's `RuntimeCommands` (e.g. `conga.RuntimeCommands`, `modules/lighthouse/centrifugo/commands.go:22`), not a hardcoded list. + +### `internal/docsite` strict YAML (site.yaml, frontmatter) +**Analog:** `modules/tide/manifest.go:85-104` +```go +func ParseManifest(raw []byte) (Manifest, error) { + var m Manifest + dec := yaml.NewDecoder(bytes.NewReader(raw), yaml.DisallowUnknownField()) + if err := dec.Decode(&m); err != nil { + return Manifest{}, fmt.Errorf("tide: parse manifest: %w", err) + } + ... +} +``` +Split `LoadX(path)` (os.ReadFile + wrapped error with path) from `ParseX(raw)`; error prefix `docsite: ...`. Import `github.com/goccy/go-yaml` (already in go.mod). + +### `internal/docsite` theme assets +**Analog:** `internal/build/scaffold.go:20-23` +```go +//go:embed stubs/*.tmpl +var stubFS embed.FS + +var stubTmpl = template.Must(template.ParseFS(stubFS, "stubs/*.tmpl")) +``` +Use `html/template` (not text/template) for pages; `embed.FS` for `theme/*.css|js`, copied verbatim into the output dir. + +### `internal/docsite/*_test.go` +**Analog:** `internal/build/build_test.go` (e.g. `TestParseManifestRejectsDuplicatesAndInvalidPaths` line 29, `dir := t.TempDir()`). Plain stdlib `testing`, `t.Fatalf("x = %v, want ...")`, no testify (repo convention). Smoke test builds the real `docs/` tree into `t.TempDir()`. Failure-path fixtures written into temp dirs. + +### `modules//example_test.go` +No Example analog exists. Convention to establish: `package _test`, functions `ExampleNewRoot`, `ExampleCall`, ... naming real identifiers, each ending in `// Output:`. Use `// docs:start ` / `// docs:end ` markers for `src=path#region`. Reusable fixture shape from `modules/bonfire/call_test.go:11-36` (inline `[]Command{{Name: "acme:echo", ...}}` + `Call(ctx, cmds, name, args, &out)`), rewritten with the `bonfire.` qualifier and `context.Background()` instead of `t.Context()`. Use neutral names (`acme`, `blog`). For DB-bound modules (lagoon, conga, beachcomber, lighthouse), prefer non-DB identifiers or regions in existing `_test.go` packages; do not start Postgres in Examples. + +### `docs/examples/blog/**` +**Analog:** `examples/hello/plugins/greeter/{go.mod,plugin.go,plugin_test.go}`, `examples/hello/plugins/base/{config,lang,views}`, and `examples/hello/hello_test.go` (package main, imports modules `backpack, bonfire, compass, pact, party, phrasebook, postcard, surf, towel`). The plugin layout leaves come from `internal/build/scaffold.go` `pluginLeaves` (`models`, `classes`, `controllers`, `console`, `jobs`, ...), so the scaffold-layout test can compare against that slice. Note: examples/hello uses its own `go.mod` per plugin; decide whether blog is its own module (then `go test ./...` at root will not cover it; the gate must run it explicitly, as check-phase11 does for the app). + +### `scripts/check-phase11.1.sh` +**Analog:** `scripts/check-phase11.sh` (latest) for structure; `scripts/check-phase10.2.sh` for `refuse`/`expect_refusal`. +- Header comment describing the gate, then `set -euo pipefail`, `ROOT="${PHASE11_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"` (11.sh:19-21), `PHASE_DIR=...`. +- `usage()` heredoc listing modes, `exit 2` (11.sh:33-45). +- `refuse() { echo "refuse: $*" >&2; return 1; }` (10.2.sh:25-28). +- `expect_refusal name want ...` : run the check in a scratch copy, fail if it passes, fail if stderr lacks `want` (10.2.sh:105-116). +- `run_self_test`: `bash -n "${BASH_SOURCE[0]}"`, `mktemp -d`, `trap 'rm -rf ...' RETURN`, copy README.md + module READMEs, plant violations (10.2.sh:118-130). +- `run_go`: `(cd "$ROOT" && go vet ./...)` then tests (11.sh:621-627); each mode echoes `phase11.1 passed`. +- Final `case "${1:-}" in --self-test) ...;; --all) ...;; *) usage ;; esac` (11.sh tail). +- README-table check to reuse for `--preconditions`: `grep -qF "| [$m](modules/$m/README.md) |" "$tree/README.md"` (11.sh:~260). +Modes per RESEARCH Q7: `--preconditions --deps --forbidden --docs --claude --self-test --go --all`. Semantic checks stay in Go tests. + +### `.gitignore` +Add `/site/` under the `# Go` block (next to `/dist/`). + +### `CLAUDE.md` +Documentation section, 4 bullets ending with the `go doc ./modules/ ` rule. Add the D-13 bullet and amend the go-doc bullet to name `go test ./internal/docsite/...`. Separate commit from code. + +## Shared Patterns + +- **Errors:** wrap with package prefix and `%w` (`fmt.Errorf("tide: read manifest %s: %w", path, err)`); commands return errors, `main` prints them. +- **Tests:** stdlib `testing` only, `t.TempDir()`, `t.Fatalf` with got/want. +- **Neutral names:** `acme`, `blog`; the forbidden list (`fonoteka|płytarium|plytarium`) as a constant shared by test and gate. +- **Module discovery:** iterate `modules/*/` dirs dynamically (like hygiene loop in check-phase11.sh around line 255-265) so Phase 11 modules are covered with no code changes. + +## No Analog Found + +| File | Role | Reason | +|---|---|---| +| goldmark pipeline / renderer in `internal/docsite` | transform | No Markdown rendering in repo; use RESEARCH.md (goldmark v1.8.6 parser/extension notes) | +| search index + `search.js`, `theme-init.js` | frontend asset | No plain-JS assets; admin uses Vue/Tailwind. Take tokens from `admin/src/styles/main.css:83-125` per UI-SPEC | +| `docs/**/*.md` content, `llms.txt`/`llms-full.txt` formats | content | Follow UI-SPEC and RESEARCH (llmstxt.org, Mintlify block format) | + +## Metadata + +**Analog search scope:** `cmd/summer`, `internal/build`, `modules/{bonfire,conga,lighthouse,tide}`, `examples/hello`, `scripts/check-phase*.sh`, `.gitignore` +**Pattern extraction date:** 2026-09-30