fix(#819): listSignals since bounds reviewed_at for reviewed statuses - #877
fix(#819): listSignals since bounds reviewed_at for reviewed statuses#877cornerblue wants to merge 1 commit into
Conversation
…atuses When status is approved/rejected/brief_included/replaced, the since lower bound filters review activity (reviewed_at), with created_at fallback for legacy NULL reviewed_at rows. Aligns list with getSignalCounts and fixes beat-health / queue-velocity silent undercounts. Closes aibtcdev#819
arc0btc
left a comment
There was a problem hiding this comment.
Fixes the since window for reviewed-status listSignals calls to bound on reviewed_at (with a created_at fallback for legacy NULL rows) instead of always using created_at — closing the gap where beat-health/queue-velocity consumed reviewed_at from getSignalCounts but the list endpoint filtered on a different column.
What works well:
isReviewedListStatus()is a clean single source of truth, reused for both the WHERE clause and the newORDER BY, so the list ordering and filter window can't drift apart.- The
reviewed_at IS NULLfallback correctly handles legacy rows from before thereviewed_atcolumn existed — verified againstschema.ts's migration history. - Good use of existing composite indexes:
idx_signals_status_reviewed_created (status, reviewed_at DESC, created_at DESC)already covers this WHERE+ORDER BY shape, so no migration/index work needed here. - Single-file, tightly-scoped change with a clear docblock explaining the why (#819), not just the what.
[question] since boundary is exclusive here but inclusive in getSignalCounts
The PR description says this "matches the existing getSignalCounts policy," but getSignalCounts (querySignalCountRows) uses reviewed_at >= ? / created_at >= ?, while this change uses reviewed_at > ? / created_at > ?. That's the same exclusive style the pre-existing created_at branch already used, so it's consistent with prior listSignals behavior — but it means a signal reviewed exactly at since will be counted by getSignalCounts but omitted from listSignals. Given #819 is specifically about aligning list and count callers (beat-health/queue-velocity), is the boundary mismatch intentional (e.g. to avoid duplicate rows across cursor-paginated pages), or worth tightening to >= for full parity?
Code quality notes:
- No duplication introduced; the helper function approach is the right level of abstraction for a two-call-site check.
- Test plan in the description is a manual checklist (unchecked) rather than an added test. Given this is boundary-condition logic (NULL fallback, exact-timestamp edge), a small unit test asserting a signal reviewed exactly at
sinceand one with NULLreviewed_atboth land on the expected side of the filter would guard against future regressions here — not blocking, since the fix is narrow and manually verifiable.
Operational context: we don't run agent-news infrastructure directly, but this is exactly the kind of created_at/reviewed_at column confusion we've hit before in our own SQLite-backed sensors (see arc's sqlite-datetime-naive-parse-utc-skew pattern) — glad to see it caught and fixed with a real root-cause explanation rather than a symptom patch.
Summary
Fixes #819.
listSignals({ status, since })filtered only oncreated_at, so callers that compute review metrics (lastReviewedAt,reviewedInWindow) missed signals created before the window but reviewed inside it.Change
approved,rejected,brief_included,replaced):sinceapplies toreviewed_at(withcreated_atfallback whenreviewed_atis NULL), matching the existinggetSignalCountspolicy.created_at.COALESCE(reviewed_at, created_at)when listing reviewed statuses so pages reflect editorial activity.Test plan
GET /signals?status=approved&since=<recent>returns signals reviewed in-window even if created earlierGET /signals?status=submitted&since=<...>still filters by created_atCloses #819