Skip to content

test(pending): start a launched agent's same-kind replacement before the first one ends - #2380

Merged
devswha merged 1 commit into
mainfrom
test/pending-replacement-overlap
Oct 29, 2026
Merged

devswha merged 1 commit into
mainfrom
test/pending-replacement-overlap

Conversation

@devswha

@devswha devswha commented Oct 29, 2026

Copy link
Copy Markdown
Owner

Found by the flake-hunt lane: Integration failed and passed on a rerun with no code change on 2026-10-28 13:24Z (job 122843077413, after #2222 fixed the sibling test the same way): server/pending-input.contract.test.ts "a create request's first message > queued while the shell was still in front, is bound to the agent the launch brought up: a same-kind replacement before its page attaches gets it held, never typed" expected pending_target_changed and received first_message_launch_ended.

Cause (test flake)

The test brought the launched agent up with agent; exec agent2 and killed the first one. Until the shell ran exec, the shell alone was in front. If a status event arrived in that gap, the drain's learnLaunched read the shell back in front (launchGone's shell-back branch in server/core/pending.ts) and rightly held the first message with first_message_launch_ended. A held reason is never revised by later events, so the test's pending_target_changed failed. Both reasons hold the message and never type it, so this is not a delivery bug.

Reproduced: with a builtin gap (read -t 1, which keeps the shell itself in front) and an idle/working report during it, the old test fails 5/5 with CI's exact Received: "first_message_launch_ended". A sleep 1 gap does not reproduce it: then sleep is in front, and the read counts as a target change.

Change

As #2222 does for the sibling test, the replacement starts through the launcher's SIGUSR1. The launcher ends the first agent only once the second runs, so a claude process is in front throughout. The test then waits until herdr no longer lists the first agent, and checks that the replacement is a live foreground agent with another pid.

Proof

  • Fail-first: with the gap and the status events, the old test fails 5/5.
  • After: with the same idle/working events fired during the replacement, the new test passes 5/5. Plain runs pass 10/10, then 3/3 after the review's control-line change.
  • Whole file: server/pending-input.contract.test.ts passes 105/0.
  • Local checks: bun run check fast ok. One earlier run failed only on the server/codex-processes.test.ts READY-line flake, which this PR does not touch and which is fixed separately; the rerun was ok.

Test-only.

Not reproduced (noted, not fixed here)

  • The same file's :475 "queued command was not recorded" (the "see C:\temp" test, once on main 2026-10-29 01:09Z): the recorder saw no CR within 8 s, and the log holds no state to tell an unsent Enter from a missed notification.

Reviews

  • omo-native-code-reviewer: APPROVE, CLEAR. It confirmed the cause in launchGone/learnLaunched. As a mutation check, it stopped learn() from recording the launched process, and the test failed with the message typed into the replacement, so it still tests "never typed".
    • LOW-1 (the control line also passed with no claude listed) was taken: the test now checks the replacement exists first.
    • LOW-2: the launcher command repeats setup()'s, because this test creates its pane through /api/tab/create.
  • Test-only, so no Codex review (notes/pr-policy.md).

…the first one ends

The create-request test for a replacement before the page attaches ran
`agent; exec agent2`: after the first agent was killed, the shell alone was
in front until the exec. A status event in that gap made the drain read the
shell back in front, rightly hold the first message with
first_message_launch_ended, and later events never revise a held reason, so
the test's pending_target_changed failed (2026-10-28, after #2222 fixed the
sibling test). Start the replacement through the launcher's SIGUSR1, which
ends the first agent only once the second runs, as #2222 does, and wait until
herdr no longer lists the first.
@coderabbitai

coderabbitai Bot commented Oct 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 8a2dbcc and 4b57385.

Files selected for processing: 2
  • changelog.d/integration-flake-pending-launch-replacement.md
  • server/pending-input.contract.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devswha

devswha commented Oct 29, 2026

Copy link
Copy Markdown
Owner Author

Merging 4b57385. Test-only: the pending-input contract case for a launched agent's same-kind replacement now uses a launcher that starts the second agent before ending the first, so a read in the gap between them (where the shell alone is in front) no longer races the assertion. Diff read by the merge pass; no CodeRabbit review needed.

@devswha
devswha merged commit 73d1826 into main Oct 29, 2026
26 of 28 checks passed
@devswha
devswha deleted the test/pending-replacement-overlap branch October 29, 2026 20:51
devswha added a commit that referenced this pull request Oct 29, 2026
…s exit too (#2396)

This is the second commit of #2373, which merged at its first commit
(7597f65) before this one reached the branch. It was reviewed there; it
is cherry-picked onto current main here.

Found by the flake-hunt lane on #2380's Integration run (job
123700768179): `server/take-over.contract.test.ts` "consumes a click
when the running ordinary retry succeeds, before later displacement"
failed at `:89`, where `pty-data` contained "terminal attach taken
over".

## Cause (test flake)

This is the same cause as #2373: the 100 ms default attach hold.
Displaced by another client's `--takeover`, herdr prints its teardown
and "terminal attach taken over", then exits. The bridge keeps an
attach's last line in the output tail for the hold (`tailTimer` in
`server/core/terminal-process.ts`) and drops it at a displaced exit
(`flushTail(displaced)`). An exit more than 100 ms after the line, as on
a busy runner, let the line reach clients first.

## Change

A 2 s hold for this test too, as #2373 gave the ordinary-failure test.
The changelog fragment from #2373 now names both tests.

## Proof

- **Fail-first:** with the fixture's `real` wrapper exiting 300 ms after
herdr (scratch), the old test failed 3/3 with CI's `not.toContain` and
the new one passed 3/3.
- **Whole file:** passed 9/9 three times. On current main with this
cherry-pick it passed 9/9 again (`bun run check run bun test
server/take-over.contract.test.ts`).
- **Local checks:** `bun run check fast` ok.

Test-only.

## Reviews

- **omo-native-code-reviewer:** APPROVE, CLEAR (on #2373's branch). It
confirmed the tail-hold mechanism and that the test still asserts the
consumed click, the retry without `--takeover`, and no taken-over text.
- LOW product note, not fixed here: production also holds the tail 100
ms, so on a loaded machine, when another client takes over, a user can
briefly see herdr's teardown line until the next attach redraws. A
longer tail hold for displacement would remove it.
- Test-only, so no Codex review (notes/pr-policy.md).
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.

1 participant