← back to New Import Viewer
Add one-shot auto first-run (429-gated validated 42-batch + CNCP report + self-disable)
4573e7cc5265d4f2dddae2e88ed800ddfcf5e7ce · 2026-06-19 09:43:46 -0700 · SteveStudio2
Files touched
A auto-first-run.shA com.steve.dw-first-run.plist
Diff
commit 4573e7cc5265d4f2dddae2e88ed800ddfcf5e7ce
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Fri Jun 19 09:43:46 2026 -0700
Add one-shot auto first-run (429-gated validated 42-batch + CNCP report + self-disable)
---
auto-first-run.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++
com.steve.dw-first-run.plist | 29 +++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/auto-first-run.sh b/auto-first-run.sh
new file mode 100755
index 0000000..b96e15c
--- /dev/null
+++ b/auto-first-run.sh
@@ -0,0 +1,76 @@
+#!/bin/zsh
+# AUTO FIRST-RUN — one-shot validated 42-SKU live run, gated on the Shopify
+# daily-variant-429 clearing. Steve approved (2026-06-19) "auto-retry at ~4 PM PT,
+# run the first 42 and report".
+#
+# Behavior:
+# • Fired hourly by launchd (com.steve.dw-first-run) but ONLY acts from 16:00
+# local (PDT) onward — earlier ticks exit immediately (429 still active).
+# • Runs ONE live 42-batch via run-cadence.sh (consumer.js publishes to Online
+# Store via the 2026-06-19 publish fix; soft-stops on 429, creates nothing if
+# still blocked).
+# • Verifies via Shopify: products created in the last 15 min that are PUBLISHED.
+# • On first success (>=1 published): posts a CNCP card, writes a result file,
+# and BOOTS ITSELF OUT of launchd (one-shot — does NOT become a 24/7 cadence).
+# • If still blocked: logs, leaves itself scheduled to retry next hour.
+# • At/after 21:00 local with still no success: posts a one-time CNCP escalation.
+#
+# This validates the pipeline with ONE real batch. Enabling the full 42/hr × 24
+# cadence (com.steve.dw-cadence) is a SEPARATE Steve action after this proves out.
+set -uo pipefail
+cd "$(dirname "$0")"
+export PATH="/opt/homebrew/bin:/usr/bin:/bin:/usr/local/bin:$PATH"
+
+LABEL="com.steve.dw-first-run"
+LOG="data/first-run.log"
+RESULT="data/first-run-result.json"
+ESC_FLAG="data/.first-run-escalated"
+HOUR_LOCAL=$(date +%H)
+TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
+
+log(){ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG"; }
+
+# Gate: do nothing before 16:00 local (429 window not expected to clear yet).
+if [ "$HOUR_LOCAL" -lt 16 ]; then
+ log "tick skipped (local hour $HOUR_LOCAL < 16 — 429 window not yet expected to clear)"
+ exit 0
+fi
+
+log "tick: attempting one live 42-batch (local hour $HOUR_LOCAL)"
+LAUNCH_CONSUMER_LIVE=1 CADENCE_LIMIT=42 ./run-cadence.sh || log "run-cadence.sh returned non-zero (logged in cadence log)"
+
+# Verify: how many products were created+published in the last 15 minutes?
+TOKEN=$(grep '^SHOPIFY_ADMIN_TOKEN=' "$HOME/Projects/secrets-manager/.env" | cut -d= -f2-)
+STORE=$(grep '^SHOPIFY_STORE=' "$HOME/Projects/secrets-manager/.env" | cut -d= -f2-)
+PUBN=$(python3 - "$STORE" "$TOKEN" <<'PY'
+import sys,json,urllib.request,datetime
+store,token=sys.argv[1],sys.argv[2]
+since=(datetime.datetime.now(datetime.UTC)-datetime.timedelta(minutes=15)).strftime('%Y-%m-%dT%H:%M:%SZ')
+url=f"https://{store}/admin/api/2024-10/products/count.json?created_at_min={since}&published_status=published"
+r=urllib.request.Request(url,headers={"X-Shopify-Access-Token":token})
+try:
+ print(json.loads(urllib.request.urlopen(r).read()).get("count",0))
+except Exception as e:
+ print(0)
+PY
+)
+log "verify: $PUBN products created+published in last 15 min"
+
+cncp(){ curl -s -X POST http://127.0.0.1:3333/api/wins -H 'Content-Type: application/json' -d "$1" >/dev/null 2>&1 || true; }
+
+if [ "${PUBN:-0}" -ge 1 ]; then
+ printf '{"ts":"%s","published_last15m":%s,"status":"success"}\n' "$TS" "$PUBN" > "$RESULT"
+ cncp "{\"project\":\"dw-cadence\",\"title\":\"First 42-SKU live run validated — $PUBN published\",\"summary\":\"Daily-variant 429 cleared; one cadence batch created+published $PUBN SKUs to Online Store via the publish-gap fix (consumer.js 96cd954). Pipeline proven. Ready to enable the full 42/hr x 24 cadence (com.steve.dw-cadence).\",\"valueToday\":\"Unblocks the 1,000-published-SKUs/24h target\"}"
+ log "SUCCESS ($PUBN published) — posting CNCP card and self-disabling (bootout)"
+ launchctl bootout gui/$(id -u)/$LABEL 2>/dev/null || true
+ exit 0
+fi
+
+# Still blocked — escalate once if it's getting late and we still haven't succeeded.
+if [ "$HOUR_LOCAL" -ge 21 ] && [ ! -f "$ESC_FLAG" ]; then
+ touch "$ESC_FLAG"
+ cncp "{\"project\":\"dw-cadence\",\"title\":\"First 42-SKU run STILL 429-blocked at $HOUR_LOCAL:00 PDT\",\"summary\":\"The Shopify daily-variant-creation limit has not cleared by evening. The auto-retry is still armed and will keep trying hourly, but this needs a manual look — the burst window may be wider than ~24h.\"}"
+ log "ESCALATION posted (still blocked at local hour $HOUR_LOCAL)"
+fi
+log "still blocked — staying scheduled, will retry next hour"
+exit 0
diff --git a/com.steve.dw-first-run.plist b/com.steve.dw-first-run.plist
new file mode 100644
index 0000000..c49346d
--- /dev/null
+++ b/com.steve.dw-first-run.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.steve.dw-first-run</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/zsh</string>
+ <string>/Users/stevestudio2/Projects/new-import-viewer/auto-first-run.sh</string>
+ </array>
+ <key>WorkingDirectory</key>
+ <string>/Users/stevestudio2/Projects/new-import-viewer</string>
+ <!-- Fire hourly at HH:07. The script self-gates to act only from 16:00 local
+ (PDT) onward, runs ONE validated 42-batch when the 429 clears, then boots
+ itself out. RunAtLoad false so bootstrapping it now does not fire instantly. -->
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Minute</key>
+ <integer>7</integer>
+ </dict>
+ <key>RunAtLoad</key>
+ <false/>
+ <key>StandardOutPath</key>
+ <string>/Users/stevestudio2/Projects/new-import-viewer/data/first-run.launchd.log</string>
+ <key>StandardErrorPath</key>
+ <string>/Users/stevestudio2/Projects/new-import-viewer/data/first-run.launchd.log</string>
+</dict>
+</plist>
← b4ec23e phase8-fix: real create+publish module (mirrors consumer.js
·
back to New Import Viewer
·
Retire new-import-viewer duplicate cadence plists — consolid d85bde7 →