Skip to content

[AI-3464] Release the turn flag before an Antigravity exit waiter resumes - #1300

Merged
realtonyyoung merged 3 commits into
mainfrom
tonyyoung/ai-3464-turn-gate-release
Oct 2, 2026
Merged

realtonyyoung merged 3 commits into
mainfrom
tonyyoung/ai-3464-turn-gate-release

Conversation

@realtonyyoung

Copy link
Copy Markdown
Collaborator

AI-3464 (filed in Linear only; there is no GitHub issue)

What & why

EnterTerminal completed _terminalTcs before it cleared TurnInFlight, so a caller resumed by WaitForExitAsync could observe a stopped runtime that still held a turn: the CI failure Expected to be false but found True. The flag is now cleared first. The test also stops treating HasExited as proof of Terminal (while the turn is Executing it reports the fake process's own exit). It waits on WaitForExitAsync() under WaitAsync(HangGuard), which throws if Terminal never comes, instead of a timeout overload that returns silently.

Verification

A 200 ms pause between completing _terminalTcs and clearing the flag (old order) fails the test with the CI assertion. The same pause before completing it (new order) passes. The AntigravityActivityClockTests class passes locally.

🤖 Generated with Claude Code

…umes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Oct 2, 2026

Copy link
Copy Markdown

AI-3464

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release Antigravity turn flag before notifying exit waiters

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Clear the in-flight turn flag before signaling Terminal, so exit waiters observe a released turn
 gate.
• Make the regression test wait for Terminal and fail if that wait times out.
Diagram

graph TD
    A["Enter Terminal"] --> B["Clear turn flag"] --> C["Complete exit signal"] --> D["Resume exit waiter"]
Loading
High-Level Assessment

Keep the reordered operations: clearing the flag before completing the existing terminal signal directly establishes the waiter-visible ordering without adding synchronization.

Files changed (2) +8 / -8

Bug fix (1) +4 / -4
AntigravityHostedAgentRuntime.csClear the turn flag before signaling Terminal +4/-4

Clear the turn flag before signaling Terminal

• Moves the activity-clock flag clear ahead of terminal task completion, preventing an awakened exit waiter from observing a held turn. Updates the comment to state the ordering guarantee.

src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs

Tests (1) +4 / -4
AntigravityActivityClockTests.csWait for Terminal before asserting the turn flag +4/-4

Wait for Terminal before asserting the turn flag

• Replaces the silently timing-out exit wait and unreliable HasExited check with an unbounded terminal wait guarded by WaitAsync(HangGuard), which throws on timeout.

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs

@qodo-code-review

qodo-code-review Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Failed exit checks strand a test worker ✗ Dismissed
Description
A_throwing_turn_ended_callback_still_signals_exit calls process.ReleaseDisposal() only after its
timed waits and assertion succeed. If either wait times out or the assertion fails, the fake process
remains blocked in disposal, adding the runtime's five-second worker-join delay to the failed test
and leaving its worker unfinished.
Code

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[R118-119]

+        await rt.SendUserInputAsync("hello").WaitAsync(HangGuard);
+        await rt.WaitForExitAsync().WaitAsync(HangGuard);
Relevance

●●● Strong

Accepted cleanup precedents require finally-based resource release when assertions or waits can fail
and strand workers.

PR-#965
PR-#978
PR-#1021

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new test creates a held process and reaches its release only after the waits and assertion. The
fake's disposal has no completion path other than that release; the turn worker awaits disposal,
while runtime cleanup gives an unjoined worker only a five-second join budget.

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[109-123]
test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[186-214]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[848-851]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1140-1157]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test skips `ReleaseDisposal()` when a wait or assertion fails, leaving its turn worker blocked.
## Fix Focus Areas
- test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[109-123]
## Recommended Fix
Wrap the test's waits and assertion in `try/finally`, calling `process.ReleaseDisposal()` in the `finally` block before runtime disposal.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Exit waits hang when clock hooks throw ✗ Dismissed
Description
EnterTerminal now calls ActivityClock.SetTurnInFlight(false) before completing _terminalTcs,
but that call invokes callbacks whose exceptions are not caught. If a callback throws, the runtime
is already marked Terminal, so a retry cannot complete the signal and callers of
WaitForExitAsync() remain blocked.
Code

src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[R1007-1009]

        ActivityClock?.SetTurnInFlight(false);

+        _terminalTcs.TrySetResult();
Relevance

●●● Strong

