Skip to content

fix: address Codex review feedback (#6, #7, #13–#17) - #18

Merged
devblac merged 10 commits into
mainfrom
fix/codex-review
Oct 25, 2026
Merged

devblac merged 10 commits into
mainfrom
fix/codex-review

Conversation

@devblac

@devblac devblac commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Fixes for the Codex review comments on the earlier PRs of this stack. Each was checked against the code (and, where possible, the real API) before changing anything; every fix has a test that fails without it.

Review Fix Verified
#6 — superseded check runs counted as failures Only the newest run per app + check name counts (latestCheckRuns) Live on zephyrproject-rtos/zephyr#105183 (cited case): REST API returns a cancelled and a success run of "Prevent Merging" in two suites; was failure, now success
#7 — GovSlack webhooks hooks.slack-gov.com detected as Slack Slack docs confirm the separate domain
#13 — revalidate head SHA Before returning a final result, waitForCI re-reads the PR (304, free); if the head moved, it keeps waiting on the new commit Test simulating a push during the poll
#13, #15 — propagate cancellation GitHub client methods take a context.Context, passed to each HTTP request; cancelled polls end as timed out (2) / interrupted (130). prw run stops at once on Ctrl-C and leaves unchecked PRs untouched Tests against a hanging server: return in ~100 ms (10 s without the fix)
#16 — closed review requests lose their notification Sync looks up review-request PRs that stopped matching and keeps the closed ones so the regular check notifies and drops them; lookup errors keep the old behavior RunOnce test: merged-while-stopped PR now notifies merged
#17 — no_ci flapping on metadata updates A no_ci PR stays no_ci until a real check/status appears Watcher tests
#14 — ETag cache cleared when full Evict one random entry for a new path; refreshing a cached path evicts nothing (random, not LRU: cyclic polling is LRU's worst case) Simulation with 640 paths / 512 entries: 64% hits, 0% before

Test plan

🤖 Generated with Claude Code

devblac and others added 8 commits October 18, 2026 00:36
A PR with no checks or statuses at all was reported as "pending"
indefinitely, so `prw wait` and the MCP wait_for_ci tool blocked until
their timeout on repositories without CI or on stacked PRs whose base
branch runs none (14 of 18 real PRs in testing).

Zero checks is also what every PR looks like right after a push, so a
PR is only reported as no_ci once it has had no checks or statuses
and hasn't been updated (PR updated_at, which every push bumps) for 3
minutes; a zero/unknown updated_at keeps it pending.

- github: PullRequest.UpdatedAt, StateNoCI, ApplyNoCI, applied by
  run, wait and broadcast.
- prw wait exits 4 for no_ci (not 0: `prw wait && deploy` must not
  deploy unverified PRs); MCP summaries and tool descriptions cover it.
- prw run doesn't notify on a transition into no_ci, and notifies
  normally if CI shows up later.

Verified live: 11 real PRs moved from pending to no_ci; `prw wait` on
one returns in 2s with exit 4 instead of waiting 30 minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a workflow runs more than once for the same commit (e.g. an older run
cancelled by `concurrency: cancel-in-progress`), the check-runs API returns one
run per check suite, so the cancelled one kept the PR "failed" forever even
after the newer run passed. Only the newest run per app and check name counts
now, like GitHub's merge box and required checks.

Verified live on zephyrproject-rtos/zephyr#105183: previously reported as
failure ("Prevent Merging" cancelled), now success.

Addresses Codex review on #6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GovSlack serves incoming webhooks from its own slack-gov.com domain, so auto
mode sent them the generic payload, which Slack rejects.

Addresses Codex review on #7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PR auto-watched with --review-requested that was merged or closed while prw
was stopped no longer matched the is:open search, so the startup sync removed
it as a withdrawn request before it was checked, and its final merged/closed
notification was lost. Before removing review-request PRs that stopped
matching, the sync now looks them up and keeps the closed ones; the regular
check then notifies and drops them. If the lookup fails, the PR is removed as
before.

Addresses Codex review on #16.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Any comment or label change bumps a PR's updated_at, which restarted the no-CI
grace period: `prw run` stored `pending` and, with the default `change` filter,
notified "no_ci → pending" although no CI had appeared, then silently went back
to no_ci three minutes later. A PR that was no_ci now stays no_ci until an
actual check or status shows up.

Addresses Codex review on #17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… before returning

Context: the GitHub client methods now take a context.Context, passed down to
each HTTP request. Previously `prw wait --timeout`, MCP `wait_for_ci`
`timeout_seconds` and client cancellation, and Ctrl-C were only noticed between
polls: a stalled network could keep a poll (PR + status + check-run pages, each
with a 15s HTTP timeout) running well past the deadline, and Ctrl-C did nothing
until it finished. A poll cancelled this way now ends as timed out (exit 2) or
interrupted (exit 130) instead of being retried as a transient error. `prw run`
also stops immediately on Ctrl-C, leaving the PRs it hadn't checked unchanged.

Head re-check: `prw wait` / `wait_for_ci` look up the PR and then its CI, so a
commit pushed in between made them return the final result of the previous
commit (e.g. `prw wait && deploy` deploying unchecked code). Before returning a
final result, the PR is read again (a free 304 when unchanged); if the head
moved, waiting continues on the new commit.

Addresses Codex reviews on #13 and #15.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the 512-entry cache was full, every new 200 response wiped it. With more
paths polled in rotation than fit (~170 PRs, fewer with paginated check runs)
it was cleared over and over and nearly every request became unconditional,
losing the free 304s. A new path now evicts a single random entry (refreshing
a cached path evicts nothing). Random rather than LRU on purpose: cyclic
polling is LRU's worst case. Simulated with 640 paths: 64% hits, was 0%.

Addresses Codex review on #14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T05:41:34.616398Z 2614d38 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2614d38b17

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/prw/wait.go Outdated
Comment on lines +271 to +272
pr, err := client.GetPullRequest(ctx, result.Owner, result.Repo, result.Number)
return err == nil && pr.Head.SHA != result.SHA

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retry a failed final head confirmation

When the final GetPullRequest fails, this expression treats the failure as “head unchanged,” so waitForCI immediately returns the terminal result from the previously fetched SHA. If a push lands during the poll and this confirmation request has a transient error, prw wait can report success for the old commit; cancellation or timeout during this request is likewise reported as success/failure instead of interrupted/timed out. Return the error from headMoved so the existing retry and context handling can process it.

Useful? React with 👍 / 👎.

Comment thread internal/watcher/autowatch.go Outdated
Comment on lines +148 to +150
if ghPR, err := client.GetPullRequest(ctx, pr.Owner, pr.Repo, pr.Number); err == nil && ghPR.IsClosed() {
closed[key] = true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Abort auto-watch cleanup when closed-PR lookups are canceled

If Ctrl-C arrives after the review-request search succeeds but while one of these PR lookups is in flight, the canceled lookup is treated as “not closed.” SyncAutoWatch then removes that PR as a withdrawn review request and persists the removal, so merely interrupting prw run can silently discard review-request PRs and their eventual merged/closed notifications. A canceled context should abort the sync before the config update rather than classifying failed lookups as removable.

Useful? React with 👍 / 👎.

devblac and others added 2 commits October 24, 2026 15:34
If the request confirming the PR head failed, `prw wait` returned the final
result of the commit it had polled, even if a push had just landed, and a
timeout or Ctrl-C during that request ended as success/failure instead of
timed out / interrupted. Its errors now go through the same path as poll
errors: retried when transient, reported as timeout or interruption when the
context is done.

Addresses Codex review on #18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A review-request PR that stopped matching its search was dropped whenever the
lookup meant to tell "merged/closed" apart from "request withdrawn" failed.
Interrupting `prw run` (Ctrl-C) during that lookup, a network error or a rate
limit therefore silently removed PRs together with their final merged/closed
notification. Now a PR is only dropped when it's confirmed open (the request
was withdrawn or answered) or GitHub answers 404; otherwise it's kept until
the next sync. A cancelled sync returns before touching the config.

Addresses Codex review on #18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devblac
devblac changed the base branch from feat/no-ci-state to main October 25, 2026 00:16
@devblac
devblac merged commit d4cf9b8 into main Oct 25, 2026
@devblac
devblac deleted the fix/codex-review branch October 25, 2026 00:16
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