| 1 | # App session ownership |
| 2 | |
| 3 | [简体中文](APP_SESSION_OWNERSHIP.zh-CN.md) |
| 4 | |
| 5 | Display identity, ordered snapshots, paging and recovery are described in |
| 6 | [Transcript projection](TRANSCRIPT_PROJECTION.md). |
| 7 | |
| 8 | Session actions capture their source when invoked. A later tab change cannot |
| 9 | redirect a pending send, cancel, approval, model update, or navigation completion |
| 10 | to the newly selected session. Layout-committed command registrations publish |
| 11 | authority; replacement generations and unmount revoke old continuations. |
| 12 | Background cancellation resolves the canonical controller target rather than a |
| 13 | UI tab identifier. Missing or replaced targets produce a stale outcome. |
| 14 | |
| 15 | Subscription scopes revoke queued deliveries before releasing registrations. |
| 16 | Terminal output uses reference-counted leases so an old cleanup cannot release |
| 17 | a newer subscriber. AppRuntime wires these owners to AppRuntimeView. App.tsx is a small composition |
| 18 | entry; the view receives committed commands and presentation data without |
| 19 | creating a second session authority. |
| 20 | |
| 21 | Remote resume rejection completes behind the tab's publication fence. Session |
| 22 | identity, title, route, pending prompts and runtime state are restored before |
| 23 | the error becomes observable. HTTP rejection, busy, listing failure, missing |
| 24 | target and transport reconciliation share that completion owner. Generation, |
| 25 | client, selection and route ownership are rechecked before restoration. |
| 26 | |
| 27 | Generation replacement, retirement, reconnect, host suspension and explicit |
| 28 | close follow the same per-tab publication order. Network handshakes and pump |
| 29 | waits remain outside the fence; map snapshots are revalidated after taking it. |
| 30 | |
| 31 | ## Local readable history and runtime readiness |
| 32 | |
| 33 | Local navigation starts a bounded canonical history read after publishing the |
| 34 | target tab identity, independently of controller activation. A readable history |
| 35 | window can appear while runtime setup is still pending. Draft input stays mounted |
| 36 | and editable, while send/control actions retain their runtime readiness fence. |
| 37 | Runtime failure preserves history that already arrived; it cannot turn an |
| 38 | unfinished history read into a successful empty transcript. Remote transitions |
| 39 | keep their existing presentation gate. |
| 40 | |
| 41 | Navigation detaches renderer subscriptions and retains history under the existing |
| 42 | store budgets; explicit close evicts it. Lazy bodies can hand off once to a newer |
| 43 | generation of the same resident owner. Eviction or close/reopen ends the old read. |
| 44 | Retained residency alone does not prove a navigation cache hit: canonical history |
| 45 | generations and legacy tab fingerprints are different identity domains, and a new |
| 46 | tab binding needs explicit ownership reconciliation. Browser-mock paint timings |
| 47 | do not establish native backend latency or cross-binding cache reuse. |
| 48 | |
| 49 | ## Remote bootstrap lock handoff |
| 50 | |
| 51 | A remote server owner can release its directory between a competing exclusive |
| 52 | mkdir and the contender's Stat. The acquisition owner retries this missing |
| 53 | observation once, through exclusive mkdir again. Only Exists or structured |
| 54 | SFTP v3 generic failure qualifies; permission, transport and cancellation |
| 55 | errors remain terminal. A second consecutive missing observation fails closed, |
| 56 | because the protocol cannot distinguish repeated contention from a permanent |
| 57 | generic failure. Observing a live lock restores the normal context-bound wait. |
| 58 | This does not change the separate stale-lock reclamation policy. |
| 59 | |
| 60 | `go test -race ./internal/remote/bootstrap` covers the release interleaving, |
| 61 | bounded permanent failure, cancellation and one-launch concurrent clients. |
| 62 | |
| 63 | ## Verification |
| 64 | |
| 65 | `pnpm test:app-lifecycle` exercises source capture, committed publication, |
| 66 | supersession, A-to-B-to-A navigation, canonical background cancellation, |
| 67 | unmount, subscription disposal, and negative memory-protocol fixtures. |
| 68 | `pnpm test:app-browser` replays real local/remote navigation, send/Stop, |
| 69 | three layouts, and Composer/Workspace DOM identity. `pnpm test:all` discovers |
| 70 | the remaining frontend regression suites. |
| 71 | |
| 72 | `cd desktop && go test -race . -run 'TestRemoteResumeFailure|TestOpenRemoteProjectTabRejectedResumeRestoresPreviousIdentity|TestRemoteRejectedResume'` |
| 73 | covers error-time identity, all rejection paths, lost ownership and publication |
| 74 | interleavings with retirement, reconnect, host suspension and close. |
| 75 | |
| 76 | ## Independent memory screening |
| 77 | |
| 78 | The App memory workflow builds the requested clean commit once. Ordinary frontend |
| 79 | pull requests run one short process with 32 full, 32 windowed, 32 safety, and 128 |
| 80 | mixed round trips. App lifecycle, Transcript, navigation, subscription ownership, |
| 81 | memory fixture and CI-routing changes run the full three-process protocol. Pushes |
| 82 | to `main-v2`, daily schedules and manual dispatches also run the full protocol: |
| 83 | each process executes 128 full, 128 windowed, 128 safety, and 512 mixed trips. |
| 84 | |
| 85 | The aggregate requires every checkpoint and heap snapshot, distinct shard |
| 86 | identities, the same workflow attempt, source/build hashes, Node/platform/ |
| 87 | architecture, fixture configuration, browser version and declared profile. |
| 88 | Missing, cancelled, mismatched, or failing shards cannot produce a passing final |
| 89 | check. The result records `screeningLevel` so a short pass is not full qualification. |
| 90 | |
| 91 | The workflow runs for frontend changes and unknown paths. Known independent |
| 92 | backend and documentation paths may skip this mock-frontend soak; existing |
| 93 | platform CI continues to cover those paths. The stable `app-memory` job checks |
| 94 | that any skip was explicitly selected and its prerequisite states agree. |
| 95 | |
| 96 | A `SHARD_PASS` is only one complete process. Aggregate `PASS` is automated |
| 97 | screening, not a whole-App memory-leak proof: heap-retainer analysis and a |
| 98 | mainline control comparison remain separate attribution work. Reports preserve |
| 99 | that pending status. PR-head evidence also does not replace integration and |
| 100 | native checks against the current target branch. |
| 101 |