From 13bfa663dd00bf513632fb6c1b9f0fb090690f8a Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Wed, 27 May 2026 19:36:30 +0000 Subject: [PATCH] fix(broadcast): correct org-root CTE for non-root senders (#1959) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first CTE in workspace_broadcast.go still used the OLD buggy pattern from before #1954: it carried `id AS root_id` from the recursive seed. For a non-root sender this resolved root_id to itself instead of the true org root, so the broadcast would under-deliver to siblings in the same org. Replace with the canonical orgRootSubtreeCTE shape from org_scope.go: - Seed with `SELECT id, parent_id` (no root_id alias) - Walk up via `JOIN ... ON w.id = c.parent_id` - Extract root with `SELECT id AS root_id FROM org_chain WHERE parent_id IS NULL` The second CTE (recipient collection) already does the correct thing — it seeds from `parent_id IS NULL` and walks downward, so `id AS root_id` is actually the root id there. Co-Authored-By: Claude Opus 4.7 --- .../internal/handlers/workspace_broadcast.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/workspace-server/internal/handlers/workspace_broadcast.go b/workspace-server/internal/handlers/workspace_broadcast.go index 27ce7a8ea..d0baa3352 100644 --- a/workspace-server/internal/handlers/workspace_broadcast.go +++ b/workspace-server/internal/handlers/workspace_broadcast.go @@ -82,18 +82,21 @@ func (h *BroadcastHandler) Broadcast(c *gin.Context) { // Find the sender's org root by walking the parent_id chain. // Workspaces with parent_id = NULL are org roots; every other workspace // belongs to the org identified by its topmost ancestor. + // Uses the same CTE shape as org_scope.go (#1954) — the recursive seed + // must NOT carry `id AS root_id` because that resolves non-root senders + // to themselves instead of their true org root (availability bug #1959). var orgRootID string err = db.DB.QueryRowContext(ctx, ` WITH RECURSIVE org_chain AS ( - SELECT id, parent_id, id AS root_id + SELECT id, parent_id FROM workspaces WHERE id = $1 UNION ALL - SELECT w.id, w.parent_id, c.root_id + SELECT w.id, w.parent_id FROM workspaces w JOIN org_chain c ON w.id = c.parent_id ) - SELECT root_id FROM org_chain WHERE parent_id IS NULL LIMIT 1 + SELECT id AS root_id FROM org_chain WHERE parent_id IS NULL LIMIT 1 `, senderID).Scan(&orgRootID) if err != nil { log.Printf("Broadcast: org root lookup for %s: %v", senderID, err) -- 2.52.0