feat(fork): surface PR comments and reviews as check wakes#15
Conversation
fm-pr-check.sh's generated per-task check.sh now polls tracked PRs for new issue comments, inline review comments, and review summaries from anyone, not just merge state - so a captain's PR comment or a secondmate's upstream review feedback wakes the owning firstmate the same way a merge does. Tracked via a durable per-task watermark (state/<id>.pr-activity-seen), seeded to "now" on first arm so history never floods the wake. Merge detection still takes precedence and short-circuits the activity poll once a PR lands, and re-arming an existing task upgrades a legacy merge-only check.sh without resetting its watermark.
gh api silently switches from GET to POST whenever -f field parameters are present unless --method is pinned explicitly. Live verification against a real fork PR caught this: the since= filter was being sent as a POST body, so gh attempted to create a new comment instead of listing existing ones, failing with a 422.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 052dfaaea2
ℹ️ 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".
|
|
||
| mkdir -p "$STATE" | ||
| ACTIVITY_SEEN="$STATE/$ID.pr-activity-seen" | ||
| [ -f "$ACTIVITY_SEEN" ] || date -u +%Y-%m-%dT%H:%M:%SZ > "$ACTIVITY_SEEN" |
There was a problem hiding this comment.
Preserve same-second PR activity
Captain, this seeds the activity watermark to the current UTC second, but the new activity poll only surfaces items with created_at/submitted_at strictly greater than that watermark. When a captain or maintainer posts a comment/review in the same second that the PR is armed, GitHub gives it an equal timestamp, so every later poll filters it out forever; store a tie-breaker/seen IDs or make equality safe with de-duping.
Useful? React with 👍 / 👎.
Intent
bin/.bin/fm-pr-check.sh's generatedstate/<id>.check.shto poll for new PR activity alongside merge state.bin/fm-pr-activity-poll.shqueries issue comments, inline review comments, and review summaries viagh api, filtered against a durable per-task watermark (state/<id>.pr-activity-seen).mergedand skips the activity poll entirely (no wastedgh apicalls on a landed task).fm-pr-check.shregeneratescheck.shso an existing task upgrades to the activity poll on next arm; a not-yet-re-armed legacy merge-onlycheck.shkeeps working untouched.pr-comment <task-id> <author> (<kind>): <text>) is deliberately dumb; AGENTS.md section 8 already routes anycheck:wake (including this one) through firstmate's normal triage (act, dispatch an amendment, relay to the captain, or ignore bot noise).sincesupport, so it's fetched in full and filtered client-side bysubmitted_at; acceptable at PR scale, not paginated defensively beyond--paginate.What Changed
bin/fm-pr-activity-poll.sh(new): the poll body, run by the generatedcheck.shonce a tracked PR is confirmed not merged.bin/fm-pr-check.sh: creates the watermark on first arm (preserved across re-arms), and generates acheck.shshim that runs the merge check first, then execs the activity poll only when the PR is still open.tests/fm-pr-check.test.sh(new): 9 cases covering watermark seeding/preservation, cross-kind activity surfacing and formatting, truncation, merge precedence, legacy-script compatibility/upgrade, defensive watermark init, and a regression test for a real bug caught during live verification (see below).AGENTS.mdsection 8: one line notingpr-commentwakes exist and are triaged like any other check wake.docs/scripts.md: registers the new script and updatesfm-pr-check.sh's description.Risk Assessment
Low - additive only. A task that never re-arms keeps its old merge-only
check.shuntouched. Once armed, the extragh apicalls are read-only (three per poll, on the existingCHECK_INTERVALcadence) and are skipped entirely once a PR is merged.Testing
shellcheck bin/*.sh bin/backends/*.sh tests/*.sh- clean.bash tests/fm-pr-check.test.sh- 9/9 pass.bash tests/fm-pr-merge.test.sh- 10/10 pass (no regression; it callsfm-pr-check.shinternally).Live verification against a real fork PR
Ran against this fork's own PR #13 (merged), using a scratch state dir so nothing outside the worktree was touched:
The test comment was deleted afterward (
gh api repos/Bre77/firstmate/issues/comments/4945027834 --method DELETE) to leave the PR clean.This live run caught a real bug the mocked unit tests could not:
gh apisilently switches from GET to POST whenever-ffield parameters are present unless--methodis pinned explicitly. The initial version offm-pr-activity-poll.shpassed-f since=<watermark>without--method GET, so instead of filtering existing comments it attempted to create a new issue comment and failed with a 422 ("body" wasn't supplied). Fixed by adding--method GETto all threegh apicalls; re-verified live per the transcript above.Full narrative / original brief
[E11.1] Make PR comments a first-class input channel: every firstmate home's tracked-PR polls must also surface NEW comments and reviews - from ANYONE - as wakes, not just merge state.
Captain's intent (two consumers, one mechanism):