docs(11.2-03): complete the unit test coverage and phase gate plan
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
---
|
||||
phase: 11.2-ready-to-share-summercms-io-website-and-newsletter-plugin
|
||||
plan: 03
|
||||
subsystem: testing
|
||||
tags: [go-test, fstest, httptest, node-test, coverage, phase-gate, bash]
|
||||
|
||||
requires:
|
||||
- phase: 11.2-01
|
||||
provides: vue-summercmsio-app with terminal.json, copyPayload, activeSection and the node:test suites
|
||||
- phase: 11.2-02
|
||||
provides: sm-summercmsio-plugin static handler and routes, the app's build/smoke/check-deploy scripts and terminal check, docsite site_url/site_label
|
||||
provides:
|
||||
- table-driven tests of every static serving rule and route behaviour of the site plugin (98.2% statement coverage)
|
||||
- every branch of checkSiteURL, siteLabel, the site_url/site_label parsing and the option-over-yaml precedence, the escaped header, the 404 and section pages, and the CLI flags in help
|
||||
- ungated tests of the D-40 terminal-check helpers and the remaining scroll-spy edge case
|
||||
- scripts/check-phase11.2.sh, a fail-closed gate across the four repositories (framework, plugin, app, site, built, smoke, deploy, terminal, full, all)
|
||||
- a validated 11.2-VALIDATION.md
|
||||
affects: [11.2 verify-work, cutover, 11.3]
|
||||
|
||||
actuals:
|
||||
tokens: 16305
|
||||
tasks: 3
|
||||
commits: 4
|
||||
commits_all_repos: 9
|
||||
plan_head_before: 2229ca3c6028fea4dd75a645f82e5f49f07fd638
|
||||
plan_head_after: a2f2d1e5c78c5aeb40363fac69ce65801d0c6031
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Phase gate per repository stage: go test -json through a detector that refuses a fail, a skip, a missing test, zero tests and no tests to run"
|
||||
- "Static-handler tests set r.URL.Path directly so the handler's own path cleaning is what is tested"
|
||||
- "Mutation checks in a scratch copy (plugin) or a git archive export (framework), never in the working tree"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- scripts/check-phase11.2.sh
|
||||
- ../sm-summercmsio-app/plugins/golem15/summercms/static_test.go
|
||||
- ../sm-summercmsio-app/plugins/golem15/summercms/routes_test.go
|
||||
modified:
|
||||
- internal/docsite/load_test.go
|
||||
- internal/docsite/theme_test.go
|
||||
- cmd/summer/docs_test.go
|
||||
- ../sm-summercmsio-app/plugins/golem15/summercms/links_test.go
|
||||
- ../sm-summercmsio-app/terminal_check_test.go
|
||||
- ../sm-summercmsio-app/vue-summercmsio-app/tests/scrollSpy.test.ts
|
||||
- .planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/11.2-VALIDATION.md
|
||||
|
||||
key-decisions:
|
||||
- "The gate's --built stage builds in release mode only when the framework checkout build.sh uses (SUMMERCMS_FRAMEWORK, default summercms.go) has v0.1.0; with the tag deferred it runs a dev build and says so"
|
||||
- "The coexistence test reads the plugin's real patterns from surf.BuildRouter(...).Routes() and registers them on a fresh ServeMux beside literal copies of cabana's admin patterns"
|
||||
- "TestTerminalScript pins the shipped override form 'git clone <override> summercms' (11.2-02 decision), not the bare 'git clone <override>' the plan text described"
|
||||
- "TestPageLinks pins the shipped pageLinks contract: duplicates kept in document order (callers dedupe), fragment links kept, og:image appended"
|
||||
|
||||
patterns-established:
|
||||
- "check-phase11.2.sh named_tests DIR PKG NAME...: per-repository go -C runs with -json and a required-PASS list; environment changes run in a subshell"
|
||||
|
||||
requirements-completed: []
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
description: "Every D-07/D-47 static serving rule of the site plugin is pinned: content types, immutable only for _nuxt (not _nuxt/builds) and _fonts, no-cache with a strong ETag elsewhere, 304, HEAD, Range, dot-segment and traversal 404s, docs 301s, redirect Locations inside /docs/ and never //, tree 404 pages, no X-Robots-Tag/CSP/X-Frame-Options"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "sm-summercmsio-plugin static_test.go#TestStaticSite,TestStaticDocs,TestStaticConditionalAndRange,TestStaticNoBlockingHeaders,TestStaticRedirectLocations,TestStaticMissing404Page,TestNewHandlersMissingIndex,TestContentType,TestSiteImmutable"
|
||||
status: pass
|
||||
- kind: other
|
||||
ref: "scripts/check-phase11.2.sh --plugin (17 named tests, coverage 98.2% >= 90.0%)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D2
|
||||
description: "The plugin assembles alone through surf.Assemble (GET only, POST 405, /backend falls to the site 404), fails closed on an unbuilt tree, registers via init as golem15.summercms with no admin controllers, and its patterns coexist with cabana's on one ServeMux"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "sm-summercmsio-plugin routes_test.go#TestRoutesAssemble,TestRoutesFailClosed,TestRoutesCoexistWithAdminPatterns,TestPluginIdentity,TestPluginEmbeddedTree"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Every branch of checkSiteURL, siteLabel, site_url/site_label parsing and option precedence; header escaping, link on index, section and 404 pages, exact unset header bytes; --site-url/--site-label in help and the label-without-URL error; docsite coverage 94.2%"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "internal/docsite#TestCheckSiteURL,TestSiteLabel,TestSiteURLPrecedence,TestParseSite,TestSiteLink; cmd/summer#TestDocsBuildSiteFlags,TestDocsSiteFlagsInHelp"
|
||||
status: pass
|
||||
- kind: other
|
||||
ref: "scripts/check-phase11.2.sh --framework (named tests, coverage >= 85.0%, check-phase11.1.sh --docs and --forbidden)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "D-40 terminal-check helpers loadTerminal, terminalScript and terminalEnv have ungated tests; the scroll-spy negative-tops edge case is covered"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "sm-summercmsio-app terminal_check_test.go#TestLoadTerminal,TestTerminalScript,TestTerminalEnv"
|
||||
status: pass
|
||||
- kind: unit
|
||||
ref: "vue-summercmsio-app tests/scrollSpy.test.ts#sections scrolled past (negative tops) still count, so the last one stays active"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D5
|
||||
description: "scripts/check-phase11.2.sh --all runs framework, plugin, app, site, built, smoke, deploy, terminal and full, and prints phase11.2 all passed"
|
||||
verification:
|
||||
- kind: e2e
|
||||
ref: "scripts/check-phase11.2.sh --all -> nine 'phase11.2 <stage> passed' lines, 'phase11.2 all passed', exit 0"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D6
|
||||
description: "11.2-VALIDATION.md is validated: per-task map filled and green, nyquist_compliant and wave_0_complete true, manual rows kept for visual UAT, rome bring-up, external links, the verbatim clone and the release build from the real tag"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "grep 'status: validated' / 'nyquist_compliant: true' / TestExternalLinks match; grep -c '⬜ pending' = 0"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D7
|
||||
description: "External link reachability and the verbatim terminal clone at cutover (D-38), and the release build from the real v0.1.0 tag (D-42)"
|
||||
verification: []
|
||||
human_judgment: true
|
||||
rationale: "Needs the user to make golem15/summercms public and create the v0.1.0 tag; the gate has --terminal --verbatim and the release branch of --built ready for that run"
|
||||
|
||||
duration: 13min
|
||||
completed: 2026-10-01
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Phase 11.2 Plan 03: Unit test coverage and the phase gate Summary
|
||||
|
||||
**Table-driven fstest tests pin every static serving and route rule of the site plugin (98.2% coverage). Every site_url/site_label branch and the D-40 helpers are tested, and one fail-closed `scripts/check-phase11.2.sh --all` proves the phase across the four repositories.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 13 min
|
||||
- **Started:** 2026-10-01T14:25:51Z
|
||||
- **Completed:** 2026-10-01T14:39:19Z
|
||||
- **Tasks:** 3 (tracer + 2 auto)
|
||||
- **Files modified:** 11 (4 in summercms.go plus VALIDATION.md, 3 in the plugin, 1 in the app, 1 in the site, plus 2 gitlinks)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- **Site plugin (98.2% statement coverage, from fixtures only).**
|
||||
- `static_test.go` covers content types, cache rules, ETag/304, HEAD, Range, dot-segment and traversal 404s, docs 301s, redirect Locations, a tree with no 404 page and the load errors.
|
||||
- `routes_test.go` covers the surf assembly, fail-closed boot, coexistence with the admin patterns, the plugin's identity and init registration, and the embedded tree.
|
||||
- `TestPageLinks` and `TestResolve` cover the link helpers.
|
||||
- **Framework (docsite coverage 94.2%).**
|
||||
- `TestCheckSiteURL` has 21 cases (5 accepted, 16 rejected).
|
||||
- `TestSiteLabel` and `TestSiteURLPrecedence` (12 cases) cover labels and option-over-yaml precedence. `TestParseSite` gains rows for blank and two-line labels.
|
||||
- `TestSiteLink` now checks the escaped label, the section page, the 404 page and the exact unset header bytes.
|
||||
- `TestDocsSiteFlagsInHelp` checks both commands' help, and `docs:build --site-label` without a URL now has an error test.
|
||||
- **App and site.**
|
||||
- `TestLoadTerminal`, `TestTerminalScript` and `TestTerminalEnv` run ungated.
|
||||
- One scroll-spy case was added for sections scrolled past. The other listed TS edge cases were already covered by the 11.2-01 tests.
|
||||
- **Gate.** `scripts/check-phase11.2.sh` has the stages `--framework`, `--plugin`, `--app`, `--site`, `--built`, `--smoke`, `--deploy`, `--terminal [--verbatim]`, `--full` and `--all`. Unknown modes exit 2. `--all` passed end to end.
|
||||
- **VALIDATION.md** is validated, with one row per task across the three plans and the cutover checks kept as manual rows.
|
||||
|
||||
## Task Commits
|
||||
|
||||
| Task | Commit | Repo | Message |
|
||||
|------|--------|------|---------|
|
||||
| 1 (tracer) | `549adaf` | sm-summercmsio-plugin | test: cover every static serving rule and the plugin routes |
|
||||
| 1 (tracer) | `e7d9a2e` | sm-summercmsio-app | test: bump the site plugin to its static and route tests (gitlink) |
|
||||
| 1 (tracer) | `18fe100` | summercms.go | test(11.2): add the phase gate with the plugin stage |
|
||||
| 2 | `c3ddd5c` | vue-summercmsio-app | test: cover terminal and scroll-spy edge cases |
|
||||
| 2 | `8c718a8` | sm-summercmsio-app | test: cover the terminal check helpers |
|
||||
| 2 | `f34c335` | sm-summercmsio-app | test: bump the site to its scroll-spy edge case (gitlink) |
|
||||
| 2 | `f5f9387` | summercms.go | test(11.2): cover site_url and site_label and gate the framework, app and site stages |
|
||||
| 3 | `29adc23` | summercms.go | test(11.2): complete the phase gate |
|
||||
| 3 | `a2f2d1e` | summercms.go | docs(11.2): validate the phase verification map |
|
||||
|
||||
Nothing was pushed. No commit has a co-author trailer. No v0.1.0 tag was created.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
**Task 1 (tracer gate).** The run is interactive in `end-of-phase` mode and the tracer's verify is automated-only, so the verify was re-run and passed:
|
||||
- `go vet` is clean.
|
||||
- The plan's verify regex gives 16 top-level PASS lines.
|
||||
- `TestStatic.*|TestRoutes.*|TestPlugin.*` gives 47 `--- PASS` lines, subtests included.
|
||||
- `scripts/check-phase11.2.sh --plugin` passes: 17 named tests and 58 passing tests, subtests included.
|
||||
- Coverage is 98.2%.
|
||||
- `bash -n` is clean, and `--bogus` exits 2.
|
||||
- A gate copy with a renamed test refuses with "named tests did not pass (missing, renamed or filtered out)".
|
||||
|
||||
**Task 1 mutation check (siteImmutable).**
|
||||
- Setup: in a scratch copy of the plugin (`GOWORK=off`), `siteImmutable` was changed to `return true` for `_nuxt/`.
|
||||
- Result: `TestStaticSite` failed on `/_nuxt/builds/latest.json` and `/_nuxt/builds/meta/x.json` with `Cache-Control = "public, max-age=31536000, immutable", want "no-cache"`.
|
||||
|
||||
**Task 2.**
|
||||
- `go vet ./...` is clean.
|
||||
- Eight top-level PASS lines from the plan's verify regex.
|
||||
- `TestCheckSiteURL` prints 21 `--- PASS: TestCheckSiteURL/` lines.
|
||||
- The app helpers give three PASS lines and no SKIP.
|
||||
- `--framework`, `--app` and `--site` pass. The site stage had 30 tests: `# pass 30`, `# fail 0`, `# skipped 0`.
|
||||
|
||||
**Task 2 mutation check (checkSiteURL).**
|
||||
- Setup: in a `git archive HEAD` export of summercms.go with the new `load_test.go`, the `//` rejection in `checkSiteURL` was removed.
|
||||
- Result: `TestCheckSiteURL/protocol-relative` failed with `checkSiteURL("//acme.example") = <nil>, want errSiteURL`.
|
||||
|
||||
**Task 3.** `scripts/check-phase11.2.sh --all` exited 0. It printed all nine `phase11.2 <stage> passed` lines and `phase11.2 all passed`, with zero `refuse:`, `FAIL`, `--- FAIL` or `--- SKIP` lines. Stage by stage:
|
||||
- **built:** a dev build, because summercms.go has no v0.1.0 tag. The three build-dependent tests passed.
|
||||
- **smoke:** `smoke: ok` on postgres:15.
|
||||
- **deploy:** `check-deploy: ok`.
|
||||
- **terminal:** used the clone override (this checkout) and passed.
|
||||
- **full:** `go vet ./...` and `go test ./... -count=1` ran with the Docker database suites.
|
||||
|
||||
**Release branch of `--built`.**
|
||||
- Setup: `SUMMERCMS_FRAMEWORK=<scratchpad>/fw-release`, the 11.2-02 scratch clone that carries a local v0.1.0 tag.
|
||||
- Result: `built: v0.1.0 found …, release build`, then `build: bin/summercms-io (release v0.1.0) ready` and `phase11.2 built passed`.
|
||||
|
||||
**Plan verification.**
|
||||
- All four repositories have an empty `git status --porcelain`. summercms.go still has the user's untracked `SummerCMS landing page.zip`, which predates this plan.
|
||||
- Plugin coverage is 98.2% (≥ 90.0%). Docsite coverage is 94.2% (≥ 85.0%).
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
**summercms.go**
|
||||
- `scripts/check-phase11.2.sh`: the phase gate, with stages and a `go test -json` detector modelled on `check-phase11.1.sh`.
|
||||
- `internal/docsite/load_test.go`: `TestCheckSiteURL`, `TestSiteLabel`, `TestSiteURLPrecedence` and new `TestParseSite` rows.
|
||||
- `internal/docsite/theme_test.go`: `TestSiteLink` covers escaping, the section page, the 404 page and the exact unset bytes.
|
||||
- `cmd/summer/docs_test.go`: `TestDocsSiteFlagsInHelp`, and the label-without-URL case in `TestDocsBuildSiteFlags`.
|
||||
- `11.2-VALIDATION.md`: validated.
|
||||
|
||||
**sm-summercmsio-plugin**
|
||||
- `static_test.go` and `routes_test.go` are new.
|
||||
- `links_test.go` gains `TestPageLinks` and `TestResolve`. The build-gated tests are unchanged.
|
||||
|
||||
**sm-summercmsio-app**
|
||||
- `terminal_check_test.go` gains the three ungated helper tests. The two gitlink bumps are in the commit table.
|
||||
|
||||
**vue-summercmsio-app**
|
||||
- `tests/scrollSpy.test.ts` gains the negative-tops case.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See `key-decisions` in the frontmatter. In short:
|
||||
- `--built` follows the same framework checkout as `build.sh`.
|
||||
- The coexistence test takes the plugin's real patterns from surf's route table.
|
||||
- The tests pin the shipped `terminalScript` override form (`git clone <override> summercms`) and the shipped `pageLinks` contract (duplicates kept).
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Interpretation notes (no production change)
|
||||
|
||||
**1. `terminalScript` override form**
|
||||
- **Plan text:** "the first command becomes `git clone /tmp/fw`".
|
||||
- **What was tested:** the shipped behaviour from the 11.2-02 Rule 1 fix, `git clone /tmp/fw summercms`. The plan says to test the shipped name and behaviour.
|
||||
|
||||
**2. `pageLinks` duplicates**
|
||||
- **Plan text:** "including duplicates removed and fragment-only links kept". This is ambiguous.
|
||||
- **What was tested:** the shipped function keeps duplicates in document order, and `TestLandingLinks` dedupes. The test pins that, along with kept fragment links, decoded entities and the appended og:image.
|
||||
|
||||
**3. Two plugin statements are not covered**
|
||||
- `plugin.go:48` and `static.go:89` are the `fs.Sub` error returns.
|
||||
- `fs.Sub` fails only for an invalid directory name, and the names here are the constants `"public"`, `"site"` and `"docs"`, so the branches cannot be reached.
|
||||
- Coverage is 98.2% without them.
|
||||
|
||||
**4. Extra tests beyond the plan's list**
|
||||
- `TestResolve` in `links_test.go` covers the redirect follower and the `SUMMERCMS_SITE_DIR` override.
|
||||
- The gate requires it too.
|
||||
|
||||
**5. Extra commits in sm-summercmsio-app**
|
||||
- The gitlink bumps (`e7d9a2e`, `f34c335`) are separate commits from the app's own test commit.
|
||||
- The sequential executor instructions require committing the updated gitlink whenever a submodule changes.
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** none needed a production fix. The new tests exposed no defect, so no production code changed in any repository. There are 5 interpretation or scope notes.
|
||||
**Impact on plan:** none. All acceptance criteria pass.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- **Scratch-copy mutation setup.** The first run needed `GOFLAGS=-mod=mod GOPROXY=off`, because the scratch module's `go.sum` lacked entries that the app's `go.work.sum` normally provides. No network was used.
|
||||
- **`env -u` and bash functions.** `env -u` cannot call a bash function, so the gate unsets variables in subshells. `named_tests` cleans up its own log.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None. This plan adds tests and a local gate script only. The T-11.2-15 mitigation (the detector refuses a skip, a fail, a missing test or zero tests, and `--bogus` exits 2) and the T-11.2-16 mitigation (the gate sets `SUMMERCMS_REQUIRE_BUILD=1` and `SUMMERCMS_TERMINAL_CHECK=1` itself and requires PASS) are in place.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None for this plan. These cutover items are unchanged from 11.2-02:
|
||||
1. Push the three site repositories.
|
||||
2. Make `golem15/summercms` public (D-38).
|
||||
3. Create and push v0.1.0 (D-42).
|
||||
4. Run `TestExternalLinks`, `scripts/check-phase11.2.sh --terminal --verbatim`, and `--built`, which will report a release build.
|
||||
5. Deploy on rome.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- Phase 11.2 has all three plans complete, and the gate is green. It is ready for `/gsd-verify-work`, where the manual rows are visual UAT and the cutover checks.
|
||||
- Phase 11.3 can reuse `TestRoutesCoexistWithAdminPatterns` when it activates the admin beside the site.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Files exist: `scripts/check-phase11.2.sh`, `internal/docsite/load_test.go`, `internal/docsite/theme_test.go` and `cmd/summer/docs_test.go`; the plugin's `static_test.go`, `routes_test.go` and `links_test.go`; the app's `terminal_check_test.go`; the site's `tests/scrollSpy.test.ts`; and `11.2-VALIDATION.md`.
|
||||
- Commits were found in each repository:
|
||||
- summercms.go: `18fe100`, `f5f9387`, `29adc23`, `a2f2d1e`
|
||||
- app: `e7d9a2e`, `8c718a8`, `f34c335`
|
||||
- plugin: `549adaf`
|
||||
- site: `c3ddd5c`
|
||||
- The summercms.go commit count was measured: `git rev-list --count 2229ca3..HEAD` = 4.
|
||||
- `git tag -l v0.1.0` in summercms.go prints nothing.
|
||||
|
||||
---
|
||||
*Phase: 11.2-ready-to-share-summercms-io-website-and-newsletter-plugin*
|
||||
*Completed: 2026-10-01*
|
||||
Reference in New Issue
Block a user