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:
@@ -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.
|
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.
|
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:
|
Plans:
|
||||||
**Wave 1**
|
**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
|
- [x] 19-05-PLAN.md — Unit tests LAST: goldens, PHP method map (59 chat + 106 chatchannels), scripts/check-phase19.sh
|
||||||
|
|
||||||
**Wave 5** *(gap closure)*
|
**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)*
|
**Wave 6** *(gap closure, tests last)*
|
||||||
- [ ] 19-07-PLAN.md — TestTeammateDMWriteIDOR, TestDeletingCascade creator path, check-phase19.sh names
|
- [ ] 19-07-PLAN.md — TestTeammateDMWriteIDOR, TestDeletingCascade creator path, check-phase19.sh names
|
||||||
|
|||||||
166
.planning/phases/19-chat-and-chatchannels/19-06-SUMMARY.md
Normal file
166
.planning/phases/19-chat-and-chatchannels/19-06-SUMMARY.md
Normal 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`
|
||||||
Reference in New Issue
Block a user