* feat(mobile): finalize structured native Codex chat
* fix(mobile): close structured chat lifecycle gaps
* wip(mobile): fence stale structured inventory and bound operation-id retention
Fence local structured-session inventory and subscription responses with a
sync generation so a toggle-off clear, reconnect restore, or retry cannot
apply a mirror from a superseded instance. Bound mobile ambiguous
operation-ID retention at 128 with unmount cleanup.
Staged on the reconcile branch only: the sync module is now 312 lines and
needs a real split before this can reach the PR head.
* fix(ci): split the structured session-tabs sync and give static analysis mobile types
The local structured session-tabs sync module outgrew the 300-line cap once it
took on generation fencing, so split it along its real seams instead of raising
the cap: the generation/cursor fence, snapshot projection, snapshot apply,
inventory refresh, and the subscription loop. The original path stays as a
barrel so no importer moves.
Repoint the host-session-mirror settle census at the apply module, which owns
two receipts now — the snapshot it mirrors in, and the toggle-off teardown that
retracts what it published. The teardown receipt is named rather than anonymous
so the pin says which direction it settles.
The changed-code quality gate lints mobile files and resolves their types from
mobile/node_modules, but mobile is a separate pnpm project that the root install
never populates, so every mobile type degraded to an `error` type and the gate
reported phantom findings. Install mobile dependencies in static analysis when
the diff touches mobile, gated on a new classifier output.
* fix(mobile): let a slow capability handshake still reach connected
The mobile capability update is an advisory whose result is discarded, yet an
unanswered one was fatal while an explicit rejection was tolerated. A 5s timeout
on the direct client force-closed the socket, and on the relay path it failed
`confirmResume` before `connected` was ever published, so a consistently slow
link redialled forever. Both paths now share one helper that settles every
ambiguous outcome (timeout, mid-flight drop) like a rejection and rejects only
when the frame never reached the wire — the one case nothing else recovers from,
since the socket's own desync force-close is gated on already being connected.
The generation guard still keeps a replaced session from connecting.
Retained structured-session operation ids were capped at 128 with oldest-first
eviction, but every retained id belongs to a send whose outcome is unknown, so
eviction turned a user's retry into a second message on the host. Bound the map
by expiry against the id's own embedded timestamp instead, mirroring the host's
operation ledger, so no id is released while the host would still honour it.
Also give the mobile CI install the root install's lockfile drift guard (mobile's
lockfile carries patchedDependencies a silent rewrite would drop), gate
mobile_dependencies on should_run, and key the pnpm store cache on both lockfiles.
* refactor(mobile): extract the relay pending-request registry
The merge composed two independently-sized changes — this branch's capability
handshake settle and main's dial-stage tracking — pushing the relay session file
to 304 lines against a 300 cap. Neither side broke it alone.
Move the in-flight request registry (id generation, tracking, settlement, and
reject-all with its delivery-ambiguity marking) into RelayPendingRequests,
matching the existing collaborator pattern alongside RelayDialStageTracker and
RpcSessionLivenessWatchdog. No behavior change.
---------
Co-authored-by: Merge Sim <sim@local>
Phase 6 of the relay split: the relay's deploy/operate surface moves under cloud/ with 24 cloud-* workflows gated on ORCA_CLOUD_OPERATIONS_ENABLED, the Cloud SQL rollout lease action, the relay Terraform root (dual-accept identities for both repositories), scripts, docs, CODEOWNERS, and a terraform validate job in Cloud Verify.
* Speed up PR CI with per-job path skips and native caches
Skip git-compat, xterm, packaging, and shell jobs when their inputs are
unchanged, reuse the composite install action (including Windows node-pty
cache), skip compiling the Windows CLI launcher on a cache hit, and cut the
test matrix from 16x2 to 8x2 shards without dropping coverage.
* Widen PR job skip prefixes for orcad browser and live shells
Chrome session/tab modules and zsh/fish wrapper templates are inputs to
required jobs the classifier previously skipped. Include that implementation
graph so those jobs still run when the files they load change.
* Fix CI cache safety and required gates
* Build scriptless Windows addons explicitly
* Preserve node-pty Windows support prebuild
* Remove duplicated Windows launcher unit lane
None of these change what CI checks — they remove work the runners
repeated on every PR.
- install-node-dependencies installed with --no-frozen-lockfile, so every
job re-resolved the graph against the registry to recompute what the
lockfile already pins. Measured at ~62 MB of packument metadata per job;
the pnpm store cache does not cover the metadata cache, so this was paid
~39 times per run. The `git diff` guard that made the re-resolution
redundant stays.
- --ignore-scripts leaves node-pty with no build/Release, so
ensure-native-runtime node-gyp-compiled it in every job asking for a
runtime. Cache the build under an ABI-bound key (runtime, resolved Node
version, node-pty patch) with no restore-keys, since a partial match is
exactly the mismatched build that would be recompiled anyway.
- The four fetch-depth: 0 checkouts pulled full history including every
historical blob (blobs are ~89% of this repo's pack). They only need the
commit graph for a merge-base diff, so fetch them blobless. Measured
30-43s each today versus 8s for the shallow checkouts. One of them,
e2e-paths, gates the entire E2E chain.
- E2E jobs ordered setup-node before pnpm, which meant setup-node could not
find the store and no E2E job cached dependencies at all. Reorder and
cache; this sits on the critical path in both the build job and each
shard.
- git_compatibility rebuilt Git 2.25.5 from a pinned tarball on every PR.
Cache the build; the sha256 assertion still guards the miss path.
- typecheck ran three independent tsc passes back to back and discarded the
.tsbuildinfo each project already emits. Run them concurrently and cache
the incremental state.
- package (windows) built the electron-vite targets serially via
build:release. Use a :parallel variant that overlaps them, matching what
the Linux package job already packages and smoke-tests from.
Contract tests cover each new cache's ordering and key so none of them can
silently start serving a stale or ABI-mismatched artifact.
The Windows release job hard-failed in run 30125672117: every SignPath
module install attempt got 403 Forbidden from the gallery's OData API,
which is behind Azure Front Door and was also serving 502/504 at the
time. That step was the only hard-fail in an otherwise fail-open signing
chain, so a gallery incident blocked the whole release.
The gallery CDN that serves the nupkg is a separate origin and stayed
healthy throughout, so fall back to a pinned version fetched from it
after the normal install path is exhausted. The fallback verifies a
SHA-256 pin, since that route skips the gallery's own package
validation.
Extracted to a composite action so the release job and the signing
rehearsal cannot drift apart.