From c5b6a8329988fa0f4601c34d01958f80d1c0eaee Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Mon, 19 Oct 2026 12:24:39 +0200 Subject: [PATCH] test(17): complete UAT - 40 passed, 0 issues --- .planning/phases/17-blog-companions/17-UAT.md | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 .planning/phases/17-blog-companions/17-UAT.md diff --git a/.planning/phases/17-blog-companions/17-UAT.md b/.planning/phases/17-blog-companions/17-UAT.md new file mode 100644 index 00000000..850a911c --- /dev/null +++ b/.planning/phases/17-blog-companions/17-UAT.md @@ -0,0 +1,289 @@ +--- +status: complete +phase: 17-blog-companions +source: [17-01-SUMMARY.md, 17-02-SUMMARY.md, 17-03-SUMMARY.md, 17-04-SUMMARY.md, 17-05-SUMMARY.md, 17-06-SUMMARY.md] +started: 2026-10-19T10:02:15Z +updated: 2026-10-19T10:24:39Z +--- + +## Current Test + +[testing complete] + +## Tests + + + +### 1. Cold Start Smoke Test +expected: On the UAT server, restart grzybyfunkcjonalne-go and the Nuxt service. Both come up without errors in the journal, and https://uat.grzybyfunkcjonalne.pl shows the homepage with the header menu and the FAQ block, and /gfadmin shows the admin login. +result: pass + +### 2. Header menu on the site +expected: Open https://uat.grzybyfunkcjonalne.pl. The header shows the PHP site's menu (main-menu). The categories entry opens a dropdown on hover and on click, listing the Journal categories, each linking to /. Esc closes the dropdown. The link to the current page is marked active. At phone width the menu collapses behind a toggle that opens and closes it. +result: pass +coverage_id: 17-05/D7 + +### 3. Homepage FAQ +expected: On the homepage, the FAQ block "what-mushrooms-can-give-you" lists the PHP site's questions. Clicking a question opens its answer and clicking again closes it. The answers read as formatted text, with no stray markup. +result: pass +coverage_id: 17-05/D7 + +### 4. Edit a menu entry in the admin +expected: In /gfadmin open Menus, then Menu entries of main-menu. Edit an entry: change its title, and for a Journal type pick the reference from the dropdown that loads after you choose the type. Save. Reload the site: the header shows the new title (the save purges the Nuxt cache). Known, not part of this check: a refused save, such as a javascript: URL, shows its error as a raw phrase key (deferred item 1 of 17-04). +result: pass +note: "First run failed against the 2026-10-12 UAT build (no save purge, 300 s page cache); passed after the 2026-10-19 redeploy." +coverage_id: 17-04/D6 + +### 5. Reorder menu entries +expected: From the Menu entries list, click Reorder. Move an entry with the mouse and with the keyboard; the page announces each move and the tree keeps parents and children together. Reload the site: the header shows the new order. +result: pass +note: "First run failed against the 2026-10-12 UAT build (no save purge, 300 s page cache); passed after the 2026-10-19 redeploy." +coverage_id: 17-02/D4 + +### 6. Edit a FAQ answer with the rich editor +expected: In /gfadmin open FAQ and the "what-mushrooms-can-give-you" entry. The questions show as repeater rows you can add, collapse, move and remove. Edit an answer in the rich editor: the toolbar (bold, italic, lists, link) works, the link popover sets a link, and the HTML view shows the markup. Type a script element in the HTML view and save: a notice says what was removed. The homepage FAQ shows the edited answer. +result: pass +coverage_id: 17-02/D1, 17-04/D6 + +### 7. Sitemap definition and settings in the admin +expected: In /gfadmin open Settings, then Sitemap. The definition form lists the items as repeater rows; add a URL item (for example /kontakt) and save. Sitemap settings open and save. https://uat.grzybyfunkcjonalne.pl/sitemap.xml lists the new URL, and in a browser it renders through the XSL stylesheet as a readable table. +result: pass +coverage_id: 17-03/D6 + + + +### 8. UAT sitemap matches the live PHP sitemap +expected: The loc set of the UAT /sitemap.xml equals the live grzybyfunkcjonalne.pl sitemap's with the host removed: all 71 live paths are present on UAT, and the only extra is /blog/uat-16-2-blog-editor, a post that exists only in UAT data. You accept that one extra as UAT data, not a difference in the plugin. +result: pass +coverage_id: 17-05/D6 + +### 9. Plugin READMEs +expected: The READMEs of sm-journal-plugin (menu item types section), sm-sitemap-plugin, sm-menu-plugin and sm-faq-plugin read correctly: API paths, example and error bodies, rate-limit buckets, host CORS paths, the Winter import workflow and the Winter adaptations are documented, and none of them names a consuming application. +result: pass +coverage_id: 17-03/D7, 17-04/D7 + + + +### 10. Typed menu item type registry: HasMenuItemTypes collected at boot by signpost.Activate in party, duplicate/empty/invalid types fail boot, layered patterns incl. PatternFrom, Resolve and ReferenceOptions +expected: Typed menu item type registry: HasMenuItemTypes collected at boot by signpost.Activate in party, duplicate/empty/invalid types fail boot, layered patterns incl. PatternFrom, Resolve and ReferenceOptions +result: pass +source: automated +coverage_id: 17-01/D1 + +### 11. Dependent dropdown (dependsOn) with GET fields/{field}/dependent-options fed by signpost.ReferenceOptions, depths, applies false for a type without references, 401 anonymous +expected: Dependent dropdown (dependsOn) with GET fields/{field}/dependent-options fed by signpost.ReferenceOptions, depths, applies false for a type without references, 401 anonymous +result: pass +source: automated +coverage_id: 17-01/D2 + +### 12. richeditor field type sanitized through seaglass on every save, clean HTML byte-identical, removals in meta.notices, non-string 422 +expected: richeditor field type sanitized through seaglass on every save, clean HTML byte-identical, removals in meta.notices, non-string 422 +result: pass +source: automated +coverage_id: 17-01/D3 + +### 13. repeater field type: nested keys only, per-row required (rows.1.title), nested richeditor sanitized, nested and top-level dependent recheck (form.dependent_invalid), row bounds +expected: repeater field type: nested keys only, per-row required (rows.1.title), nested richeditor sanitized, nested and top-level dependent recheck (form.dependent_invalid), row bounds +result: pass +source: automated +coverage_id: 17-01/D4 + +### 14. Tree reorder: config_reorder.yaml, GET/POST reorder with partition, both columns written, 409 reorder_stale for omitted or foreign nodes, 422 for cycles +expected: Tree reorder: config_reorder.yaml, GET/POST reorder with partition, both columns written, 409 reorder_stale for omitted or foreign nodes, 422 for cycles +result: pass +source: automated +coverage_id: 17-01/D5 + +### 15. Singleton controller: GET singleton first-or-create returns a stable id, list/create/delete 404, form schema singleton +expected: Singleton controller: GET singleton first-or-create returns a stable id, list/create/delete 404, form schema singleton +result: pass +source: automated +coverage_id: 17-01/D6 + +### 16. Every new route has swag annotations, regenerated admin.json/schema.d.ts, inventory entries, token classes, CSRF walk and conformance cases; docs and READMEs pass the docs checker +expected: Every new route has swag annotations, regenerated admin.json/schema.d.ts, inventory entries, token classes, CSRF walk and conformance cases; docs and READMEs pass the docs checker +result: pass +source: automated +coverage_id: 17-01/D7 + +### 17. Repeater field: add, edit nested, reorder and remove rows change form state only +expected: Repeater field: add, edit nested, reorder and remove rows change form state only +result: pass +source: automated +coverage_id: 17-02/D2 + +### 18. Dependent dropdown loads options for the sibling value and clears a stale value +expected: Dependent dropdown loads options for the sibling value and clears a stale value +result: pass +source: automated +coverage_id: 17-02/D3 + +### 19. Dist, types and phrase keys ship with the features; framework tagged v0.1.23 after human approval +expected: Dist, types and phrase keys ship with the features; framework tagged v0.1.23 after human approval +result: pass +source: automated +coverage_id: 17-02/D5 + +### 20. Journal registers its five PHP menu item types with DefaultPattern/PatternFrom, references, layered patterns, ordered per-locale alternates, nesting subtree, published filters and the x-default rule +expected: Journal registers its five PHP menu item types with DefaultPattern/PatternFrom, references, layered patterns, ordered per-locale alternates, nesting subtree, published filters and the x-default rule +result: pass +source: automated +coverage_id: 17-03/D1 + +### 21. /sitemap.xml from a stored definition (url item + registry item) equals the PHP golden byte for byte with Content-Type application/xml; 404 without a definition, empty 200 without items +expected: /sitemap.xml from a stored definition (url item + registry item) equals the PHP golden byte for byte with Content-Type application/xml; 404 without a definition, empty 200 without items +result: pass +source: automated +coverage_id: 17-03/D2 + +### 22. Url::to port (58 PHP cases), escaping, per-alternate list expansion, nesting, tiers (default rules, custom settings, off), manifest lastmod, frontend_url rewrite, BeforeAddItem skip, AddItem extra, priority precision, 50000 URL cap; tier config refusals and host replacement; manifest fail-safe +expected: Url::to port (58 PHP cases), escaping, per-alternate list expansion, nesting, tiers (default rules, custom settings, off), manifest lastmod, frontend_url rewrite, BeforeAddItem skip, AddItem extra, priority precision, 50000 URL cap; tier config refusals and host replacement; manifest fail-safe +result: pass +source: automated +coverage_id: 17-03/D3 + +### 23. sitemap:import-winter maps and drops items with a report, refuses a non-empty definition without --force, copies settings; /sitemap.xml rewrite with frontend_url; /sitemap.xsl bytes and headers; BeforeAddItem skip; sitemap:import PHP semantics +expected: sitemap:import-winter maps and drops items with a report, refuses a non-empty definition without --force, copies settings; /sitemap.xml rewrite with frontend_url; /sitemap.xsl bytes and headers; BeforeAddItem skip; sitemap:import PHP semantics +result: pass +source: automated +coverage_id: 17-03/D4 + +### 24. Sitemap admin API: singleton created once, repeater rows stored with PHP keys, 422 on a reference not offered for its type, settings form saves, 403 without golem15.sitemap.access_definitions +expected: Sitemap admin API: singleton created once, repeater rows stored with PHP keys, 422 on a reference not offered for its type, settings form saves, 403 without golem15.sitemap.access_definitions +result: pass +source: automated +coverage_id: 17-03/D5 + +### 25. FAQ admin: repeater with richeditor answers, script and onclick stripped on save with a notice under content.1.answer, locale column in the list, locale required (422, nothing written), 403 without golem15.faq.faqs +expected: FAQ admin: repeater with richeditor answers, script and onclick stripped on save with a notice under content.1.answer, locale column in the list, locale required (422, nothing written), 403 without golem15.faq.faqs +result: pass +source: automated +coverage_id: 17-04/D1 + +### 26. Menu admin: PHP beforeSave rules, D-05 type set, dependent reference recheck, url_scheme and target 422s, parent cycle, menu-scoped reorder (409 for a foreign entry), menu filter +expected: Menu admin: PHP beforeSave rules, D-05 type set, dependent reference recheck, url_scheme and target 422s, parent cycle, menu-scoped reorder (409 for a foreign entry), menu filter +result: pass +source: automated +coverage_id: 17-04/D2 + +### 27. Winter imports: FAQ locale remap by code (unknown aborts), ids kept, sequence bumped, --force/--dry-run/empty file; menu link->url and blog_categories->all-journal-categories, page subtree dropped and reported, ids and parent_id kept, sequences bumped, dry run writes nothing +expected: Winter imports: FAQ locale remap by code (unknown aborts), ids kept, sequence bumped, --force/--dry-run/empty file; menu link->url and blog_categories->all-journal-categories, page subtree dropped and reported, ids and parent_id kept, sequences bumped, dry run writes nothing +result: pass +source: automated +coverage_id: 17-04/D3 + +### 28. FAQ API: default locale, ?locale=en/pl, raw-SQL unsafe HTML served sanitized, null description, duplicate slug serves lowest id, 404 JSON for inactive, unknown slug, malformed slug, unknown and disabled locale, 429 after 120 requests per client +expected: FAQ API: default locale, ?locale=en/pl, raw-SQL unsafe HTML served sanitized, null description, duplicate slug serves lowest id, 404 JSON for inactive, unknown slug, malformed slug, unknown and disabled locale, 429 after 120 requests per client +result: pass +source: automated +coverage_id: 17-04/D4 + +### 29. Menu API: 404 JSON for unknown, inactive and malformed codes; unpublished subtree absent; sort_order then id; javascript: URL and bad target null; single type resolved title/URL; url_pattern override; list type keeps stored title/URL with stored child first then generated children (id null, parent type); ?locale=en alternates; unregistered and unresolvable entries left out; 429 after 120 requests +expected: Menu API: 404 JSON for unknown, inactive and malformed codes; unpublished subtree absent; sort_order then id; javascript: URL and bad target null; single type resolved title/URL; url_pattern override; list type keeps stored title/URL with stored child first then generated children (id null, parent type); ?locale=en alternates; unregistered and unresolvable entries left out; 429 after 120 requests +result: pass +source: automated +coverage_id: 17-04/D5 + +### 30. Host boots the three plugins from their pushed repositories, imports fixture exports, and serves the menu with Journal categories at /, the sanitized FAQ and the sitemap +expected: Host boots the three plugins from their pushed repositories, imports fixture exports, and serves the menu with Journal categories at /, the sanitized FAQ and the sitemap +result: pass +source: automated +coverage_id: 17-05/D1 + +### 31. vue-menu-layer and vue-faq-layer: typed clients, MenuNav and FaqBlock, URL allowlist and rel noopener tests, SSR smokes, tag v0.1.0 on origin +expected: vue-menu-layer and vue-faq-layer: typed clients, MenuNav and FaqBlock, URL allowlist and rel noopener tests, SSR smokes, tag v0.1.0 on origin +result: pass +source: automated +coverage_id: 17-05/D2 + +### 32. Site app renders MenuNav in the header and FaqBlock on the homepage, app menu and FAQ data deleted, Nuxt sitemap disabled +expected: Site app renders MenuNav in the header and FaqBlock on the homepage, app menu and FAQ data deleted, Nuxt sitemap disabled +result: pass +source: automated +coverage_id: 17-05/D3 + +### 33. UAT serves /sitemap.xml, /sitemap.xsl, /_menu/ and /_faq/ from Go through nginx with the server-level security headers, GET and HEAD only, and the full smoke passes +expected: UAT serves /sitemap.xml, /sitemap.xsl, /_menu/ and /_faq/ from Go through nginx with the server-level security headers, GET and HEAD only, and the full smoke passes +result: pass +source: automated +coverage_id: 17-05/D4 + +### 34. Winter menu, FAQ and sitemap rows exported read-only and imported on UAT by the ordered import step +expected: Winter menu, FAQ and sitemap rows exported read-only and imported on UAT by the ordered import step +result: pass +source: automated +coverage_id: 17-05/D5 + +### 35. Fail-closed phase gate over eight repositories with detectors proven on planted output; --all ends with 'Phase 17 gate passed' +expected: Fail-closed phase gate over eight repositories with detectors proven on planted output; --all ends with 'Phase 17 gate passed' +result: pass +source: automated +coverage_id: 17-06/D1 + +### 36. Framework unit tests: signpost activation, pattern layers and ReferenceOptions; seaglass byte stability, report and bypass corpus; pact contracts; the party hook; cabana repeater, dependent dropdown, richeditor, reorder and singleton compile and routes; conformance of the new routes' success and error answers +expected: Framework unit tests: signpost activation, pattern layers and ReferenceOptions; seaglass byte stability, report and bypass corpus; pact contracts; the party hook; cabana repeater, dependent dropdown, richeditor, reorder and singleton compile and routes; conformance of the new routes' success and error answers +result: pass +source: automated +coverage_id: 17-06/D2 + +### 37. Admin SPA specs for the UI-SPEC backstops: richeditor untouched value, link popover, notices, chunk failure; repeater bounds, remove and reorder, collapsed rows; dependent dropdown states and last request wins; reorder announcements, partition switch, tree rules; singleton form +expected: Admin SPA specs for the UI-SPEC backstops: richeditor untouched value, link popover, notices, chunk failure; repeater bounds, remove and reorder, collapsed rows; dependent dropdown states and last request wins; reorder announcements, partition switch, tree rules; singleton form +result: pass +source: automated +coverage_id: 17-06/D3 + +### 38. Plugin unit tests: Journal menu item types, sitemap parity (Url::to goldens, escaping, fillable, tiers, rewrite, hooks, manifest, item JSON, cap, backend URL), menu links, tree and model, FAQ decode, model and serializer; Postgres APIs, imports and beforeSave +expected: Plugin unit tests: Journal menu item types, sitemap parity (Url::to goldens, escaping, fillable, tiers, rewrite, hooks, manifest, item JSON, cap, backend URL), menu links, tree and model, FAQ decode, model and serializer; Postgres APIs, imports and beforeSave +result: pass +source: automated +coverage_id: 17-06/D4 + +### 39. Host wiring and layers: TestCompanionsHost with CORS preflight and sitemap headers; menu and FAQ layer link rules, clients and composable bases +expected: Host wiring and layers: TestCompanionsHost with CORS preflight and sitemap headers; menu and FAQ layer link rules, clients and composable bases +result: pass +source: automated +coverage_id: 17-06/D5 + +### 40. Filled 17-VALIDATION.md: every row with task IDs, gate commands, File Exists and status; Wave 0 ticked; manual rows keep the plan 05 human check +expected: Filled 17-VALIDATION.md: every row with task IDs, gate commands, File Exists and status; Wave 0 ticked; manual rows keep the plan 05 human check +result: pass +source: automated +coverage_id: 17-06/D6 + +## Summary + +total: 40 +passed: 40 +issues: 0 +pending: 0 +skipped: 0 +blocked: 0 + +## Gaps + +- gap_id: G-17-4 + truth: "In /gfadmin open Menus, then Menu entries of main-menu. Edit an entry: change its title, and for a Journal type pick the reference from the dropdown that loads after you choose the type. Save. Reload the site: the header shows the new title (the save purges the Nuxt cache). Known, not part of this check: a refused save, such as a javascript: URL, shows its error as a raw phrase key (deferred item 1 of 17-04)." + status: resolved + resolved_by: UAT redeploy 2026-10-19 (host master, cache purge from 19.3-04) + resolved_at: 2026-10-19 + reason: "User reported: didn't work. changed Grzyby Funkcjonalne to Grzyby and uat.grzybyfunkcjonalne.pl still shows Grzyby Funkcjonalne. two options - actually nothing got deployed and I'm testing old hardcoded faq and navigation, or there is this painful 60s cache" + severity: major + test: 4 + root_cause: "Not a code gap: UAT runs the 2026-10-12 build (17-05). The save worked (menu API returned the new title) and the page showed it once the Nuxt swr cache (s-maxage=300) expired, as the user later confirmed. The save-triggered purge exists since 19.3-04 (sm-menu-plugin 559d96b, sm-faq-plugin c60ae6e, host d604509/85939c3) but was never deployed to UAT." + artifacts: + - path: "../sm-grzybyfunkcjonalne-app (UAT /srv/grzybyfunkcjonalne/go/bin, 2026-10-12)" + issue: "deployed binary predates the site-cache purge" + missing: + - "Redeploy UAT from current host master, then re-run tests 4 and 5" +- gap_id: G-17-5 + truth: "From the Menu entries list, click Reorder. Move an entry with the mouse and with the keyboard; the page announces each move and the tree keeps parents and children together. Reload the site: the header shows the new order." + status: resolved + resolved_by: UAT redeploy 2026-10-19 (host master, cache purge from 19.3-04) + resolved_at: 2026-10-19 + reason: "User reported: failed, nothing happened, and my name change from previous step still doesn't appear. switching you to manual mode, confirm that I'm testing proper deployment" + severity: major + test: 5 + root_cause: "Same as G-17-4: the reorder saved and appeared on the site after the swr TTL; the deployed UAT build has no save-triggered purge." + artifacts: [] + missing: + - "Redeploy UAT from current host master, then re-run tests 4 and 5"