← back to Designer Wallcoverings
nightly runner: durable completion ping — check-complete.js verifies every resolvable collection is at 0-remaining, then runner fires macOS notification + CNCP win + .SWEEP-COMPLETE sentinel + self-disables the nightly job. Works with no Claude session open.
4d3e325e5ff1c5bf0d3d505d6e80dce710e032df · 2026-06-13 08:58:53 -0700 · Steve Abrams
Files touched
A DW-Programming/check-complete.jsM DW-Programming/nightly-color-clean.sh
Diff
commit 4d3e325e5ff1c5bf0d3d505d6e80dce710e032df
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jun 13 08:58:53 2026 -0700
nightly runner: durable completion ping — check-complete.js verifies every resolvable collection is at 0-remaining, then runner fires macOS notification + CNCP win + .SWEEP-COMPLETE sentinel + self-disables the nightly job. Works with no Claude session open.
---
DW-Programming/check-complete.js | 22 ++++++++++++++++++++++
DW-Programming/nightly-color-clean.sh | 19 +++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/DW-Programming/check-complete.js b/DW-Programming/check-complete.js
new file mode 100644
index 00000000..35079601
--- /dev/null
+++ b/DW-Programming/check-complete.js
@@ -0,0 +1,22 @@
+#!/usr/bin/env node
+// Exit 0 only when EVERY resolvable color collection has 0 products left to
+// process (i.e. all current members are in the .done state). Exit 1 otherwise.
+// Unresolvable colors (e.g. cream — no cream-only collection on this store) are
+// skipped, never block completion. Prints {remaining, per} JSON.
+const path = require('path'), fs = require('fs');
+const { resolveCollectionId, fetchCollectionProducts, COLOR_COLLECTIONS } = require('./color-collection-cleaner-v2.js');
+const STATE = path.join(__dirname, 'data', 'color-clean-state');
+const done = (c) => { try { return new Set(fs.readFileSync(path.join(STATE, c + '.done'), 'utf8').split('\n').filter(Boolean).map(Number)); } catch { return new Set(); } };
+(async () => {
+ let remaining = 0; const per = {};
+ for (const [color, cfg] of Object.entries(COLOR_COLLECTIONS)) {
+ const id = await resolveCollectionId(color, cfg);
+ if (!id) { per[color] = 'skip(unresolved)'; continue; }
+ const prods = await fetchCollectionProducts(id);
+ const d = done(color);
+ const left = prods.filter(p => !d.has(p.id)).length;
+ per[color] = left; remaining += left;
+ }
+ console.log(JSON.stringify({ remaining, per }));
+ process.exit(remaining === 0 ? 0 : 1);
+})().catch(e => { console.error('check-complete error:', e.message); process.exit(2); });
diff --git a/DW-Programming/nightly-color-clean.sh b/DW-Programming/nightly-color-clean.sh
index a68f1780..fecc8acd 100755
--- a/DW-Programming/nightly-color-clean.sh
+++ b/DW-Programming/nightly-color-clean.sh
@@ -48,4 +48,23 @@ else CAP=""; fi
$CAP node color-collection-cleaner-v2.js --all --conc 3 >> "$LOG" 2>&1
echo "--- report ---" >> "$LOG"
node color-clean-report.js >> "$LOG" 2>&1
+
+# --- completion ping (durable; fires even with no Claude session open) ---
+SENTINEL="$DIR/data/.SWEEP-COMPLETE"
+if [ ! -f "$SENTINEL" ]; then
+ CHK=$(node check-complete.js 2>>"$LOG"); RC=$?
+ echo "$(date): completeness check rc=$RC $CHK" >> "$LOG"
+ if [ "$RC" -eq 0 ]; then
+ REMOVED=$(grep -c '"dry_run": *false\|"dry_run":false' data/color-clean-ledger.jsonl 2>/dev/null)
+ echo "$CHK" > "$SENTINEL"
+ # 1. desktop ping
+ /usr/bin/osascript -e "display notification \"Live color-collection sweep COMPLETE — all collections processed, ${REMOVED} mis-tagged products removed. Review then decide on cream.\" with title \"Color Cleaner ✅\" sound name \"Glass\"" 2>/dev/null
+ # 2. CNCP win (best-effort)
+ curl -s -X POST http://127.0.0.1:3333/api/wins -H 'Content-Type: application/json' \
+ -d "{\"project\":\"Designer-Wallcoverings\",\"title\":\"Live color-collection sweep COMPLETE\",\"summary\":\"All resolvable color collections fully processed on the live store. ${REMOVED} mis-tagged products removed (reversible via ledger). Cream skipped (no cream-only collection). Banner re-crawl queue populated.\"}" >/dev/null 2>&1
+ # 3. self-disable the nightly job — nothing left to do
+ launchctl bootout gui/$(id -u)/com.steve.color-cleaner-nightly 2>/dev/null
+ echo "$(date): SWEEP COMPLETE — notified, win logged, nightly job self-disabled" >> "$LOG"
+ fi
+fi
echo "=== $(date) nightly color-clean end ===" >> "$LOG"
← 6f9d054f nightly runner: chain-aware quota probe (proceed if ANY chai
·
back to Designer Wallcoverings
·
nightly runner: add best-effort George email on sweep comple 49cb6051 →