docs(16-05): Phase 16 validation sign-off

Per-task rows bound to their plan tasks with threat refs, all green after
scripts/check-phase16.sh --all; Wave 0 ticked; nyquist_compliant: true.
This commit is contained in:
2026-10-09 20:16:02 +02:00
parent c5e03f4a3a
commit a8c65bc71a

View File

@@ -3,10 +3,11 @@ phase: "16"
slug: "grzybyfunkcjonalne-pl-on-reusable-blog-views"
# status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6)
# audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117)
status: draft
nyquist_compliant: false
wave_0_complete: false
status: validated
nyquist_compliant: true
wave_0_complete: true
created: "2026-10-09"
validated: "2026-10-09"
---
# Phase 16 — Validation Strategy
@@ -41,20 +42,24 @@ Testable logic lives in pure TS under `app/utils/` (no `.vue` imports), because
## Per-Task Verification Map
Seeded from RESEARCH.md § Validation Architecture; the planner binds task IDs.
Built by the named plan tasks; the tests land in 16-05 (CLAUDE.md rule 3). Commands run from the repo named in brackets; `scripts/check-phase16.sh --all` (summercms.go) runs every row except the staging smoke.
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| TBD | TBD | TBD | SC-2 | — | route config: defaults, overrides, `false` disables, invalid path rejected | unit | `node --test tests/routes.test.ts` (layer) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-2 | — | client builds query (`page`, `per_page` clamp ≤30, `category`, `include_empty`), parses envelope | unit | `node --test tests/client.test.ts` (layer) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-2 | — | pagination: page validity, prev/next, 404 on out-of-range | unit | `node --test tests/pagination.test.ts` (layer) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-2 | stored XSS | HTML gate rejects the same 3 patterns as Go `FormatHTML` | unit | `node --test tests/htmlGate.test.ts` (layer) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-3 | — | sitemap entries from posts + categories use route config | unit | `node --test tests/sitemap.test.ts` (layer) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-1 | admin exposure | host boots with `backend.uri: /gfadmin`; `/backend` 404 | unit/boot | `go test ./... -run TestBoot` (host) | ✅ extend `boot_test.go` | ⬜ pending |
| TBD | TBD | TBD | SC-1 | — | featured-image migration: map parse, blob key, row fields, idempotent skip | unit | `go test ./... -run FeaturedImages` (host) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-1 | uploaded-file XSS | deploy configs: `nginx -t`, supervisor parse, storage extension allowlist | config check | `scripts/check-deploy.sh` (host) | ❌ adapt | ⬜ pending |
| TBD | TBD | TBD | SC-1 | — | built Nuxt server renders `/`, `/blog`, a post, a category against fixture API | integration | `node --test tests/ssr.test.ts` (app) | ❌ W0 | ⬜ pending |
| TBD | TBD | TBD | SC-3 | — | every old URL → expected status; canonical keeps `?page=N`; `/rss.xml` is RSS | smoke | `scripts/smoke.sh https://<staging>` (host) | ❌ W0 | ⬜ pending |
| 16-01-T2/T4, 16-05-T2 | 01, 05 | 1, 5 | SC-2 | — | route config: defaults, overrides, `false` disables, invalid path rejected naming `journal.routes.<key>`; path filling encodes per segment (D-06) | unit | `node --test tests/routes.test.ts` (layer) | ✅ | ✅ green |
| 16-01-T3, 16-05-T2 | 01, 05 | 1, 5 | SC-2 | — | client builds query (`page`, `per_page` clamp 1..30, `category`, `tag`), `include_empty=1` on every categories request (D-24), 404 → null, 500 rethrown | unit | `node --test tests/client.test.ts` (layer) | ✅ | ✅ green |
| 16-01-T3, 16-05-T2 | 01, 05 | 1, 5 | SC-2 | — | pagination: page validity, 404 on `0`/`-1`/`1.5`/`abc`/arrays and out-of-range, page window | unit | `node --test tests/pagination.test.ts` (layer) | ✅ | ✅ green |
| 16-01-T2, 16-05-T2 | 01, 05 | 1, 5 | SC-2 | T-16-01 | HTML gate rejects the Go `FormatHTML` cases (script, iframe, event handler, `javascript:`, `vbscript:`, `data:`, upper case too); headings, tables, links pass | unit | `node --test tests/htmlGate.test.ts` (layer) | ✅ | ✅ green |
| 16-01-T4, 16-05-T2 | 01, 05 | 1, 5 | SC-3 | — | sitemap entries from posts + categories use `journal.routes` (custom `/:category`, disabled routes, nested categories, lastmod) (D-06, D-13); SEO description fallback, absolute og:image, list titles; pl/en key and placeholder parity (D-16) | unit | `node --test tests/sitemap.test.ts tests/seo.test.ts tests/i18n.test.ts` (layer) | ✅ | ✅ green |
| 16-03-T1, 16-05-T3 | 03, 05 | 3, 5 | SC-1 | T-16-10 | host boots with `backend.uri: /gfadmin`; `cabana.AdminPrefix` is `/gfadmin`; admin routes under `/gfadmin/`, none under `/backend` (D-09); grzyby commands registered | unit/boot | `go test ./... -run '^(TestBootUserTranslateJournal\|TestBackendURIGfadmin\|TestGrzybyCommandsRegistered)$'` (host) | ✅ | ✅ green |
| 16-03-T1, 16-05-T3 | 03, 05 | 3, 5 | SC-1 | T-16-12 | featured-image migration: map parse, disk-name validation, traversal refused before any read, blob at `attach.BlobKey`, `system_files` row fields, idempotent skip, base slug through the export, type/size/sniff failures, dry run (D-22) | unit + DB | `go -C plugins/grzyby test ./... -race -run 'FeaturedImage\|DiskName'` (host, `GRZYBY_TEST_ADMIN_DSN` or Docker) | ✅ | ✅ green |
| 16-03-T2, 16-05-T3 | 03, 05 | 3, 5 | SC-1 | — | category import: pl values preferred, `content` written (D-21), unchanged rerun, unknown slug failed, dry run | unit + DB | `go -C plugins/grzyby test ./... -race -run 'Categor'` (host) | ✅ | ✅ green |
| 16-05-T3 | 05 | 5 | SC-4 | T-16-23 | the test harness creates `grzyby_test_<random>` and drops only that database; DB tests fail, not skip, outside `-short` | unit | `go -C plugins/grzyby test ./console` (host; fails without a database) | ✅ | ✅ green |
| 16-03-T3, 16-04-T2 | 03, 04 | 3, 4 | SC-1 | T-16-11 | deploy configs: `nginx -t`, supervisor parse, storage extension allowlist with nosniff, `/backend` 404 | config check | `scripts/check-deploy.sh` (host) | ✅ | ✅ green |
| 16-02-T1, 16-05-T1 | 02, 05 | 2, 5 | SC-1, SC-3 | T-16-01, T-16-07 | built Nuxt server against the fixture API: every PHP URL form's status (D-15), static pages over `/:category`, canonical keeps `?page=N`, titles, pl only (D-16), empty category (D-24), category content (D-21), unsafe body blocked, XFF forwarded, feeds, no forms (D-14), GA only for a valid `NUXT_PUBLIC_GA_ID` (D-23) | integration | `pnpm build && node --test tests/ssr.test.ts` (app) | ✅ | ✅ green |
| 16-02-T2/T3, 16-05-T2 | 02, 05 | 2, 5 | SC-1 | T-16-07 | `gaHeadScripts` gives nothing for empty or malformed ids; FAQ has 16 entries; menu kinds and every `t()` key resolve | unit | `node --test tests/analytics.test.ts tests/content.test.ts` (app) | ✅ | ✅ green |
| 16-05-T3 | 05 | 5 | SC-4 | T-16-24 | phase gate fails closed on fail, skip, todo, no tests, missing named tests and races | gate | `scripts/check-phase16.sh --all` (summercms.go) | ✅ | ✅ green |
| 16-03-T3, 16-04-T3 | 03, 04 | 3, 4 | SC-3 | — | every old URL → expected status; canonical keeps `?page=N`; `/rss.xml` is RSS | smoke | `scripts/smoke.sh` (local rehearsal) and `scripts/smoke.sh --url https://uat.grzybyfunkcjonalne.pl` on the server (host) | ✅ | ✅ green (98 urls on staging, 16-04) |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
@@ -62,10 +67,10 @@ Seeded from RESEARCH.md § Validation Architecture; the planner binds task IDs.
## Wave 0 Requirements
- [ ] Spike: pnpm git dependency from Gitea + `extends` + `nuxt build` (RESEARCH A1, Pitfall 10)
- [ ] `vue-journal-layer/tests/` and `package.json` test script
- [ ] `vue-grzybyfunkcjonalne-app/tests/` + a fixture API (small Node `http` server serving recorded JSON) for SSR tests
- [ ] `sm-grzybyfunkcjonalne-app/scripts/urls.txt`, generated from the live sitemap (71 URLs) + static/negative cases
- [x] Spike: pnpm git dependency from Gitea + `extends` + `nuxt build` (RESEARCH A1, Pitfall 10) — 16-01 `check-git-install.sh v0.0.1`
- [x] `vue-journal-layer/tests/` and `package.json` test script — 16-05 Task 2
- [x] `vue-grzybyfunkcjonalne-app/tests/` + a fixture API (small Node `http` server serving recorded JSON) for SSR tests — layer `testing/fixture-api.mjs` (16-01), app `tests/ssr.test.ts` (16-05 Task 1)
- [x] `sm-grzybyfunkcjonalne-app/scripts/urls.txt`, generated from the live sitemap (71 URLs) + static/negative cases — 16-03 Task 3
---
@@ -81,11 +86,11 @@ Seeded from RESEARCH.md § Validation Architecture; the planner binds task IDs.
## Validation Sign-Off
- [ ] All tasks have `<automated>` verify or Wave 0 dependencies
- [ ] Sampling continuity: no 3 consecutive tasks without automated verify
- [ ] Wave 0 covers all MISSING references
- [ ] No watch-mode flags
- [ ] Feedback latency < 90s
- [ ] `nyquist_compliant: true` set in frontmatter
- [x] All tasks have `<automated>` verify or Wave 0 dependencies
- [x] Sampling continuity: no 3 consecutive tasks without automated verify
- [x] Wave 0 covers all MISSING references
- [x] No watch-mode flags
- [x] Feedback latency < 90s per touched repo (`pnpm test` in the layer under 1 s; the app's `nuxt build` plus tests about 60 s; the full gate a few minutes)
- [x] `nyquist_compliant: true` set in frontmatter
**Approval:** pending
**Approval:** approved 2026-10-09 (16-05): `scripts/check-phase16.sh --all` ended with "Phase 16 gate passed" (layer 78 tests, app 25 tests and 36 + 2 smoke checks, host 4 named boot tests, grzyby 10 tests with `-race` against a throwaway Postgres 18.6 database, check-deploy ok). The staging visual review (Manual-Only row 2) remains a human check.