docs(19-06): complete participant-only send and GDPR reassignment plan

Record CR-01/CR-02 gap closure and mark the 19-06 ROADMAP checkbox. Plugin repos were committed separately and not pushed.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-17 22:31:22 +02:00
parent 29d06bc70e
commit d1852f6cda
2 changed files with 168 additions and 2 deletions

View File

@@ -1198,7 +1198,7 @@ Plans:
3. Golden tests show that the serializers (`Message.toApiArray` with attachments, thread summaries, channel, category, pref, pin and mention arrays) and every realtime event (name, channel and payload) match PHP output captured from Wavepath. Route-level parity of `/_wave` is checked at the Wavepath port.
4. The new code has unit tests, delivered in the phase's last plan.
**Plans:** 5/7 plans executed
**Plans:** 6/7 plans executed
Plans:
**Wave 1**
@@ -1215,7 +1215,7 @@ Plans:
- [x] 19-05-PLAN.md — Unit tests LAST: goldens, PHP method map (59 chat + 106 chatchannels), scripts/check-phase19.sh
**Wave 5** *(gap closure)*
- [ ] 19-06-PLAN.md — Participant-only canSend (CR-01) and created_by reassignment on user.Deleting (CR-02)
- [x] 19-06-PLAN.md — Participant-only canSend (CR-01) and created_by reassignment on user.Deleting (CR-02)
**Wave 6** *(gap closure, tests last)*
- [ ] 19-07-PLAN.md — TestTeammateDMWriteIDOR, TestDeletingCascade creator path, check-phase19.sh names

View File

