From 374088eccfe1359a84ea3fbbcf37de159d0fc1c8 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sun, 18 Oct 2026 15:43:18 +0200 Subject: [PATCH] docs(19.1-02): complete forum tracer plan --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 18 +- .planning/WINDOWS.md | 34 ++- .../19.1-chat-satellites/19.1-02-SUMMARY.md | 241 ++++++++++++++++++ .planning/state.json | 2 +- 5 files changed, 287 insertions(+), 14 deletions(-) create mode 100644 .planning/phases/19.1-chat-satellites/19.1-02-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 4faaf97f..d746ad21 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -1235,7 +1235,7 @@ Plans: 3. Already met: fonoteka's PHP userfriends tree equals Wavepath 182b514; fonoteka.go has no port and Wavepath's copy is the single source. 4. The new code has unit tests, delivered in the phase's last plan. -**Plans:** 4/6 plans executed +**Plans:** 5/6 plans executed Plans: **Wave 1** @@ -1244,7 +1244,7 @@ Plans: - [x] 19.1-04-PLAN.md — webpush-go note, then herald subscriptions, PublicOnly send, rollback-sends-0 tracer **Wave 2** *(D-17 gate for forum; chatvideo after chat)* -- [ ] 19.1-02-PLAN.md — forum repo after D-17 Render/Purify, DeleteContext, GFM/XSS HTTP tracer +- [x] 19.1-02-PLAN.md — forum repo after D-17 Render/Purify, DeleteContext, GFM/XSS HTTP tracer - [x] 19.1-05-PLAN.md — LiveKit v2 note, then chatvideo sessions, authorizer, generic reconciler **Wave 3** *(blocked on Waves 1–2)* @@ -1434,7 +1434,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 18. Payment Gateway | 8/8 | Complete | 2026-10-14 | | 18.1. Payment Gateway Subscriptions | 9/9 | Complete | 2026-10-16 | | 19. Chat and ChatChannels | 7/7 | Complete | 2026-10-17 | -| 19.1. Chat satellites | 4/6 | In Progress| | +| 19.1. Chat satellites | 5/6 | In Progress| | | 19.2. Chat polish against WavePath clients | 0/TBD | Not started | - | | 19.3. Framework transport and infrastructure for WavePath | 6/6 | In Progress| | | 19.4. OIDC provider on wristband | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 85a9805d..0daa465f 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,16 +4,16 @@ milestone: v1.0 current_phase: "19.1" current_phase_name: Chat satellites status: executing -stopped_at: Completed 19.1-05-PLAN.md -last_updated: "2026-10-18T12:55:02.551Z" +stopped_at: Completed 19.1-02-PLAN.md +last_updated: "2026-10-18T13:42:14.977Z" last_activity: 2026-10-18 last_activity_desc: "Completed quick task 261018-k9s: add the D-17 module in summercms.go (modules/breakwater); 19.1-02 forum plan unblocked" -state_head: 98bc6de8f57fda4bd3ccc1880ba22b9ce1d6582a +state_head: 1f204f5a6c2d2289d434105e0e22f94693ae5705 progress: total_phases: 41 completed_phases: 33 total_plans: 204 - completed_plans: 202 + completed_plans: 203 gsd_state_version: "1.0" milestone_name: milestone --- @@ -30,7 +30,7 @@ See: .planning/PROJECT.md (updated 2026-10-12) ## Current Position Phase: 19.1 (Chat satellites) — EXECUTING -Plan: 4 of 6 +Plan: 5 of 6 Status: Ready to execute Last activity: 2026-10-18 — Completed quick task 261018-k9s: add the D-17 module in summercms.go (modules/breakwater); 19.1-02 forum plan unblocked @@ -255,6 +255,7 @@ Progress: [████████░░] 80% | Phase 19.1 P19.1-03 | 7 min | 3 tasks | 32 files | | Phase 19.1-chat-satellites P19.1-04 | 11 | 4 tasks | 35 files | | Phase 19.1-chat-satellites P19.1-05 | 10min | 4 tasks | 37 files | +| Phase 19.1 P19.1-02 | 9 min | 4 tasks | 36 files | ## Accumulated Context @@ -863,6 +864,9 @@ Recent decisions affecting current work: - [Phase 19.1]: Locked D-02 baseline id 202610180001_create_golem15_chatvideo_baseline and D-05 prefix /_chatvideo/api/v1; remote policy follows plan 01 proceed-and-push — These names land in adopting apps and published clients. - [Phase 19.1]: tea repos create --owner golem15 --name sm-chatvideo-plugin succeeded; main pushed at 38179b5 (never force). summercms.go was not pushed. — Remote policy is proceed-and-push after Task 4 green. - [Phase 19.1]: After APIs exist, execute should run the security-review agent (CONTEXT). This execute did not spawn it. — CONTEXT discretion; planner and execute both refuse to spawn the reviewer. +- [Phase 19.1]: Task 2 reply verbatim: proceed — Human locked D-02 baseline id 202610180001_create_golem15_forum_baseline and D-05 prefix /_forum/api/v1 before the sibling repo existed. Remote policy follows plan 01 proceed-and-push. +- [Phase 19.1]: Locked D-02 baseline id 202610180001_create_golem15_forum_baseline and D-05 prefix /_forum/api/v1; remote policy follows plan 01 proceed-and-push — Continuation recorded the lock from the human proceed reply; Task 1 and Task 2 were not re-asked. +- [Phase 19.1]: tea repos create --owner golem15 --name sm-forum-plugin succeeded; main pushed at 6a40030 (never force). summercms.go was not pushed. — Plan 01 remote policy proceed-and-push; tea-create only after Task 4 green. ### Pending Todos @@ -946,6 +950,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-10-18T12:02:32.177Z -Stopped at: Completed 19.1-05-PLAN.md +Last session: 2026-10-18T13:41:50.737Z +Stopped at: Completed 19.1-02-PLAN.md Resume file: None diff --git a/.planning/WINDOWS.md b/.planning/WINDOWS.md index d55e5f55..0115ae1c 100644 --- a/.planning/WINDOWS.md +++ b/.planning/WINDOWS.md @@ -1,10 +1,10 @@ --- schema_version: 1 -open_count: 14 +open_count: 16 waived_count: 0 fixed_count: 7 -total_count: 21 -last_updated: 2026-10-10T14:17:06.621Z +total_count: 23 +last_updated: 2026-10-18T13:42:55.096Z --- # Broken Windows Ledger @@ -36,6 +36,8 @@ last_updated: 2026-10-10T14:17:06.621Z | 19 | 16.2 | todo | .planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-05-SUMMARY.md | | 16.2-05 UAT root step: install the staging vhost with frame-src https://www.youtube-nocookie.com, nginx -t and reload; unpublish or delete test post uat-16-2-blog-editor (id 105) | open | | 2026-10-10T11:35:57.234Z | | | 20 | 16.2 | unrun-verify | modules/cabana/field_type_postgres_test.go | | 16.2-06 TestFieldTypeSavePostgres (real-database save, show, untouched and refused update, upload in and out of scope) compiles under go vet but needs a Docker host; run bash scripts/check-phase16.2.sh postgres | open | | 2026-10-10T14:17:06.378Z | | | 21 | 16.2 | unrun-verify | .planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-06-PLAN.md | | sm-journal-plugin: 16.2-06 TestCategoriesAdminBlogEditor (categories_admin_editor_test.go) and the rewritten three-stage TestPostsAdminResaveKeepsHTML compile under go vet but need a Docker host; run bash scripts/check-phase16.2.sh postgres | open | | 2026-10-10T14:17:06.621Z | | +| 22 | 19.1 | deviation | sm-forum-plugin/go.mod | | go.mod lists bluemonday and goldmark as // indirect via breakwater; no direct require | open | | 2026-10-18T13:42:54.900Z | | +| 23 | 19.1 | deviation | classes/lifecycle.go | | Task 4 methods besides DeleteContext live in classes/lifecycle.go | open | | 2026-10-18T13:42:55.096Z | | ````json [ @@ -311,6 +313,32 @@ last_updated: 2026-10-10T14:17:06.621Z "recorded_at": "2026-10-10T14:17:06.621Z", "resolved_at": null, "milestone": "v1.0" + }, + { + "id": 22, + "kind": "deviation", + "phase": "19.1", + "file": "sm-forum-plugin/go.mod", + "line": null, + "description": "go.mod lists bluemonday and goldmark as // indirect via breakwater; no direct require", + "status": "open", + "reason": "", + "recorded_at": "2026-10-18T13:42:54.900Z", + "resolved_at": null, + "milestone": "v1.0" + }, + { + "id": 23, + "kind": "deviation", + "phase": "19.1", + "file": "classes/lifecycle.go", + "line": null, + "description": "Task 4 methods besides DeleteContext live in classes/lifecycle.go", + "status": "open", + "reason": "", + "recorded_at": "2026-10-18T13:42:55.096Z", + "resolved_at": null, + "milestone": "v1.0" } ] ```` diff --git a/.planning/phases/19.1-chat-satellites/19.1-02-SUMMARY.md b/.planning/phases/19.1-chat-satellites/19.1-02-SUMMARY.md new file mode 100644 index 00000000..fd09f951 --- /dev/null +++ b/.planning/phases/19.1-chat-satellites/19.1-02-SUMMARY.md @@ -0,0 +1,241 @@ +--- +phase: 19.1-chat-satellites +plan: 02 +subsystem: forum +tags: [forum, markdown, breakwater, jwt, postgres, gorm, testcontainers, deny-all] + +# Dependency graph +requires: + - phase: 19 + provides: analog sibling-plugin layout (boot steps, IF NOT EXISTS baseline, jwt.auth generic API, deny-all seam, test-only proof host) + - phase: 19.1 + provides: plan 01 tea-create / proceed-and-push remote policy; D-17 breakwater.Render/Purify +provides: + - "new repository sm-forum-plugin (module git.golem15.com/golem15/sm-forum-plugin, package forum, plugin golem15.forum), pushed to git.golem15.com at 6a40030" + - "idempotent baseline 202610180001_create_golem15_forum_baseline (four PHP v1.1.0 tables)" + - "ForumService write path with breakwater.Render on write, stored content_html, DenyAll ForumAccessResolver, generic /_forum/api/v1 tracer" + - "DeleteContext, forum:rewrite-context-types, GDPR null authorship on user.Deleting" +affects: [19.1-06] + +actuals: + tokens: 35796 + tasks: 4 + commits: 11 +plan_head_before: eb341147d816a4e5ed254bcfe3370d4d79fdfcb9 +plan_head_after: 1f204f5a6c2d2289d434105e0e22f94693ae5705 + +tech-stack: + added: [] + patterns: + - "Forum consumes D-17 breakwater.Render/Purify; go.mod does not directly require bluemonday or goldmark" + - "ForumAccessResolver DenyAll default + setter nil→DenyAll + Boot Warn; test harness swaps allow-all after Boot" + - "DeleteContext is generic morph-pair soft-delete; host wires group-deleted; forum never imports userfriends" + +key-files: + created: + - .planning/notes/2026-10-18-bluemonday-forum-policy.md + - ../sm-forum-plugin/plugin.go + - ../sm-forum-plugin/boot.go + - ../sm-forum-plugin/routes.go + - ../sm-forum-plugin/classes/forum_service.go + - ../sm-forum-plugin/classes/deny_all.go + - ../sm-forum-plugin/classes/lifecycle.go + - ../sm-forum-plugin/contracts/access_resolver.go + - ../sm-forum-plugin/console/rewrite_context_types.go + - ../sm-forum-plugin/updates/202610180001_create_golem15_forum_baseline.go + - ../sm-forum-plugin/http_tracer_test.go + - ../sm-forum-plugin/README.md + modified: [] + +key-decisions: + - "Task 2 reply verbatim: proceed" + - "Locked D-02 baseline id 202610180001_create_golem15_forum_baseline and D-05 prefix /_forum/api/v1; remote policy follows plan 01 proceed-and-push" + - "tea repos create --owner golem15 --name sm-forum-plugin succeeded; main pushed at 6a40030 (never force). summercms.go was not pushed." + +patterns-established: + - "forum proof host: golem15.user + golem15.forum + a test-only teams fixture; harness SetAccessResolver(allow-all) after Boot; TestAccessResolverDefault asserts DenyAll before that swap" + +requirements-completed: [SC-19.1-1, D-01, D-02, D-03, D-04, D-05, D-08, D-16, D-17, D-18] + +coverage: + - id: D1 + description: "D-16 named bluemonday forum-policy note (v1.0.27, PHP allow-list, nofollow, target blank, not richeditor UGC)" + requirement: D-16 + verification: + - kind: other + ref: ".planning/notes/2026-10-18-bluemonday-forum-policy.md" + status: pass + human_judgment: false + - id: D2 + description: "D-17 Render/Purify consumed from modules/breakwater; forum go.mod has no direct require of bluemonday or goldmark" + requirement: D-17 + verification: + - kind: other + ref: "grep func Render( and func Purify( in modules/breakwater/breakwater.go" + status: pass + human_judgment: false + - id: D3 + description: "Human lock of D-02 baseline id and D-05 prefix /_forum/api/v1 before the sibling repo existed" + requirement: D-02 + verification: [] + human_judgment: true + rationale: "Task 2 was checkpoint:decision gate=blocking-human; the user replied proceed and that lock cannot be asserted by a unit test" + - id: D4 + description: "sm-forum-plugin tracer: category+thread+GFM table post; stored content_html has table and no script; mark read; unread 0" + requirement: D-05 + verification: + - kind: unit + ref: "go -C ../sm-forum-plugin test -count=1 -short ./..." + status: pass + - kind: integration + ref: "../sm-forum-plugin/http_tracer_test.go#TestHTTPTracer" + status: pass + human_judgment: false + - id: D5 + description: "DeleteContext, forum:rewrite-context-types, GDPR null authorship; no userfriends import" + requirement: D-08 + verification: + - kind: unit + ref: "go -C ../sm-forum-plugin test -count=1 -short ./..." + status: pass + - kind: other + ref: "grep DeleteContext, forum:rewrite-context-types, DeletingEvent; TestNoUserfriendsImport" + status: pass + human_judgment: false + - id: D6 + description: "Gitea remote golem15/sm-forum-plugin created and main pushed (never force)" + requirement: SC-19.1-1 + verification: + - kind: other + ref: "tea repos create --owner golem15 --name sm-forum-plugin; git push -u origin main" + status: pass + human_judgment: false + +duration: 9min +completed: 2026-10-18 +status: complete +--- + +# Phase 19.1 Plan 02: Forum repo, baseline, GFM tracer, DeleteContext Summary + +**Sibling `sm-forum-plugin` consumes `breakwater.Render`/`Purify` (D-17), ships the v1.1.0 IF NOT EXISTS baseline, a deny-all ForumAccessResolver, a GFM table HTTP tracer under `/_forum/api/v1`, generic `DeleteContext`, `forum:rewrite-context-types`, and GDPR null authorship.** + +## Performance + +- **Duration:** 9 min (this continuation; Task 1–2 ran in the prior wave) +- **Started:** 2026-10-18T13:30:10Z +- **Completed:** 2026-10-18T13:39:35Z +- **Tasks:** 4 +- **Files modified:** 35 in the sibling plugin plus the D-16 note in summercms.go + +## Task 2 human reply (verbatim) + +proceed + +Meaning recorded at resume: lock D-02 baseline id `202610180001_create_golem15_forum_baseline` and D-05 prefix `/_forum/api/v1`; implement; remote policy follows plan 01 proceed-and-push. After Task 4 is green, tea-create the remote and push main (never force). summercms.go is not pushed. Task 1 and Task 2 were not re-asked. + +## Accomplishments + +- D-16 note `.planning/notes/2026-10-18-bluemonday-forum-policy.md` (commit `2740ab2`) names bluemonday v1.0.27, the PHP allow-list, schemes http/https/mailto, RequireNoFollowOnLinks, AddTargetBlankToFullyQualifiedLinks, and is not the richeditor UGC policy. +- D-17 asserted before the forum repo: `modules/breakwater` exports `Render(markdown string) string` and `Purify(html string) string`. Printed `d17-ready`. +- New independent git repo `../sm-forum-plugin`: module `git.golem15.com/golem15/sm-forum-plugin`, package `forum`, PluginID `golem15.forum`, `Requires()` = `golem15.user` only. Never requires chat or userfriends. +- Idempotent baseline `202610180001_create_golem15_forum_baseline`: `golem15_forum_categories` (context_type NOT NULL, no FK, unique owner+slug), threads, posts, thread_reads. threads/posts `user_id` nullable SET NULL. `deletion_reason` varchar CHECK self|moderator or null. +- `contracts.AccessResolver`: CanRead / CanPost / CanManage / CanManageContext. `classes.DenyAll` all false. `New` and `SetAccessResolver(nil)` install DenyAll. Boot Warns while default is active. +- Write path `CreateCategory`, `CreateThread`, `Reply` inside `lagoon.Transaction`. New/edited posts call `breakwater.Render` and store `content_html`. GET returns stored HTML (D-18). +- Generic API `forum.APIPrefix` (`/_forum/api/v1`) behind `jwt.auth` and `forum-api` 120/min. +- Test host: `golem15.user` + `golem15.forum` + `acme.teams`. After Boot the harness installs allow-all. `TestAccessResolverDefault` (short) asserts DenyAll. `TestHTTPTracer` (Docker): GFM table + script tag; stored `content_html` has a table and no script; mark read; unread 0. +- `ForumService.DeleteContext(ctx, type, id)` soft-deletes categories (and cascaded threads/posts) for the morph pair. `forum:rewrite-context-types` walks `RegisterContext` LegacyPHPClass → alias, idempotent. GDPR: Listen `user.Deleting`; null `threads.user_id` and `posts.user_id`; keep bodies. +- Remaining PHP methods: seedDefaultCategory, renameCategory, reorderCategories, deleteCategory, editPost, deletePost, deleteThread, unreadThreadCount, markThreadRead; HTTP PUT/DELETE categories, reorder, GET threads/posts, PUT/DELETE posts, DELETE threads, preview. +- Remote created: `https://git.golem15.com/golem15/sm-forum-plugin`. `git push -u origin main` succeeded (never force). summercms.go was not pushed. + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: D-16 forum-policy note and D-17 gate** - `2740ab2` (docs, summercms.go) +2. **Task 2: Confirm D-02 forum baseline id and D-05 prefix** - none (decision only; human: proceed). Halt record `ceabc9c` (docs, summercms.go) +3. **Task 3: End-to-end forum post — category, thread, GFM table, no script element** - `0fee845` (feat, sm-forum-plugin) +4. **Task 4: DeleteContext, morph rewrite, remaining routes, GDPR null authorship** - `6a40030` (feat, sm-forum-plugin) + +**Sibling HEAD:** `6a40030` on `origin/main`. + +**Plan metadata:** (this SUMMARY commit) + +## Files Created/Modified + +- `.planning/notes/2026-10-18-bluemonday-forum-policy.md` - D-16 named forum policy +- `../sm-forum-plugin/` - full plugin tree (go.mod Go 1.27.0, analog pins, replace summercms => ../summercms.go; go.work also replaces sm-user-plugin) + +## Decisions Made + +- Task 2 reply verbatim: proceed. +- Locked D-02 / D-05 as named in the continuation. Remote policy follows plan 01 proceed-and-push. +- After Task 4 verify was green, `tea repos create --owner golem15 --name sm-forum-plugin` then `git push -u origin main` (never force). + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Indirect bluemonday/goldmark in go.mod** +- **Found during:** Task 3 +- **Issue:** Acceptance grep of `bluemonday|goldmark` in `go.mod` is non-zero because `go mod tidy` records them as `// indirect` through `summercms/modules/breakwater`. Direct `require (` does not list them; forum does not vendor either library. +- **Fix:** Left as transitive of D-17. No direct require. TestNoUserfriendsImport still greps friends. Documented here so the verifier does not treat the indirect lines as a new library. +- **Files modified:** `../sm-forum-plugin/go.mod` +- **Verification:** `grep` of the direct require block is empty; `go test -short` and `TestHTTPTracer` pass +- **Committed in:** `0fee845` + +**2. [Rule 2 - Missing Critical] Task 4 methods live in `classes/lifecycle.go` plus `DeleteContext` on `forum_service.go`** +- **Found during:** Task 4 +- **Issue:** Remaining PHP methods would have made `forum_service.go` too large; acceptance grep requires `DeleteContext` on `forum_service.go`. +- **Fix:** `DeleteContext` is on `forum_service.go`; other Task 4 methods are `classes/lifecycle.go` in the same package. +- **Files modified:** `../sm-forum-plugin/classes/forum_service.go`, `../sm-forum-plugin/classes/lifecycle.go` +- **Verification:** `grep -n 'func (s *ForumService) DeleteContext' classes/forum_service.go` prints one line +- **Committed in:** `6a40030` + +--- + +**Total deviations:** 2 auto-fixed (1 blocking, 1 missing critical) +**Impact on plan:** Indirect deps are the correct way to consume D-17. File split does not change behavior. + +## Issues Encountered + +Task 1 and Task 2 were not re-asked. `../sm-forum-plugin` did not exist at Task 3 start. D-17 had landed in `modules/breakwater`. Docker was available; `TestHTTPTracer` ran. + +## TDD Gate Compliance + +N/A — TDD is not applicable for this plan. Tracer verify is automated-only (`HUMAN_VERIFY_MODE=end-of-phase`). After Task 3 automated verify passed: Tracer verified end-to-end — expanding. + +## Auth gates + +Task 2 `checkpoint:decision` `blocking-human` — user replied `proceed`. No further auth gates. + +## Known Stubs + +None. + +## User Setup Required + +None - no external service configuration required. The Gitea repo was created in-session. + +## Next Phase Readiness + +Ready for 19.1-06 (unit tests, goldens, PHP maps, `scripts/check-phase19.1.sh`) and remaining incomplete plan 19.1-06. Forum is adoptable: host must `SetAccessResolver`; `DeleteContext` is generic. + +--- +*Phase: 19.1-chat-satellites* +*Completed: 2026-10-18* + +## Self-Check: PASSED + +- FOUND: `.planning/notes/2026-10-18-bluemonday-forum-policy.md` (`2740ab2`) +- FOUND: `modules/breakwater` `func Render(` and `func Purify(` (d17-ready) +- FOUND: `../sm-forum-plugin/plugin.go` (`PluginID golem15.forum`, `Requires golem15.user`) +- FOUND: `../sm-forum-plugin/classes/forum_service.go` (`DeleteContext`) +- FOUND: `../sm-forum-plugin/console/rewrite_context_types.go` (`forum:rewrite-context-types`) +- FOUND: `../sm-forum-plugin/boot.go` (`DeletingEvent`) +- FOUND: `../sm-forum-plugin/updates/202610180001_create_golem15_forum_baseline.go` +- FOUND: `../sm-forum-plugin/http_tracer_test.go` +- FOUND: sibling commits `0fee845`, `6a40030`; summercms.go `2740ab2`, `ceabc9c` +- FOUND: remote `https://git.golem15.com/golem15/sm-forum-plugin` pushed `main` at `6a40030` +- FOUND: Task 2 human reply verbatim `proceed` + diff --git a/.planning/state.json b/.planning/state.json index 3751adca..476d9a97 100644 --- a/.planning/state.json +++ b/.planning/state.json @@ -214,5 +214,5 @@ "label": "Advance to the next step", "reason": "Phase 19.1 of 41 · executing" }, - "updated_at": "2026-10-18T12:02:25.797Z" + "updated_at": "2026-10-18T13:41:48.501Z" }