The stream-gating hook (#13608) and the subscription parking installer
(#13621) each reimplemented `isWindowVisible() || isDocumentVisibilityProvenStale()`
plus its visibilitychange + stale-recovery subscription, and each carried
its own 500ms park delay that agreed only by coincidence.
Extract both into `lib/window-park-visibility.ts` and leave the two
consumers as thin wrappers: `useWindowStreamVisible` feeds the snapshot
and subscribe into `useSyncExternalStore`, the parking installer calls
them imperatively. The subscribe now always uses the defensive
`typeof document` guard the parking side already had, and registers
stale recovery before the visibilitychange listener so the stale latch
is cleared before the callback reads it.
Both park delays now derive from one `WINDOW_HIDE_PARK_GRACE_MS`: they
debounce the same signal against the same user behaviour (a quick
app-switch round trip). The parking side's 8x reveal-side backoff stays
where it is - that models its own resume cost, not the grace window.
Renderer-authoritative gating (#13622 native chat, #13634 editor panels)
is deliberately left alone; it keys off Zustand routing state, not OS
visibility.
Also switch the active-runtime ref writes in web-session-tabs-sync to
`useLayoutEffect` so no resume event can land between paint and the
passive flush, and correct the stale comment above them - the install
effect reads neither ref (both readers are gated on `isVisibilityResume`).
Mark invalidated diff content stale instead of dropping it, mirroring the file-content treatment from #13634. The diff read-generation fence (diffReadGenerationRef) already rejects a superseded read's write-back, so retaining the bytes and swapping them on arrival is safe and keeps every RPC saving -- it just stops the loading placeholder flashing on each reveal.
The git-status reload effect now treats a stale entry like a missing one so the lazy-load effect stays the single fetcher for it.
Co-authored-by: Orca <help@stably.ai>
* perf(native-chat): suspend hidden transcript streams
* fix(native-chat): keep assembly renders pure
* fix(native-chat): keep a transient error from stranding a revealed chat
- An error snapshot frame no longer latches frameArrived, so the in-flight
read can still seed the pane instead of leaving it on the error surface.
- Retained history is shown over a full-pane read error for the same source.
- The paged read window survives a hide/reveal; only a source change resets it.
Co-authored-by: Orca <help@stably.ai>
* fix(mobile): match the trimmed native-chat retention signature
The shared retention type no longer takes `loading`, so mobile's call was an
excess-property error that broke the mobile typecheck job. Dropping it also
lets mobile inherit the desktop behavior: a stream error or dropped client
keeps the last transcript instead of swapping it for the error empty state.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* perf(renderer): park hidden remote browser screencasts
* test(renderer): pin stale-visibility term and parked-unmount teardown
Restores the WHY behind the '|| isDocumentVisibilityProvenStale()' term the
emulator-module dedupe dropped, and pins it plus the close-tab-while-parked
path with tests. Extracts the lifecycle harness so the spec stays under
max-lines without a suppression.
Co-authored-by: Orca <help@stably.ai>
* fix(ci): exclude test-support modules from the localization audit
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* perf(remote): park hidden session mirrors
* perf(renderer): bound visibility resume cost and repair fences
- Back off the park delay after a park the user undoes quickly; each resume
re-enumerates every paired host, so short hide/reveal churn now stops
parking instead of paying that cost per cycle.
- Expire the active-worktree omission fence one visibility generation after
the inventory that set it, and name the unfiltered-inventory invariant it
depends on.
- Never skip the unchanged resume inventory for a worktree whose repair
replay is already armed.
Co-authored-by: Orca <help@stably.ai>
* fix(renderer): move active-runtime ref writes out of render
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* perf(editor): park hidden external reloads
* fix(editor): sync content refs after commit
* fix(editor): close post-commit ref window
* test(editor): cover commit-time visibility
* fix(editor): keep invalidated content visible and stop redundant reads
- Mark invalidated file content stale instead of dropping it so a reveal swaps
bytes in place; the read-generation fence already blocks stale write-backs.
- Skip the lazy read when the newest read for the tab is still outstanding, so
a worktree flip-flop cannot double-fetch.
- Stop claiming Cmd/Ctrl+S outside the workspace view, where no mounted panel
owns the request and the keystroke was silently swallowed.
A write landing during a full scan was recorded by the post-scan gate stat,
so the next tick saw a clean gate and the create/delete waited up to 15 ticks
(~30s) for the backstop. Sample each gate dir's signature before its listing
so a racing write reads as stale and forces one rescan on the next tick.
Also fixes the flaky 'retires stale marker probes' spec: a folder caught
mid-rm opened a pending-marker window that the swallowed gate change kept
alive for the whole backstop gap (43 probes vs the 30 budget).
Co-authored-by: Orca <help@stably.ai>
* Add copy button to quick commands with visual feedback
Quick command rows now display a copy button that copies the command body to clipboard. The button shows brief visual feedback ("Copied" or "Couldn't copy") and is disabled when the command body is empty. Includes desktop and mobile UI, tests, and full i18n support.
* fix(ci): unblock verify for quick-command copy button
Key feedback to the copied body so prop changes drop stale labels without
setState-in-effect, and mock expo-clipboard in the mobile list test.
* perf(renderer): dedupe remote status hydration
* fix(runtime-status): re-list host catalog when the listing goes stale
Coverage matching cannot observe catalog edits made by another client or the
orca CLI, so gate hydration on catalog listing age too.
Co-authored-by: Orca <help@stably.ai>
* test(runtime-status): reset the catalog listing clock between tests
The staleness guard keeps its last-listed timestamp in module scope, so the
TTL test left fake time behind and made every following test in the file
depend on its position. Add a reset hook, call it in beforeEach, and pin the
TTL invariant on an externally added host rather than the timer alone.
Also extracts the coverage predicate in fetchSettings and restores the WHY
comment about compat failures clearing on a reachable status.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* perf(codex): skip migration scans for nonshared reattaches
* fix(codex): require provenance to skip migration scans and bound ignored launches
Drops the exit-match escape hatch that skipped a scan without route provenance, and ages out ignored reattach launches on the existing 60s/256 lease policy so a lost exit can no longer pin an active launch (and its completion marker) for the process lifetime.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* perf(runtime): avoid forced SSH hydration on project refresh
* fix(runtime): backfill SSH states for targets learned without a state read
A failed-connect resync labelled a target with no ssh.getState, and the new
metadata-refresh gates then skipped it forever: no SSH chip and every worktree
mutation to that host failed the connection-generation check.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>