← back to Designerwallcoverings

scripts/anna-french-rolls/af-noroll-resume.sh

57 lines

#!/bin/bash
# af-noroll-resume.sh — daily, self-terminating build of the missing Anna French (DWAA)
# "Sold Per Roll" variants for the 131 sample-only products the reprice logged as no-roll.
#
# af-build-noroll.js prices each at the new single-roll basis (retail x0.45/0.65/0.85),
# self-heals the Shopify default-variant-consumes-sample trap, skips Title-option products,
# and aborts cleanly on the daily variant-creation cap (resumable next morning).
#
# Runs at 5:45am — BEFORE com.steve.sample-split-resume (6:15) and com.steve.schu-build-resume
# (7:00) — so its small 121-variant job grabs cap headroom first and finishes in ~1 day, then
# boots itself out and hands the full daily cap back to the longer-running jobs.
set -u
export PATH="/usr/local/bin:/opt/homebrew/bin:/opt/homebrew/opt/postgresql@14/bin:/usr/bin:/bin"
cd /Users/macstudio3/Projects/designerwallcoverings || exit 1
DIR=scripts/anna-french-rolls
BUDGET="$HOME/Projects/designerwallcoverings/scripts/variant-budget/budget.cjs"
LOG=/tmp/af-noroll-resume-$(date +%Y%m%d).log
{
  echo "=== af-noroll build $(date) ==="
  # Shared kill-switch (2026-06-19): this job previously ignored it entirely.
  if [ -f "$HOME/.dw-fixer-stop" ]; then echo "kill-switch present — skip"; echo "=== done $(date) ==="; exit 0; fi
  # Shared variant-budget gate (2026-06-19): af-build-noroll.js adds 1 roll variant per product,
  # so REPRICE_LIMIT is a variant count. Draw from the live 'upload' pool (== global ~864/day
  # Shopify ceiling minus osborne) and clamp the build to the grant so the whole writer fleet
  # can't blow the daily cap. take returns min(req, upload-remaining, global-remaining); 0 → skip.
  GRANT=$(node "$BUDGET" take upload 131 2>/dev/null || echo 131)
  if [ "${GRANT:-0}" -lt 1 ]; then echo "no variant budget this run (grant=$GRANT) — exit clean"; echo "=== done $(date) ==="; exit 0; fi
  echo "budget grant=$GRANT variants — building (REPRICE_LIMIT=$GRANT)"
  AF_OUT=$(COMMIT=1 REPRICE_LIMIT="$GRANT" node "$DIR/af-build-noroll.js" 2>&1)
  echo "$AF_OUT"

  # ── refund the unused upload grant (budget-integrity, 2026-06-20; DTD verdict A) ──
  # We took GRANT variants UP FRONT (== REPRICE_LIMIT) but af-build-noroll.js adds only 1 roll variant
  # per product actually built. It ALWAYS prints a trailing JSON tally with "made": N (even on the cap
  # break), so N is reliable; a cap/empty slot builds 0 (refund whole grant), a partial slot fewer.
  # Without this the unused grant silently drains the shared 864 upload slice. GUARD: refund ONLY when
  # the "made": N field was found (AF_MADE non-empty) — a crash that printed no tally keeps its debit
  # (conservative; never over-refunds → never over-grants against Shopify's real cap).
  AF_MADE=$(printf '%s' "$AF_OUT" | grep -oE '"made":[[:space:]]*[0-9]+' | grep -oE '[0-9]+' | tail -1)
  if [ -n "$AF_MADE" ]; then
    AF_REFUND=$(( GRANT - AF_MADE ))   # 1 roll variant per product built
    if [ "$AF_REFUND" -gt 0 ]; then
      AF_GOT=$(node "$BUDGET" refund upload "$AF_REFUND" 2>/dev/null || echo 0)
      echo "budget refund: grant=$GRANT used=$AF_MADE (built×1) → refunded $AF_GOT upload variants"
    fi
  fi
  echo "--- remaining check ---"
  NOROLL=$(grep -c . "$DIR/out/af-reprice-noroll.jsonl" 2>/dev/null || echo 0)
  DONE=$(grep -c . "$DIR/out/af-build-noroll-done.txt" 2>/dev/null || echo 0)
  echo "done=$DONE / noroll=$NOROLL"
  if [ "$DONE" -ge "$NOROLL" ] && [ "$NOROLL" -gt 0 ]; then
    echo "AF NO-ROLL BUILD COMPLETE — self-unloading com.steve.af-noroll-resume"
    launchctl bootout gui/$(id -u)/com.steve.af-noroll-resume 2>/dev/null
  fi
  echo "=== done $(date) ==="
} >> "$LOG" 2>&1