Files
PaperClipAI/packages
DottaandPaperclip 18b1637b63 fix(runner): accept late Antigravity login URL during drain (#18254)
## Thinking Path

> - Paperclip manages work performed by AI agents.
> - The native Runner owns Antigravity subscription sign-in.
> - Sign-in receives completion on stdout and the browser URL on stderr.
> - The two pipes can deliver the completion result before the valid
URL.
> - The owner rejected that URL after it entered the completed phase.
> - This pull request accepts one validated URL while the same child
drains.
> - A real child regression now proves the order and the failure
controls.

## Linked Issues or Issue Description

Refs #18188, #18189, and #18190. Related qualification work: #18345 and
#18356. The duplicate search found this existing PR, so this update
preserves its history and adds the real child proof here.

**What happened?**

A valid sign-in can fail when the authenticate response arrives before
the authorization URL on the other pipe. The completed phase then
rejects the valid URL. The same existing success case failed in [current
follow-up
CI](https://github.com/paperclipai/paperclip/actions/runs/41138618869/job/124347859445).
That log has no stream-order trace, so it does not prove its inner
failure branch.

**Expected behavior**

Both valid delivery orders must succeed. Invalid or duplicate URLs,
unexpected protocol requests, failed retirement, and failed credential
verification must still fail.

**Steps to reproduce**

1. Run a synthetic native child that completes authenticate on stdout.
2. Wait for stdin EOF before it emits the authorization URL on stderr.
EOF proves that the parent accepted the result and began retirement.
3. The valid case fails on frozen master
`45a3a92e6dc52d20923b9aa34a22fee2ec5443f9`. The invalid and duplicate
controls pass there.
4. Run the same regression with this PR's existing production fix. All
three cases pass.

**Paperclip version or commit**

Existing reviewed PR parent: `646f5cdf37898ad54e1fa1cdfe39f59844da3e7c`.
Frozen actual master for the real child RED:
`45a3a92e6dc52d20923b9aa34a22fee2ec5443f9`.

## What Changed

- Accept one fully validated authorization URL in the authentication or
completed-drain phase. Keep duplicate rejection and all existing URL
checks.
- Retain the ten existing in-memory controls for both valid orders and
eight failure paths.
- Add three real child cases for valid, invalid, and duplicate late
URLs. Use stdin EOF to order the streams without sleeps or a mocked
retirement handler.
- Check exact protocol requests, child exit, close-once behavior,
Google-call counts, and persisted refresh rotation. This update changes
only the existing test file; it adds no production delta to the reviewed
parent.

## Verification

- Frozen actual master: the new valid real child case fails, while both
negative controls pass. The original eight-control parent calibration
also remains recorded in this PR's history.
- Existing fixed source plus the new tests: 24 passed. This includes 11
existing authentication tests, ten stream controls, and three real child
cases.
- Late invalid and duplicate URLs fail with zero Google calls. The valid
case makes two mocked identity calls and saves the rotated synthetic
refresh token. All three retire the real child and close the command
lease once.
- Scoped owning TypeScript `noEmit` passes for the auth module and both
test files. The temporary configuration is not committed. Diff and
credential-pattern checks pass.
- The tests use real child pipes and private synthetic files. Google
responses and the command installation are mocked. No provider account,
network request, model run, app, or QA deployment was used.
- Full monorepo typecheck, tests, and build were not run locally. Fresh
[normal
CI](https://github.com/paperclipai/paperclip/actions/runs/41140757050)
passes on `1744c9f3374f78b10c2f15c42f3cf5d3af8c3119`: 56 successful
checks, two skipped, and one neutral. Typecheck, build, Rust, static,
Runner, server and browser lanes pass. Greptile gives that exact head a
fresh 5/5 with zero unresolved threads. The PR is mergeable and clean.
The earlier parent's passing CI remains historical evidence only.

## Risks

The change accepts a URL while the same authenticated child drains. It
still validates the exact OAuth URL and rejects a second URL. Success
still requires the authenticate result, verified credentials, and proven
process retirement. No provider pins, contracts, timeout bounds,
retries, or public APIs change. Existing documentation already specifies
these sign-in semantics; no documentation change is needed.

## Model Used

OpenAI Codex, based on GPT-6, with tool use and code execution. The
exact runtime model ID and context window were not exposed in this
session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 18:05:05 -05:00
..