forge_notify: leave delivered threads unread, dedupe wakes in-memory
This commit is contained in:
parent
4342a50895
commit
f5ac6d79e3
2 changed files with 143 additions and 16 deletions
|
|
@ -70,9 +70,46 @@ Background task spawned once per harness boot. Polls
|
|||
`GET /api/v1/notifications?all=false` every 30 seconds (Forgejo's
|
||||
unread-only filter), formats each notification as a broker
|
||||
`Wake { from: "forge" }` message, and delivers it to the agent's own
|
||||
inbox so claude's normal turn loop picks it up. Mark-read happens
|
||||
after successful delivery so a failed-delivery notification
|
||||
resurfaces on the next tick.
|
||||
inbox so claude's normal turn loop picks it up.
|
||||
|
||||
### Mark-read on read, not on delivery
|
||||
|
||||
Delivered conversation threads are deliberately left **unread** in
|
||||
forge. The hive-forge read-before-comment guard keys off forge's own
|
||||
notification read-state (`GET /notifications?all=false`) to refuse a
|
||||
comment when a thread has unread activity by others — so the agent
|
||||
reading the thread via the CLI (`hive-forge comments` / `view`,
|
||||
which `PATCH`es `/notifications/threads/{id}`) is the single
|
||||
mark-read point. If `forge_notify` marked threads read on delivery,
|
||||
that unread signal would be consumed before the agent acts and the
|
||||
guard could never fire.
|
||||
|
||||
Because a delivered thread stays unread, it reappears in every
|
||||
`?all=false` poll. An in-memory **delivery-dedupe cursor** (thread
|
||||
id → last-delivered `updated_at`, held in the poll loop) stops the
|
||||
same version from re-firing a wake; a new comment bumps `updated_at`
|
||||
so genuinely new activity re-delivers. The cursor is pure anti-spam,
|
||||
not a correctness oracle: lost on harness restart it just
|
||||
re-delivers currently-unread threads once (harmless — `recv`
|
||||
tolerates redelivery), so it carries none of the persisted-mirror
|
||||
fragility that ruled out an on-disk seen-cursor. Each poll prunes
|
||||
the cursor to the threads still in the unread set. A failed wake
|
||||
delivery is left unread **and** out of the cursor, so it resurfaces
|
||||
next tick.
|
||||
|
||||
Two paths still mark-read directly (no read-before-comment value):
|
||||
self-echo notifications (the agent's own writes, see below) and
|
||||
`HIVE_FORGE_NOTIFY_SKIP_REASONS` drop-listed reasons.
|
||||
|
||||
> Note: the unread list grows for threads the agent never reads via
|
||||
> the CLI, since nothing else trims it. This does not affect guard
|
||||
> correctness (the guard does a per-thread, repo-scoped query) nor
|
||||
> wake delivery (Forgejo orders unread newest-first, so new activity
|
||||
> always lands in the polled window). Bounding the unread list via a
|
||||
> reason-independent firehose-reduction is a separate follow-up — the
|
||||
> existing auto-unsubscribe below is gated on a `reason` field that
|
||||
> this Forgejo's notification API does not actually emit, so it never
|
||||
> fires today.
|
||||
|
||||
### Activation gates (graceful no-ops)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue