cmux-next: session registration resyncs on a same-process reconnect, and a seen refusal does not show again

LA
6d ago
+54-16

Summary

Follow-ups from the sixth review of #28056 (B7a, session registration). Stacked on #28056: this branch starts at #28056's head 8f39adf578f; it should land after #28056, and its own diff is the two commits on top.

  • Same-process reconnect. SessionRegistrar's observation key now holds the home store's connection epoch. A disconnect and a reconnect to the same daemon process that both landed before one key check gave an equal key, so a record waiting for an event after its timed retries was not sent again. The epoch changes only together with connectionState, so it adds no wakeup.
  • A seen refusal no longer shows again. SessionRegistration forgot the shown refusal whenever a new send dropped a pending notice, also a "no answer" notice; a refusal the person had already seen then showed again. It now remembers which pending notices are refusals and forgets only those.
  • SessionRegistrationLedger.retain's doc now says the owner forgets a gone session's shown refusal.
  • Arabic and Thai reasons no longer use one word for both "record" and "log" (the same issue fixed for Spanish in #28056).

Not in this PR: a test that drives SessionRegistrar's observation loop end to end (start the registrar, reconnect or restart the home daemon, check that put-session is sent again). My first note said this needs a production seam; the review showed it does not: existing tests start a real DaemonService against a same-tree cmux-tui (AgentCLIUpdateRecoveryJourneyTests.swift:24-45, also AgentTabSessionTopologyTests, ClassicImportTests). It is a named follow-up as an integration test of that kind. Today the epoch regression test covers homeKey only; that SessionRegistrar passes store.connectionEpoch is checked by reading, not by a test.

Known edge cases, older than this PR (review, low): after a refusal, a "no answer" toast and the same refusal again on a new epoch, the toast keeps the "did not answer" reason (the "not saved" statement stays true); and with refusal A shown, refusal B pending with no window, then the record back to A, A shows a second time (the ledger remembers one shown record per session).

R9: the change is in the notice rule (R-L5: a lost record is shown, once per refusal the person has not seen) and the resend trigger; no new cap.

Owner of the area: PL-daemon (session cmux-b6), plans/cmux-next/OWNERS.md.

Testing

Red commit 2f43463caf2 (tests, homeKey takes the epoch and ignores it), fix e250cb29ef5. The test files are the same at both (git diff 2f43463caf2 e250cb29ef5 -- Packages/macOS/CmuxNext/Tests is empty).

  • SessionRegistrarWiringTests.aReconnectToTheSameDaemonProcessChangesTheKey
  • SessionRegistrationTests.aDroppedNoAnswerNoticeDoesNotShowASeenRefusalAgain

Compile-check of the head and the Mac red (at 2f43463caf2) and green (at the head) of both suites: job ids follow in a comment.

Observed / Not run

  • Observed: prepush-gate.py --base 62e7f04c16b (#28056's merge base) adds no violations; check-l10n.sh has 0 errors at its ceiling.
  • Not run: the fleet jobs (pending). No live check in a running app. Austin's-day numbers: pending harness; no restore step in the scenario.

Changelog

none

Proof

No capture: the only UI is the existing text toast; this changes when it shows, not how.