From 935bdcb47958d1682e0162d266e229f647210ec7 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sat, 17 Oct 2026 21:36:02 +0200 Subject: [PATCH] docs(19-03): complete ChatChannels core plan Co-authored-by: Cursor --- .../19-chat-and-chatchannels/19-03-SUMMARY.md | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 .planning/phases/19-chat-and-chatchannels/19-03-SUMMARY.md diff --git a/.planning/phases/19-chat-and-chatchannels/19-03-SUMMARY.md b/.planning/phases/19-chat-and-chatchannels/19-03-SUMMARY.md new file mode 100644 index 00000000..a617b06e --- /dev/null +++ b/.planning/phases/19-chat-and-chatchannels/19-03-SUMMARY.md @@ -0,0 +1,207 @@ +--- +phase: 19-chat-and-chatchannels +plan: 03 +subsystem: chatchannels +tags: [chatchannels, festival, beachcomber, postgres, gorm, testcontainers] + +# Dependency graph +requires: + - phase: 19-01 + provides: sm-chat-plugin events MessageCreated/Updated/Deleted, classes.Service, contracts.Registry, acme.teams proof host +provides: + - "new repository sm-chatchannels-plugin (module git.golem15.com/golem15/sm-chatchannels-plugin, package chatchannels, plugin golem15.chatchannels), pushed to git.golem15.com at b0ab8a4" + - "idempotent baseline 202610160001_create_golem15_chatchannels_baseline (eight PHP v1.6.0 tables IF NOT EXISTS; users.handle not added)" + - "contracts.AccessResolver deny-all default; classes.ChannelService PHP public method set; Boot Warn until host SetAccessResolver" + - "festival Listen MessageCreated/Updated/Deleted for mentions and fail-open beachcomber Sync; SearchableAs messages" + - "command chatchannels:rewrite-context-types (D-12 channels.context_type from LegacyPHPClass)" +affects: [19-04, 19-05, sm-user-plugin, Wavepath port] + +# Actuals (#2632) — chars/4 over the new plugin tree +actuals: + tokens: 37470 + tasks: 3 + commits: 3 +plan_head_before: c9e5b14e27ba0093a8b8c52aba7374eaa43caea0 +plan_head_after: pending-summary-commit +commits: 3 + +tech-stack: + added: [] + patterns: + - "Channel.context is the host (teams); Conversation.context is the channel alias + channel.ID (Pitfall 6)" + - "DenyAll ChannelAccessResolver until the host SetAccessResolver; Boot slog.Warn while default remains" + - "chatchannels listens to chat festival events; it never imports chat models to patch Searchable" + - "MessageIndex.SearchableAs returns messages (no scout prefix); indexer fail-open Warn" + +key-files: + created: + - ../sm-chatchannels-plugin/plugin.go + - ../sm-chatchannels-plugin/boot.go + - ../sm-chatchannels-plugin/search.go + - ../sm-chatchannels-plugin/contracts/access_resolver.go + - ../sm-chatchannels-plugin/classes/deny_all.go + - ../sm-chatchannels-plugin/classes/channel_service.go + - ../sm-chatchannels-plugin/classes/mention_parser.go + - ../sm-chatchannels-plugin/classes/search_indexer.go + - ../sm-chatchannels-plugin/models/channel.go + - ../sm-chatchannels-plugin/models/category.go + - ../sm-chatchannels-plugin/models/personal_category.go + - ../sm-chatchannels-plugin/models/prefs.go + - ../sm-chatchannels-plugin/models/member.go + - ../sm-chatchannels-plugin/models/mention.go + - ../sm-chatchannels-plugin/models/pin.go + - ../sm-chatchannels-plugin/models/user_context_pref.go + - ../sm-chatchannels-plugin/models/message_index.go + - ../sm-chatchannels-plugin/updates/202610160001_create_golem15_chatchannels_baseline.go + - ../sm-chatchannels-plugin/console/rewrite_context_types.go + - ../sm-chatchannels-plugin/tracer_test.go + - ../sm-chatchannels-plugin/README.md + modified: [] + +key-decisions: + - "Reused 19-01 Task 1 reply proceed-and-push (did not re-ask)" + - "Display names ChatChannels / Kanały (user-prompt lock; plan text said Chat Channels / Kanały czatu)" + - "tea repos create --owner golem15 --name sm-chatchannels-plugin succeeded; main pushed at b0ab8a4 (never force). summercms.go was not pushed." + - "users.handle is not a chatchannels migration (D-15 stays plan 04); ResolveMentionedParticipantIDs skips silently if the column is missing" + +patterns-established: + - "chatchannels proof host: golem15.user + golem15.chat + golem15.chatchannels + test-only acme.teams (channel-as-context adapter + allow-all resolver after Boot Warn)" + +requirements-completed: [SC-19-1, SC-19-2, D-04, D-12, D-13, D-14, D-20] + +coverage: + - id: D1 + description: "golem15.chatchannels sibling plugin with the v1.6.0 IF NOT EXISTS baseline (no users.handle) and deny-all ChannelAccessResolver" + requirement: D-04 + verification: + - kind: unit + ref: "go -C ../sm-chatchannels-plugin test -count=1 -short ./..." + status: pass + - kind: integration + ref: "go -C ../sm-chatchannels-plugin test -count=1 -run '^TestCreateChannel$' -v ." + status: pass + human_judgment: false + - id: D2 + description: "CreateChannel persists a channel and backing conversation with context_type=channel; Boot Warns until the host sets a resolver" + requirement: D-14 + verification: + - kind: integration + ref: "git.golem15.com/golem15/sm-chatchannels-plugin#TestCreateChannel" + status: pass + - kind: unit + ref: "git.golem15.com/golem15/sm-chatchannels-plugin#TestAccessResolverDefault" + status: pass + human_judgment: false + - id: D3 + description: "ChannelService PHP public method set including PublishMentionsChanged (mentions.changed) and SeverUserFromContext" + requirement: SC-19-1 + verification: + - kind: other + ref: "acceptance greps on classes/channel_service.go (60 methods, mentions.changed, SeverUserFromContext)" + status: pass + human_judgment: false + - id: D4 + description: "Festival Listen MessageCreated/Updated/Deleted; MentionParser bounded {2,255}; MessageIndex SearchableAs messages fail-open" + requirement: D-13 + verification: + - kind: unit + ref: "git.golem15.com/golem15/sm-chatchannels-plugin#TestSearchIndexer" + status: pass + - kind: unit + ref: "git.golem15.com/golem15/sm-chatchannels-plugin#TestMentionParser" + status: pass + human_judgment: false + - id: D5 + description: "chatchannels:rewrite-context-types updates golem15_chatchannels_channels.context_type from LegacyPHPClass (D-12)" + requirement: D-12 + verification: + - kind: other + ref: "acceptance greps plus console/rewrite_context_types.go present" + status: pass + human_judgment: false + +duration: 11min +completed: 2026-10-17 +status: complete +--- + +# Phase 19: Chat and ChatChannels — Plan 03 Summary + +**sm-chatchannels-plugin exists as a compiled golem15.chatchannels sibling: CreateChannel writes a channel plus a backing conversation, and chat MessageCreated listeners accrue mentions without failing the send when search is down.** + +## Performance + +- **Duration:** 11 min +- **Started:** 2026-10-17T19:24:10Z +- **Completed:** 2026-10-17T19:35:08Z +- **Tasks:** 3 +- **Files created:** 33 in sm-chatchannels-plugin + +## Accomplishments + +- New module `git.golem15.com/golem15/sm-chatchannels-plugin`, package `chatchannels`, PluginID `golem15.chatchannels`, Requires `golem15.chat` and `golem15.user`. Display names ChatChannels / Kanały. +- Baseline `202610160001_create_golem15_chatchannels_baseline`: eight PHP v1.6.0 tables, every statement `IF NOT EXISTS`; visibility CHECK public|private; notify_pref default mentions; no `users.handle`; no FKs to messages. +- `contracts.AccessResolver` default `classes.DenyAll`; Boot `slog.Warn` until the host `SetAccessResolver`. +- `classes.ChannelService` PHP public method set (60 methods) including CreateChannel, AdoptConversation, mention accrue/reconcile/remove, pins, GDPR `SeverUserFromContext`, lighthouse `mentions.changed`. +- Festival `Listen` on chat `MessageCreated` / `MessageUpdated` / `MessageDeleted`. MentionParser bounded `{2,255}` (RE2 lookbehind emulation). Resolve against conversation participants excluding sender; skip silently if `users.handle` is missing. +- `MessageIndex.SearchableAs` returns `messages`; indexer fail-open Warn. Command `chatchannels:rewrite-context-types`. +- Remote `https://git.golem15.com/golem15/sm-chatchannels-plugin` created with tea; `main` pushed at `b0ab8a4`. + +## Task Commits + +| Task | Repo | Hash | Message | +|------|------|------|---------| +| 1 | sm-chatchannels-plugin | `e6b56a968b774871cae459ee079a9b645583fe87` | feat(19-03): task 1 tracer: chatchannels plugin, v1.6.0 baseline, CreateChannel and deny-all resolver | +| 2 | sm-chatchannels-plugin | `948084376a9b3dd95581150f517d79dba55fea96` | feat(19-03): task 2 expand ChannelService to the PHP public method set | +| 3 | sm-chatchannels-plugin | `b0ab8a4f5c2687ff7b78dd2356de02dcc170265f` | feat(19-03): task 3 festival listeners, MentionParser, fail-open search and D-12 rewrite | + +## Task 1 reply + +`proceed-and-push` (reused from 19-01; not re-asked) + +## TestCreateChannel + +pass (Docker available) + +## tea / push + +succeeded — `tea repos create --owner golem15 --name sm-chatchannels-plugin`; `git push -u origin main` (never force). summercms.go was not pushed. + +## Deviations from Plan + +1. **Display names ChatChannels / Kanały.** Plan action text said "Chat Channels / Kanały czatu"; the executor prompt locked ChatChannels / Kanały. Followed the lock. + +2. **Nested `lagoon.Transaction` (Rule 1).** `ReconcileMentions` called `RecordMentions`, which opened a second tx on `s.db`. Inlined `FirstOrCreate` on the outer tx. Auto-fixed in Task 2. + +3. **PHP lookbehind is not RE2.** Ported `'/(?` greps pass +- plan-level `` green (vet, short tests, TestCreateChannel PASS)