[object Object]

← 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

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 →