29 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, estimate, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | estimate | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260928-lf2 | 01 | execute | 1 |
|
true |
|
|
|
This implements the user-approved design at /home/jin/.claude/plans/in-phase-10-2-we-enchanted-candy.md faithfully (template, rules, root README outline, CLAUDE.md rule, commit split, verification). That design is locked: do not add, drop or reorder template sections, and do not skip any verification check.
Purpose: framework consumers (and agents) get accurate per-module docs; the framework repo stops describing one consuming application, matching the two-repository boundary. Output: 18 rewritten module READMEs, a rewritten root README, a new CLAUDE.md Documentation section, three docs commits. No Go code changes.
<execution_context>
@/.claude/gsd-core/workflows/execute-plan.md
@/.claude/gsd-core/templates/summary.md
</execution_context>
Repo root (all commands run from here): /media/nvme/dev/golem15/summercms.io/summercms/summercms.go. Module path: git.golem15.com/golem15/summercms. The Bash tool runs bash even though the login shell is fish.
Module README template (locked, from the approved design)
# <name>
<One-sentence summary of what the package does.>
`import "git.golem15.com/golem15/summercms/modules/<name>"`
## Overview
2–4 sentences: the responsibility, where it sits in the framework, and its WinterCMS counterpart if one exists.
## Features
Bullets built from the real exported API.
## Usage
A short, correct Go snippet using real exported identifiers, checked against the source.
## API reference
A table of the main exported types and functions with one-line descriptions. It stays selective: no dump of every symbol.
## Configuration (only if the module reads compass keys / env vars)
## CLI commands (only if it registers cobra commands, e.g. lagoon, cabana, surf route:list)
## Dependencies
Other summercms modules and third-party libraries it imports, taken from its import list.
## Testing
How to run its tests (`go test ./modules/<name>/...`), plus any build tag or testcontainers requirement (lagoon postgres tests, postcard mailpit).
The parenthetical notes after "Configuration" and "CLI commands" are template guidance, not heading text: the headings are exactly ## Configuration and ## CLI commands.
Rules (locked)
- Never name a consuming application (the names in the forbidden-name grep below). Say "the application" or "host application", and use neutral example names (
blog,acme). - Every identifier in a README must exist in the package. Verify with
go doc ./modules/<name>andgrep. - Leave out any optional section that does not apply rather than padding it.
Facts gathered at plan time (verify, do not trust blindly)
- Go packages: the 18 modules plus one subpackage,
modules/lagoon/attach(importgit.golem15.com/golem15/summercms/modules/lagoon/attach).phrasebook/lang,phrasebook/backend/lang,boardwalk/distandpostcard/assetsare embedded asset trees, not packages. - No module uses
//go:buildtags. testdata/exists incabanaandtide.- testcontainers-go is used by tests in
bouncer,cabana,lagoon(includinglagoon/attach) andpostcard(Mailpit). Those tests need Docker and skip undergo test -short. - Non-test files that register CLI commands:
modules/cabana/commands.go,modules/lagoon/commands.go,modules/lagoon/keygen.go,modules/surf/serve.go,modules/surf/routelist_command.go.modules/pact/capabilities.godeclares the command capability contract only. - Likely Configuration candidates (confirm by grepping non-test sources for config key reads and
os.Getenv): cabana (admin.* / backend.), compass (the loader itself and theSUMMER_env overlay), fetchguard (http.fetch.), lagoon (database.dsn, app.key, app.previous_keys), phrasebook (app.locale, app.fallback_locale), postcard (mail.*), surf. summerCLI commands (cmd/summer): build, dev, plugin:add, make:plugin, make:model, make:migration, make:command, make:job, make:admin-controller, parity:proxy, parity:record, parity:replay. Built app binaries get migrate, migrate:rollback, migrate:status, key:generate, serve, route:list, admin:create, admin:reset-password from the modules.examples/hellobuilds binaryhellointoexamples/hello/bin/(gitignored); its config has no database section.examples/hello/go.modshows the localreplace git.golem15.com/golem15/summercms => ../..pattern.admin/package.jsonscripts: dev, build, typecheck, test, gen:api..planning/notes/holds six notes; two have the forbidden application token in their filename, so the root README must link the notes directory and the four app-neutral notes (why-go-not-scala.md, apparatus-dissolved-into-framework.md, plugin-layout-winter-directories.md, oauth2-wristband-direct-port.md) only.scripts/check-phase10.2.sh --readmesrequires all 18 module READMEs to exist;--statusrefuses the old pre-alpha status line in README.md.
Module batches (source size balanced; for Task 1 fan-out)
- Batch A: cabana, backpack, towel, wire, festival, party
- Batch B: tide, lagoon (with lagoon/attach), bonfire, boardwalk, compass, pact
- Batch C: wristband, surf, bouncer, phrasebook, postcard, fetchguard
Then write modules/<name>/README.md following the template exactly: H1 is the bare module name; one summary sentence; the backticked import line; ## Overview (2–4 sentences, including the WinterCMS counterpart when one exists, e.g. compass vs Winter config, lagoon vs Winter models/migrations, cabana vs Winter backend controllers/behaviors, bonfire vs artisan console, party vs Winter PluginBase/PluginManager); ## Features bullets from the exported API; ## Usage with one short Go snippet using real exported identifiers whose argument lists match the go doc signatures; ## API reference as a selective Markdown table (identifier, one-line description); ## Configuration only when the module reads config keys or env vars (list each key, its default and what it controls, all confirmed in source); ## CLI commands only for modules that register commands (cabana, lagoon, surf: list each command name and its flags from the source); ## Dependencies from the import list (write "Standard library only." if there are none beyond stdlib); ## Testing with go test ./modules/<name>/..., and for bouncer, cabana, lagoon and postcard state that the integration tests start containers through testcontainers-go, need Docker, and are skipped by go test -short ./modules/<name>/.... Document lagoon/attach inside the lagoon README (its own import line and table rows in API reference), not as a separate README.
Writing conventions that make the automated checks meaningful: outside code blocks, write Go identifiers package-qualified (surf.BuildRouter, backpack.App, bonfire.Flag.Repeatable, attach.Publish) so the resolver can check them; only backtick a capitalised word when it is a Go identifier of that module (put HTTP methods, header values and prose words in plain text); link other modules with relative paths such as ../surf/README.md. Per the locked rules: no consuming-application names anywhere, neutral example names (blog, acme) in snippets and config examples, no secret-looking example values (use placeholders like change-me or <secret>), and no padding of sections that do not apply.
Pilot then fan out: write modules/wire/README.md first and run all four verify checks below against it; adjust the approach until it passes. Then, when a subagent spawner is available, run the three batches from the context block in parallel with 3 general-purpose agents (6 modules each); give each agent this task's research steps, the template, the rules, the writing conventions and the finished wire README as the reference example, and tell them to write files only (no git). When no spawner is available, process the batches sequentially yourself. Afterwards review all 18 for consistency: same heading set and order, same table column headers (Identifier | Description), same Testing phrasing for the Docker-backed modules, summary sentences that each fit on one line.
Commit only the 18 README paths, staged by explicit path (the working tree holds unrelated planning changes, so never stage everything): one commit with subject docs(modules): rewrite module READMEs, or one commit per batch with that same subject, as the approved design allows. No co-author trailer in any commit message (project and user rule).
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && ! grep -riE 'fonoteka|płytarium|plytarium|plytadmin' modules//README.md && echo NAMES OK
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && fail=0; for d in modules//; do n=$(basename "$d"); r="$d/README.md"; head -1 "$r" | grep -qx "# $n" || { echo "TITLE $n"; fail=1; }; grep -qF "`import "git.golem15.com/golem15/summercms/modules/$n"`" "$r" || { echo "IMPORT $n"; fail=1; }; grep -E '^## ' "$r" | sed 's/^## //' | paste -sd';' | grep -qxE 'Overview;Features;Usage;API reference(;Configuration)?(;CLI commands)?;Dependencies;Testing' || { echo "SECTIONS $n"; fail=1; }; grep -qF "go test ./modules/$n/..." "$r" || { echo "TESTCMD $n"; fail=1; }; done; for n in cabana lagoon surf; do grep -qx '## CLI commands' "modules/$n/README.md" || { echo "CLI $n"; fail=1; }; done; for n in bouncer cabana lagoon postcard; do grep -qF -- '-short' "modules/$n/README.md" || { echo "SHORT $n"; fail=1; }; done; [ $fail = 0 ] && echo STRUCTURE OK; exit $fail
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && fail=0; mods="$(ls modules | paste -sd'|')|attach"; for r in modules//README.md; do n=$(basename "$(dirname "$r")"); for t in $(grep -oE "\b($mods).[A-Z][A-Za-z0-9_](.[A-Z][A-Za-z0-9_])?" "$r" | sort -u); do p=${t%%.}; s=${t#*.}; d=./modules/$p; [ "$p" = attach ] && d=./modules/lagoon/attach; go doc "$d" "$s" >/dev/null 2>&1 || { echo "UNRESOLVED $r: $t"; fail=1; }; done; for t in $(grep -oE '[A-Z][a-z][A-Za-z0-9]*(\.[A-Z][A-Za-z0-9]*)?' "$r" | tr -d '' | sort -u); do go doc "./modules/$n" "$t" >/dev/null 2>&1 || { echo "UNRESOLVED $r: bare $t"; fail=1; }; done; done; [ $fail = 0 ] && echo IDENTS OK; exit $fail</automated> <automated>cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && fail=0; for r in modules/*/README.md; do d=$(dirname "$r"); for l in $(grep -oE '\]\([^)#[:space:]]+' "$r" | sed 's/^](//' | grep -vE '^(https?|mailto):'); do [ -e "$d/$l" ] || { echo "BROKEN $r -> $l"; fail=1; }; done; done; [ $fail = 0 ] && echo LINKS OK; exit $fail</automated> <automated>cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && bash scripts/check-phase10.2.sh --readmes && echo READMES EXIST</automated> </verify> <done>All 18 module READMEs follow the locked template and section order, name no consuming application, resolve every checked identifier through go doc, have no broken relative links, document CLI commands for cabana/lagoon/surf and the Docker/-short behaviour for bouncer/cabana/lagoon/postcard, and are committed as docs(modules): rewrite module READMEs` (one commit or one per batch) with no co-author trailer.
Before writing the quick start, confirm every command: run go run ./cmd/summer --help, then run summer build inside examples/hello (an installed binary, or go run ../../cmd/summer build from that directory) and ./bin/hello --help, and quote only command names that appear in that output. Afterwards git status --porcelain examples/ must be empty (bin/ is gitignored); if generation touched a tracked file, restore it with git checkout -- examples/hello. If serve or migrate cannot run without a database, say so in the README and show the env var rather than inventing a flag.
Per the approved design, drop the application-specific run steps, the cutover status section, the admin path of the consuming application and any sibling application repository link: the root README must not name a consuming application at all (same forbidden-name grep as Task 1). Do not edit any other repository; if that material is missing from the application repo's own README, record it as a follow-up in the SUMMARY instead. Keep the pre-alpha status line refused by scripts/check-phase10.2.sh --status out of the file.
Commit only README.md, staged by explicit path, with subject docs: generic root README and no co-author trailer.
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && ! grep -iE 'fonoteka|płytarium|plytarium|plytadmin' README.md && echo NAMES OK
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && fail=0; for n in $(ls modules); do grep -qF "](modules/$n/README.md)" README.md || { echo "TABLE $n"; fail=1; }; done; for s in 'git.golem15.com/golem15/summercms' 'replace git.golem15.com/golem15/summercms' 'examples/hello' 'summer build' 'go vet ./...' 'go test ./...' 'go test -short' 'npm --prefix admin' '.planning/notes' 'Go 1.27' 'PostgreSQL'; do grep -qF -- "$s" README.md || { echo "MISSING $s"; fail=1; }; done; for dir in admin cmd examples internal modules scripts; do grep -qF "$dir/" README.md || { echo "LAYOUT $dir"; fail=1; }; done; [ $fail = 0 ] && echo ROOT OK; exit $fail
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && fail=0; for r in README.md modules/*/README.md; do d=$(dirname "$r"); for l in $(grep -oE ']([^)#[:space:]]+' "$r" | sed 's/^](//' | grep -vE '^(https?|mailto):'); do [ -e "$d/$l" ] || { echo "BROKEN $r -> $l"; fail=1; }; done; done; [ $fail = 0 ] && echo LINKS OK; exit $fail
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && bash scripts/check-phase10.2.sh --status && st=$(git status --porcelain examples/) && test -z "$st" && echo STATUS OK
README.md is a generic framework README covering all nine outline items, links all 18 module READMEs from the modules table, names no consuming application, has no broken relative links, passes check-phase10.2.sh --status, leaves examples/ clean, and is committed as docs: generic root README with no co-author trailer.
The section states the approved rule as short bullets: (1) any change to a package under modules/ that touches its exported API, config keys, CLI commands or dependencies must update that module's README.md in the same change (the same commit or PR); (2) a new module ships with a README.md that follows the standard structure (H1 name, summary sentence, import line, Overview, Features, Usage, API reference, optional Configuration and CLI commands, Dependencies, Testing) and gets a row in the root README.md modules table; (3) framework READMEs must never name a consuming application, and examples use neutral names such as blog or acme; (4) identifiers named in a README must exist in the package, checked with go doc ./modules/<name> <Identifier>. Phrase rule (3) generically, without naming any application.
Leave every other part of CLAUDE.md byte-identical. Commit only CLAUDE.md, staged by explicit path, with subject docs(claude): require module README updates and no co-author trailer.
Then run the plan-wide sanity checks: go vet ./... and go test ./... from the repo root (docs-only change, so they must stay green; the Postgres/Mailpit tests need Docker), and confirm no .go file changed and none of the three new commits carries a co-author trailer.
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && doc=$(grep -n '^## Documentation$' CLAUDE.md | cut -d: -f1) && commit=$(grep -n '^## Commit rules$' CLAUDE.md | cut -d: -f1) && marker=$(grep -n '^<!-- GSD:project-start' CLAUDE.md | cut -d: -f1) && [ "$commit" -lt "$doc" ] && [ "$doc" -lt "$marker" ] && sed -n "${doc},${marker}p" CLAUDE.md | grep -qF 'README.md' && sed -n "${doc},${marker}p" CLAUDE.md | grep -qF 'modules/' && sed -n "${doc},${marker}p" CLAUDE.md | grep -qi 'modules table' && ! sed -n "${doc},${marker}p" CLAUDE.md | grep -qiE 'fonoteka|płytarium|plytarium' && ns=$(git diff cc584e906e --numstat -- CLAUDE.md) && [ "$(printf '%s' "$ns" | cut -f2)" = 0 ] && echo CLAUDE OK
cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && go vet ./... && go test ./... && st=$(git status --porcelain -- '.go') && test -z "$st" && gd=$(git diff --name-only cc584e906e HEAD -- '.go') && test -z "$gd" && msgs=$(git log cc584e906e2a67f7e04b979ac632d6e24c21011d..HEAD --format=%B) && ! printf '%s' "$msgs" | grep -qi 'co-authored-by' && echo SANITY OK
CLAUDE.md has a ## Documentation section between ## Commit rules and the first GSD marker stating the four-part rule without naming any application, the commit only adds lines, go vet ./... and go test ./... pass, no Go file changed, and the commit docs(claude): require module README updates has no co-author trailer.
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| repository docs to public readers | READMEs are published with the framework and read by consumers and agents |
STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|---|---|---|---|---|---|
| T-lf2-01 | Information disclosure | README config and usage examples | medium | mitigate | Task 1 and Task 2 actions require placeholder values (change-me, <secret>) for keys, DSNs and JWT secrets; no real credentials or hostnames of a consuming application; the forbidden-name grep keeps application details out |
| T-lf2-02 | Tampering (misleading docs) | module README identifiers and links | low | mitigate | go doc resolution check and relative-link check in Task 1/Task 2 verify fail on invented or stale identifiers and dead links |
| T-lf2-03 | Repudiation (rule drift) | CLAUDE.md Documentation rule | low | mitigate | Section placed outside GSD-managed marker blocks so regeneration cannot drop it; verify asserts placement |
| T-lf2-SC | Tampering | npm/pip/cargo installs | high | accept | No package installs in this plan; only existing tooling (go doc, go list, go vet, go test) runs |
| </threat_model> |
cc584e906e HEAD -- '*.go'` lists nothing.
<success_criteria>
- 18 module READMEs match the locked template, section order and rules; each documents the real exported API, dependencies and test requirements.
- Root README is a generic framework README with all nine outline items and an 18-row modules table.
- CLAUDE.md carries the Documentation rule outside GSD-managed blocks.
- All automated checks in the three tasks pass; three (or up to five, if the module commit is split per batch) docs-only commits with the approved subjects and no co-author trailer. </success_criteria>