From ebedba8c94560f502f6bfc3851af024c8c9dbb72 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sun, 18 Oct 2026 16:11:13 +0200 Subject: [PATCH] docs(19.1): persist verification, UAT and review disposition --- .../19.1-REVIEW-DISPOSITION.md | 62 +++++ .../phases/19.1-chat-satellites/19.1-UAT.md | 32 +++ .../19.1-chat-satellites/19.1-VERIFICATION.md | 252 ++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 .planning/phases/19.1-chat-satellites/19.1-REVIEW-DISPOSITION.md create mode 100644 .planning/phases/19.1-chat-satellites/19.1-UAT.md create mode 100644 .planning/phases/19.1-chat-satellites/19.1-VERIFICATION.md diff --git a/.planning/phases/19.1-chat-satellites/19.1-REVIEW-DISPOSITION.md b/.planning/phases/19.1-chat-satellites/19.1-REVIEW-DISPOSITION.md new file mode 100644 index 00000000..dc063e17 --- /dev/null +++ b/.planning/phases/19.1-chat-satellites/19.1-REVIEW-DISPOSITION.md @@ -0,0 +1,62 @@ +--- +phase: 19.1 +review: 19.1-REVIEW.md +titles: json +findings: + - id: WR-01 + severity: warning + disposition: open + title: "LiveKit RoomService never uses the TrustedMode fetchguard client" + - id: WR-02 + severity: warning + disposition: open + title: "Start commits an active session before CreateRoom succeeds" + - id: WR-03 + severity: warning + disposition: open + title: "Reconcile ends empty rooms with no grace, including ringing calls" + - id: WR-04 + severity: warning + disposition: open + title: "Generic chatbots dispatch ignores IsAvailable" + - id: WR-05 + severity: warning + disposition: open + title: "Chatvideo starter delete cascades the whole session and skips LiveKit cleanup" + - id: IN-01 + severity: info + disposition: open + title: "Forum SetAccessResolver is a silent no-op before Boot" + - id: IN-02 + severity: info + disposition: open + title: "screen_share config is copied and never applied to tokens" + - id: IN-03 + severity: info + disposition: open + title: "Herald Deliver swallows every per-subscription send error" + - id: IN-04 + severity: info + disposition: open + title: "Group invite created_by has no FK and is not cleared on user delete" +open: 9 +total: 9 +recorded: 2026-10-18T14:16:00Z +--- + +# Phase 19.1: Code Review Disposition + +| Finding | Severity | Disposition | Source | +|---------|----------|-------------|--------| +| WR-01 | warning | open | 19.1-REVIEW.md | +| WR-02 | warning | open | 19.1-REVIEW.md | +| WR-03 | warning | open | 19.1-REVIEW.md | +| WR-04 | warning | open | 19.1-REVIEW.md | +| WR-05 | warning | open | 19.1-REVIEW.md | +| IN-01 | info | open | 19.1-REVIEW.md | +| IN-02 | info | open | 19.1-REVIEW.md | +| IN-03 | info | open | 19.1-REVIEW.md | +| IN-04 | info | open | 19.1-REVIEW.md | + +Dispositions: `open` (recorded, not yet triaged), `fixed`, `skipped`, `deferred`. +Set `deferred` by hand and put the reason in the Source cell; both are preserved. diff --git a/.planning/phases/19.1-chat-satellites/19.1-UAT.md b/.planning/phases/19.1-chat-satellites/19.1-UAT.md new file mode 100644 index 00000000..7403033b --- /dev/null +++ b/.planning/phases/19.1-chat-satellites/19.1-UAT.md @@ -0,0 +1,32 @@ +--- +status: testing +phase: 19.1-chat-satellites +source: [19.1-VERIFICATION.md] +started: 2026-10-18T14:10:42.648Z +updated: 2026-10-18T14:10:42.648Z +--- + +## Current Test + +number: 1 +name: Accept an override that ../sm-userfriends-plugin/go.mod may require sm-chat-plugin so Boot can Lookup[*chatcontracts.Registry], while Plugin.Requires() stays []string{"golem15.user"} only. +expected: | + Override recorded. No code change. Removing the go.mod require would make the D-08 soft adapter uncompilable. +awaiting: user response + +## Tests + +### 1. Accept an override that ../sm-userfriends-plugin/go.mod may require sm-chat-plugin so Boot can Lookup[*chatcontracts.Registry], while Plugin.Requires() stays []string{"golem15.user"} only. +expected: Override recorded. No code change. Removing the go.mod require would make the D-08 soft adapter uncompilable. +result: [pending] + +## Summary + +total: 1 +passed: 0 +issues: 0 +pending: 1 +skipped: 0 +blocked: 0 + +## Gaps diff --git a/.planning/phases/19.1-chat-satellites/19.1-VERIFICATION.md b/.planning/phases/19.1-chat-satellites/19.1-VERIFICATION.md new file mode 100644 index 00000000..0c9ad157 --- /dev/null +++ b/.planning/phases/19.1-chat-satellites/19.1-VERIFICATION.md @@ -0,0 +1,252 @@ +--- +phase: 19.1-chat-satellites +verified: 2026-10-18T14:15:00Z +status: human_needed +score: 16/16 must-haves verified +covered_files: + - .planning/ROADMAP.md + - .planning/notes/2026-10-18-bluemonday-forum-policy.md + - .planning/notes/2026-10-18-livekit-server-sdk-go.md + - .planning/notes/2026-10-18-webpush-go.md + - .planning/phases/19.1-chat-satellites/19.1-01-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-01-SUMMARY.md + - .planning/phases/19.1-chat-satellites/19.1-02-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-02-SUMMARY.md + - .planning/phases/19.1-chat-satellites/19.1-03-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-03-SUMMARY.md + - .planning/phases/19.1-chat-satellites/19.1-04-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-04-SUMMARY.md + - .planning/phases/19.1-chat-satellites/19.1-05-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-05-SUMMARY.md + - .planning/phases/19.1-chat-satellites/19.1-06-PLAN.md + - .planning/phases/19.1-chat-satellites/19.1-06-SUMMARY.md + - README.md + - docs/services/markdown.md + - modules/breakwater/README.md + - modules/breakwater/breakwater.go + - modules/breakwater/breakwater_test.go + - modules/breakwater/example_test.go + - scripts/check-phase19.1.sh +covered_digest: "v2:sha256:2311abea5e82d375f2b20a2ae8ba39cb0849574ac0d8cdfc27ac48b689d72069" +behavior_unverified: 0 +overrides_applied: 0 +decision_coverage: + honored: 18 + total: 18 + not_honored: [] +human_verification: + - test: "Accept an override that ../sm-userfriends-plugin/go.mod may require sm-chat-plugin so Boot can Lookup[*chatcontracts.Registry], while Plugin.Requires() stays []string{\"golem15.user\"} only." + expected: "Override recorded. No code change. Removing the go.mod require would make the D-08 soft adapter uncompilable." + why_human: "Plan 01 prohibition literally says go.mod never require sm-chat-plugin. The same plan's D-08 truth requires a typed Lookup of the chat Registry. Those two statements cannot both be true in Go. Implementation honors D-08 (Requires() is user-only; missing chat is a skip). A human must accept the deviation." +--- + +# Phase 19.1: Chat satellites Verification Report + +**Phase Goal:** The remaining shared plugins that Wavepath's app plugin requires run on SummerCMS: chatbots, chatvideo, forum, herald and userfriends. +**Verified:** 2026-10-18T14:15:00Z +**Status:** human_needed +**Re-verification:** No — initial verification + +Roadmap `**Mode:** mvp` is set, but the ROADMAP goal is not a user-story sentence (`user-story.validate` → `false`). Verification proceeded because execute-phase `verify_phase_goal` asked for this report and each plan already carries an application-mounts-satellites user story. A `/msd mvp-phase 19.1` rewrite of the ROADMAP goal is optional bookkeeping, not a code gap. + +This is an infrastructure/plugin-port phase (sibling repos, generic JWT APIs, no end-user UI). Human verification is therefore limited to the one planner-prohibition contradiction below — not invented UI walkthroughs. + +## User Flow Coverage + +Aggregated from the six plan user stories (ROADMAP goal is not a user story): + +| Step | Expected | Evidence | Status | +|------|----------|----------|--------| +| Mount Friends | Host binds no extra seam; JWT `/_userfriends/api/v1` request/accept/list works | `../sm-userfriends-plugin/routes.go`; `TestHTTPTracer` passed (postgres) | ✓ | +| Mount Forum | Host binds `ForumAccessResolver`; context-scoped categories; GFM stored, XSS stripped | `../sm-forum-plugin/routes.go`; `breakwater.Render` on write; `TestHTTPTracer` passed | ✓ | +| Mount Chat bots | Host registers slash commands; dispatch invoker is the JWT actor | `../sm-chatbots-plugin/api/commands.go` uses `actor()` / `bouncer.User`; `TestHTTPTracer` passed | ✓ | +| Mount Herald | Host stores subscriptions and sends Web Push without PHP | `../sm-herald-plugin/routes.go`; `TestHTTPTracer` + `TestSendEventRollback` passed | ✓ | +| Mount Chat video | Host starts/joins/ends conversation video; stale sessions reconcile | `../sm-chatvideo-plugin/routes.go`; `TestHTTPTracer` + `TestReconcileEmptyRoom` passed | ✓ | +| Fail-closed gate | Skipped/missing named tests fail `scripts/check-phase19.1.sh` | `--self-test`, `--plugins`, `--docs`, `--postgres` all exit 0 this session | ✓ | + +## Goal Achievement + +### Observable Truths + +Merged from ROADMAP success criteria (SC-19.1-1..4) plus PLAN `must_haves.truths` (D-01..D-18). Roadmap wording kept where a plan restated an SC. + +| # | Truth | Status | Evidence | +| --- | ------- | ---------- | -------------- | +| 1 | SC-19.1-1: each plugin ports schema, models, routes and events 1:1 against its PHP original | ✓ VERIFIED | Five sibling repos exist with Winter layout, `202610180001_create_golem15_*_baseline`, models, JWT routes, and (where applicable) festival/lighthouse events. PHP method maps: userfriends 31, forum 25, chatbots 22, herald 14 declarations / 13 unique, chatvideo 0 in-plugin + Wavepath generic-or-N/A. | +| 2 | SC-19.1-2: webpush-go, LiveKit, and bluemonday decision notes exist and name the locked modules/versions | ✓ VERIFIED | `.planning/notes/2026-10-18-webpush-go.md` (`SherClockHolmes/webpush-go` v1.4.0); `2026-10-18-livekit-server-sdk-go.md` (`server-sdk-go/v2` v2.19.0, pion/media-sdk/buildkit flag); `2026-10-18-bluemonday-forum-policy.md` (v1.0.27, PHP allow-list, not UGC). `check-phase19.1.sh --docs` passed. | +| 3 | SC-19.1-3: ROADMAP marks criterion 3 already met; fonoteka.go has no userfriends port | ✓ VERIFIED | ROADMAP criterion 3 text is the “already met” wording; Repos line names `summercms.go`. Grep of `../fonoteka.go` for `userfriends` / `golem15.userfriends` returned no matches. | +| 4 | SC-19.1-4 / D-04: last plan delivers unit tests, PHP method maps, goldens, fail-closed gate | ✓ VERIFIED | `TestPHPMethodMap` ×5, goldens in all five repos, `scripts/check-phase19.1.sh` self-test/plugins/docs/postgres all green this session. | +| 5 | D-01: module paths, plugin IDs, Requires() match the frozen contract | ✓ VERIFIED | `golem15.userfriends` Requires `golem15.user` only; `golem15.forum` Requires user; `golem15.chatbots` Requires chat+user (no AI plugin; `TestNoGolem` passed); `golem15.herald` Requires empty; `golem15.chatvideo` Requires chat. | +| 6 | D-02: one idempotent IF NOT EXISTS baseline per plugin; demo-seed IDs are comments | ✓ VERIFIED | Baseline IDs `202610180001_create_golem15_{userfriends,forum,chatbots,herald,chatvideo}_baseline`. Userfriends comment records v1.0.1 demo-seed and inserts no demo rows. `TestBaseline` ×5 passed under `-short`. | +| 7 | D-03: DenyAll access seams with Boot Warn + setter; GDPR cascades | ✓ VERIFIED | Forum/chatbots/herald DenyAll + Warn + setter. `TestAccessResolverDefault`, `TestBotAuthResolverDefault`, `TestPresenceGateDefault` exist. Postgres: `TestUserDeletingHeir` (admin then member by `role ASC, created_at ASC`), `TestUserDeletionAnonymizes` (null `user_id`, keep bodies), `TestUserDeletionCascadesBotFlag`. | +| 8 | D-05: generic JWT APIs under documented prefixes; actor from token; named buckets | ✓ VERIFIED | `/_userfriends/api/v1` (`community-join` 10/min on request/join); `/_forum/api/v1/contexts/{type}/{id}/...`; `/_chatbots/api/v1` commands+dispatch; `/_herald/api/v1/push/*`; `/_chatvideo/api/v1/conversations/{id}/video/{start,join,leave,end,status}` + `/call-links/{code}` (`video-initiate` 5/min on start only). Five `TestHTTPTracer` runs passed (postgres). | +| 9 | D-06: herald ships the generic API (PHP “no routes” reversed) | ✓ VERIFIED | `routes.go` mounts subscription + vapid-public-key. README states the reversal and D-06. | +| 10 | D-07: legacy `/api/friends`, `/api/video`, Winter components, bundled JS, demo seeders not registered | ✓ VERIFIED | Userfriends and chatvideo `Routes()` only mount `/_* /api/v1`. No `FriendsList` / `VideoCall` components. Demo seeders are comments. | +| 11 | D-08: group festival events; soft chat adapter; forum `DeleteContext`; forum never imports userfriends | ✓ VERIFIED | `userfriends.GroupCreated/GroupDeleted/MemberJoined/MemberLeft`; `Fire` inside write tx; `Lookup[*chatcontracts.Registry]` skip if absent; `Requires()` omits chat. `ForumService.DeleteContext` soft-deletes the morph pair. `TestNoUserfriendsImport` passed. | +| 12 | D-10 / D-11: PublicOnly subscribe/send; enqueue on caller tx; rollback sends 0; 410/404 prune | ✓ VERIFIED | `ValidateEndpoint` rejects non-HTTPS; `NewSender` uses `fetchguard.PublicOnlyMode`; `Options.HTTPClient = s.http`; `jobs.Enqueue` on caller `tx`; `TestSendEventRollback` passed; `Deliver` prunes 404/410. No `EndpointGuard` type. | +| 13 | D-12: VAPID config keys + `herald:vapid-generate`; private key not logged | ✓ VERIFIED | `golem15.herald.vapid.{subject,public_key,private_key}`. Command prints `VAPID_PUBLIC_KEY=` / `VAPID_PRIVATE_KEY=` via `bonfire.Output`, not slog. GET vapid-public-key returns public key only. | +| 14 | D-13 / D-14 / D-15: LiveKit RoomAPI, token golden, video authorizer segment 2, 5-minute reconciler | ✓ VERIFIED | `type RoomAPI interface`; `TrustedMode` to operator URL; `parseVideoSessionChannel` splits segment 2 (`video:session:{id}`), capabilities `["prs"]`; `TestLiveKitTokenClaims` + `TestVideoAuthorizer` passed (`-short`); `chatvideo:reconcile-sessions` + `golem15.chatvideo.reconcile_sessions` MaxAttempts 1 + `Every(5 * time.Minute)`; `TestReconcileEmptyRoom` passed. Unique `active_conversation_id`, `join_code`, nullable `card_message_id`. | +| 15 | D-16 / D-17 / D-18: breakwater `Render`/`Purify`; forum write-path render; adopted `content_html` served stored | ✓ VERIFIED | `modules/breakwater` exports both funcs; forum `go.mod` has no direct bluemonday/goldmark require (indirect via summercms). `forum_service.go` / `lifecycle.go` call `breakwater.Render` on write. `api/json.go` copies stored `ContentHTML`. `TestAdoptedContentHTML` + forum `TestHTTPTracer` (table present, no `