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).