perf/fix: PR#48 observability followup — readdir cache, bootstrap spawns, morphdom id, localStorage GC - #12
Merged
Conversation
Fix 1 - readdir cache hot path: detectSubagentTransitions() now statSync's the subagentsDir first. If the dir mtime hasn't changed since the previous call, no new files can have appeared, so we skip readdirSync entirely and skip statSync for any unknown-file entries. Known-active entries still get statSync so the stability timer keeps advancing. Session-local cache: _prevDirMtime, _subFileList on session object. Edge case: when the previous scan returned 0 files, we always rescan regardless of mtime (fast-write within same clock tick). Fix 2 - synthetic spawn for live bootstrap files: Cold-start agents with mtime within BOOTSTRAP_LIVE_MS (60 s) are 'looksAlive'. Previously they were recorded silently, meaning the renderer's liveSubagents / activeSubagents Maps never had a spawned event for them, so any subsequent subagent-completed was a no-op. Now we emit subagent-spawned with _bootstrap:true so the renderer can set up its tracking state. The _bootstrap flag lets it dedupe if it already has independent state. The bootstrap branch continues to use 'continue', keeping it strictly mutually exclusive with the post-bootstrap spawn path.
Assign id='orphan-' + fId to the orphan-subagents container element. Without a stable id, morphdom couldn't match the element between renders and rebuilt it from scratch on every flush, causing minor flicker on projects with many orphan subagents. The id follows the same pattern as other keyed elements in buildSessionsList (sessions-<fId>, older-<fId>, older-list-<fId>).
Add _gcExpandedSubagentsOnce() called lazily on first getExpandedSubagents() invocation. It intersects the stored set with the current sessionMap keys and saves the pruned result, preventing unbounded growth of the key across long-lived Switchboard instances with many agent sessions. The GC is guarded by a module-level boolean so it runs at most once per page load regardless of how many times the sidebar re-renders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Non-blocking improvements from the PR#48 (subagent observability) review.
All 40 tests pass, 0 lint errors.
Fix 1 —
session-transitions.js: readdir cache hot pathdetectSubagentTransitions()previously calledfs.readdirSync()+ N ×fs.statSync()on every flush. With 1372 subagents this blocked the main thread ~70 ms per flush.The function now
statSyncs the subagents dir first. If the dir mtime hasn't changed since the last scan, no new files can have appeared → skipreaddirSyncentirely AND skipstatSyncfor unknown-file entries. Known-active entries still getstatSyncso the stability timer keeps advancing.Session-local cache:
_prevDirMtime,_subFileListstored on the session object (per-session, per-folder). Edge case handled: when the previous scan returned 0 files, we always rescan regardless of mtime (protects against fast writes within the same filesystem-clock tick).Fix 2 —
session-transitions.js: synthetic spawn for live bootstrap filesCold-start agents with mtime within
BOOTSTRAP_LIVE_MS(60 s) arelooksAlive. Previously they were recorded silently, meaning the renderer'sliveSubagents/activeSubagentsMaps never saw aspawnedevent for them, so any subsequentsubagent-completedwas a no-op.Now we emit
subagent-spawnedwith_bootstrap: trueso the renderer can set up tracking state. Thecontinueafter the bootstrap block ensures mutual exclusivity with the post-bootstrap path.Fix 3 —
public/sidebar.js: orphan group stable idAssign
id = 'orphan-' + fIdto the orphan-subagents container element. Without it, morphdom couldn't key the element between renders and rebuilt it from scratch every flush, causing minor flicker on projects with many orphan subagents.Fix 4 —
public/sidebar.js: localStorageexpandedSubagentsGCAdded
_gcExpandedSubagentsOnce()called lazily on the firstgetExpandedSubagents()invocation. It intersects the stored set with the currentsessionMapkeys and saves the pruned result. Guarded by a module-level boolean so it runs at most once per page load.Tests
🤖 Generated with Claude Code