tear down the previous workspace's services on project switch (T-367)
buildDispatcher composed a fresh PaneRegistry, FilesService, SearchService, and EditorRegistry per workspace, but their shutdown() methods had zero callers — every project switch left the old set's file watcher emitting into the new workspace's bus and its PTYs alive. The dispatcher now pairs with a teardown closure that the serialized swap invokes after the old server stops; the same-path reuse fast-path drops the unused new set without teardown since its services are inert until a command starts them. SearchService gains the shutdown() it was missing (cancels in-flight searches). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3951,3 +3951,5 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBR4636GSRJBWFJDAZ6ZA0', 'status', 'in_progress', 'done', NULL, '2026-06-11 22:34:31', '2026-06-11 22:34:31', '2026-06-11 22:34:31', NULL, '254ae09f42b4da439a04d59d675d8f42', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBPQE4J4YBJX92812ZK6DR', 'status', 'backlog', 'in_progress', NULL, '2026-06-11 22:34:51', '2026-06-11 22:34:51', '2026-06-11 22:34:51', NULL, '14a7d3d6d6c71cae423ce12c71b6c540', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBPQE4J4YBJX92812ZK6DR', 'status', 'in_progress', 'done', NULL, '2026-06-11 22:39:04', '2026-06-11 22:39:04', '2026-06-11 22:39:04', NULL, 'ad1c483fe26d5e417b2e1cd8986114f3', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBWE2W1226T58CX37E50HC', 'status', 'backlog', 'in_progress', NULL, '2026-06-11 22:39:32', '2026-06-11 22:39:32', '2026-06-11 22:39:32', NULL, '9983d6ca4c8b8b49724fb5fe42b541cd', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBWE2W1226T58CX37E50HC', 'status', 'in_progress', 'done', NULL, '2026-06-11 22:44:05', '2026-06-11 22:44:05', '2026-06-11 22:44:05', NULL, '7846c244fccd1cd444f6715ed7472549', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -4019,3 +4019,9 @@ Fix: route editor.open/editor.save through path_safety like files.*. Tests: trav
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBPQE4J4YBJX92812ZK6DR', 'bug', '06FBHBGHNEQTAEPGNJKN42C1E8', 'editor.open/editor.save skip path confinement entirely', 'lib/src/editor/registry.dart:215-219 returns absolute paths verbatim — no .. normalization, no path_safety call — an unconfined read AND write primitive over IPC while files.read is carefully guarded.
|
||||
|
||||
Fix: route editor.open/editor.save through path_safety like files.*. Tests: traversal and absolute-escape attempts rejected for both verbs. Longer-term the confinement should move to the dispatch layer (see the systemic ticket filed with this epic).', 'done', 'high', NULL, NULL, NULL, '2026-06-11 21:55:26', '2026-06-11 22:39:04', NULL, '50c42cb7af7715e9ea6417212be0ebdc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_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 (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBWE2W1226T58CX37E50HC', 'bug', '06FBHBGHNEQTAEPGNJKN42C1E8', 'Project switch leaks the entire previous workspace service set', 'lib/main.dart:335-344 — switching projects builds a new dispatcher with fresh PaneRegistry, FilesService, EditorRegistry, etc., but nothing calls the old set''s shutdown() methods (which exist and have zero callers). Old file watchers keep emitting into the new workspace''s bus.
|
||||
|
||||
Fix: dispose/shutdown the previous service set before (or while) standing up the new one. Test: after a workspace switch, the old FilesService watcher no longer delivers events.', 'in_progress', 'high', NULL, NULL, NULL, '2026-06-11 21:56:13', '2026-06-11 22:39:32', NULL, 'c0fdac5acbf4332f8d2a632edbc94085', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_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 (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBWE2W1226T58CX37E50HC', 'bug', '06FBHBGHNEQTAEPGNJKN42C1E8', 'Project switch leaks the entire previous workspace service set', 'lib/main.dart:335-344 — switching projects builds a new dispatcher with fresh PaneRegistry, FilesService, EditorRegistry, etc., but nothing calls the old set''s shutdown() methods (which exist and have zero callers). Old file watchers keep emitting into the new workspace''s bus.
|
||||
|
||||
Fix: dispose/shutdown the previous service set before (or while) standing up the new one. Test: after a workspace switch, the old FilesService watcher no longer delivers events.', 'done', 'high', NULL, NULL, NULL, '2026-06-11 21:56:13', '2026-06-11 22:44:05', NULL, 'ab0fad47ab342a3578b9fec64dd886e7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_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