--- type: knowledge summary: Deciding which identity acts needs no session; connecting does — conflating them deadlocks one way and silently breaks sharing the other --- # Settling is not connecting Two acts of different nature hide behind "sign in": - **`settle`** — decide which identity is acting, from the URL, from storage, or by asking at the `barrier`, then persist it. Pure DOM and storage. **No session required.** - **connect** — restore what was shared with that identity and drain its inbox. **Requires a live session.** They must stay apart, and the reason is not tidiness. ## Why they cannot be one call `init()` starts the broker redirect as its first statement when the page is top-level, so anything the barrier needs to show must already be in place. The `barrier` must therefore appear **before** `init()`. But an identity cannot connect before `init()` either: connecting reaches the application's session thunk, which only `init()`'s own callback resolves. Await the whole of sign-in before `init()` and it deadlocks; call it after and the `barrier` never appears. The way out is that only *half* of it has that dependency. Settling is awaited by this package's `init()` wrapper before it delegates; connecting stays in the published call, awaited where a session exists. **The invariant is carried by the composition from `init()` onwards** — which is why an application must call this package's `init`, not the one it injected: calling it settles the identity whether or not the published call has run. It does **not** cover calling the published sign-in strictly first and awaiting it: the connection work it adds waits for a session only `init()` resolves, so it deadlocks in silence. Half an invariant carried by a mechanism, half still owed to the caller — and the half still owed fails silently, which is the worst kind. ## The failure this cost Settling once reached the session, because recording who is acting also fired the connection. In the reference application `init()` is called *from inside the executor that builds the session promise*, so the thunk could not answer by construction. It threw, the account lookup answered null, and the connection run abandoned **without restoring or draining** — having already registered itself as in flight. The published call then joined that dead run and resolved having done nothing. Symptom: a document shared with someone did not open for them. No error, just unreadable content. Nothing had changed in the connection logic. What changed was *when* the identity was recorded. Before the split, nothing recorded an identity during module evaluation: a session existed, the run was healthy, and joining it was harmless. Hence the shape of the fix — recording who acts and starting to connect are separate operations, and the session-free half only records. To validate: the session thunk must never be called while settling. ## The lesson worth keeping A "session-free" half that calls something which fires a session lookup is not session-free. When splitting on a dependency, check what the *side effects* of each remaining call reach, not only what the call itself does.