← back to York Reprice 2026 08

cadence/york-auto-onboard.mjs

60 lines

#!/usr/bin/env node
/**
 * york-auto-onboard.mjs — the ONE place the York cadence is allowed to WRITE to Shopify.
 *
 * Steve authorized (2026-07-13, AskUserQuestion): the cadence auto-onboards New York items as
 * DRAFT, capped ~100 per run. This drips the pre-vetted onboard queue
 * (data/onboard-payloads-enriched.json) into Shopify over successive mornings until exhausted.
 *
 * HARD RAILS (never widened here):
 *   • DRAFT only — york-new-create sets status:'DRAFT'; nothing goes ACTIVE. Publish stays a
 *     separate, explicit, Steve-gated step.
 *   • Cap 100 NEW creates per run (--limit); idempotent — SKUs already live are skipped.
 *   • ONBOARD bucket only. Reprice + disco remain strictly propose-only (memo, never auto-write).
 *   • The queue is PRE-VETTED: settlement-deepened (flora/fauna held), 39 image-flags excluded,
 *     dead-CDN images dropped, priced (naturals@roll_price_single, standard@MAP), gate-clean.
 *   • Fail-safe: any error is caught and logged; it never throws up into the cadence diff.
 *
 * Called at the tail of york-cadence.mjs. Returns {created,skipped,err,total_remaining}.
 */
import fs from 'node:fs';
import { execSync } from 'node:child_process';

const ROOT = process.env.HOME + '/Projects/york-reprice-2026-08';
const QUEUE = ROOT + '/data/onboard-payloads-enriched.json';
const CAP = 100;

export function autoOnboard() {
  const result = { created: 0, skipped: 0, err: 0, queue_size: 0, ran: false, note: '' };
  try {
    if (!fs.existsSync(QUEUE)) { result.note = 'no onboard queue file — nothing to onboard'; return result; }
    const queue = JSON.parse(fs.readFileSync(QUEUE, 'utf8'));
    result.queue_size = queue.length;
    if (!queue.length) { result.note = 'onboard queue empty'; return result; }

    // Spawn the vetted creator (DRAFT, idempotent, cap=CAP new creates). cwd=ROOT for its relative paths.
    // Use process.execPath (absolute path of THIS node), not bare `node` — launchd's stripped PATH
    // has no Homebrew node, so `node ...` silently ExecSync-failed every 6:35am run (fixed 2026-07-14).
    const out = execSync(
      `"${process.execPath}" york-new-create.mjs --file=data/onboard-payloads-enriched.json --limit=${CAP} --apply --i-am-steve`,
      { cwd: ROOT, encoding: 'utf8', timeout: 30 * 60 * 1000 }
    );
    result.ran = true;
    // parse the creator's DONE line: "DONE — N DRAFT created, M create-err, K skipped(exists), ..."
    const m = out.match(/DONE — (\d+) DRAFT created, (\d+) create-err, (\d+) skipped/);
    if (m) { result.created = +m[1]; result.err = +m[2]; result.skipped = +m[3]; }
    result.note = m ? `created ${result.created}, skipped(exists) ${result.skipped}, err ${result.err}` : 'ran; could not parse creator output';
    // tail of creator output for the log
    result.tail = out.trim().split('\n').slice(-4).join(' | ');
  } catch (e) {
    result.note = 'auto-onboard error (caught, cadence unaffected): ' + String(e.message || e).slice(0, 160);
  }
  return result;
}

// Standalone run (for testing / manual drip): `node cadence/york-auto-onboard.mjs`
if (import.meta.url === `file://${process.argv[1]}`) {
  const r = autoOnboard();
  console.log('york-auto-onboard:', JSON.stringify(r, null, 2));
}