bind each Claude pane to its own session id (T-146)
A regression from T-137: every pane rendered the newest .jsonl in the workspace dir, so concurrent sessions collided — a secondary tab showed the primary's conversation. Each pane now spawns claude with its own --session-id (a transcript is named <session-id>.jsonl), tails that exact file via TranscriptReader's file: param, and uses a per-session MessageBus channel so controllers don't cross-talk. The primary's id is deterministic from its session name (stable → it resumes across restarts, like /resume off the same history file); secondaries get a fresh random id so a clean session is always available. The reader now waits for the bound file to appear rather than throwing. Migration: an existing tmux session created before this (no --session-id, claude chose its own id) must be killed once (claude.kill-all-sessions) so the next spawn binds the controlled id. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,3 +19,4 @@ INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted
|
||||
INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-135', 'T-137', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'ae447ef31c40b8003cb8e372ec0b23b0', 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-136', 'T-137', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'cb44e9c64d3051a320f314e2d81ee552', 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'T-141', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'e2c7e7ea34fb4b007bd3d384ab788ae7', 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-145', 'T-141', '2026-05-23 06:08:24', '2026-05-23 06:08:24', NULL, '1426109288c2a7bbf5a3190940e09fbd', 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
|
||||
@@ -2151,3 +2151,44 @@ INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by,
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-144', 'status', 'in_progress', 'done', NULL, '2026-05-22 22:43:45', '2026-05-22 22:43:45', '2026-05-22 22:43:45', NULL, 'da17b2710e17b1821882d47724790cbb', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'status', 'backlog', 'in_progress', NULL, '2026-05-22 22:50:41', '2026-05-22 22:50:41', '2026-05-22 22:50:41', NULL, 'ad063f0c3c65e5b35d3dcea036412ad9', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'status', 'in_progress', 'done', NULL, '2026-05-22 23:16:28', '2026-05-22 23:16:28', '2026-05-22 23:16:28', NULL, 'add82dc118e2081500f19cbb321272d4', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-140', 'status', 'backlog', 'done', NULL, '2026-05-22 23:31:46', '2026-05-22 23:31:46', '2026-05-22 23:31:46', NULL, 'e6204c6f0a0dbd38396a69dfef2c7080', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-145', 'description', NULL, 'A compact per-session status strip in the lead Claude pane header AND each teammate tile header (T-140), showing: current model, permission mode (accept-edits / plan / default / bypass), and context-window usage %.
|
||||
|
||||
Shared status source (this ticket owns it): extract per-session status in the drift-contained reader/observer (D-75) — do NOT parse CC internals in the widgets.
|
||||
- Model: team config member.model, overridden by the latest assistant message.model in the transcript when present.
|
||||
- Permission mode: the transcript''s `permission-mode` records (TranscriptReader currently SKIPS these — surface the latest instead). Also honor config member.planModeRequired for teammates.
|
||||
- Context %: latest assistant message.usage (input_tokens + cache_read_input_tokens + cache_creation_input_tokens + output_tokens) over the model''s context limit.
|
||||
|
||||
Delivery: emit a per-session status to the UI via the bus/events (e.g. a TeamMemberStatus event or an extra MessageBus channel) so BOTH the header strip and the T-141 sidebar render from one source without re-tailing.
|
||||
|
||||
Applies to the lead session and every teammate. Re-validate field names against a live team run / CC version bump (undocumented, per T-134).
|
||||
|
||||
Acceptance: lead pane header and each teammate tile header show current model + an accept-edits/plan-mode badge + a context-usage indicator, updating live from the transcript. Blocked by T-137 (done), T-140 (done).
|
||||
', NULL, '2026-05-23 06:07:59', '2026-05-23 06:07:59', '2026-05-23 06:07:59', NULL, '26bb1c89f3fef8d916f3eb6a1ba9d065', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-141', 'description', 'New sidebar panel contributed to Slots.sidebar: roster from ~/.claude/teams config; live status verb / elapsed / down+up tokens / edit-mode from transcript tailing; team token budget pulled from the Anthropic usage API on a timer. Acceptance: roster matches list-panes/config; budget refreshes on the timer; appears in team mode. Blocked by T7.', 'New sidebar panel (contributed to Slots.sidebar), visible only in team mode: a roster row per team member that MIRRORS the per-session status surfaced by T-145, plus team-wide meta.
|
||||
|
||||
Per-member row:
|
||||
- Identity from the team config + observer: name, agentType, color; membership/lifecycle from TeamMemberJoined/Left.
|
||||
- Mirror of T-145''s shared status: current model, permission-mode badge (accept-edits / plan / default / bypass), context-window usage %. Consume the SAME status source/event T-145 emits — do NOT re-tail transcripts or re-parse CC internals here (D-75).
|
||||
- Live status verb + elapsed-since-last-activity + down/up token deltas from that same status feed.
|
||||
|
||||
Team-wide:
|
||||
- Team/account token budget pulled from the Anthropic usage API on a timer (distinct from per-conversation context above).
|
||||
|
||||
Acceptance: roster matches list-panes/config; each row mirrors the member''s model + accept-edits/plan badge + context-usage; status verb and token deltas update live; account budget refreshes on its timer; panel appears only when a team is active. Depends on T-145 (status source) + T-139 (done).
|
||||
', NULL, '2026-05-23 06:08:24', '2026-05-23 06:08:24', '2026-05-23 06:08:24', NULL, 'cfa1ce349be286d89a1f8e169605f04d', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-146', 'description', NULL, 'Regression from T-137: every Claude pane renders the newest .jsonl in the workspace''s munged dir, so concurrent sessions in one workspace (primary + secondaries) all converge on the same transcript — a secondary tab shows the primary''s conversation (and the primary follows whichever session is newest). The pre-T-137 terminal pane rendered each tab''s own PTY, so tabs were independent.
|
||||
|
||||
Fix: bind each pane to a specific Claude session id.
|
||||
- claude CLI supports `--session-id <uuid>` (verified via --help). Spawn each pane''s claude with its own UUID; a transcript is named <session-id>.jsonl, so the pane''s transcript is <munged-cwd>/<uuid>.jsonl.
|
||||
- Reader targets that exact file via TranscriptReader''s `file:` param (added in T-139). Guard _tail against the file not existing yet (claude writes it shortly after spawn).
|
||||
- Each pane publishes/subscribes on a per-session MessageBus channel (conversation/<uuid>) so primary and secondary controllers don''t cross-talk.
|
||||
- UUID per pane, seeded by the tmux session name (the identity we already have): primary = deterministic from its stable session name (clide-claude-<slug>) so it RESUMES across restarts (D-41 continuity); secondary = random per spawn so each is a clean/fresh session (a deterministic secondary id would make starting a clean session impossible).
|
||||
|
||||
Migration caveat: an existing tmux session created by the OLD code (no --session-id, claude picked its own id) won''t match the new deterministic id — it must be killed (claude.kill-all-sessions) once so the next spawn binds the controlled id.
|
||||
|
||||
Open question to validate live: whether `claude --session-id <existing-uuid>` resumes vs. errors when re-spawned after the tmux session was killed (display works either way since the file is <uuid>.jsonl, but worth confirming claude starts).
|
||||
|
||||
Acceptance: a secondary tab shows its OWN fresh conversation, independent of the primary; the primary keeps its conversation; both update live. Regression of T-137; relates to D-41.
|
||||
', NULL, '2026-05-23 06:19:51', '2026-05-23 06:19:51', '2026-05-23 06:19:51', NULL, '9e46b8eec7cc5e42132249a81d4925d1', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-146', 'status', 'backlog', 'in_progress', NULL, '2026-05-23 06:19:51', '2026-05-23 06:19:51', '2026-05-23 06:19:51', NULL, 'dd4ec6cfbbc3118cd4cf02604b91108b', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -2496,3 +2496,43 @@ INSERT INTO tickets (id, type, parent_id, title, description, status, priority,
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-144', 'task', 'T-132', 'Claude message card with brand-orange accent', 'Extend the distinct-card treatment (T-143) to Claude''s text responses with a different accent: Claude''s brand coral-orange (#D97757), vs the user card''s focus-colour stripe. Refactor _userCard into a shared _messageCard(label, accent, body). conversation_view.dart.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:40:42', '2026-05-22 22:43:45', NULL, '1ce891624631502279b0356c5cdffae2', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'task', 'T-132', 'tmux team observer (lifecycle + identity + per-teammate transcripts)', 'New lib/builtin/claude/src/team_observer.dart: detect teammate spawn/exit (control-mode or list-panes -a poll on -L clide), map pane->teammate via ~/.claude/teams config + agentId, spin a TranscriptReader per teammate, emit new TeamMemberBorn/TeamMemberDied ClideEvents (lib/kernel/src/events/types.dart). ALL fragile CC-internals parsing isolated here (single drift-containment point; key off the version field). Cite D-75. Acceptance: a real team run emits born/died with correct identity; per-teammate content streams. Blocked by T2, T4.', 'in_progress', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 22:50:41', NULL, 'a5f4b20a0a37332ab35de8fa07e22298', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'task', 'T-132', 'tmux team observer (lifecycle + identity + per-teammate transcripts)', 'New lib/builtin/claude/src/team_observer.dart: detect teammate spawn/exit (control-mode or list-panes -a poll on -L clide), map pane->teammate via ~/.claude/teams config + agentId, spin a TranscriptReader per teammate, emit new TeamMemberBorn/TeamMemberDied ClideEvents (lib/kernel/src/events/types.dart). ALL fragile CC-internals parsing isolated here (single drift-containment point; key off the version field). Cite D-75. Acceptance: a real team run emits born/died with correct identity; per-teammate content streams. Blocked by T2, T4.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:16:28', NULL, 'bd5e9cc5ae0e8bdbac4ad8cc57b33b58', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-140', 'story', 'T-132', 'Teammate tile grid (faithful tiling, responsive auto-wrap)', 'Tiling host: lead ConversationView (left, with composer) + teammate ConversationViews (right) in a responsive auto-wrap grid (1->2->3 columns by count); resizable lead/teammate split. Workspace currently only vertical-splits, so extend _WorkspaceSlot (lib/app.dart) or add team slots in lib/kernel/src/panels/layout_preset.dart; reuse DragResizeHandle (lib/kernel/src/panels/drag_resize.dart). Driven by TeamMemberBorn/Died from the observer. Acceptance: tiles appear/disappear with lifecycle; grid wraps 1->2->3 by count; split resizes; select-across-tiles works. Blocked by T5, T7.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:31:46', NULL, '9c4254dcfca0f81367a0d909c72e9dd4', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-145', 'task', 'T-132', 'Per-session status strip: model / permission-mode / context%', 'A compact per-session status strip in the lead Claude pane header AND each teammate tile header (T-140), showing: current model, permission mode (accept-edits / plan / default / bypass), and context-window usage %.
|
||||
|
||||
Shared status source (this ticket owns it): extract per-session status in the drift-contained reader/observer (D-75) — do NOT parse CC internals in the widgets.
|
||||
- Model: team config member.model, overridden by the latest assistant message.model in the transcript when present.
|
||||
- Permission mode: the transcript''s `permission-mode` records (TranscriptReader currently SKIPS these — surface the latest instead). Also honor config member.planModeRequired for teammates.
|
||||
- Context %: latest assistant message.usage (input_tokens + cache_read_input_tokens + cache_creation_input_tokens + output_tokens) over the model''s context limit.
|
||||
|
||||
Delivery: emit a per-session status to the UI via the bus/events (e.g. a TeamMemberStatus event or an extra MessageBus channel) so BOTH the header strip and the T-141 sidebar render from one source without re-tailing.
|
||||
|
||||
Applies to the lead session and every teammate. Re-validate field names against a live team run / CC version bump (undocumented, per T-134).
|
||||
|
||||
Acceptance: lead pane header and each teammate tile header show current model + an accept-edits/plan-mode badge + a context-usage indicator, updating live from the transcript. Blocked by T-137 (done), T-140 (done).
|
||||
', 'backlog', 'medium', NULL, NULL, NULL, '2026-05-23 06:07:59', '2026-05-23 06:07:59', NULL, '5047ae730e9065c684fcecf557353de7', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-141', 'task', 'T-132', 'Team-meta sidebar (roster + token budget)', 'New sidebar panel (contributed to Slots.sidebar), visible only in team mode: a roster row per team member that MIRRORS the per-session status surfaced by T-145, plus team-wide meta.
|
||||
|
||||
Per-member row:
|
||||
- Identity from the team config + observer: name, agentType, color; membership/lifecycle from TeamMemberJoined/Left.
|
||||
- Mirror of T-145''s shared status: current model, permission-mode badge (accept-edits / plan / default / bypass), context-window usage %. Consume the SAME status source/event T-145 emits — do NOT re-tail transcripts or re-parse CC internals here (D-75).
|
||||
- Live status verb + elapsed-since-last-activity + down/up token deltas from that same status feed.
|
||||
|
||||
Team-wide:
|
||||
- Team/account token budget pulled from the Anthropic usage API on a timer (distinct from per-conversation context above).
|
||||
|
||||
Acceptance: roster matches list-panes/config; each row mirrors the member''s model + accept-edits/plan badge + context-usage; status verb and token deltas update live; account budget refreshes on its timer; panel appears only when a team is active. Depends on T-145 (status source) + T-139 (done).
|
||||
', 'backlog', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-23 06:08:24', NULL, '54edba4b89b8926c3527b4f1174c2a4c', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-146', 'bug', 'T-132', 'Secondary Claude panes render the primary''s transcript', 'Regression from T-137: every Claude pane renders the newest .jsonl in the workspace''s munged dir, so concurrent sessions in one workspace (primary + secondaries) all converge on the same transcript — a secondary tab shows the primary''s conversation (and the primary follows whichever session is newest). The pre-T-137 terminal pane rendered each tab''s own PTY, so tabs were independent.
|
||||
|
||||
Fix: bind each pane to a specific Claude session id.
|
||||
- claude CLI supports `--session-id <uuid>` (verified via --help). Spawn each pane''s claude with its own UUID; a transcript is named <session-id>.jsonl, so the pane''s transcript is <munged-cwd>/<uuid>.jsonl.
|
||||
- Reader targets that exact file via TranscriptReader''s `file:` param (added in T-139). Guard _tail against the file not existing yet (claude writes it shortly after spawn).
|
||||
- Each pane publishes/subscribes on a per-session MessageBus channel (conversation/<uuid>) so primary and secondary controllers don''t cross-talk.
|
||||
- UUID per pane, seeded by the tmux session name (the identity we already have): primary = deterministic from its stable session name (clide-claude-<slug>) so it RESUMES across restarts (D-41 continuity); secondary = random per spawn so each is a clean/fresh session (a deterministic secondary id would make starting a clean session impossible).
|
||||
|
||||
Migration caveat: an existing tmux session created by the OLD code (no --session-id, claude picked its own id) won''t match the new deterministic id — it must be killed (claude.kill-all-sessions) once so the next spawn binds the controlled id.
|
||||
|
||||
Open question to validate live: whether `claude --session-id <existing-uuid>` resumes vs. errors when re-spawned after the tmux session was killed (display works either way since the file is <uuid>.jsonl, but worth confirming claude starts).
|
||||
|
||||
Acceptance: a secondary tab shows its OWN fresh conversation, independent of the primary; the primary keeps its conversation; both update live. Regression of T-137; relates to D-41.
|
||||
', 'in_progress', 'high', NULL, NULL, NULL, '2026-05-23 06:19:51', '2026-05-23 06:19:51', NULL, 'c47ada73a71c18d1998cc6fdc36d1b22', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
Reference in New Issue
Block a user