logtail: the sweep closes only queued rows, with reason "reconcile" (audit H3)

reconcile() closed a row through UpdateStatus (WHERE queue_id AND to_addr),
which could overwrite a "sent" the tailer wrote between the listing and the
close, and rewrite an old row of a reused queue id. store.CloseUnreported
sets status bounced and reason "reconcile" (store.ReasonReconcile; the
0006 column, no schema change) WHERE ... AND status = 'queued'; the sweep
counts rows actually closed.

Tests: store - a queued row is closed with the reason, a sent row is left
alone (0 rows); logtail - the sweep's close goes through CloseUnreported.

CHANGELOG [Unreleased], audit plan line ticked, roadmap 9/61.
Evidence: go vet ./... clean; go test ./internal/store ok, ./internal/logtail
ok but for TestFollowTailsAndRotates (Windows rename of an open file, fails
here always); the server run of the stage follows before the push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-14 14:16:26 +03:00
co-authored by Claude Opus 5.5
parent dfe10f6c27
commit 9adb44845c
9 changed files with 88 additions and 8 deletions
+4
View File
@@ -23,6 +23,10 @@ func (s *retentionProbeStore) ListQueuedOlderThan(time.Time) ([]store.QueuedDeli
return nil, nil
}
func (s *retentionProbeStore) CloseUnreported(string, string) (int64, error) {
return 0, nil
}
func (s *retentionProbeStore) DeleteSendLogBefore(cutoff time.Time) (int64, error) {
s.mu.Lock()
s.cutoff = cutoff