Files
orca/mobile/src
Jinwoo Hong 77829142ac fix(mobile): a terminal opens once at the phone's size, on the page and natively (OTA phase C follow-up) (#22960)
* refactor(mobile): extract the once-per-route terminal viewport measure

Behaviour-preserving move of measureViewportOnce into a pure module so the
first-subscribe ordering can be tested without mounting the session route.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): send phone dims on a terminal's first subscribe

A fresh terminal document has no xterm until its first init, so the viewport
measure could not answer before the first subscribe. The subscribe went out
without dims, the host serialized the snapshot at the desktop's size, the
phone painted it, measured, resubscribed and replayed the whole snapshot a
second time at the phone's size.

The first subscribe of each document now opens an empty terminal, measures,
and only then subscribes, so the host fits the PTY before serializing and the
phone paints once. Measure failure still subscribes without dims and the
existing fit pass takes over.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): converge the fit pass on the viewport the subscribe sent

A frame-height refit can clear the measured flag after the first subscribe
has already carried the phone's viewport. The fit pass then treated the
snapshot as dimensionless and resubscribed, replaying the whole snapshot a
second time at the same size. It now judges convergence against the
viewport that subscribe actually sent; the refit still owns real layout
changes through updateViewport.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* test(mobile): reject the failing measure without an async wrapper

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): keep the fit-pass decision on the measured flag

Converging on the viewport a subscribe carried accepted a stale one: after
native chat covered the terminal through a rotate or dock, the return
resubscribe sent the old dims, the host matched them and the pass never
re-measured (#4579). The decision is back on the measured flag; the sent
viewport only lets a matching fresh measure skip the round trip.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): forget a document's first-subscribe mark only on web-ready

The terminal handle re-attaches null then new on every theme or text-size
change, and clearing the mark there let the next resubscribe post an empty
init onto a live document. web-ready is the one signal that a new document
started, so the mark is dropped there instead.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* test(mobile): pin each held-subscribe teardown guard on its own

Splits the teardown test so dropping either the generation check or the
in-flight check alone fails a test, and shares one MutableRef type.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
2026-09-25 21:02:10 -04:00
..