Files
summercms/.planning/phases/10.2-nest-framework-packages-under-modules-and-write-run-docs/10.2-01-PLAN.md
2026-09-28 01:56:53 +02:00

22 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
10.2-nest-framework-packages-under-modules-and-write-run-docs 01 execute 1
modules/**
cmd/summer/**
internal/build/build.go
internal/build/build_test.go
internal/build/stubs/artifacts.tmpl
internal/build/stubs/registry.tmpl
internal/build/stubs/plugin.tmpl
internal/dev/**
examples/hello/**
admin/vite.config.ts
scripts/check-phase2.sh
scripts/check-phase3.sh
scripts/check-phase4.sh
scripts/check-phase9.sh
scripts/check-phase10.sh
scripts/check-admin-dist.sh
scripts/check-admin-openapi.sh
../fonoteka.go/main.go
../fonoteka.go/app/**
../fonoteka.go/parity/**
../fonoteka.go/plugins/**
true
tokens raw_tokens tasks confidence
140000 70000 3 low
truths artifacts key_links prohibitions
D-01/D-02: The 18 beach packages live only under modules/<name>/ with the same package names; none of those 18 names is a directory at the summercms.go repo root.
D-03: admin/, cmd/, examples/, internal/, scripts/, go.mod and README.md stay at repo root; there is still exactly one go.mod (not one Go module per beach package); go.work still uses . and ./examples/hello* only.
D-04/D-05: Every remaining importer in summercms.go, examples/, and ../fonoteka.go (including plugin modules) uses git.golem15.com/golem15/summercms/modules/<name>; replace directives still point at the summercms.go tree.
D-06: Beach names are unchanged; packages are not remapped onto Winter system/backend/cms names.
D-05: go vet ./... and go test ./... are green in summercms.go, and the same pair plus plugin modules is green in ../fonoteka.go.
path provides
modules/festival/ tracer nest of one beach package proving git mv + importer rewrite + go test
path provides
modules/ all 18 beach packages after expansion (backpack boardwalk bonfire bouncer cabana compass festival fetchguard lagoon pact party phrasebook postcard surf tide towel wire wristband)
path provides
scripts/check-admin-openapi.sh swag --dir modules/cabana
path provides
scripts/check-admin-dist.sh drift compare against modules/boardwalk/dist
path provides
admin/vite.config.ts Vite outDir ../modules/boardwalk/dist
path provides
internal/build/stubs/plugin.tmpl generated plugin imports under the modules/ prefix
from to via pattern
modules/backpack/app.go modules/festival backpack's final post-migration location imports festival through git.golem15.com/golem15/summercms/modules/festival modules/festival
from to via pattern
scripts/check-admin-openapi.sh modules/cabana --dir modules/cabana --generalInfo admin_openapi.go --dir modules/cabana
from to via pattern
scripts/check-admin-dist.sh modules/boardwalk/dist diff against the embedded SPA tree after boardwalk moves modules/boardwalk/dist
from to via pattern
admin/vite.config.ts modules/boardwalk/dist build.outDir after the nest ../modules/boardwalk/dist
from to via pattern
../fonoteka.go/go.mod ../summercms.go replace git.golem15.com/golem15/summercms stays; only import paths change replace git.golem15.com/golem15/summercms
Do not rename packages or remap them onto Winter system/backend/cms (D-01, D-06).
Do not add a go.mod under any modules/<name>/ and do not add modules as go.work use entries (D-03).
Do not rewrite historical .planning/phases/** path literals.
Do not change fonoteka.go replace paths that point at the summercms.go tree.
Do not leave any of the 18 beach names as a directory at the summercms.go repo root.
Do not add Go or npm dependencies.

Phase Goal

Nest the 18 beach-named framework libraries under modules/ with rewritten import paths in both repos, then leave a green go test so Phase 11 does not add more packages at the repo root.

Prove the nest on one package, then move the remaining 17 and rewrite every importer plus the path-literal scripts so both repositories compile and test green.

Purpose: D-01 through D-06. Root ls must show modules/, cmd/, admin/, examples/, internal/, scripts/ instead of eighteen beach directories beside go.mod, and this must land before Phase 11.

Output: modules/<name>/ for all 18 packages, import prefix git.golem15.com/golem15/summercms/modules/<name>, retargeted phase/admin scripts, updated internal/build stubs, green go vet/go test in summercms.go and ../fonoteka.go.

Repos: summercms.go and ../fonoteka.go. Planning docs stay in summercms.go. Commit each repo separately; planning docs and code in separate commits; never add co-author tags.

<execution_context> @/.claude/gsd-core/workflows/execute-plan.md @/.claude/gsd-core/templates/summary.md </execution_context>

@CLAUDE.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/todos/pending/nest-framework-packages-under-modules.md @.planning/todos/pending/per-module-readmes-after-nest.md @.planning/todos/pending/rewrite-summercms-readme.md @README.md @scripts/check-phase10.sh @scripts/check-admin-dist.sh @scripts/check-admin-openapi.sh @internal/build/build.go @internal/build/stubs/plugin.tmpl @admin/vite.config.ts @../fonoteka.go/go.mod Single Go module at repo-root go.mod (D-03). After a git mv, the import path is the module path plus the new directory. Package clause names stay the beach names (D-01). fonoteka.go replace directives already point at the summercms.go tree and must keep that path. examples/hello/go.mod replace `git.golem15.com/golem15/summercms => ../..` stays valid. go.work uses `.` and `./examples/hello*` only. boardwalk embed is `all:dist` relative to the boardwalk package, so the committed dist tree moves with the package to modules/boardwalk/dist.

Artifacts this phase produces

  • Directory modules/ holding the 18 beach packages (same package names)
  • Import path prefix git.golem15.com/golem15/summercms/modules/<name>
  • Tracer package modules/festival (discretion: festival, not compass — see Task 1)
  • Retargeted literals: scripts/check-admin-openapi.sh --dir modules/cabana; scripts/check-admin-dist.sh and admin/vite.config.ts → modules/boardwalk/dist; scripts/check-phase2.sh and scripts/check-phase3.sh → modules/tide/testdata/one-route-spec.yaml; scripts/check-phase4.sh → ./modules/phrasebook ./modules/postcard; scripts/check-phase9.sh → ./modules/bouncer ./modules/cabana ./modules/lagoon and Package git.golem15.com/golem15/summercms/modules/lagoon; scripts/check-phase10.sh HYGIENE_DIRS / ./modules/cabana / ./modules/bouncer / ./modules/surf / ./modules/boardwalk / Package git.golem15.com/golem15/summercms/modules/cabana
  • Updated internal/build/build.go string literals and internal/build/stubs/*.tmpl
  • Tests that must stay green: TestEventBusesAreAppScoped, TestFireRunsAllListenersAndJoinsErrors, TestGetApiArrayEventMerge, then full go test ./... in both repos
Task 1: Nest festival end to end — git mv, rewrite its importers, test the moved package Import-path rewrite touches every importer of the moved package; the module is v0.0.0 and unpublished, so this is costly, not one-way, and needs no checkpoint. modules/festival/**, backpack/app.go, examples/hello/plugins/greeter/plugin.go, ../fonoteka.go/plugins/golem15/user/classes/events_test.go .planning/todos/pending/nest-framework-packages-under-modules.md; festival/bus.go; festival/bus_test.go; backpack/app.go; backpack/app_test.go; examples/hello/plugins/greeter/plugin.go; ../fonoteka.go/plugins/golem15/user/classes/events_test.go; go.mod; examples/hello/go.mod; ../fonoteka.go/go.mod Discretion: do not use compass as the tracer. Grep on 2026-09-28 showed compass imported from about 32 files in this repo plus about 10 in ../fonoteka.go. festival has exactly three importers and no framework imports of its own, so it is the thinnest end-to-end slice (D-01, D-02, D-04).

Re-verify dependents before the move: search both repos and examples/ for importers of package festival. Expected three files only: backpack/app.go, examples/hello/plugins/greeter/plugin.go, ../fonoteka.go/plugins/golem15/user/classes/events_test.go. If grep finds more, rewrite those too; do not stop at the expected three.

Create modules/ if needed. git mv the festival directory to modules/festival/. Do not rename the Go package clause (D-01). Do not add a go.mod under modules/festival (D-03).

Rewrite only festival importers to git.golem15.com/golem15/summercms/modules/festival (D-04). Leave every other beach import on the root-form path. Do not touch ../fonoteka.go replace directives. Do not rewrite .planning/ docs.

Do not expand to the other 17 packages in this task. test -d modules/festival && test ! -d festival && go test ./modules/festival -count=1 && go test ./backpack -run '^TestEventBusesAreAppScoped$' -count=1 && go test -run '^$' ./examples/hello/... ./examples/hello/plugins/base/... ./examples/hello/plugins/greeter/... ./examples/hello/plugins/optional/... && (cd ../fonoteka.go && go test ./plugins/golem15/user -run '^TestGetApiArrayEventMerge$' -count=1) <fails_when>non-zero exit; festival still exists at repo root; modules/festival missing; a named-test command shows FAIL or lacks its requested test; the compile-only examples command fails to build any workspace module</fails_when> <acceptance_criteria> - test -d modules/festival &amp;&amp; test ! -d festival succeeds. - go test ./modules/festival -count=1 prints PASS including TestFireRunsAllListenersAndJoinsErrors. - go test -run '^$' ./examples/hello/... ./examples/hello/plugins/base/... ./examples/hello/plugins/greeter/... ./examples/hello/plugins/optional/... exits 0, compiling the greeter importer in its nested module context without depending on unrelated example runtime tests. - grep -F 'git.golem15.com/golem15/summercms/modules/festival' backpack/app.go examples/hello/plugins/greeter/plugin.go ../fonoteka.go/plugins/golem15/user/classes/events_test.go prints a hit in each of those three files. - A search of tracked *.go for a festival import that is not under /modules/ prints no production importer (the three files above use the modules/ form). </acceptance_criteria> festival lives at modules/festival, its three importers compile against the new path in the framework, examples workspace, and fonoteka contexts, and the moved package plus named importer tests pass.

Task 2: Nest the remaining 17 packages and rewrite every leftover importer and path literal The remaining import-path rewrite touches ~220 files across both repos; costly, not one-way, no checkpoint. modules/**, cmd/summer/**, internal/build/build.go, internal/build/build_test.go, internal/build/stubs/artifacts.tmpl, internal/build/stubs/registry.tmpl, internal/build/stubs/plugin.tmpl, internal/dev/**, examples/hello/**, admin/vite.config.ts, scripts/check-phase2.sh, scripts/check-phase3.sh, scripts/check-phase4.sh, scripts/check-phase9.sh, scripts/check-phase10.sh, scripts/check-admin-dist.sh, scripts/check-admin-openapi.sh, ../fonoteka.go/main.go, ../fonoteka.go/app/**, ../fonoteka.go/parity/**, ../fonoteka.go/plugins/** .planning/todos/pending/nest-framework-packages-under-modules.md; internal/build/build.go; internal/build/stubs/plugin.tmpl; internal/build/stubs/registry.tmpl; internal/build/stubs/artifacts.tmpl; cmd/summer/main.go; cmd/summer/runtime.go; cmd/summer/parity.go; admin/vite.config.ts; scripts/check-admin-openapi.sh; scripts/check-admin-dist.sh; scripts/check-phase10.sh; scripts/check-phase9.sh; scripts/check-phase4.sh; scripts/check-phase3.sh; scripts/check-phase2.sh; examples/hello/go.mod; ../fonoteka.go/go.mod; ../fonoteka.go/plugins/golem15/fonoteka/go.mod; ../fonoteka.go/plugins/golem15/user/go.mod Per D-02, git mv each remaining root beach directory into modules/<name>/: backpack, boardwalk (including dist), bonfire, bouncer, cabana, compass, fetchguard, lagoon, pact, party, phrasebook, postcard, surf, tide, towel, wire, wristband. Keep package clause names (D-01). Single root go.mod only (D-03). Do not add modules as go.work use entries.

Per D-04/D-05, rewrite every remaining importer in this repo (~100 files), examples/, and ../fonoteka.go (~124 files, including plugins/golem15/fonoteka and plugins/golem15/user) so the import is git.golem15.com/golem15/summercms/modules/<name>. Cover cmd/summer/, internal/build/build.go string literals, internal/build/build_test.go, internal/build/stubs/plugin.tmpl, registry.tmpl and artifacts.tmpl, and internal/dev/ if they name a beach import. Leave replace directives pointing at the summercms.go tree. Do not rewrite historical .planning/phases/** files.

Retarget path literals so later gates do not go red or pass vacuously on missing directories (D-05):

  • scripts/check-admin-openapi.sh: --dir modules/cabana (keep --generalInfo admin_openapi.go)
  • scripts/check-admin-dist.sh: compare and message against modules/boardwalk/dist
  • admin/vite.config.ts: build.outDir '../modules/boardwalk/dist'
  • scripts/check-phase2.sh and scripts/check-phase3.sh: --spec modules/tide/testdata/one-route-spec.yaml
  • scripts/check-phase4.sh: go test -race paths ./modules/phrasebook ./modules/postcard
  • scripts/check-phase9.sh: ./modules/bouncer ./modules/cabana ./modules/lagoon and the self-test Package string git.golem15.com/golem15/summercms/modules/lagoon
  • scripts/check-phase10.sh: HYGIENE_DIRS boardwalk/cabana/phrasebook become modules/boardwalk modules/cabana modules/phrasebook; phase10_tests/phase10_go package dirs ./modules/cabana ./modules/bouncer ./modules/surf ./modules/boardwalk; hygiene greps of boardwalk/dist become modules/boardwalk/dist; self-test Package string git.golem15.com/golem15/summercms/modules/cabana

Do not remap names onto Winter system/backend/cms (D-06). Do not rebuild admin dist (files move with boardwalk). Do not add dependencies. test -d modules/cabana && test ! -d cabana && test -d modules/boardwalk/dist && grep -F -- '--dir modules/cabana' scripts/check-admin-openapi.sh && grep -F 'modules/boardwalk/dist' scripts/check-admin-dist.sh admin/vite.config.ts && grep -F 'modules/tide/testdata/one-route-spec.yaml' scripts/check-phase2.sh scripts/check-phase3.sh && grep -F './modules/phrasebook' scripts/check-phase4.sh && grep -F './modules/lagoon' scripts/check-phase9.sh && grep -F './modules/cabana' scripts/check-phase10.sh && grep -F '../modules/boardwalk/dist' admin/vite.config.ts <fails_when>non-zero exit; any of the 18 beach names still a directory at repo root; any listed grep prints no matching line</fails_when> <acceptance_criteria> - ls at repo root lists modules/, cmd/, admin/, examples/, internal/, scripts/ and does not list any of the 18 beach names as directories. - git ls-files -- '*.go' '*.tmpl' '*.sh' filtered to this repo plus ../fonoteka.go, excluding .planning/, contains no import of git.golem15.com/golem15/summercms/&lt;beach&gt; that lacks /modules/. - test -f go.mod &amp;&amp; test ! -f modules/cabana/go.mod &amp;&amp; test ! -f modules/festival/go.mod succeeds. - grep -n 'use (' -A20 go.work still lists only . and ./examples/hello* entries. - grep -F 'replace git.golem15.com/golem15/summercms => ../summercms.go' ../fonoteka.go/go.mod prints 1. </acceptance_criteria> All 18 packages live under modules/, every importer and listed script/stub/vite outDir uses the nested path, and root ls no longer shows beach directories.

Task 3: go vet and go test both repositories including fonoteka plugin modules modules/**, ../fonoteka.go/plugins/** .planning/todos/pending/nest-framework-packages-under-modules.md; go.mod; ../fonoteka.go/go.mod; ../fonoteka.go/plugins/golem15/fonoteka/go.mod; ../fonoteka.go/plugins/golem15/user/go.mod Per D-05, from summercms.go run go vet ./... and go test ./.... Explicitly vet the examples/hello root plus base, greeter, and optional nested modules, then compile all four module contexts with go test -run '^$'; the root module wildcard does not traverse nested Go modules, and the compile-only run verifies import resolution without coupling this migration to unrelated example runtime assertions. From ../fonoteka.go run go vet ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/... and go test ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/... (same plugin-module set scripts/check-phase10.sh already uses). Do not treat a skipped PostgreSQL test as a pass for a required package that should run. Do not add dependencies. If either repo fails on an old import or a stale script path, fix the leftover from Task 2 and re-run; do not weaken tests. go vet ./... && go test ./... && go vet ./examples/hello/... ./examples/hello/plugins/base/... ./examples/hello/plugins/greeter/... ./examples/hello/plugins/optional/... && go test -run '^$' ./examples/hello/... ./examples/hello/plugins/base/... ./examples/hello/plugins/greeter/... ./examples/hello/plugins/optional/... && (cd ../fonoteka.go && go vet ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/... && go test ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/...) non-zero exit; any package FAIL; output contains "build failed" or "no required module provides package" for a beach import - Both repository commands exit 0. - The examples/hello root and base, greeter, and optional nested modules all exit 0 under `go vet` and compile-only `go test -run '^$'`. - `test ! -d compass && test -d modules/compass` succeeds (spot-check a non-tracer package). - A `git grep` of tracked `*.go` `*.tmpl` `*.sh` in both repos (exclude `.planning/`) for `git.golem15.com/golem15/summercms/` followed immediately by a beach name with no `modules/` segment prints nothing. Both repos vet and test green on the nested import paths, every examples/hello module vets and compiles, and fonoteka plugin modules are included.

<threat_model>

Trust Boundaries

Boundary Description
Importer → framework package path A leftover root-form import fails the build or, worse, could compile against a shadow copy if a beach dir were left at root
Phase/admin scripts → on-disk package dirs Greps over missing old directories return empty and can pass vacuously; testdata and swag --dir miss after the move
App repo replace → framework tree replace stays; only import paths change. A mistaken replace rewrite would pull the wrong tree

STRIDE Threat Register

Threat ID Category Component Severity Disposition Mitigation Plan
T-10.2-01 Tampering repo-root beach directories high mitigate git mv only; Task 3 and later 10.2-02 gate refuse if any of the 18 names is still a directory at root
T-10.2-02 Tampering import paths in .go/.tmpl high mitigate Rewrite every importer to the modules/ prefix; go test ./... in both repos fails closed on a missing package
T-10.2-03 Tampering scripts/check-phase*.sh, check-admin-*.sh, admin/vite.config.ts high mitigate Retarget every listed path literal so hygiene greps scan modules/ and cannot pass on a missing old dir
T-10.2-04 Tampering modules/*/go.mod or go.work medium mitigate Keep the single root go.mod (D-03); Task 2 acceptance asserts no per-package go.mod and unchanged go.work use list
T-10.2-05 Tampering package names medium mitigate Keep beach package clauses (D-01/D-06); do not remap onto Winter system/backend/cms
T-10.2-SC Tampering npm/pip/cargo installs high mitigate No new dependencies this plan; do not run npm install; T-10.2-SC stays reserved
</threat_model>
After Task 1, the festival slice is green in the framework, examples/hello greeter module, and fonoteka importer contexts. After Task 2, root ls has no beach dirs and the listed scripts contain the nested path literals. After Task 3, `go vet ./... && go test ./...` in summercms.go, explicit vet plus compile-only test across every examples/hello workspace module, and the matching pair plus plugin modules in ../fonoteka.go exit 0.

<success_criteria>

  • ls at summercms.go root shows modules/, cmd/, admin/, examples/, internal/, scripts/ and none of the 18 beach directories.
  • No tracked .go/.tmpl/.sh importer still uses the root-form beach import.
  • Both repos test green, and every examples/hello module vets and compiles. Scripts that later gates run now point at modules/. </success_criteria>
Create `.planning/phases/10.2-nest-framework-packages-under-modules-and-write-run-docs/10.2-01-SUMMARY.md` when done.