* fix(web): fix dock view task-switching regressions
Three bugs caused broken UI when switching tasks in the dock view:
1. Environment key migration was dead code — data stored under fallback
sessionId keys became invisible when the environmentIdBySessionId
mapping was later set, because migrateEnvKeyedData was never called
in production (only in tests via registerSessionEnvironment).
2. Orphaned portals leaked on every fast-path session switch — the
isRestoringLayout guard in setupPortalCleanup blocked portal release
for panels removed during the fast path, accumulating invisible React
trees with live WS subscriptions.
3. Chat panel gap during fast-path transition — old session tab was
removed synchronously but new tab was deferred to a useEffect,
leaving a brief layout gap.
* fix(web): remove superfluous args in test helper
Address CodeQL finding — createSessionSlice only takes `set`, not
`get` and `api`.
* fix(web): add addPanel test assertions and doc comment
Address claude-review blocker: assert that fast-path creates the
session panel with correct id/params, and skips creation when it
already exists. Add doc comment noting syncEnvironmentMapping
requires the combined store draft.
* test(web): add PanelPortalManager.reconcile tests
Export PanelPortalManager class for testability and add tests covering
reconcile removal, no-op, and listener notification paths.
* refactor: re-key dockview panel state by environmentId instead of sessionId
- Remove terminal from SESSION_SCOPED_COMPONENTS (uses useEnvironmentSessionId internally)
- Convert ChangesContent and file-editor-panel to useEnvironmentSessionId()
- Re-key sessionCommits store from bySessionId to byEnvironmentId
- Re-key useCumulativeDiff cache by environmentId
- Update WS handler to resolve envKey before invalidating cumulative diff cache
- Update comments across portal manager, session switch, and layout files
* fix: revert useEnvironmentSessionId in file-editor-panel
file-editor is session-scoped and ephemeral — portal is destroyed on
session switch, so useEnvironmentSessionId() has no practical effect.
* fix: address CodeRabbit review comments
- Pass appStore to setupPortalCleanup so terminal tab close still calls
stopUserShell via activeSessionId fallback (entry.sessionId is now
undefined for global panels)
- Add request version guard to useCumulativeDiff to discard stale
responses after environment switches
* fix: scope activeSessionId fallback to terminal only in portal cleanup
vscode is session-scoped and always has entry.sessionId — the
activeSessionId fallback should only apply to terminal (now global).
* fix: migrate stranded env-keyed data on registerSessionEnvironment
When registerSessionEnvironment(sessionId, environmentId) is called,
any data previously stored under the fallback sessionId key is now
migrated to the proper environmentId key. This prevents data from
"vanishing" when selectors start reading by environmentId after the
mapping is registered.
Applies to: sessionCommits, gitStatus, shell outputs/statuses,
userShells.
* fix: extract migrateEnvKeyedData helper to fix lint max-lines
* fix: address CodeRabbit review comments
- Always delete orphaned sessionId key in migrateEnvKeyedData even when
environmentId key already exists (prevents stale accumulation)
- Reset loading state when switching to an envKey with warm cache to
avoid brief spinner flash
* fix: always reset loading on envKey switch in useCumulativeDiff
Prevents stuck loading state on rapid A→B→A env switches where the
stale in-flight response is discarded by version guard but loading
is never reset.
* fix: move sync effect before fetch effect in useCumulativeDiff
React 18 batches effects in declaration order. With the sync effect
after the fetch effect, setLoading(false) from the sync overrode
setLoading(true) from the fetch on cold-cache env switches. Moving
the sync effect first ensures the fetch effect's setLoading(true)
wins the batch.
* test: add migrateEnvKeyedData coverage for registerSessionEnvironment
Tests 4 cases: normal migration, don't-clobber existing data,
no-op when sessionId equals environmentId, and partial sub-key
migration.
* fix: close stale-diff gaps in useCumulativeDiff sync effect
- Bump requestVersionRef on envKey change so in-flight fetches for
the previous envKey are discarded
- Clear loadingState[envKey] so the fetch effect isn't blocked on
re-entry (A→B→A scenario)