Repository navigation
investigate(android): separate ADB transport addressing from device-command payload #2617
Description
Activity
Design trace complete — production path taken in #2632
The bounded trace, the prototype, and the migration all happened. #2632 is the production cut set. Per this issue's own instruction ("do not mark this issue as a completed implementation"), I am leaving it open for a maintainer disposition and recording the artifacts here.
Route table (as shipped)
Every row states who parses, who owns device selection, who owns the adb server, and where flat argv is finally produced. Flat argv is produced in exactly one function,
serializeAndroidAdbInvocation, and consumed by exactly one lowering,lowerAndroidAdbInvocation.Ingress Parses Owns device selection Owns adb server Emits argv Local device route ( createLocalAndroidAdbProvider().exec/.spawn,createDeviceAdbExecutor)parseAndroidAdbArgvthe route's device id deviceServerPort: lease → built-with port → per-call optionserializer + androidManagedAdbEnvironmentProvider-scoped device command (ALS scope holding a provider) parseAndroidAdbArgvscope serial provider's own transport; caller argv minus the scope's -spair (androidAdbPayloadWithoutSerial)provider decides Host command inside a lease ( runAndroidHostAdb)parseAndroidAdbArgvscope serial adopted lease port, carried in the target serializer Ambient host command (no scope) parseAndroidAdbArgvcaller's -s, kept as typed addressingcaller's -P/ inherited envserializer re-emits the remembered argv unchanged Background spawn ( AndroidAdbSpawner, scoped background transport)parseAndroidAdbArgvas the device route same single channel host spawnAdbLimrun session builder, no parse tunnel serial ambient host port → serializer Root binding ( src/platform-runtime-android-adb-host.ts)nothing (input already typed) target requireAndroidAdbServerPortserializer + env lowering API as built
AndroidAdbInvocation = { target: { selector, server, waitFor?, hostGlobals? }, command, rawArgv? }. Grammar data (ADB_GLOBAL_OPTIONSarity, 20wait-for[-TRANSPORT][-STATE]forms, managed-forbidden commands) is one table read by the parser, the managed policy, and their tests. Operations:parseAndroidAdbArgv,serializeAndroidAdbInvocation,androidAdbInvocation,androidAdbSerialTarget,androidAdbOwnedServerPort,requireAndroidAdbServerPort,applyManagedAndroidAdbServer,requireManagedAndroidAdbSerial|Command|Addressing,requireAmbientAndroidAdbSerial,androidAdbPayloadWithoutSerial,androidManagedAdbEnvironment.Relays removed, additions
Removed:
findAdbSerialIndex,readAdbSerial,stripAdbSerialArgs,withServerPort,scopedServerPort,adbInvocation(the-s/-Pstitcher),assertManagedAdbCommand,transportMismatch, the inline['-s', serial, ...args]/['-P', String(port)]stitching at six call sites,LimrunAdbInvocation(structural type copy), and a second argv projection in the provider. Added: one parse/serialize pair, one port reconciliation, one payload projection. No registry, no framework, no new seam.Characterization against the current path
Against
pnpm test:unitandvitest --project provider-integration, including the 21-selector managed oracle and the provider recording/lifecycle scenarios. Three intentional deltas, each pinned by a test:- Under a private server, global options that transport cannot restate (
-t,-H,-L,-a,-d,-e, a second-s, a secondwait-for) are refused withmanaged-device-transport-mismatchinstead of being silently left behind or restated. - Provider forwarding keeps the caller's argv (readiness tokens and globals included) instead of a rebuild.
- A per-call
serverPortthat disagrees with the port the route owns is refused; without a lease the built-with port wins, as before.
Cost
27 files, +1508/−350 gross. Production-only: 13 files, +726/−240, net +486 — the grammar table, the algebra, and the managed rules that were previously spread across five relay functions. Eager closure did not move:
mechanicsevaluates 177 modules as at the merge base,adb-host1,provider-limrun/indexunchanged; ADR-0019's no-growth gate passes with no budget row edited. Addressing lives insideadb-transport.tsprecisely because a new module on a façade path would fail that gate.Released API
The published
agent-device/android-adbsurface is untouched on this branch:AndroidAdbExecutor,AndroidAdbExecutorOptions(serverPortanddetachedretained), and its nine*WithAdbhelpers keep their shapes, andsrc/__tests__/android-adb-public.test.tsneeded no edit. Nothing published was removed, so nogit tag --containsobligation arose.Recommendation
Continue — the migration is worth what it cost and is done. Residual evidence still owed, not obtainable in this environment: a live managed-lease run against a real private adb server (no Simlock host/token here) and a live Limrun session (no API key).
snapshot/pressUI checks additionally needpackage:android-snapshot-helperassets this worktree lacks. Live coverage here was the ambient local route onemulator-5554.- Under a private server, global options that transport cannot restate (
- added 4 commits that reference this issue
on Sep 15, 2026 Maintainer disposition: closing. The investigation's deliverables (route table, proposed API, continue/stop recommendation, cut set) are in the comment above, and the production cut landed as #2632 (
17eabc8fd1, iOS/macOS/Linux lanes green on main). The residual live evidence it names (managed-lease against a private adb server, a Limrun session) is #2632's obligation, and theserverPorttype cleanup it identified is tracked as #2640.
investigate(android): separate ADB transport addressing from device-command payload
Question and evidence
Can typed transport addressing eliminate repeated flattening/reparsing of ADB arguments while preserving local, provider and managed-device routing?
At PR #2611
a3a0ea216356813323b0008642c05f6f5dc57fcc, transport prefixes and device commands share one argv. Provider scope reads and strips serials, Limrun adds one again, managed-host wiring rewrites ports, and generic host copies relay device-shell provenance.Evidence: kernel construction/relay,
packages/platform-android/src/adb-provider-scope.ts, Limrun prefix, managed host normalization, andsrc/platform-runtime-host.ts/src/platform-runtime-operation-host.ts.Investigation scope
This issue authorizes a bounded design trace and disposable prototype, not a production migration.
serialandserverPortrepresent the entire ADB grammar.{ target, command }, where target carries validated transport selection and the shell command retains kernel-owned quoting/provenance. Identify where generic argv enters and where final argv is serialized.Acceptance and stop criteria
Dependencies and exclusions
Blocked by: #2611 landing. Re-audit its merged transport shape first. #2026 owns quoting and the exhaustive current migration; this investigation must not broaden or block it. #2545 owns daemon/root closure, not ADB invocation representation. No HarmonyOS redesign, provider admission redesign, new enforcement framework or issue-driven production changes in this spike.
Effort: M for investigation; production migration likely L. Risk: medium–high for a later migration because routing and device isolation depend on normalization. No existing issue found for separating these representations.