docs(19.3-05): summary through Task 6 and the release sheet; state at the Task 7 checkpoint
This commit is contained in:
@@ -4,16 +4,16 @@ milestone: v1.0
|
||||
current_phase: "19.3"
|
||||
current_phase_name: Framework transport and infrastructure for WavePath (INSERTED)
|
||||
status: executing
|
||||
stopped_at: Completed 19.3-04-PLAN.md
|
||||
last_updated: "2026-10-15T17:17:13.871Z"
|
||||
stopped_at: 19.3-05 Task 7 release checkpoint (tasks 1-6 done, gate green; awaiting release / tag-only / hold)
|
||||
last_updated: "2026-10-15T18:01:50.208Z"
|
||||
last_activity: 2026-10-15
|
||||
last_activity_desc: Phase 19.3 execution started
|
||||
state_head: 6f9f2e20a42996474165747c090e87ca29a7bfa1
|
||||
state_head: 8f5325300c94fe7fb18e60b47102bc2443a0a17c
|
||||
progress:
|
||||
total_phases: 40
|
||||
completed_phases: 31
|
||||
total_plans: 190
|
||||
completed_plans: 186
|
||||
completed_plans: 187
|
||||
gsd_state_version: "1.0"
|
||||
milestone_name: milestone
|
||||
---
|
||||
@@ -823,6 +823,8 @@ Recent decisions affecting current work:
|
||||
- [Phase 19.3]: pact.ReorderAfterSave runs inside cabana's reorder transaction; reorderPost uses lagoon.Transaction so AfterCommit fires
|
||||
- [Phase 19.3]: Journal golem15.journal.site_cache.* kept as deprecated aliases for one release; framework keys win
|
||||
- [Phase 19.3]: 19.3-04 Task 4 reply push-all: plugins, layers, summercms master pushed; layer tags vue-faq/menu v0.2.0, vue-journal v0.4.0; no framework tag
|
||||
- [Phase 19.3]: 19.3-05: phase gate scripts/check-phase19.3.sh requires every new test by name (go test -json / TAP detectors); --all green incl. Docker
|
||||
- [Phase 19.3]: 19.3-05: miniredis v2.40.0 test-only in modules/cooler (Task 4 reply: approved)
|
||||
|
||||
### Pending Todos
|
||||
|
||||
@@ -901,6 +903,6 @@ Items acknowledged and carried forward from previous milestone close:
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-10-15T17:17:13.150Z
|
||||
Stopped at: Completed 19.3-04-PLAN.md
|
||||
Resume file: None
|
||||
Last session: 2026-10-15T18:01:46.843Z
|
||||
Stopped at: 19.3-05 Task 7 release checkpoint (tasks 1-6 done, gate green; awaiting release / tag-only / hold)
|
||||
Resume file: .planning/phases/19.3-framework-transport-and-infrastructure-for-wavepath/19.3-05-SUMMARY.md
|
||||
|
||||
@@ -1,23 +1,218 @@
|
||||
---
|
||||
phase: 19.3-framework-transport-and-infrastructure-for-wavepath
|
||||
plan: 05
|
||||
subsystem: testing
|
||||
tags: [gate, bouncer, turnstile, cors, api-docs, cooler, redis, miniredis, rate-limit, s3, build-tags, site-cache, nuxt-layers, release]
|
||||
status: in-progress
|
||||
|
||||
requires:
|
||||
- phase: 19.3-01
|
||||
provides: "modules/cooler (caches, Redis rate-limit store, Install, FromApp), surf store lookup"
|
||||
- phase: 19.3-02
|
||||
provides: "bouncer token cookies and Turnstile, surf CORS hardening, CORS profiles, api-docs"
|
||||
- phase: 19.3-03
|
||||
provides: "summer.yaml build.tags, attach S3 build tag, DiskExtension, public_url"
|
||||
- phase: 19.3-04
|
||||
provides: "cooler site-cache purger, pact.ReorderAfterSave, plugin purge helpers, layer purge route"
|
||||
provides:
|
||||
- "scripts/check-phase19.3.sh: fail-closed gate with self-test, go, docker, plugins, layers and docs stages and --all"
|
||||
- "SC-4 unit tests for every piece of new code of the phase, in summercms.go, three plugins and three layers"
|
||||
- "github.com/alicebob/miniredis/v2 v2.40.0 as a test-only dependency (human-approved)"
|
||||
- "19.3-VALIDATION.md per-task map filled, wave_0_complete true"
|
||||
affects: [19.3 release (Task 7), /msd-verify-work 19.3, /msd-validate-phase 19.3]
|
||||
|
||||
actuals:
|
||||
tokens: 53300
|
||||
tasks: 6
|
||||
commits: 8
|
||||
plan_head_before: 6035ccc194a74a9124ece17ce3c8301689cbc8ac
|
||||
plan_head_after: 8f5325300c94fe7fb18e60b47102bc2443a0a17c
|
||||
|
||||
tech-stack:
|
||||
added:
|
||||
- "github.com/alicebob/miniredis/v2 v2.40.0 (test-only; brings github.com/yuin/gopher-lua v1.1.1 indirect)"
|
||||
patterns:
|
||||
- "One behaviour table run through several stores (parity adapter: real-time sleep for MemoryStore and Docker Redis, FastForward for miniredis)"
|
||||
- "Gate stages require tests by exact top-level name through go test -json and TAP detectors; a skip, a missing name or zero tests fails"
|
||||
- "Route handler specs in node --test: Nitro auto-imports stubbed on globalThis, the real route file imported"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- scripts/check-phase19.3.sh
|
||||
- modules/bouncer/cookie_test.go
|
||||
- modules/bouncer/turnstile_test.go
|
||||
- modules/surf/cors_profile_test.go
|
||||
- modules/surf/apidocs_test.go
|
||||
- modules/cabana/reorder_hook_test.go
|
||||
- internal/build/manifest_tags_test.go
|
||||
- modules/lagoon/attach/s3_test.go
|
||||
- modules/lagoon/attach/diskext_test.go
|
||||
- modules/cooler/memory_test.go
|
||||
- modules/cooler/redis_test.go
|
||||
- modules/cooler/ratelimit_test.go
|
||||
- modules/cooler/install_test.go
|
||||
- modules/cooler/docker_test.go
|
||||
- ../sm-journal-plugin/site_cache_keys_test.go
|
||||
- ../sm-faq-plugin/controllers/site_cache_test.go
|
||||
- ../sm-menu-plugin/controllers/site_cache_test.go
|
||||
modified:
|
||||
- modules/surf/store_lookup_test.go
|
||||
- modules/lagoon/attach/store_test.go
|
||||
- modules/lagoon/attach/url_test.go
|
||||
- modules/cooler/sitecache_test.go
|
||||
- modules/cooler/README.md
|
||||
- go.mod
|
||||
- go.sum
|
||||
- ../sm-journal-plugin/site_cache_admin_test.go
|
||||
- ../vue-faq-layer/tests/sitePurge.test.ts
|
||||
- ../vue-menu-layer/tests/sitePurge.test.ts
|
||||
- ../vue-journal-layer/tests/sitePurge.test.ts
|
||||
- .planning/phases/19.3-framework-transport-and-infrastructure-for-wavepath/19.3-VALIDATION.md
|
||||
|
||||
key-decisions:
|
||||
- "Phase gate reuses check-phase18.1.sh's go test -json detector: a skip, a missing name, no tests, zero tests or a build failure fails the stage"
|
||||
- "miniredis is test-only: only _test.go files in modules/cooler import it (Task 4 reply: approved)"
|
||||
- "Journal's plan-04 Docker test renamed to TestCategoriesAdminFrameworkKeysWin so the unit test owns TestSiteCacheFrameworkKeysWin"
|
||||
- "Release proposal: framework tag v0.1.27 (highest v0.1.26 plus one, free on origin); nothing pushed or tagged before the Task 7 reply"
|
||||
|
||||
requirements-completed: []
|
||||
|
||||
duration: 41min (plan wall time so far, both executor runs)
|
||||
completed: pending (Task 7 release decision)
|
||||
---
|
||||
|
||||
# Phase 19.3 Plan 05: unit tests, phase gate and release decision (in progress)
|
||||
# Phase 19.3 Plan 05: unit tests, phase gate and release decision Summary
|
||||
|
||||
**Fail-closed gate `scripts/check-phase19.3.sh` requiring every new 19.3 test by name across the framework, three plugins and three Nuxt layers. Green on all six stages, Docker included. Release v0.1.27 waits on the human's decision.**
|
||||
|
||||
## Checkpoint replies
|
||||
|
||||
### Task 4 (miniredis legitimacy check)
|
||||
|
||||
Reply, verbatim, recorded before any go.mod change of Task 5:
|
||||
Reply, verbatim, recorded (commit b139651) before any go.mod change of Task 5:
|
||||
|
||||
> approved
|
||||
|
||||
Orchestrator instruction with it: install github.com/alicebob/miniredis/v2@v2.40.0 as test-only (only `_test.go` files in modules/cooler may import it).
|
||||
Orchestrator instruction with it: install github.com/alicebob/miniredis/v2@v2.40.0 as test-only (only `_test.go` files in modules/cooler may import it). Verified after Task 5: `grep -n 'github.com/alicebob/miniredis/v2 v2.40.0' go.mod` prints line 10; `grep -rl 'alicebob/miniredis' --include='*.go' modules | grep -vc '_test.go$'` prints 0.
|
||||
|
||||
### Task 7 (release decision)
|
||||
|
||||
Pending.
|
||||
Pending. Proposed tag: **v0.1.27**. The reply, the tag and every pushed hash go here.
|
||||
|
||||
<!-- The full SUMMARY replaces this file when the plan completes. -->
|
||||
## Performance
|
||||
|
||||
- **Started:** 2026-10-15T17:19:19Z (first executor run; resumed after the Task 4 checkpoint)
|
||||
- **Tasks:** 6 of 7 complete (Task 7 is the blocking release checkpoint)
|
||||
- **Framework commits since the plan ledger:** 8 (6035ccc..8f53253)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- The gate has stages `--self-test`, `go`, `docker`, `plugins`, `layers` and `docs`, plus `--all`. A stage fails when a required test is missing, skipped or red. `--all` reports NOT RUN docker when no Docker daemon answers, and fails instead when PHASE193_REQUIRE_DOCKER=1.
|
||||
- The cooler suites cover the memory and Redis caches and the rate-limit parity table, run through surf.MemoryStore, miniredis and real Redis. They also cover concurrency, the fallback on a Redis error, the key prefixes, Install, FromApp, and the site-cache purge on Postgres (rollback, commit, nested transactions, a 500 answer, a slow receiver and an unreachable one).
|
||||
- In the plugins: the FAQ and menu `purgeSiteCache` helper tests, and the Journal's deprecated-key tests (framework keys win; alias keys deprecated or invalid; no keys).
|
||||
- In the layers: the shared purge spec grows from 6 to 11 tests, byte-identical in all three layers. New ones include route-handler specs for 404, 401 and 200, the purge count and the log line, timing-safe comparison across bearer lengths, and parse edge cases.
|
||||
|
||||
## Task Commits
|
||||
|
||||
| Task | Repo | Commit | Message |
|
||||
|------|------|--------|---------|
|
||||
| 1 (tracer) | summercms.go | 619916b | test(19.3-05): phase gate with bouncer cookie and Turnstile unit suites |
|
||||
| 2 | summercms.go | 055f51c | test(19.3-05): surf CORS, profiles, api-docs and store lookup; cabana reorder hook |
|
||||
| 3 | summercms.go | 38f6d65 | test(19.3-05): build tags, S3 tag guard, DiskExtension and public_url |
|
||||
| (docs) | summercms.go | df7db6c | docs(19.3-05): log S3 object content-type observation in deferred items |
|
||||
| 4 | summercms.go | b139651 | docs(19.3-05): record the miniredis checkpoint reply |
|
||||
| 5 | summercms.go | 78ba385 | test(19.3-05): cooler caches, rate-limit parity, Install and after-commit purge |
|
||||
| 6 | sm-journal-plugin | ebfb710 | test(19.3-05): Journal site-cache keys: framework keys win, alias keys deprecated |
|
||||
| 6 | sm-faq-plugin | e117bb4 | test(19.3-05): purgeSiteCache does nothing without a transaction or purger |
|
||||
| 6 | sm-menu-plugin | 6c08f1a | test(19.3-05): purgeSiteCache does nothing without a transaction or purger |
|
||||
| 6 | vue-faq-layer | 96b6bc0 | test(19.3-05): site purge route handler specs and edge cases |
|
||||
| 6 | vue-menu-layer | dd0ee35 | test(19.3-05): site purge route handler specs and edge cases |
|
||||
| 6 | vue-journal-layer | 5936f66 | test(19.3-05): site purge route handler specs and edge cases |
|
||||
| 6 | summercms.go | f57fc12 | test(19.3-05): gate plugins, layers and docs stages |
|
||||
| 6 | summercms.go | 8f53253 | docs(19.3-05): validation map filled, wave 0 complete |
|
||||
|
||||
## Test names per repository (all required by the gate)
|
||||
|
||||
- **summercms.go, go stage (-short):**
|
||||
- bouncer: 17 names (TestLoadCookieConfigDefaults … TestTurnstileNeverLogsSecret).
|
||||
- surf: 23 names (TestCORSCredentialsWildcardRefused … TestBuildRouterNeverDials, including TestCORSOptionsMatchesLaravel).
|
||||
- internal/build: 4 names.
|
||||
- attach: 4 names, run twice (untagged and `-tags summercms_s3`).
|
||||
- cooler: TestMemoryCache, TestMemoryCacheTTL, TestMemoryCacheBounded, TestMemoryIncrementConcurrent, TestRememberDegrades, TestRedisCache, TestRedisFlushOnlyPrefix, TestRateLimitParity, TestRateLimitConcurrentNeverExceedsMax, TestRateLimitFallbackOnError, TestRateLimitKeyPrefix, TestInstallConfigErrors, TestInstallPingWarning, TestInstallReusesFromApp, TestFromAppLazy, TestInstallSiteCacheValidation, TestSiteCachePurgeConfig, TestSiteCachePurgeRequest, TestSiteCacheFromApp.
|
||||
- **summercms.go, docker stage:**
|
||||
- cabana: TestReorderHookRunsInTx, TestReorderHookErrorRollsBack, TestReorderWithoutHookUnchanged.
|
||||
- attach: TestStoreDiskExtension.
|
||||
- cooler: TestRateLimitParityDocker, TestRedisCacheDocker, TestSiteCacheAfterCommitOnly, TestSiteCacheFailureNeverFails.
|
||||
- **Plugins, plugins stage:**
|
||||
- FAQ and menu `./controllers`: TestPurgeSiteCacheWithoutTx, TestPurgeSiteCacheWithoutPurger.
|
||||
- Journal: TestSiteCacheFrameworkKeysWin, TestSiteCacheAliasKeysDeprecated, TestSiteCacheNoKeys; `./classes` TestSiteCachePurgeConfig, TestSiteCachePurgeRequest.
|
||||
- **Plugins, docker stage:** TestFaqAdminPurgesSiteCache, TestMenuAdminPurgesSiteCache, TestCategoriesAdminPurgesSiteCache, TestPostsAdminPurgesSiteCache, TestCategoriesAdminFrameworkKeysWin.
|
||||
- **Layers, layers stage:** 11 `sitePurge:` names per layer, plus `cmp` of server/lib/siteCachePurge.ts, server/api/__site__/cache/purge.post.ts and tests/sitePurge.test.ts across the three layers.
|
||||
|
||||
## Gate runs
|
||||
|
||||
Run on 2026-10-15 on a Docker host:
|
||||
|
||||
- `bash scripts/check-phase19.3.sh --all`: PASS self-test, go, plugins, layers, docs, docker. "Phase 19.3 gate passed". Docker ran; it was not NOT RUN.
|
||||
- `go test -count=1 -run '^TestDocsTree$' ./cmd/summer`: ok. `(cd examples/hello && go test ./...)`: ok. Result: release-gate-ok.
|
||||
- Full `go test -count=1 ./...` (all Docker suites): exit 0, 41 packages ok, no FAIL lines.
|
||||
- Fail-closed checks:
|
||||
- Task 1: renaming TestForgetTokenCookie made the go stage exit 1 (reverted, not committed), and `nosuchstage` exits 2 with usage.
|
||||
- Task 6: a planted consuming-application name in modules/cooler/redis.go made `docs` exit 1, and a one-line drift in vue-menu-layer's spec made `layers` exit 1. Both were reverted and never committed.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- The gate reuses check-phase18.1.sh's `go test -json` detector. A skip, a missing name, no tests, zero tests or a build failure all fail the stage.
|
||||
- The cooler Docker suites start one container per test (Postgres for the purge, redis:7-alpine for the rest) instead of a TestMain. Nothing starts before flag parsing, and `-short` skips them inside the test.
|
||||
- The docs stage checks the lines the phase added (`git diff <first 19.3 commit>^`, `.planning` excluded) for consuming-application names. The names are split in the script so it does not match itself; PHASE193_BASE overrides the base.
|
||||
- Test expectation for TestStoreDiskExtension: the "js under octet-stream" row expects content_type text/javascript (from the extension when the sniff is generic, the plan 03 rule) and the disk name `.bin` (D-15).
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Task 3 verify grep could never match**
|
||||
- **Found during:** Task 3
|
||||
- **Issue:** `grep -q -- '^--- PASS: TestOpenBucketS3$'` cannot match because `go test -v` appends the duration.
|
||||
- **Fix:** checked with `grep -qE '^--- PASS: <name>( |$)'` instead (T3-VERIFY-OK). The gate itself uses the JSON detector.
|
||||
- **Commit:** 38f6d65
|
||||
|
||||
**2. [Rule 3 - Blocking] Duplicate test name in the Journal test binary**
|
||||
- **Found during:** Task 6
|
||||
- **Issue:** plan 04 had added a Docker test `TestSiteCacheFrameworkKeysWin` in package journal_test, and the plan gives the same name to the new unit test in package journal. `-run '^TestSiteCacheFrameworkKeysWin$'` matched both, so under `-short` one skipped and the gate's skip detector failed the stage.
|
||||
- **Fix:** renamed the Docker test to `TestCategoriesAdminFrameworkKeysWin` (it saves a category with both key sets) and required it in the docker stage. The unit test keeps the plan's name.
|
||||
- **Files modified:** ../sm-journal-plugin/site_cache_admin_test.go
|
||||
- **Commit:** ebfb710
|
||||
|
||||
**3. [Discretion] Branch the plugin helper unit tests cannot reach**
|
||||
- `TestPurgeSiteCacheWithoutPurger` covers a nil app, a nil app result and an app without keys. A unit test cannot reach the branch "inside a transaction, no purger": cabana has no exported constructor for a context carrying a transaction, and this plan allows no production changes. The plugins' Docker admin suites reach it. Logged in deferred-items.md.
|
||||
|
||||
No production code changed in this plan.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- go-redis logs `failed to dial after 5 attempts` to stderr on each failing call against a stopped Redis. On a dead Redis, `Cache.Remember` waits for those retries (about 1.7 s) unless the caller's context has a deadline. Logged in deferred-items.md as a follow-up. The earlier follow-up, a committed test for the Redis-outage fallback of the rate-limit store, is now TestRateLimitFallbackOnError: each attempt answers from the fallback within about AttemptTimeout, with one warning naming the endpoint.
|
||||
- Earlier finding (df7db6c), unchanged: S3 object metadata carries the sniffed content type, so an HTML body uploaded as note.txt is stored with Content-Type text/html.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None.
|
||||
|
||||
## Release sheet (Task 7, awaiting the human's reply)
|
||||
|
||||
- **Proposed tag:** v0.1.27. The current latest framework tag is v0.1.26 (5c2b0e1, 2026-10-14). `git ls-remote --tags origin refs/tags/v0.1.27` prints nothing, so the tag is free.
|
||||
- **Preflight:** framework paths clean. `git fetch origin --tags` done. `HEAD..origin/master` is empty. origin/master is af9dad6.
|
||||
- **Public surfaces the tag publishes:**
|
||||
- cooler and its keys `redis.url`, `cache.*` and `http.rate_limit.store`, plus `site_cache.purge_url` and `site_cache.purge_token`.
|
||||
- `auth.cookie.*` and the bouncer cookie and Turnstile API.
|
||||
- `http.cors` hardening, `http.cors_profiles` and `cors:<profile>`.
|
||||
- `turnstile.*` and `http.api_docs.*`.
|
||||
- summer.yaml `build.tags` and the `summercms_s3` tag.
|
||||
- `storage.uploads.public_url` and `pact.ReorderAfterSave`.
|
||||
- **Framework commits to push:** origin/master..HEAD, which is plan 04's 6f9f2e2 and 6035ccc plus this plan's commits from 619916b on (with the final SUMMARY commit). v0.1.26..HEAD holds the whole phase.
|
||||
- **Plugin and layer commits not pushed yet** (all test-only, from this plan): sm-faq-plugin e117bb4, sm-menu-plugin 6c08f1a, sm-journal-plugin ebfb710, vue-faq-layer 96b6bc0, vue-menu-layer dd0ee35, vue-journal-layer 5936f66. The layer tags v0.2.0 and v0.4.0 from plan 04 are already on origin.
|
||||
- **App commits from plan 04 Task 5 not pushed yet:** vue-grzybyfunkcjonalne-app 0ee97d0 (push first), then sm-grzybyfunkcjonalne-app f9cafe2, d604509, 85939c3 and 129c0df.
|
||||
- **Plugin go.mod:** the three plugins require summercms v0.1.23 (with a local replace). After "release" they move to v0.1.27 through `GOWORK=off go get` and `go mod tidy`.
|
||||
- Apps building against ../summercms.go need `go mod tidy` once for go-redis, otter and the AWS SDK modules (sm-grzybyfunkcjonalne-app already has f9cafe2).
|
||||
|
||||
<!-- Self-check runs at plan completion, after Task 7. -->
|
||||
|
||||
@@ -16,3 +16,5 @@ Out-of-scope findings logged by executors. Not fixed in the plan that found them
|
||||
## From 19.3-05
|
||||
|
||||
- Security observation (not a test failure; plan 03 kept the stored `content_type` rule by design): `attach.Store` writes the blob with the sniffed content type as object metadata, so an HTML body uploaded as `note.txt` is stored as `<id>.txt` with `Content-Type: text/html`, and a generic sniff takes the type from the extension (`app.js` with binary bytes is stored as `.bin` with `text/javascript`). The surf uploads route neutralises this (nosniff, sandbox CSP, attachment disposition), but with `storage.uploads.public_url` pointing at an S3 bucket the bucket serves the object's stored Content-Type directly, so such a file renders as HTML on the bucket or CDN host. `docs/services/storage.md`'s deploy note says a CDN "picks the Content-Type from the file extension", which is not true for S3 object metadata. A follow-up could write a non-rendering content type (or `Content-Disposition: attachment`) for non-inline types to the blob metadata, and correct the deploy note. Pinned by `TestStoreDiskExtension` rows "html named txt" and "js under octet-stream".
|
||||
- Redis outage latency (follow-up from 19.3-01 now pinned by tests): `TestRateLimitFallbackOnError` asserts a rate-limit attempt against a stopped Redis answers from the fallback within `AttemptTimeout` (about 500 ms per throttled request during an outage). `Cache.Remember` on the Redis driver has no internal bound: against a stopped Redis it waits for go-redis's dial retries (about 1.7 s, five dial attempts) unless the caller's context has a deadline, and go-redis logs `failed to dial after 5 attempts` to stderr on every failing call, outside slog and the once-per-minute warner. A follow-up could bound Remember's read and write (as Attempt does), lower `MaxRetries`/dial timeout in `OpenRedis`, and route go-redis's logger through slog.
|
||||
- Coverage note: the plugins' `purgeSiteCache` branch "inside a save transaction but no purger configured" cannot be reached from a unit test, because cabana has no exported way to put a transaction in a context (`withTx` is internal). The plugins' Docker admin suites run every save through it without purge keys; a test-only helper in cabana (like `cabana.WithFieldWrites`) would let a unit test reach it.
|
||||
|
||||
Reference in New Issue
Block a user