fix(#2106): persist forge-notify dedupe cursor to disk so rebuilds don't re-deliver the unread backlog
This commit is contained in:
parent
5264828091
commit
2549cc51ba
2 changed files with 164 additions and 24 deletions
|
|
@ -92,17 +92,28 @@ 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.
|
||||
`?all=false` poll. A **delivery-dedupe cursor** (thread id →
|
||||
last-delivered `updated_at`) 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.
|
||||
Each poll prunes it 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.
|
||||
|
||||
The cursor is **persisted** to
|
||||
`$HYPERHIVE_STATE_DIR/forge-notify-cursor.json` (atomic tmp+rename,
|
||||
flushed only when it changed) and reloaded on boot, so a container
|
||||
rebuild/restart doesn't re-deliver the whole currently-unread backlog
|
||||
(#2106 — previously the in-memory-only cursor was lost on restart and
|
||||
every old still-unread thread re-fired a wake). This is safe because a
|
||||
thread is recorded **after** a successful broker delivery, and the
|
||||
broker inbox is durable sqlite — so a persisted "delivered" entry can
|
||||
never swallow a wake the agent never received. Crucially the cursor
|
||||
file is a private dedup mirror, **not** forge's read-state: it does
|
||||
not reintroduce the read-before-comment coupling that ruled out the
|
||||
old mark-read-on-delivery approach. A missing (first boot) or corrupt
|
||||
cursor file degrades to empty — re-deliver the unread set once — never
|
||||
an abort.
|
||||
|
||||
Self-echo notifications (the agent's own writes, see below) are the
|
||||
one path still marked-read directly (no read-before-comment value).
|
||||
|
|
|
|||
Loading…
Reference in a new issue