Skip to content

fix(server): fall back to the connected tab when a lease cannot launch - #861

Open
kushals256 wants to merge 6 commits into
reticlehq:mainfrom
kushals256:fix/lease-fallback-open-tab
Open

fix(server): fall back to the connected tab when a lease cannot launch#861
kushals256 wants to merge 6 commits into
reticlehq:mainfrom
kushals256:fix/lease-fallback-open-tab

Conversation

@kushals256

Copy link
Copy Markdown
Contributor

Summary

  • reticle_lease dead-ended when Chromium could not launch (missing binary, acquire throw), even when a human tab was already connected and driveable — including one flagged throttled. Reporters then drove that tab by hand and it worked.
  • When launch fails and reticle_sessions already lists a live non-leased tab, acquire now returns that session with fellBackToExisting: true and expiresInMs: 0. It is not a pool lease; the HUD stays on that tab. Isolation still mints when launch works.
  • Windows Playwright resolution and the doctor mismatch from Lease Chromium failures all report the same wrong cause, and there is no fallback #691 are untouched.

Addresses the fallback ask of #691.

Test plan

  • Chromium-absent preflight with a live tab returns that session and never calls the pool
  • acquire throw with a live tab returns that session instead of "is the app running?"
  • Chromium-absent with no tab still throws the install hint
  • Existing "never refuses the lease" path still mints when launch works
  • pnpm --filter @reticlehq/server exec tsc -b and lease-tools unit tests green

Made with Cursor

kushals256 and others added 2 commits September 8, 2026 11:51
Chromium missing or acquire throwing used to dead-end reticle_lease even
when a human tab was already connected and driveable. Isolation still
mints when launch works; the fallback is not a pool lease.

Addresses the fallback ask of reticlehq#691.

Signed-off-by: Kushal S <skushal.mys@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@divshekhar
divshekhar enabled auto-merge (squash) September 8, 2026 09:16
divshekhar added a commit that referenced this pull request Sep 8, 2026
Every other branch of this check names its evidence. The missing-browser line prints the path it
probed — its own comment says why: "naming the path is what turns 'missing' from a verdict into
evidence". The mismatch line prints the wanted revision and what the root actually holds. The
playwright-absent branch said a bare "the playwright package is not installed" with nothing to
check it against.

A reporter on Windows installed that exact Playwright version in BOTH the frontend and the repo
root, confirmed Chromium sat in the npx cache, and kept reading the same line. They were not
wrong and the line was not lying. It means "not installed WHERE THIS PROCESS CAN RESOLVE IT", and
a daemon run from npx or a global install resolves from its own location and never from the
user's project. With no roots printed there is no way to see that, and the only reading left is
that the check is broken — the unbreakable loop this file's header was written to end.

The existence filter is what makes it evidence rather than noise. Node's ancestor chain starts
with directories nobody ever created: measured from the built daemon the two nearest are
`dist/cli/node_modules` and `dist/node_modules`, and the informative one — the daemon's own
`node_modules` — is third. Printing the first two unfiltered would name two paths the reader
cannot check and hide the one they can, which is the same failure in a new coat.

Gathered in the probe rather than the hint, so the hint stays pure: only the probe knows which
module did the resolving.

Part of #691. Items 1 and 2 of that issue were already done (install-deps for a missing shared
library, and the wrong-revision line); item 3 is #861, in review.

Signed-off-by: Divyanshu Shekhar <imdshekhar@gmail.com>
@divshekhar

Copy link
Copy Markdown
Contributor

Reviewed. The fallback is right and I want it in — one change requested first, from a duplicate PR that arrived 11 hours after yours.

#871 (@Bhumika-1432006, now closed in your favour) implemented the same ask with a different envelope, and theirs is better on one specific point:

// yours
{ "fellBackToExisting": true, "expiresInMs": 0 }
// theirs
{ "noManagedBrowser": { "sessionId": "...", "reason": "Chromium is not installed …" } }

Please carry the reason. fellBackToExisting: true tells the agent it did not get isolation; it does not tell it why, and the three causes have three different fixes — a missing binary wants install chromium, a missing shared library wants install-deps, and a build mismatch wants neither. chromiumHint(probe) already composes exactly that sentence, so this should be threading a string you already have rather than new logic.

Two smaller notes, both optional:

  • expiresInMs: 0 as the "this is not a real lease" signal works, but it is a sentinel a caller has to know to read. A named field says it outright. Your call — fellBackToExisting already carries the meaning, so this is taste rather than correctness.
  • Their description puts the severity better than ours does, and it is worth stealing for the changelog entry: a lease is what the daemon actively recommends when a tab is hidden or throttled, so refusing at exactly that moment strands the agent with no path forward while a driveable session sits right there.

Everything else — covering the preflight and the launch, keeping isolation when launch works, and the throttled-tab case — is exactly what #691 asked for. Add the reason and I will merge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants