fix(#1637): don't label later activity (bodiless reviews) as new PR

This commit is contained in:
damocles 2026-06-13 11:59:30 +02:00 committed by mara
commit e6edfea0a8
2 changed files with 150 additions and 2 deletions

View file

@ -140,13 +140,14 @@ lookahead.
### Wrapper format
Four shapes, distinguished by the notification's classification:
Five shapes, distinguished by the notification's classification:
| Trigger | Wrapper |
| --- | --- |
| Comment on issue / PR | `[comment on PR #N owner/repo] title\nurl: ...\n\nauthor: body\nassignee: ...\nreason: mention` |
| Review submission | `[PR approved #N owner/repo] title\nurl: ...\n\nreviewer: body\nassignee: ...\nreason: review_requested` |
| New issue / PR | `[new PR #N owner/repo] title\nurl: ...\n\n<body excerpt>\nassignee: ...\nreason: subscribed` |
| Later activity (open, not creation) | `[activity on PR #N owner/repo] title\nurl: ...\n\n<body excerpt>\nassignee: ...\nreason: subscribed` |
| State change | `[PR merged #N owner/repo] title\nurl: ...\nassignee: ...\nreason: subscribed` |
Review labels come from the Forgejo `state` field: `APPROVED`
@ -155,6 +156,22 @@ Review labels come from the Forgejo `state` field: `APPROVED` →
submitted yet — no peer-visible event). Unknown states fall back to
the generic comment wrapper.
### "new" vs "activity on"
A review submitted with **no body** carries no `latest_comment_url`,
so it misses the comment path and lands on the state-change path with
`state == "open"` — exactly like a freshly opened PR. Labeling that
`new PR` is misleading: agents dismiss it as a duplicate of the
original open notification and miss the review (#1637). So the `open`
state only earns the `new <kind>` label when the notification's event
time (`updated_at`) is within `NEW_ITEM_TOLERANCE_SECS` (120s) of the
subject's `created_at`. Anything later is labeled `activity on <kind>`
— neutral and non-misleading, since we can't cheaply say *what* the
activity was without an extra reviews fetch. Missing/unparseable
timestamps default to `new` (preserve prior behavior rather than mask a
genuine new item). Timestamps are parsed by a small dependency-free
RFC 3339 → epoch-seconds helper (`parse_rfc3339_secs`).
Number is extracted from `subject.html_url`'s last path segment
(strips `#anchor` first); repo slug from `repository.full_name`.
Both degrade gracefully when absent (number → blank, repo → blank)