Fix the try on bb594652: a const batch gap unit tests assert directly, wait for the bundle's own subscribe before publishing, and a migration-0001 database built through the real path (issues 1520, 1518, 1431, 1517)

This commit is contained in:
jochen
2026-10-21 01:24:57 +02:00
parent bb594652fa
commit cfea9de530
7 changed files with 190 additions and 36 deletions
@@ -16,13 +16,20 @@ import (
"time"
)
// BatchGap is how long must pass between the start of one batch and the next (ADR 0459 §15, 1520/AC1): a
// var, never a setting, so an integration test can shorten it in its own build alone (issue 1431's own
// fix: batch_gap_integration.go, `//go:build integration`, never part of a production build) without
// production pacing ever becoming configurable. Every normal build (including every unit test) keeps this
// at 160s; TestNextBatchWait and TestThirtyWaitingMailsRunAsThreeBatchesAtLeast160sApart still prove that
// value, on a test clock, in batch_test.go.
var BatchGap = 160 * time.Second
// MinBatchGap is the pace no production path may ever lower (ADR 0459 §15, 1520/AC1): at least 160s
// between the start of one batch and the next. It is a const, never read by anything an integration
// build could shorten; the unit tests in batch_test.go assert against this literal, not against the var
// below, so they keep proving 160s even when compiled into a binary whose BatchGap has been shortened
// (issue 1520, fixed per the lead's try feedback on bb594652).
const MinBatchGap = 160 * time.Second
// BatchGap is the gap the running binary actually paces its batches by: a var, never a setting, so an
// integration test can shorten it for its own build alone (issue 1431's own fix: batch_gap_integration.go,
// `//go:build integration`, never part of a production build) without production pacing ever becoming
// configurable. Every normal (non-integration) build starts it at MinBatchGap and never changes it;
// TestRunningBatchGapIsMinBatchGap (batch_gap_test.go, `//go:build !integration`) proves that for the
// binary actually shipped, not just for a literal.
var BatchGap = MinBatchGap
// JudgeWithin is the bound every judgement asks: never above 40 seconds (ADR 0459 §14, 1520/AC2).
const JudgeWithin = 40 * time.Second
@@ -100,17 +107,19 @@ func NewJudge(ask Ask, node string, now func() time.Time) JudgeFunc {
}
}
// nextBatchWait is how long to wait before the next batch may start (1520/AC1): zero once BatchGap has
// passed since the last start (or no batch has started yet), else the remainder.
func nextBatchWait(lastStart, now time.Time) time.Duration {
// nextBatchWait is how long to wait before the next batch may start (1520/AC1): zero once gap has
// passed since the last start (or no batch has started yet), else the remainder. gap is given explicitly
// by the caller (RunBatches passes BatchGap; the unit tests in batch_test.go pass MinBatchGap directly)
// so this pure function never itself reaches into a var an integration build might have shortened.
func nextBatchWait(lastStart, now time.Time, gap time.Duration) time.Duration {
if lastStart.IsZero() {
return 0
}
elapsed := now.Sub(lastStart)
if elapsed >= BatchGap {
if elapsed >= gap {
return 0
}
return BatchGap - elapsed
return gap - elapsed
}
func senderOf(from []Person) (name, address string) {
@@ -235,7 +244,7 @@ func RunBatches(ctx context.Context, store Store, readText ReadTextFunc, judge J
if ctx.Err() != nil {
return
}
if wait := nextBatchWait(lastStart, now()); wait > 0 {
if wait := nextBatchWait(lastStart, now(), BatchGap); wait > 0 {
sleep(wait)
continue
}