@@ -0,0 +1,166 @@
---
phase: 19-chat-and-chatchannels
plan: 06
subsystem: chat
tags: [chat, chatchannels, canSend, GDPR, user.Deleting, D-08, D-13, SC-19-1]
requires:
- phase: 19-02
provides: ChatService SendMessage, GetOrCreateDm, GetGroupChat
- phase: 19-04
provides: user.Deleting, FireDeletingEvent, ChannelService.WithDB analog
provides:
- "CR-01 / D-08 / SC-19-1: canSend is participant-only; teammate DM write is ErrNotParticipant"
- "CR-02 / D-13: chat-owned ReassignCreatedBy on user.Deleting so remaining members keep the conversation"
- "TestGapClosureSmoke (postgres, skipped under -short)"
affects: [19-07, Wavepath port]
actuals:
tokens: 3037
tasks: 3
commits: 1
plan_head_before: 29d06bc70e0e1e4f0d24dcb72a3dd304863994cb
plan_head_after: pending-summary-commit
tech-stack:
added: []
patterns:
- "canSend returns s.isParticipant after nil/zero-id guards; host ChatEnabled stays on GetGroupChat / GetOrCreateDm"
- "Service.WithDB clones like ChannelService.WithDB so the deleting event Tx is the session"
- "Chat owns user.Deleting reassignment so DMs survive when chatchannels is not mounted"
key-files:
created:
- ../sm-chat-plugin/gap_closure_test.go
modified:
- ../sm-chat-plugin/classes/service.go
- ../sm-chat-plugin/boot.go
- ../sm-chat-plugin/README.md
- ../sm-chatchannels-plugin/README.md
- .planning/ROADMAP.md
key-decisions:
- "Chat owns ReassignCreatedBy; chatchannels SeverUserFromContext is unchanged"
- "canSend is participation-only; ChatEnabled is not folded into canSend"
- "GetGroupChat still ignores addParticipant errors (IN-01 stays open)"
- "TestGapClosureSmoke is not added to check-phase19.sh (19-07)"
patterns-established:
- "Gap-closure smoke lives in the plugin repo and is skipped under -short via TestMain"
- "GDPR created_by reassignment is chat-owned so DMs and channel-backed groups both survive"
requirements-completed: [SC-19-1, D-08, D-13]
coverage:
- id: D1
description: "canSend is participant-only; a third teammate cannot SendMessage into a two-person DM (CR-01 / D-08 / SC-19-1)"
requirement: SC-19-1
verification:
- kind: integration
ref: "../sm-chat-plugin/gap_closure_test.go#TestGapClosureSmoke"
status: pass
human_judgment: false
- id: D2
description: "user.Deleting reassigns created_by to another remaining participant so the DM row survives GDPR delete (CR-02 / D-13)"
requirement: D-13
verification:
- kind: integration
ref: "../sm-chat-plugin/gap_closure_test.go#TestGapClosureSmoke"
status: pass
human_judgment: false
- id: D3
description: "READMEs document participant-only send and created_by reassignment; WR-01..WR-04 and IN-01..IN-02 stay open"
requirement: D-08
verification:
- kind: other
ref: "grep ReassignCreatedBy/participant/created_by in plugin READMEs"
status: pass
human_judgment: false
duration: 4min
completed: 2026-10-17
status: complete
---
# Phase 19 Plan 06: Chat/ChatChannels Gap Closure Summary
**Participant-only canSend and chat-owned created_by reassignment on user.Deleting so DMs and shared channels survive GDPR delete**
## Performance
- **Duration:** 4 min
- **Started:** 2026-10-17T20:28:09Z
- **Completed:** 2026-10-17T20:32:00Z
- **Tasks:** 3
- **Files modified:** 5
## Accomplishments
- `canSend` now returns only `s.isParticipant` after nil/zero-id guards. A teammate who is not a DM participant gets `ErrNotParticipant` (HTTP 404 mapping unchanged).
- `Service.WithDB` and `Service.ReassignCreatedBy` land; Boot Listens `user.Deleting` and reassigns `created_by` to another remaining participant before the user row is deleted. The IF NOT EXISTS baseline CASCADE is untouched.
- `TestGapClosureSmoke` proves both post-fix behaviours on one postgres path (Carol refused on Alice/Bob DM; Alice send succeeds; Carol GetGroupChat lazy-join then send succeeds; after Alice delete the DM remains with `created_by` = Bob).
## Task Commits
Each task was committed atomically in the plugin repos; this SUMMARY is the summercms.go metadata commit.
1. **Task 1 + 2 + 3 (sm-chat-plugin):** `0aee785` (feat) — participant-only send, ReassignCreatedBy, TestGapClosureSmoke, README
2. **Task 2 + 3 (sm-chatchannels-plugin):** `7d49c3c` (docs) — GDPR bullet that chat reassigns created_by
3. **Plan metadata (summercms.go):** this commit (docs)
_Plugin SHAs are local only. No remotes were pushed. fonoteka submodule pointers were not bumped._
## Files Created/Modified
- `../sm-chat-plugin/classes/service.go` — participant-only `canSend`; `WithDB`; `ReassignCreatedBy`
- `../sm-chat-plugin/boot.go` — `listeners` step; `Listen[*userclasses.DeletingEvent]`
- `../sm-chat-plugin/gap_closure_test.go` — `TestGapClosureSmoke`
- `../sm-chat-plugin/README.md` — send-rights, GetGroupChat lazy-join, user.Deleting / ReassignCreatedBy
- `../sm-chatchannels-plugin/README.md` — remaining members keep the channel because chat reassigns created_by
## Decisions Made
- Chat owns `user.Deleting` reassignment so DMs survive even when chatchannels is not mounted. chatchannels `SeverUserFromContext` still only removes that user's members/prefs/participants/personal categories.
- `canSend` is participation-only. Host `ChatEnabled` stays on `GetGroupChat` and `GetOrCreateDm`.
- `GetGroupChat` keeps `_ = addParticipant(...)` (IN-01 stays open).
- Named postgres tests `TestTeammateDMWriteIDOR` / `TestDeletingCascade` creator-delete assertions and `scripts/check-phase19.sh` list updates wait for 19-07.
## Deviations from Plan
None - plan executed exactly as written.
**Total deviations:** 0 auto-fixed
**Impact on plan:** None.
## Issues Encountered
None.
## User Setup Required
None - no external service configuration required.
## Verification Results
- `go -C ../sm-chat-plugin vet ./...` — PASS
- `go -C ../sm-chat-plugin test -count=1 -short ./...` — PASS (Task 1 and Task 2)
- `go -C ../sm-chatchannels-plugin test -count=1 -short ./...` — PASS
- `go -C ../sm-chat-plugin test -count=1 -run '^TestGapClosureSmoke$' -v .` — PASS (`--- PASS: TestGapClosureSmoke (0.72s)`)
- Baseline `golem15_chat_conversations_created_by_foreign` / `ON DELETE CASCADE` unchanged
- WR-01..WR-04 and IN-01..IN-02 confirmed unread: GetGroupChat still ignores addParticipant errors; download Content-Disposition unchanged; JoinChannel / PinMessage unchanged; FormAfterDelete remains the only production `FireDeletingEvent` site
- No remotes pushed (`sm-chat-plugin` and `sm-chatchannels-plugin` are `ahead 1`)
## Next Phase Readiness
Ready for 19-07: `TestTeammateDMWriteIDOR`, `TestDeletingCascade` creator-delete assertions, and `scripts/check-phase19.sh` required-name updates. Production CR-01 and CR-02 are closed.
---
*Phase: 19-chat-and-chatchannels*
*Completed: 2026-10-17*
## Self-Check: PASSED
- FOUND: `.planning/phases/19-chat-and-chatchannels/19-06-SUMMARY.md`
- FOUND: `../sm-chat-plugin/gap_closure_test.go`
- FOUND: `../sm-chat-plugin` commit `0aee785`
- FOUND: `../sm-chatchannels-plugin` commit `7d49c3c`