Exclude !post from the daily cap

Manual !post overrides were counted toward daily_cap_total, so a few
forced posts could starve the round-robin rotation for the rest of the
day. Tag forced rows in post_log and skip them in CountAllPostsInWindow
so the cap only meters the auto-rotation.
This commit is contained in:
prosolis
2026-05-26 17:15:53 -07:00
parent a15025089d
commit b617d403b7
7 changed files with 30 additions and 19 deletions

View File

@@ -109,7 +109,7 @@ func (q *Queue) ForcePost(channel string) bool {
slog.Info("force-posting story on demand",
"guid", item.GUID, "channel", channel)
return q.postItem(item)
return q.postItem(item, true)
}
func (q *Queue) drain() {
@@ -194,21 +194,23 @@ func (q *Queue) drainChannel(channel string) {
q.queues[channel] = items[1:]
q.mu.Unlock()
q.postItem(item)
q.postItem(item, false)
}
// PostNow sends a story immediately, bypassing the in-memory queue and all
// pacing limits. Last-mile canonical-URL dedup still applies. Used by !post
// to satisfy on-demand requests with stories pulled directly from storage.
func (q *Queue) PostNow(item QueueItem) {
q.postItem(item)
q.postItem(item, true)
}
// postItem returns true when a Matrix event was actually sent, false on
// any non-success path (dedup-skip, transport failure with or without
// retry, dead-letter). ForcePost uses the return value to decide whether
// to acknowledge the user-initiated !post or fall back to a DB lookup.
func (q *Queue) postItem(item QueueItem) bool {
// forced=true marks the resulting post_log row so it's excluded from the
// global daily cap (manual overrides shouldn't steal the rotation budget).
func (q *Queue) postItem(item QueueItem, forced bool) bool {
// Last-mile dedup: if this canonical URL was already posted to this channel
// within the cooldown window, drop silently. Catches "same article, different
// GUID across feeds" and any race where two items slipped past ingest dedup.
@@ -264,7 +266,7 @@ func (q *Queue) postItem(item QueueItem) bool {
}
// Record in post log (INSERT OR IGNORE via unique index)
storage.InsertPostLog(item.GUID, item.Channel, string(eventID), canonical)
storage.InsertPostLog(item.GUID, item.Channel, string(eventID), canonical, forced)
slog.Info("story posted",
"guid", item.GUID,