Skip to content

feat: Add --trigger to await-pause-point for one-command verification#1920

Merged
hatayama merged 4 commits into
feature/round7-pause-point-improvementsfrom
feat/pause-point-trigger
Jul 21, 2026
Merged

feat: Add --trigger to await-pause-point for one-command verification#1920
hatayama merged 4 commits into
feature/round7-pause-point-improvementsfrom
feat/pause-point-trigger

Conversation

@hatayama

@hatayama hatayama commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • await-pause-point and enable-pause-point --await now accept --trigger '<uloop command>', so waiting for a pause point and triggering the action that hits it is a single call instead of a manually raced pair of commands.

User Impact

  • Before: hitting a pause point from a scripted action required starting the triggering command in the background, then separately calling await-pause-point/enable-pause-point --await and hoping the timing lined up.
  • After: pass the triggering command directly via --trigger, and the CLI dispatches it right after the marker is armed, then reports its result inline as TriggerResult in the same JSON response — no more manual backgrounding or timing races.

Changes

  • Added --trigger parsing: quote-aware tokenization of the trigger command string, with fail-fast validation that rejects targeting await-pause-point/enable-pause-point (would deadlock) and rejects --project-path inside the trigger string (the triggered command always runs against the same project).
  • The trigger command runs concurrently via a goroutine dispatched through the same in-process command entry point every CLI invocation uses, and is joined with a short grace window once the wait itself settles.
  • TriggerResult (Command, Completed, Response, Error) is embedded in the wait's JSON output only when --trigger was used — omitted entirely otherwise, so existing callers see no schema change.
  • Added a regression harness scenario (scripts/regression-harness-pause-point-trigger.sh) that reuses the existing KeyStateAfterPauseInterruption scene to verify the trigger hits within the marker's timeout rather than waiting out the triggered command's full duration.
  • The trigger is only dispatched after confirming the marker is actually enabled (or already hit) via one status query — an unknown or already-expired --id reports its own failure without also injecting the trigger's action into the running game.

Verification

  • sh scripts/check-go-cli.sh: 0 issues across all four Go modules, all tests pass.
  • go test ./internal/projectrunner/... -run 'Trigger|PausePoint': all new and updated table-driven tests pass, including a case asserting the trigger is never dispatched when the marker isn't armed.
  • Live E2E (hit path): enable-pause-point + await-pause-point --trigger "simulate-keyboard --action Press --key Space --duration 5" against the KeyStateAfterPauseInterruption scene hits in ~280ms with TriggerResult.Response.InterruptedByPausePoint: true, instead of waiting out the full 5s duration.
  • Live E2E (not-armed path): await-pause-point --id <nonexistent> --trigger "simulate-keyboard --action Press --key Space --duration 5" returns NotEnabled in ~74ms with no TriggerResult in the response — the trigger never ran.

hatayama added 2 commits July 21, 2026 21:30
Waiting for a pause point and then triggering the action that hits it
required two separate CLI calls with a manual race (start a background
simulate-* command, then await). --trigger dispatches the given uloop
subcommand in-process right after the marker is armed, and embeds its
response (or dispatch error) as TriggerResult in the wait's own JSON
output, collapsing that into a single call.

- Quote-aware tokenizer parses the --trigger value into argv-style tokens.
- Fail-fast validation rejects targeting await-pause-point/enable-pause-point
  (would deadlock) and --project-path inside the trigger string (implicit
  project inheritance only).
- The trigger runs concurrently via a goroutine and is joined with a short
  grace window after the wait itself settles, reusing
  pausePointFinalStatusProbeTimeout for consistency with the existing
  final-status-probe pattern.
- Verified end-to-end against the KeyStateAfterPauseInterruption regression
  harness: enable-pause-point + await-pause-point --trigger "simulate-keyboard
  ..." now hits in ~280ms instead of running the full press duration.
The --trigger flag's own manual verification procedure needs to stay
runnable beyond this one review round, so capture it as a permanent
harness script rather than a throwaway command sequence — reusing the
KeyStateAfterPauseInterruption scene scaffolding from the existing trap
harness. Confirmed passing locally: enable-pause-point + await-pause-point
--trigger hits in 0s instead of waiting out the 5s triggered Press.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@hatayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad20cac2-70b0-41a6-bd67-11677b623ea0

📥 Commits

Reviewing files that changed from the base of the PR and between df3c171 and 9a5fc98.

📒 Files selected for processing (11)
  • cli/project-runner/internal/projectrunner/native_command_help.go
  • cli/project-runner/internal/projectrunner/pause_point_enable.go
  • cli/project-runner/internal/projectrunner/pause_point_enable_test.go
  • cli/project-runner/internal/projectrunner/pause_point_trigger.go
  • cli/project-runner/internal/projectrunner/pause_point_trigger_test.go
  • cli/project-runner/internal/projectrunner/pause_point_types.go
  • cli/project-runner/internal/projectrunner/pause_point_wait.go
  • cli/project-runner/internal/projectrunner/pause_point_wait_test.go
  • cli/project-runner/internal/projectrunner/runner_commands.go
  • docs/regression-harness.md
  • scripts/regression-harness-pause-point-trigger.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pause-point-trigger

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.

The advisor's final review found that await-pause-point's extendPausePointExpiryBeforeWait
step is best-effort and does not confirm the marker is actually enabled, so a --trigger
command (e.g. a 5s simulate-keyboard Press) was being dispatched into the running game
even when the wait was about to fail immediately with NotEnabled — a typo'd or expired
--id would still inject the triggered action with no corresponding wait watching for it.

waitForPausePoint now runs one status query up front and only starts the trigger once the
marker is confirmed enabled or already hit; a query failure is also treated as not armed.
Verified live: await-pause-point --id <nonexistent> --trigger "simulate-keyboard ..."
now returns NotEnabled in ~74ms with no TriggerResult in the response, instead of letting
Press run.
@hatayama hatayama changed the title feat: await-pause-point can now trigger the action that hits it in one call feat: Add --trigger to await-pause-point for one-command verification Jul 21, 2026
A skipped trigger (marker not confirmed armed) previously left TriggerResult
entirely omitted, indistinguishable from "the trigger ran but never reported
back in time" (Completed=false with a Command). If the initial arm-check
query hits a transient IPC error while the marker itself is actually armed,
the trigger silently never fires, the marker never gets hit, the wait times
out, and nothing in the response explains why.

waitForPausePoint now always returns a TriggerResult when --trigger was
given: on skip, Completed=false with an explanatory Error, so the contract
is simply "passing --trigger always yields a TriggerResult."
@hatayama
hatayama merged commit 8e19067 into feature/round7-pause-point-improvements Jul 21, 2026
1 of 2 checks passed
@hatayama
hatayama deleted the feat/pause-point-trigger branch July 21, 2026 12:46
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