@@ -15,6 +15,7 @@ import {
1515 effectiveDailyBudgetCents ,
1616 engagementsForDailyBudget ,
1717 glidedDailyBudgetCents ,
18+ deliverySpacingSeconds ,
1819 deliveryWindowLimit ,
1920 type BudgetGlide ,
2021} from '../constants/freebuff-ads'
@@ -272,3 +273,47 @@ describe('deliveryWindowLimit', () => {
272273 expect ( limit ( 0 , '2026-08-28T03' ) ) . toBe ( 0 )
273274 } )
274275} )
276+
277+ describe ( 'deliverySpacingSeconds' , ( ) => {
278+ const gap = ( cap : number , windowKey = '2026-08-28T09' , jitterBps = 2_500 ) =>
279+ deliverySpacingSeconds ( { capEngagements : cap , seed : SEED , windowKey, jitterBps } )
280+
281+ test ( 'a day divided into the day: 300/day is roughly five minutes apart' , ( ) => {
282+ const value = gap ( 300 )
283+ expect ( value ) . toBeGreaterThan ( 200 )
284+ expect ( value ) . toBeLessThan ( 380 )
285+ } )
286+
287+ test ( 'a smaller cap is spaced further apart' , ( ) => {
288+ // The tail of a taper delivers less often, not in a shorter burst.
289+ expect ( gap ( 50 ) ) . toBeGreaterThan ( gap ( 300 ) )
290+ expect ( gap ( 300 ) ) . toBeGreaterThan ( gap ( 2_000 ) )
291+ } )
292+
293+ test ( 'an hour of spacing roughly reproduces the hourly ceiling' , ( ) => {
294+ // Spacing and the window limit are two expressions of the same rate; if
295+ // they disagreed badly, one of them would be doing nothing.
296+ const perHour = 3_600 / gap ( 300 )
297+ expect ( perHour ) . toBeGreaterThan ( 9 )
298+ expect ( perHour ) . toBeLessThan ( 18 )
299+ } )
300+
301+ test ( 'bounded at both ends' , ( ) => {
302+ // A huge cap still gets a floor, so delivery is never instantaneous...
303+ expect ( gap ( 1_000_000 ) ) . toBe ( 15 )
304+ // ...and a tiny one never waits longer than the window it lives in.
305+ expect ( gap ( 1 ) ) . toBe ( 3_600 )
306+ } )
307+
308+ test ( 'stable within the hour, different across hours' , ( ) => {
309+ expect ( gap ( 300 , '2026-08-28T09' ) ) . toBe ( gap ( 300 , '2026-08-28T09' ) )
310+ const hours = Array . from ( { length : 12 } , ( _ , h ) =>
311+ gap ( 300 , `2026-08-28T${ String ( h ) . padStart ( 2 , '0' ) } ` ) ,
312+ )
313+ expect ( new Set ( hours ) . size ) . toBeGreaterThan ( 6 )
314+ } )
315+
316+ test ( 'a zero cap has no spacing to compute' , ( ) => {
317+ expect ( gap ( 0 ) ) . toBe ( 0 )
318+ } )
319+ } )
0 commit comments