A first visit resolved to Chinese regardless of the browser: LocaleService
read `dsh.locale` and fell straight back to `zh` when nothing was stored,
ignoring the languages the browser already states it reads.
The initial locale now resolves through three ordered sources — the persisted
preference, then `navigator` (first entry of the ordered language list whose
primary subtag names a shipped locale, so `zh-Hans-CN` -> zh and `en-GB` ->
en), then `FALLBACK_LOCALE`. An explicit choice still wins and nothing writes
the detected locale back to storage, so "has the user chosen?" stays a
question only the stored value answers.
Specs asserting the shipped Chinese copy now state the browser they assume:
the web e2e scenarios open their page with `locale: ZH_BROWSER_LOCALE`, and
package specs pin it through the new `pinBrowserLanguages` test helper.
`settings-chrome.e2e.ts` gains an English-browser scenario as the
assembled-app proof.
Review follow-up: the llm/adapters-updated listener's disposer was
discarded, leaving it firing (harmlessly, behind isDisposed()) between
TUI shutdown and fiber disposal, asymmetric with the sibling channel
listeners. The controller now exposes detach(), and the channel's
detachListeners() calls it on both the dispose() and startup-failure
paths.
The master merge added a required archivedSessionIds field to WorkspaceListState;
the read-card spec's DetailsPanel fixture state needs it to typecheck.
The card is a React child of the wrapper, so capture-phase presses on it
reached the wrapper's dismissal handler: the first pointerdown of a text
selection closed the card, contradicting its JSDoc contract. Restrict the
immediate close to presses outside the card, keeping it mounted under a
held press (and the browser click with it), and align onPointerLeave's
grace arming with Menu (only while open).
Pin both new behaviors in hover-card.spec and update the bilingual Agent
Note.
session-telemetry-otel owns the identity as its own module (src/user-id.ts):
getOrCreateAnonymousUserId() returns the bare UUID line in $DSH_HOME/.userid,
minting a random UUID v4 on first use — synchronous IO with a process-lifetime
memo keyed by resolved path, an exclusive-create (wx) settle for concurrent
first launches, best-effort on read-only homes, and deletion resetting the
identity on the next launch by design.
The backend carries the id as the Resource's user.id (the OTel semconv user
attribute), once per export batch alongside service.name/service.version.
The identity belongs to the OTel feed alone; the dsh-sdk launcher telemetry
keeps its own separate store.