Accepted precedent requires isolating throwing callbacks so terminal teardown and waiter completion
cannot be skipped.

PR-#508

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
SetTurnInFlight invokes publicly settable callbacks without catching exceptions. EnterTerminal
changes the phase before that invocation, and its phase check makes a later call return without
reaching _terminalTcs.TrySetResult(); WaitForExitAsync() awaits that task.

src/Capacitor.Cli.Daemon/Services/AgentActivityClock.cs[199-221]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[994-1010]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1089-1099]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An exception from an activity-clock callback now prevents `EnterTerminal` from completing its exit signal after marking the runtime Terminal.

## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1002-1013]
- src/Capacitor.Cli.Daemon/Services/AgentActivityClock.cs[199-221]

## Recommended Fix
Keep the turn-flag update before the exit signal, but catch and log exceptions from the clock call so terminal signaling and the remaining terminal cleanup still run. Add a test with a throwing clock callback that verifies the exit waiter completes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
Review mode: 🚀 Fast: This is a localized, test-only reliability cleanup adding exception-safe disposal and clearer awaited terminal-state assertions, with no production or high-risk behavior changes.

Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 9853b80

Results up to commit db68e0a ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Exit waits hang when clock hooks throw ✗ Dismissed
Description
EnterTerminal now calls ActivityClock.SetTurnInFlight(false) before completing _terminalTcs,
but that call invokes callbacks whose exceptions are not caught. If a callback throws, the runtime
is already marked Terminal, so a retry cannot complete the signal and callers of
WaitForExitAsync() remain blocked.
Code

src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[R1007-1009]

        ActivityClock?.SetTurnInFlight(false);

+        _terminalTcs.TrySetResult();
Relevance

●●● Strong

Accepted precedent requires isolating throwing callbacks so terminal teardown and waiter completion
cannot be skipped.

PR-#508

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
SetTurnInFlight invokes publicly settable callbacks without catching exceptions. EnterTerminal
changes the phase before that invocation, and its phase check makes a later call return without
reaching _terminalTcs.TrySetResult(); WaitForExitAsync() awaits that task.

src/Capacitor.Cli.Daemon/Services/AgentActivityClock.cs[199-221]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[994-1010]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1089-1099]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An exception from an activity-clock callback now prevents `EnterTerminal` from completing its exit signal after marking the runtime Terminal.

## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1002-1013]
- src/Capacitor.Cli.Daemon/Services/AgentActivityClock.cs[199-221]

## Recommended Fix
Keep the turn-flag update before the exit signal, but catch and log exceptions from the clock call so terminal signaling and the remaining terminal cleanup still run. Add a test with a throwing clock callback that verifies the exit waiter completes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 66cedab ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Failed exit checks strand a test worker ✗ Dismissed
Description
A_throwing_turn_ended_callback_still_signals_exit calls process.ReleaseDisposal() only after its
timed waits and assertion succeed. If either wait times out or the assertion fails, the fake process
remains blocked in disposal, adding the runtime's five-second worker-join delay to the failed test
and leaving its worker unfinished.
Code

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[R118-119]

+        await rt.SendUserInputAsync("hello").WaitAsync(HangGuard);
+        await rt.WaitForExitAsync().WaitAsync(HangGuard);
Relevance

●●● Strong

Accepted cleanup precedents require finally-based resource release when assertions or waits can fail
and strand workers.

PR-#965
PR-#978
PR-#1021

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new test creates a held process and reaches its release only after the waits and assertion. The
fake's disposal has no completion path other than that release; the turn worker awaits disposal,
while runtime cleanup gives an unjoined worker only a five-second join budget.

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[109-123]
test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[186-214]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[848-851]
src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs[1140-1157]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test skips `ReleaseDisposal()` when a wait or assertion fails, leaving its turn worker blocked.
## Fix Focus Areas
- test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Antigravity/AntigravityActivityClockTests.cs[109-123]
## Recommended Fix
Wrap the test's waits and assertion in `try/finally`, calling `process.ReleaseDisposal()` in the `finally` block before runtime disposal.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread src/Capacitor.Cli.Daemon/Harness/Antigravity/AntigravityHostedAgentRuntime.cs Outdated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

/agentic_review

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 66cedab

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

/agentic_review

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 9853b80

@realtonyyoung
realtonyyoung merged commit 5b25849 into main Oct 2, 2026
8 checks passed
@realtonyyoung
realtonyyoung deleted the tonyyoung/ai-3464-turn-gate-release branch October 2, 2026 18:37
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