Repository navigation
Conversation
… §Discovery ladder) The port scan took the first answering server, which on a machine with parallel worktrees is often another project's. The scan now reads X-React-Native-Project-Root from GET /status and compares it with this project's root. A foreign server is skipped. When only foreign servers answer, discovery is unreachable and reports them in foreignServers, and status prints them. A server with no header is accepted with projectRootVerified: false. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9CwPuoTfcRMrAGrgqGRza
…ead, and checks the log port (llp/0004 §Discovery ladder) A /status that times out is no longer the same as no header: it is retried once, then the port is not accepted and the reason names it. The start.log port gets the same project-root check as a scanned port. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9CwPuoTfcRMrAGrgqGRza
…other project (llp/0004 §Discovery ladder) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9CwPuoTfcRMrAGrgqGRza
…t, so a Metro on 8081 no longer skips it (llp/0004 §Discovery ladder) The lock's fallback is the step's --port, so pinning one makes 8081 irrelevant. Run with a stand-in foreign Metro on :::8081 answering /status with another project root: the test runs and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry ladder, §A busy port) The four commits before this one cite the rejected branch's llp/0028 and llp/0030, which main never had. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… checked before the lock publishes, and the port watch requires isRunning (llp/0004 §Discovery ladder) Review fixes for #132. A server whose /status is slow is judged within 3 s on two tries, not within the probe's 800 ms. The lock checks a named port for another project's root before it publishes, as it already did for the fallback. The port watch after a foreign fallback has no deadline, so isRunning is required. projectRootVerified and ForeignDevServer.url, which nothing read, are gone, with the duplicate @ref and a cast. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…verAsync's doc block, not inside it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d status reads it within its own budget (llp/0004 §Discovery ladder) A read that used its budget is unproved at once, so a stalled /status costs one budget, not two. status passes its 1.5 s probe budget as the read's, so the specific reason reaches the report instead of its 3 s deadline cutting the read off. The constant's comment says what the budget does: a slow /status is accepted, a stalled one is unproved. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
During parallel native builds, another worktree can claim a detached child's initial port before its Metro starts. The parent previously accepted that foreign server's ready response and reported success while its own build continued. Follow the child's lock throughout the readiness wait, cancel the old status request when the port changes, and reject explicit project-root mismatches. Keep one timeout budget, preserve child-failure reporting and older Metro versions without a root header, and honor --wait-ready when reusing an existing server. Final status checks also reject a foreign root. Validation: all 4,785 unit tests pass; all 27 detached-start end-to-end tests pass, including real HTTP/lock-socket port changes and cancellation of an obsolete request. Typecheck, build, formatting and lint pass (existing warnings outside changed files). Place immediately after #132 and before #133. The regression tests reproduce the false success against the original implementation. Native command-connection cleanup is separate Expo work.
…unner, digestOf, and one xcrun stub (llp/0030) Moves the simctl, adb and EAS session-stop parsers and runners into src/device, exports digestOf, adds the Runner type, and makes installedAppStubs' installStubXcrunAsync the one xcrun stub of navigate, stop and runtime-reload. This changes no behavior. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d, as the real one boots it (llp/0030) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d under a lock and read by every verb (llp/0031 §The module) src/deviceBinding/ holds the records, the lock, the lease, the choice, the inspect table and the rung loop of llp/0030, with the iOS boot through simctl bootstatus -b. No caller yet. The reap and the Android half arrive with llp/0032 and llp/0033. The five design files land with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ads the binding (llp/0031 §How `dev` uses it, §Readers, §smoke) The resolver binds for a serving draft before its presence probe; a building draft is bound after the refusals; every run and install step carries --device <udid>, and the open takes the bound device. dev --detach on a running server reuses the parked simulator or refuses not-reusable, and the child's DEVICE_* and NO_BOUND_DEVICE refusals reach the caller unchanged through the verdict's code row. navigate, runtime:*, status and the installed readers walk the rung loop; the EAS fallback accepts the dotenv id only. smoke's iOS boot is the registry's, left bound. The first-booted probe, pickSimulator, the iOS boot and NO_DEVICE go. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…or, two worktrees get two simulators, and the docs name the bound device (llp/0031 §Tests, §Docs) The stub xcrun binds the booted simulator it lists; the smoke boot cases assert the registry file and bootstatus -b; a two-worktree dev case pins distinct E2E-CREATED-* udids on each run:ios --device. The first-booted sentences of llp/0004, 0005, 0022, 0025 and 0026 read the bound device. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y line stays the dev command, the relayed refusal keeps its data, and the old simulator reader goes (llp/0031 §How `dev` uses it) A Mac without an Android SDK reaches `absent` again, because the iOS inspection answered. A NO_BOUND_DEVICE refusal keeps `dev` as its Try line; --print-url is an Or: door. The detached child's code row carries `data`, and only the Try line next to it counts. smoke keeps the How line in its boot reason and prints the acquire line. The EAS fallback asks the service only when the dotenv names a session. The booted-only simulator reader is deleted. The named tests produce the child's log through logCmdError, forward a --device the pin replaces, and pin the acquire line before the report. 0031 says the order built and the decisions taken; 0030 gains the boot-failed row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…runtime that lists one, not the newest runtime's only iPhone (llp/0030 §Choice) iOS 27.1 lists iPhone Duo alone, and no app rendered on it. The choice now walks the available runtimes newest first and takes the first with an `iPhone <n> Pro`, else an `iPhone <n>`; only when no runtime has one does the newest runtime's first iPhone apply. The RFC's §Choice sentence says so, and §Risks gains the observation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… pass on Windows (llp/0031 §How `dev` uses it) The live-cloud suite runs dev --ios --no-open on a Linux worker to serve for an EAS session it opens itself; the acquire ran xcrun there and failed. iOS simulators exist on macOS only, so the callback binds nothing elsewhere, as on main. On Windows the function-length guard split on LF and never saw a lone closing brace in a CRLF checkout, and the binding's project root is the canonical path, which is a drive path there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o dev creates on a runtime that works (llp/0030 §Choice) simctl keeps listing such a simulator with isAvailable false. The reuse took it, bootstatus failed, the failed boot kept the binding, and every retry picked it again. The choice and the listing now read an unavailable simulator as missing: the binding is removed and a new simulator is created, and read verbs report gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ktree on a free console port, and kills only what it spawned (llp/0032 §Android boot) acquireDeviceAsync takes 'android': adb devices -l and emulator -list-avds before the lock, busyPorts and the first free even port in 5554..5584 under it, the detached spawn and one binding with serial and pid in the same section, sys.boot_completed after it. inspect reads get-state plus the pid for a spawned instance. The let-go of a spawned binding removes the file, then kills the pid only while ps names its -avd and -ports. The injected Android rung stays for its one caller until the next commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…oid acquires, the readers inspect get-state, smoke binds and keeps it, and run:android gets --device <serial> (llp/0032 §Wiring) The injected Android rung, the first-adb-device probe, the emulator boot and the emu-kill shutdown go. The presence probe asks the bound device on both platforms and pins nothing, because withDevice pins every run and install step. The installed reader takes the bound serial, and lists only to filter --device. The e2e stub adb answers get-state and sys.boot_completed, a stub emulator stays up until killed, and the dev e2e spawns two read-only instances on 5554 and 5556. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nges, and what was decided while building (llp/0032 §Decided while building) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…creenshot tests guardedCloudArgs carries the controller target as base64, but two unit tests still parsed it as JSON. guardedCloudTarget decodes it beside the encoder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vonovak
force-pushed
the
codex/eas-session-binding
branch
3 times, most recently
from
October 12, 2026 20:20
aa67ba1 to
09287d2
Compare
vonovak
force-pushed
the
codex/eas-session-binding
branch
from
October 19, 2026 21:08
09287d2 to
7cbeeae
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Local
runtime:reload --method devicepreviously stopped the app and reopened a bare route link, which could leave a development client at its launcher or connected to its previous Metro. This change opens a development-client connection URL for the selected Metro, even when an old debugger target remains listed, and forwards the port on the selected Android emulator. It resolves the device before stopping, respects the remaining reload budget, and sends an optional route once after the existing reconnection evidence wait.Android emulator allocation also reserves the console ports of every listed emulator, including offline instances started outside the CLI. A separate inventory supplies port reservation; the existing readiness filter still controls command targets. This prevents starting a new emulator on an occupied port while another instance is booting or disconnected from adb.
Expo Go detection receives only an explicit
--app-idas an override. A configured bundle identifier or package name no longer misclassifies a disconnected Expo Go project as a development build. The stop and reopen use Expo Go's platform-specific app ID when Expo Go is selected, and explicit development-build overrides retain their behavior.Depends on #139.
Validation:
Open issues before leaving draft: