Dw Rotation Activator

repo: ~/Projects/dw-rotation-activator · 39 commits · 1 in last 24h, 3 in last 7d · █ ▄

Search the build

39 commits indexed

  1. 90be0b4 2026-09-26 TK-11856 rc-propagation (SHOPIFY): rotation-activator drain.sh exits with activator rc (then prune rc)
  2. f16fc54 2026-09-22 TK-11786: mirror tokiwa/tokiwa usa into leakGuard PL_LEAK_HARD (sync with denylist.json)
  3. ce4a6ca 2026-09-22 leakGuard: mirror mdc/mdcwall/mdc wall/as creation denylist terms (TK-12015)
  4. 9f91f6c 2026-09-11 TK-11471: weight go-live gate on the rotation activator (highest blast radius in the fleet)
  5. 1e149c4 2026-09-10 fix: remove a NUL byte I introduced in 7e0039b's cache key
  6. 7e0039b 2026-09-10 TK-11384: scope stagingColorFor() to the vendor on shared catalog tables
  7. 0bd5974 2026-09-09 Record verified 462-product loading and unresolved Google channel exceptions
  8. 0add27a 2026-09-09 Require confirmed Online Store availability before counting publication
  9. 9720a3e 2026-09-09 Enable verified one-day activation catch-up within daily allowance
  10. ea60cf7 2026-09-09 Keep released runtime worker locks out of repository snapshots
  11. 7396a48 2026-09-09 Verify full Gemini-free batch and shared hourly activation limit
  12. c3b8011 2026-09-09 auto-data-snapshot: 2026-09-09T11:09:48 (1 data files) — .drain.lock/TK-11321-owner.json
  13. b03419a 2026-09-09 Apply Steve-authorized Gemini skip and verify first live product
  14. f9e5125 2026-09-09 Record successful scheduled activation and remaining image funding block
  15. c88ff69 2026-09-09 Restore draft readiness checks and verify live activation canary
  16. 37bb28a 2026-09-03 TK-11186 Step D prep: rotation-activator skips showroom vendors (no activate/New Arrival tag/browse publish)
  17. 99013ea 2026-09-01 feat(golive-gate): mfr_sku provenance gate blocks blank/fabricated codes at DRAFT->ACTIVE
  18. d9e84e1 2026-08-31 rotation-activator: block $4.25 sample-leak price from passing the activation gate (TK-10456)
  19. c4f1747 2026-08-28 Fail closed on malformed activation fields
  20. ee136fc 2026-08-28 Unify pre-activation five-field checks
  21. 3b23d46 2026-08-11 chore: fail-closed activation guard in drain.sh (session close)
  22. 6074d75 2026-08-11 rotation drain: pre-flight re-intro guard check — abort activation tick on drift (TK-10474)
  23. 382423f 2026-08-11 collapse rotation-order.js to single source: symlink activator copy → canonical calendar copy (kills the two-drifting-copies footgun)
  24. 81ca301 2026-08-10 TK-10446 Tier-1: live-verify (892 orphans/48 have-roll/3 inactive) + gated revert script (dry-run default, re-checks live before each revert)
  25. 7f4f53f 2026-08-10 Save TK-10446 Tier-1 cleanup id list (943 rotation-published last-7d)
  26. 0117f7a 2026-08-10 Exclude samples, Gracie/bespoke vendors, and re-introductions from activation queue (TK-10446)
  27. 6ec5f49 2026-07-26 chore: refactor (summary label reflects COMMIT vs DRY mode), session close
  28. 04ef58e 2026-07-26 Add mdc-activate.js: private-label MDC→Phillipe Romano activator (mdc_catalog PID-scoped, settlement+5-field gate, ex-Google, MDC-coinage leak guard, Dublin-Vital hold)
  29. f8d9655 2026-07-25 auto-save: 2026-07-25T12:36:15 (1 files) — cmo-activate.js
  30. 0b70591 2026-07-23 rotation gate: quote-only ('quotes' tag) lines exempt from no-sellable-variant too (Koroseal/Vahallan sample-only by design)
  31. 469d6e0 2026-07-22 leakGuard: add rigo / rigowall / rigo wallcovering (RIGO PL onboard 2026-07-22)
  32. e06f84c 2026-07-22 drain: prune the activation-calendar cadence after each hourly run
  33. 3466936 2026-07-21 chore: clarify _HARD_RE/_VENDOR_RE are [token,RegExp] pairs (session close)
  34. 3f4f5ae 2026-07-21 activator: word-boundary leak matching — fixes 'versa' false-positive on legit Versace brand
  35. eb84eed 2026-07-21 activator: align leak guard to canonical dw-leak-scanner denylist (add york/brewster/lillian-august/momentum/versa; drop schumacher); cite source (DTD-B)
  36. ade810f 2026-07-21 activator: private-label leak guard — never activate a product with a source name (Greenland/WallQuest/etc) in title or vendor
  37. 329e3f2 2026-07-21 Add per-product settlement gate to rotation activator (texture auto-pass + Gemini vision, fail-closed, dual-key)
  38. 9976a6b 2026-07-21 add hourly drip drain.sh + STAGED launchd plist (not loaded — bootstrap gated on Steve approval)
  39. fca7d4c 2026-07-21 rotation activator: textures-first + vendor round-robin DRAFT->ACTIVE, all 15,863 drafts, live 5-field re-gate, own daily activation cap

Authors

Agents used

  • none detected

Skills used

  • /claude3
  • /code3
  • /mdc2
  • /weight-gate2
  • /macstudio31
  • /dw-rotation-activator1
  • /tokiwa1
  • /mdcwall1
  • /curate1
  • /rotation-order1
  • /day1
  • /run1
  • /scripts1
  • /weight-guard1
  • /extra1
  • /leak1
  • /mfr1
  • /server1
  • /auditor1
  • /check1
  • /browse1
  • /fabricated1
  • /mfr-gate1
  • /mfr-gate-resolve1
  • /null1
  • /unknown1
  • /no-price1
  • /bespoke1
  • /brewster1
  • /lillian-august1

Creative ideas + design notes

Commits with substantial prose (≥120 chars) — the rationale behind each move.

90be0b4 · 2026-09-26 · TK-11856 rc-propagation (SHOPIFY): rotation-activator drain.sh exits with activator rc (then prune rc)
Exit-code ONLY, no behavior change (Steve ruling 2026-09-26 Q1/Q2): every step still runs as
before; the wrapper now exits with the first nonzero rc of its side-effecting step(s) instead of
swallowing it, so cron-fire-canary's exit corroboration can see a failed run. No heartbeat file added.
Revert: git -C /Users/macstudio3/Projects/dw-rotation-activator revert <this sha>

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YaiWjfgEuKQLTb5cdDreS3
f16fc54 · 2026-09-22 · TK-11786: mirror tokiwa/tokiwa usa into leakGuard PL_LEAK_HARD (sync with denylist.json)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PH1rVLG7Nvp8EcmaARzAv4
ce4a6ca · 2026-09-22 · leakGuard: mirror mdc/mdcwall/mdc wall/as creation denylist terms (TK-12015)
Mirror of the canonical dw-leak-scanner denylist change. mdcwall/mdc wall/as creation
-> PL_LEAK_HARD (unambiguous, title+vendor); bare 'mdc' -> PL_LEAK_VENDOR_ONLY (short
acronym, block only when the source vendor is MDC). 'astek' intentionally omitted
(real customer-facing brand; per-SKU /curate -> Phillipe Romano is Steve-gated).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session
9f91f6c · 2026-09-11 · TK-11471: weight go-live gate on the rotation activator (highest blast radius in the fleet)
This is the biggest unguarded path found in the TK-11414 lineage, and it was missed by
every prior sweep — including mine. com.steve.dw-rotation-activator fires HOURLY at :25
and rotate-activate.js is a GLOBAL DRAFT->ACTIVE funnel: lib/rotation-order.js queries
`WHERE status = 'DRAFT'` across the whole shopify_products catalog, not scoped to any
vendor, capped at 500/day, against a queue of ~1,396. `grep -rn weight` over the entire
repo returned ZERO hits. Its documented "5-field gate" (sample variant, sellable variant,
price>0, description, >=2 tags, width) simply had no weight condition.

It is currently activating ~0/run only because an unrelated mfr-provenance gate is
blocking 1,393 of the queue. That is not safety — it is a coincidence, and clearing that
backlog is the drain's explicit purpose. The moment it clears, this flips thousands of
products ACTIVE with no weight check, independent of every creator this ticket fixed.

