← back to Dw Rotation Activator
add hourly drip drain.sh + STAGED launchd plist (not loaded — bootstrap gated on Steve approval)
9976a6b4488fe4c6b8f59c0ac7821f20cb4e384f · 2026-07-21 13:02:12 -0700 · Steve
Files touched
A com.steve.dw-rotation-activator.plist.STAGEDA drain.sh
Diff
commit 9976a6b4488fe4c6b8f59c0ac7821f20cb4e384f
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Jul 21 13:02:12 2026 -0700
add hourly drip drain.sh + STAGED launchd plist (not loaded — bootstrap gated on Steve approval)
---
com.steve.dw-rotation-activator.plist.STAGED | 27 ++++++++++++++++++++++++
drain.sh | 31 ++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/com.steve.dw-rotation-activator.plist.STAGED b/com.steve.dw-rotation-activator.plist.STAGED
new file mode 100644
index 0000000..590fc6c
--- /dev/null
+++ b/com.steve.dw-rotation-activator.plist.STAGED
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- STAGED — NOT loaded. Bootstrap only after Steve APPROVES the go-live memo:
+ launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.steve.dw-rotation-activator.plist
+ (copy this file there first, dropping the .STAGED suffix). Hourly at :25 so it
+ does not collide with the field-fix drain (:10 in generate-schedule's model). -->
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.steve.dw-rotation-activator</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/zsh</string>
+ <string>/Users/macstudio3/Projects/dw-rotation-activator/drain.sh</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Minute</key>
+ <integer>25</integer>
+ </dict>
+ <key>RunAtLoad</key>
+ <false/>
+ <key>StandardOutPath</key>
+ <string>/tmp/dw-rotation-activator.log</string>
+ <key>StandardErrorPath</key>
+ <string>/tmp/dw-rotation-activator.log</string>
+</dict>
+</plist>
diff --git a/drain.sh b/drain.sh
new file mode 100755
index 0000000..189ed2a
--- /dev/null
+++ b/drain.sh
@@ -0,0 +1,31 @@
+#!/bin/zsh
+# Hourly rotation-activator drip. Activates the next per-slot batch of gate-passing
+# DRAFTs in the canonical textures-first + vendor-round-robin order, capped by the
+# activator's OWN daily activation ledger (~500/day). Idempotent, resumable,
+# singleton-guarded. Activation is NOT a variant-create, so it never touches the
+# budget.cjs variant ledger — the field-fix drain and this run in independent lanes.
+set -u
+export PATH="/opt/homebrew/opt/postgresql@14/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
+SK="$HOME/Projects/dw-rotation-activator"
+LOG="$SK/drain.log"
+LOCKDIR="$SK/.drain.lock"
+EXE="$SK/rotate-activate.js"
+ts(){ date '+%Y-%m-%d %H:%M:%S'; }
+
+# singleton (atomic mkdir lock, stale after 2h)
+if ! mkdir "$LOCKDIR" 2>/dev/null; then
+ if [ -d "$LOCKDIR" ] && [ "$(find "$LOCKDIR" -maxdepth 0 -mmin +120 2>/dev/null)" ]; then
+ rmdir "$LOCKDIR" 2>/dev/null; mkdir "$LOCKDIR" 2>/dev/null || { echo "[$(ts)] locked, skip" >>"$LOG"; exit 0; }
+ else
+ echo "[$(ts)] already running, skip" >>"$LOG"; exit 0
+ fi
+fi
+trap 'rmdir "$LOCKDIR" 2>/dev/null' EXIT
+
+# ~21/slot spreads the 500/day activation cap across the 24 hourly slots; the
+# activator's daily ledger hard-caps the day's total regardless of per-slot ask.
+SLOT_MAX="${DW_ROTATION_SLOT_MAX:-21}"
+echo "[$(ts)] rotation-activate start slot_max=$SLOT_MAX" >>"$LOG"
+/opt/homebrew/bin/node "$EXE" --max "$SLOT_MAX" --commit >>"$LOG" 2>&1
+RC=$?
+echo "[$(ts)] rotation-activate end rc=$RC" >>"$LOG"
← fca7d4c rotation activator: textures-first + vendor round-robin DRAF
·
back to Dw Rotation Activator
·
Add per-product settlement gate to rotation activator (textu 329e3f2 →