From 967449bf624b4539fc90c380882937295cd201db Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sat, 10 Oct 2026 00:58:28 +0200 Subject: [PATCH] docs(16.1): add phase verification; record Docker-host suites green --- .../16.1-VALIDATION.md | 8 +- .../16.1-VERIFICATION.md | 274 ++++++++++++++++++ 2 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VERIFICATION.md diff --git a/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VALIDATION.md b/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VALIDATION.md index d407359..b4c364f 100644 --- a/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VALIDATION.md +++ b/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VALIDATION.md @@ -53,8 +53,8 @@ Pre-existing red, not caused by this phase: `scripts/check-phase10.sh --hygiene` | 16.1-02-02 | 02 | 2 | D-04 | T-16.1-07, T-16.1-08 | Uploaded binary sha256 equals the local build; previous binary kept as `.prev`; no `.env` rsynced | e2e (server) | on-server `scripts/smoke.sh --url https://uat.grzybyfunkcjonalne.pl` via loopback resolve | ✅ | ✅ green (plan 02: smoke: ok (98 urls), sha256 match) | | 16.1-02-03 | 02 | 2 | D-02, D-03 | T-16.1-09, T-16.1-10 | Read-only SQL and log checks; only posts 53 and 64 are re-saved, by a human | integration (server, read-only) | `ssh grzybyfunkcjonalne-uat "psql -X -d grzybyfunkcjonalne -tAc ..."` (raw-HTML marker count 0, post 64 footer present) | ✅ | ✅ green (plan 02: SQL check 0:1, no SQLSTATE 42703 since restart) | | 16.1-03-01 | 03 | 3 | D-01 | T-16.1-11 | Storage helpers survive disabled storage; logout clears list keys only | unit (vitest) | `npm --prefix admin test -- tests/state/listState.test.ts tests/state/useAuth.test.ts tests/list/ListView.test.ts tests/form/FormView.test.ts` | ✅ created (plan 03) | ✅ green | -| 16.1-03-02 | 03 | 3 | D-02, D-03 | T-16.1-11, T-16.1-12 | Polymorphic relations and unknown columns refused (422); search value never inlined into SQL | unit (DryRun) + Postgres (Docker host) | `go test -count=1 -run '^(TestListRelationSQL\|TestEnabledLocalesDefaultFirst)$' -v ./modules/cabana` | ✅ extend files from plan 01 | ✅ green (pure); Postgres test on a Docker host: manual | -| 16.1-03-03 | 03 | 3 | D-03 | T-16.1-02, T-16.1-11 | Every unsafe case is sanitized (bluemonday, post-review CR-01 fix), scheme-like text and raw HTML survive, CheckHTML refuses unsafe category HTML | unit + journal harness (Docker host) | `go -C ../sm-journal-plugin test -count=1 -run '^(TestFormatHTMLSanitizesUnsafeHTML\|TestFormatHTMLKeepsSchemeLikeText\|TestFormatHTMLKeepsRawHTML\|TestCheckHTML)$' -v ./classes/` (four top-level PASS lines) | ✅ extend | ✅ green (pure); harness re-save test on a Docker host: manual | +| 16.1-03-02 | 03 | 3 | D-02, D-03 | T-16.1-11, T-16.1-12 | Polymorphic relations and unknown columns refused (422); search value never inlined into SQL | unit (DryRun) + Postgres (Docker host) | `go test -count=1 -run '^(TestListRelationSQL\|TestEnabledLocalesDefaultFirst)$' -v ./modules/cabana` | ✅ extend files from plan 01 | ✅ green (pure); ✅ Postgres green on Docker 2026-10-09/10 | +| 16.1-03-03 | 03 | 3 | D-03 | T-16.1-02, T-16.1-11 | Every unsafe case is sanitized (bluemonday, post-review CR-01 fix), scheme-like text and raw HTML survive, CheckHTML refuses unsafe category HTML | unit + journal harness (Docker host) | `go -C ../sm-journal-plugin test -count=1 -run '^(TestFormatHTMLSanitizesUnsafeHTML\|TestFormatHTMLKeepsSchemeLikeText\|TestFormatHTMLKeepsRawHTML\|TestCheckHTML)$' -v ./classes/` (four top-level PASS lines) | ✅ extend | ✅ green (pure); ✅ harness re-save green on Docker 2026-10-09/10 | *Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* @@ -94,7 +94,7 @@ Pre-existing red, not caused by this phase: `scripts/check-phase10.sh --hygiene` - Quick Go commands: four top-level `--- PASS` lines for `TestListRelationSearchSmoke`, `TestListRelationSQL`, `TestEnabledLocalesDefaultFirst` and `TestEnabledLocalesDefaultFirstSmoke`; `go -C ../sm-journal-plugin test -count=1 ./classes/` ok, with four top-level `--- PASS` lines for `TestFormatHTMLSanitizesUnsafeHTML`, `TestFormatHTMLKeepsSchemeLikeText`, `TestFormatHTMLKeepsRawHTML` and `TestCheckHTML` (updated 2026-10-10 after the CR-01 fix replaced `TestFormatHTMLRejectsUnsafeHTML`). - Full local suite: `go vet ./...`, `go -C ../sm-journal-plugin vet ./...`, `TestDocsTree`, `npm --prefix admin run typecheck`, `npm --prefix admin test` (76 files, 1144 tests) and `scripts/check-admin-dist.sh` ("dist matches a fresh build") printed `phase-16.1-local-gate-ok`. -- Docker-host suites: still pending (manual row above). `TestListRelationSearchPostgres` and `TestPostsAdminResaveKeepsHTML` fail here with "failed to create Docker provider", as designed (fail, not skip). +- Docker-host suites: still pending at plan 03 time (`TestListRelationSearchPostgres` and `TestPostsAdminResaveKeepsHTML` failed with "failed to create Docker provider", as designed). **Update 2026-10-10:** after the golem user joined the docker group, the full `go test -count=1 ./...` passed with Docker in summercms.go (37 packages, before and after cd25af0, and again for the v0.1.17 release) and in sm-journal-plugin, including `TestListQueryContract`, `TestListRelationSearchPostgres`, `TestPostsAdminResaveKeepsHTML` and the translation harness tests; the verifier re-ran them. - Manual UAT rows: the plan 02 executor confirmed posts 53 and 64 by read-only SQL. The list-state, form-locale and search checks were reported by the human before the re-saves reached UAT, so they stay open for `/msd-verify-work`. -**Approval:** pending (Docker-host suites and the manual UAT rows) +**Approval:** pending (manual UAT rows only; Docker-host suites green 2026-10-10) diff --git a/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VERIFICATION.md b/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VERIFICATION.md new file mode 100644 index 0000000..8e902c5 --- /dev/null +++ b/.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-VERIFICATION.md @@ -0,0 +1,274 @@ +--- +phase: 16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f +verified: 2026-10-09T23:05:00Z +status: human_needed +score: 32/33 must-haves verified +covered_files: + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-01-PLAN.md + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-01-SUMMARY.md + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-02-PLAN.md + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-02-SUMMARY.md + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-03-PLAN.md + - .planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-03-SUMMARY.md + - admin/src/main.ts + - admin/src/state/listState.ts + - admin/src/state/useAuth.ts + - admin/src/state/useSidebar.ts + - admin/src/views/ListView.vue + - admin/tests/form/FormView.test.ts + - admin/tests/list/ListView.test.ts + - admin/tests/smoke/list.smoke.test.ts + - admin/tests/state/listState.test.ts + - admin/tests/state/useAuth.test.ts + - docs/backend/forms.md + - docs/backend/lists-and-filters.md + - modules/cabana/README.md + - modules/cabana/http.go + - modules/cabana/locale_order_test.go + - modules/cabana/query.go + - modules/cabana/query_relation_test.go + - modules/phrasebook/backend/lang/en/lang.yaml + - modules/phrasebook/backend/lang/pl/lang.yaml + - scripts/check-phase10.sh +covered_digest: "v2:sha256:7e043180d992853a3d04039e3304ee81d631fc8574eeec0e96264b3b6ad7873d" +behavior_unverified: 0 +overrides_applied: 0 +human_verification: + - test: "Install the hardened staging vhost as root: copy /srv/grzybyfunkcjonalne/deploy/grzybyfunkcjonalne-staging.conf (host commits fc10094, 387d0f4) over /etc/nginx/sites-available/uat.grzybyfunkcjonalne.pl, run sudo nginx -t, reload nginx, and compare sha256 of the installed and uploaded copies" + expected: "nginx -t passes; curl -sI https://uat.grzybyfunkcjonalne.pl/ (on the server, resolved to loopback) shows Content-Security-Policy-Report-Only, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy; /gfadmin keeps its auth_basic exemption; smoke.sh --url still ends 'smoke: ok ('" + why_human: "Needs root on the UAT server. Read-only check on 2026-10-09 23:00 UTC: the uploaded file has the CSP Report-Only header (count 1), the enabled vhost does not (count 0)" + - test: "UAT posts list search: in /gfadmin/golem15/journal/posts search 'cordyceps' (a category name)" + expected: "Rows appear; no 'The list could not be loaded.'; the Go log shows no SQLSTATE 42703 after 2026/10/09 22:47:29" + why_human: "Needs UAT basic auth and an admin login. Automated proof covers the SQL on real Postgres (TestListRelationSearchPostgres) and a clean log since the restart, but the Go log does not record successful searches, so it cannot show that a search ran on the real categories pivot" + - test: "UAT list state (D-01): set a sort and a category filter, open a post, press back; repeat with save-and-close; leave through the navigation rail and return; paste the URL in a new tab; log out and in" + expected: "Sort and filter survive every return and are in the URL; the pasted URL shows the same list; after logout and login the list opens unfiltered" + why_human: "Interactive flow behind UAT basic auth; the human report ('all works') predates the re-saves and the v0.1.17 deploy (which changed the storage key to be per admin), so it is not independent confirmation of the deployed build" + - test: "UAT post form (D-03): open any imported post" + expected: "The locale selector shows pl first; title, slug, content and excerpt are filled with the stored values" + why_human: "Visual check on real data. Supporting evidence: the UAT locales table has en at sort_order 1 and the default pl at sort_order 2, the exact order the fix reorders, and enabledContentLocales is covered by 12 unit cases" + - test: "Review the nine judgment-tier prohibitions in the Prohibitions section below" + expected: "Each LLM-judge verdict (all 'not violated') is accepted or overturned" + why_human: "unverified-prohibition: judgment tier, the verifier's verdict is non-authoritative" +--- + +# Phase 16.1: Journal admin urgent fixes Verification Report + +**Phase Goal:** The Journal posts list and post form in the admin work on real imported data found on UAT. The fixes are released as a summercms tag, the host is bumped, UAT is redeployed and the staging smoke re-runs. +**Verified:** 2026-10-09T23:05:00Z +**Status:** human_needed +**Re-verification:** No, initial verification + +All code, tests, tags, pushes and the deployed binary were checked against the repositories and the UAT server (read-only). Every automated must-have holds. What remains: the nginx vhost install, which needs root, and the browser checks on UAT that only a human can run. + +## Goal Achievement + +### Observable Truths + +**Roadmap contract (success criteria derived from the goal)** + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 1 | List search no longer fails with "Server error" on a belongsToMany relation | ✓ VERIFIED | `modules/cabana/query.go:369-449` builds `EXISTS (SELECT 1 FROM pivot AS cabana_p0 JOIN related AS cabana_r0 ...)` from `stmt.Schema.Relationships.Relations[field]`. `TestListRelationSearchPostgres` passed against real Postgres (run here through the Docker sudo path). The UAT Go log has 0 `SQLSTATE 42703` lines in the 32 lines since the 22:47:29 restart. | +| 2 | List sort and filters are remembered after opening a record and going back | ✓ VERIFIED | `ListView.vue:200-221` restores the stored query before the first request. `FormView.test.ts` "returning to the list keeps its query (D-01)" covers back, cancel, save-and-close and delete. 4 files / 144 tests pass; the full suite has 76 files / 1171 tests. | +| 3 | The post form shows the stored content | ✓ VERIFIED (code) | `http.go:986-993` moves `DefaultLocale` to index 0. `TestEnabledLocalesDefaultFirst` (12 cases) passes. The UAT `golem15_translate_locales` table has `en` at sort 1 and the default `pl` at sort 2, which confirms the root cause the fix targets. The on-UAT visual check is a human item. | +| 4 | The post form shows the stored excerpt | ✓ VERIFIED (code) | Same mechanism as #3: the excerpt lives in the host column, under the default locale. | +| 5 | Released as a summercms tag | ✓ VERIFIED | `git ls-remote`: v0.1.16 is d8e3536 on d77393b; v0.1.17 is c37de45 on c21fe36. v0.1.17 contains 06d75cb, bd8626e, 9cac45c, a8bce9c, 837922c and cd25af0. | +| 6 | Host is bumped | ✓ VERIFIED | Host HEAD 0b93ac2 equals origin/master. The journal gitlink is c60abc6, equal to sm-journal-plugin origin/main. The translate gitlink is 54cf93b, the vue app gitlink is ada03b2, and go.mod requires summercms v0.1.17. | +| 7 | UAT is redeployed | ✓ VERIFIED | Server sha256 is `e5b0ad28…3af232` and `.prev` is `e1ba3587…148ceb` (the CR-01 hotfix). The Go and Nuxt processes started at 22:47:28 and 22:47:32 UTC. | +| 8 | The staging smoke re-runs | ✓ VERIFIED | I re-ran it on the server myself (loopback resolve, GETs only): `smoke: ok (98 urls)` | + +**16.1-01 must_haves** + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 9 | belongsToMany search goes through EXISTS, with names taken from GORM's parsed relationship | ✓ VERIFIED | `relationSubquery` uses `gorm.Statement.Parse` and `Relationships.Relations`. TestListRelationSQL covers custom `joinForeignKey`/`joinReferences` pivot names. | +| 10 | hasMany, hasOne and belongsTo searches are correlated EXISTS; there is no outer JOIN, so a record is counted once | ✓ VERIFIED | `applyListSearch` (query.go:476-490). TestListRelationSQL checks there is no JOIN outside the subqueries next to `user_id = 7` and `id IN (3)`. The Postgres test gives total 1 for a post matching through 2 tags. | +| 11 | A to-many sort uses `string_agg` plus the PK tiebreak; a to-one sort keeps the join | ✓ VERIFIED | query.go:313-336; TestListRelationSQL covers both directions; the Postgres test gives [2 1] and [1 2] | +| 12 | Polymorphic relations and unknown columns give 422, never 500 | ✓ VERIFIED | query.go:378-390 refuses via `rel.Polymorphic` and `PrimaryValue`; TestListRelationSQL has 5 refusal cases | +| 13 | meta.enabledLocales lists the default locale first | ✓ VERIFIED | http.go:986-993, TestEnabledLocalesDefaultFirst(Smoke) | +| 14 | FormatHTML keeps imported raw HTML and dangerous markup is not stored on any write path | ✓ VERIFIED (superseded mechanism) | The plan's "refuses" became "strips" under the accepted decision note `notes/journal-html-sanitizing-bluemonday.md`, the CR-01 fix in a3551f2, which is stronger than the planned regex gate. All three write paths call FormatHTML: posts.go:213, import_posts.go:185, posts_helpers.go:511/567. Translations go through FormatTranslation (0d00ec8). Duplicate attributes are handled in 5f47083. TestFormatHTMLKeepsRawHTML and TestFormatHTMLSanitizesUnsafeHTML pass. | +| 15 | List params stay in the URL; stored per list; an empty query is never stored | ✓ VERIFIED | `listState.ts`. The key is now `summer-admin.list::` (the WR-03 fix in cd25af0 is stricter than the plan's key). `writeListState` removes the key on an empty query. | +| 16 | Entry without params restores before the first request; URL params win; logout removes every stored query | ✓ VERIFIED | ListView.vue watch; `clearUser()` calls `setListStateOwner(null)`, which removes all list keys. `main.ts:27` sends `onUnauthorized` to `expireSession`. Covered by vitest. | +| 17 | Commits staged by path, holding only this plan's files; the journal commit in its own repo | ✓ VERIFIED | `git show --name-only` for 06d75cb, bd8626e and 9cac45c matches the plan. The one extra file in 9cac45c (`list.smoke.test.ts`) is a documented deviation. 528d2d8 is in sm-journal-plugin. | +| 18 | go vet clean; smoke tests, vitest, TestDocsTree and the dist check green | ✓ VERIFIED | Re-run here: `go vet ./...` ok, both repos' vet ok, TestDocsTree ok, `check-admin-dist.sh` printed "matches a fresh build", vitest 1171/1171 | + +**16.1-02 must_haves** + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 19 | An annotated tag containing every 16.1-01 commit is on origin | ✓ VERIFIED | v0.1.16 and v0.1.17 are both on origin (see #5) | +| 20 | sm-journal-plugin main with the require is on origin; the host gitlink points at it; README and DEPLOY.md lost the re-save warning | ✓ VERIFIED | c60abc6 equals origin/main and requires v0.1.17. Host gitlink c60abc6. `grep -ci 'omitted\|re-sav'` gives 0 in both README.md and DEPLOY.md. | +| 21 | UAT runs the build; sha256 matches; both programs run; `.prev` kept; smoke ok | ✓ VERIFIED | See #7 and #8. I could not compare against the local build byte for byte; the server hash matches the release record. | +| 22 | After the restart, no SQLSTATE 42703 (and search returns rows) | ✓ VERIFIED (log + Postgres test) | 0 in 32 lines since 22:47:29. The human search on UAT is a human item. | +| 23 | Posts 53 and 64 repaired: no placeholder, post 64 has its footer | ✓ VERIFIED | Read-only psql now prints `0:1`. The public page `/blog/ekstrakt-z-turkey-tail` renders `