- lib/weight-gate.js: self-contained (same decoupling rationale as this repo's
  private-label leak guard, DTD verdict B 2026-07-21 — a ~/Projects app does not
  cross-import another app's tree). Constants identical to the canonical
  designerwallcoverings/scripts/lib/weight-guard.mjs and lib/weight_guard.py.
  SAMPLES COUNT (43 of the 83 live offenders were samples); the .mjs's sample-filtering
  zeroWeightBlockers() bug is deliberately not reproduced.
  FAIL-SAFE: a response that does not carry the weight FIELD is a failure, not a pass —
  a future query regression that drops the field cannot silently re-open the hole behind
  a green gate.
- rotate-activate.js: STATUS_Q now selects inventoryItem measurement weight value+unit
  (without this the gate would measure nothing and pass 100%), productType added, and
  weight.ok ANDed into `passes` alongside gate/extra/leak/mfr. HOLDs rather than
  self-heals, matching every other gate here: this script activates, it is not a creator.

test/weight-gate.test.js — 16/16 PASS, offline. Includes 4 structural checks that the
gate cannot be vacuous (query really selects weight; weight.ok really reaches `passes`;
gate precedes the ACTIVATE call site; constants have not drifted from the canonical .mjs)
and unit-conversion cases so it is not trigger-happy. Mutation-verified RED on scratch
copies: strip weight from STATUS_Q -> 1 failure; drop weight.ok from `passes` -> 1
failure; reintroduce the sample-filtering bug -> 2 failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJHxAzaEMMxado57mFjiCk
1e149c4 · 2026-09-10 · fix: remove a NUL byte I introduced in 7e0039b's cache key
7e0039b's vendorScopeFor() cache key was written as `${table}<NUL>${vendor}` — a literal
0x00 landed where a separator was intended. Node parsed it fine and the function behaved
correctly, so it passed `node --check` and the behavioural test, but the byte made the
whole file read as `data` rather than text.

That is worse than it sounds: `grep` treats a binary file as unmatched and exits 1, so
`grep -c vendorScopeFor` reported ZERO on a file that plainly contained it. Any future
audit grepping this file for the scoping fix would have concluded it was missing. The
previous committed version was clean UTF-8; the corruption entered with my change.

Separator is now `::`. Verified after: file is UTF-8 text, 0 NUL bytes, `node --check`
passes, plain `grep` finds the symbol again, and the behaviour is unchanged — mfr 5016840
still resolves Backdrop -> "Seaglass Wallcovering" and Schumacher -> "SEAGLASS".

Also re-checked every other file I touched today with binary-safe greps
(vendor-command-center/server.js, dw-golive-gate-canary/auditor.mjs,
dw-blank-mfr-visibility-canary/check.py): all clean UTF-8, 0 NULs, and every earlier
verification claim re-confirms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7e0039b · 2026-09-10 · TK-11384: scope stagingColorFor() to the vendor on shared catalog tables
stagingColorFor() ran `SELECT color_name FROM ${table} WHERE mfr_sku = … LIMIT 1` with no
vendor filter and no ORDER BY. For the 29 vendors whose catalog_table is the shared
`vendor_catalog` — a table holding 157 distinct vendor_codes, in which 11,640 mfr_sku
values are used by more than one vendor — that returned whichever row the seq scan reached
first, i.e. potentially another vendor's colour.

Demonstrated, not inferred. mfr 5016840 exists as schumacher "sage green" and backdrop
"Seaglass Wallcovering". Before this change, asking for Backdrop returned Schumacher's
row; after it, Backdrop correctly returns "Seaglass Wallcovering" (Schumacher resolves to
its own private schumacher_catalog and is unaffected).

Matters because com.steve.dw-rotation-activator is loaded and runs hourly with --commit.
Impact today was bounded — the value feeds one placeholder-colour test and only one
mfr_sku fleet-wide could flip a verdict — but the query was wrong regardless, and the
blast radius grows with every shared-table vendor added.

Follows this module's fail-open doctrine: a shared table it cannot scope returns null, so
the gate fails OPEN on that dimension rather than reading another vendor's row. Added
ORDER BY color_name for determinism.

NOT changed, flagged for follow-up: reusedMfrSet() still COALESCEs down to
shopify_products.mfr_sku, the column proven polluted with descriptive name strings under
TK-11384. Correcting that alters gate verdicts on an hourly --commit job and wants its own
review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99013ea · 2026-09-01 · feat(golive-gate): mfr_sku provenance gate blocks blank/fabricated codes at DRAFT->ACTIVE
Adds lib/mfr-gate.js (pure, tested) + lib/mfr-gate-resolve.js (dw_unified I/O),
wired into rotate-activate.js / mdc-activate.js / cmo-activate.js before the flip.
Blocks: blank/null/unknown mfr, cross-vendor reused counters, and fabricated
<base>+<seq> runs (Carnegie Grain 6300->63001.. via placeholder 'Color N' staging).
Blocked drafts tag Needs-MfrSKU + hold; by-colour lines (Novasuede) exempt. TK-11063.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d9e84e1 · 2026-08-31 · rotation-activator: block $4.25 sample-leak price from passing the activation gate (TK-10456)
The 5-field gate required a sellable variant with price>0, but the universal
$4.25 memo-sample price is >0, so any draft whose only sellable roll was stuck
at $4.25 passed the gate and the rotation flipped it DRAFT->ACTIVE — re-leaking
reverted discontinued/no-price products (5 Thibaut murals + 6 Chloe re-activated
at $4.25 hours after being reverted). Now a sellable variant priced at exactly
the sample-leak $4.25 no longer counts as a real price; a real price on any
sellable variant still passes. Fail-safe: can only block an activation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e06f84c · 2026-07-22 · drain: prune the activation-calendar cadence after each hourly run
After flipping the per-slot batch DRAFT->ACTIVE, call the calendar's
prune-active.js so already-live SKUs never linger in the projected cadence
between nightly regens (Steve: cadence = staged items only).

File tree

43 files tracked. Click any to browse the source at HEAD.

Other build journals

← Dw Retail Halving Preview  ·  all 4 projects  ·  Dw Sarah Rowland Searchfix →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 5ms