[object Object]

← back to Dw Daily Catchup 20260909

Bound catch-up retries to the 462 verified remaining candidates

7ec14eb0b3acf6b9b94b3b33f18159d2320546f5 · 2026-09-09 11:30:25 -0700 · Steve Abrams

Files touched

Diff

commit 7ec14eb0b3acf6b9b94b3b33f18159d2320546f5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 9 11:30:25 2026 -0700

    Bound catch-up retries to the 462 verified remaining candidates
---
 config/daily-catchup-2026-09-09.json | 1 +
 lib/activation-allowance.js          | 5 +++--
 rotate-activate.js                   | 5 ++++-
 test/activation-allowance.test.js    | 6 ++++--
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/config/daily-catchup-2026-09-09.json b/config/daily-catchup-2026-09-09.json
index 4685757..e4a3033 100644
--- a/config/daily-catchup-2026-09-09.json
+++ b/config/daily-catchup-2026-09-09.json
@@ -5,6 +5,7 @@
   "approved_by": "Steve",
   "authorization": "start loading for the day now",
   "starting_daily_used": 37,
+  "max_additional": 462,
   "max_daily": 500,
   "scope": "One-time catch-up for this date. Skip hourly pacing only when explicitly invoked; preserve the fixed vendor authorization, all other gates, zero Gemini and daily500."
 }
diff --git a/lib/activation-allowance.js b/lib/activation-allowance.js
index 8ece3e6..e8ef87b 100644
--- a/lib/activation-allowance.js
+++ b/lib/activation-allowance.js
@@ -5,7 +5,7 @@ function assertDailyCatchup(date, authorization, now = new Date()) {
       authorization?.schema_version !== 1 || authorization.ticket !== 'TK-11326' ||
       authorization.date !== date || authorization.approved_by !== 'Steve' ||
       authorization.authorization !== 'start loading for the day now' ||
-      authorization.starting_daily_used !== 37 || authorization.max_daily !== 500)
+      authorization.starting_daily_used !== 37 || authorization.max_additional !== 462 || authorization.max_daily !== 500)
     throw new Error('Daily catch-up authorization is invalid or expired');
 }
 
@@ -21,7 +21,8 @@ function activationAllowance({ dailyUsed, hourlyUsed, requested = null, dailyCap
   if (catchupDate !== null) {
     assertDailyCatchup(catchupDate, authorization, now);
     if (dailyUsed < authorization.starting_daily_used) throw new Error('Daily ledger is below approved catch-up baseline');
-    return { cap: Math.min(requested ?? dailyRemaining, dailyRemaining), mode: 'daily-catchup', dailyRemaining, hourlyRemaining };
+    const authorizedRemaining = Math.max(0, authorization.starting_daily_used + authorization.max_additional - dailyUsed);
+    return { cap: Math.min(requested ?? dailyRemaining, dailyRemaining, authorizedRemaining), mode: 'daily-catchup', dailyRemaining, hourlyRemaining };
   }
   return { cap: Math.min(requested ?? dailyRemaining, dailyRemaining, hourlyRemaining), mode: 'hourly', dailyRemaining, hourlyRemaining };
 }
diff --git a/rotate-activate.js b/rotate-activate.js
index faa9b56..a3a4443 100644
--- a/rotate-activate.js
+++ b/rotate-activate.js
@@ -416,7 +416,10 @@ function leakGuard(title, vendor) {
 
       // COMMIT: flip → ACTIVE, add 'New Arrival', publish to channels (ex-Google).
       if (CATCHUP_DATE !== null) assertDailyCatchup(CATCHUP_DATE, CATCHUP_AUTHORIZATION);
-      if (ledgerUsed() >= DAILY_ACTIVATION_CAP) throw new Error('Daily activation cap reached during run');
+      const activeCeiling = CATCHUP_DATE !== null
+        ? Math.min(DAILY_ACTIVATION_CAP, CATCHUP_AUTHORIZATION.starting_daily_used + CATCHUP_AUTHORIZATION.max_additional)
+        : DAILY_ACTIVATION_CAP;
+      if (ledgerUsed() >= activeCeiling) throw new Error('Daily activation allowance reached during run');
       const ar = await gqlRetry(ACTIVATE, { id: n.id });
       const aue = ar.json?.data?.productUpdate?.userErrors;
       if (!confirmedActivation(ar, n.id)) {
diff --git a/test/activation-allowance.test.js b/test/activation-allowance.test.js
index 68cf9fd..98d7489 100644
--- a/test/activation-allowance.test.js
+++ b/test/activation-allowance.test.js
@@ -12,11 +12,12 @@ test('normal scheduled runs retain the21/hour cap', () => {
 });
 test('explicit current-day catch-up can use remaining daily allowance', () => {
   const result = activationAllowance(catchup());
-  assert.equal(result.cap, 463); assert.equal(result.mode, 'daily-catchup');
+  assert.equal(result.cap, 462); assert.equal(result.mode, 'daily-catchup');
   assert.equal(activationAllowance(catchup({ requested: 1 })).cap, 1);
 });
 test('retries cannot exceed500 total activations', () => {
-  assert.equal(activationAllowance(catchup({ dailyUsed: 499 })).cap, 1);
+  assert.equal(activationAllowance(catchup({ dailyUsed: 498 })).cap, 1);
+  assert.equal(activationAllowance(catchup({ dailyUsed: 499 })).cap, 0);
   assert.equal(activationAllowance(catchup({ dailyUsed: 500 })).cap, 0);
   assert.equal(activationAllowance(catchup({ dailyUsed: 501 })).cap, 0);
 });
@@ -25,6 +26,7 @@ test('having an authorization file does not enable catch-up for a scheduled invo
 });
 test('missing, altered, future and expired authorizations fail closed', () => {
   for (const change of [{ authorization: null }, { authorization: { ...authorization, max_daily: 501 } },
+    { authorization: { ...authorization, max_additional: 463 } },
     { authorization: { ...authorization, approved_by: 'someone else' } }, { catchupDate: '2026-09-10' },
     { now: new Date('2026-09-10T00:00:00Z') }, { now: new Date('2026-09-08T23:59:59Z') }])
     assert.throws(() => activationAllowance(catchup(change)));

← 5e650c1 Add dated daily activation catch-up while retaining the 500  ·  back to Dw Daily Catchup 20260909  ·  Record catch-up audit exceptions before publication repair 8f77ddc →