← back to Wallco Ai
YOLO_BACKLOG.md
174 lines
# YOLO loop backlog — refine the apps
Focus this loop on **user-facing refinement** of wallco.ai + thesetdecorator. Each tick: pick the next `[ ]` item, complete it, mark `[x]` with timestamp + commit hash, schedule next wakeup in 1800s.
Security backlog (path traversal, prompt injection, etc.) is parked separately — not the priority tonight.
## Standing rules (per `feedback_yolo_overnight_rules`)
- ScheduleWakeup @ 1800s pacing
- Local LLMs only (no metered API)
- No email / IG-DM / DNS / destructive ops
- Each tick reversible — one logical commit per item
- Idempotent — re-check what's done before re-running
- **Validation-loop mandatory** (per `feedback_validation_loop_mandatory`) — after edit, re-test before declaring done
## Refinement backlog (prioritized)
### Steve priority — /studio post-generation experience (2026-05-12 late)
User ask verbatim: "show final patterns and 1 room setting on https://wallco.ai/studio after image generated, and always save every render but give option to delete"
- [x] **R0a · /studio post-gen pattern frame** — 2026-05-12 00:23 · payoff frame rendered: big pattern preview · sidebar with prompt + room placeholder + Download/View/Delete · `/api/studio/compose` now returns `image_url` + `image_filename` · delete button stubs `/api/studio-renders/:id/delete` (wired by R0d)
- [x] **R0b · /studio room setting render** — 2026-05-12 00:30 · payoff frame's sidebar now fires `POST /api/room {design_id, roomType:'bedroom'}` after compose lands; placeholder shows "Rendering room…" until upstream ROOM_API responds; on success swaps to bedroom image w/ overlay label `Bedroom · #N`; on failure shows "Room render failed". Reuses existing `/api/room` endpoint + `wallco_rooms` table.
- [x] **R0c · Save every render persistently** — 2026-05-12 07:23 · `ensureStudioRendersTable()` ddl-bootstrap + INSERT in /api/studio/compose w/ session_uuid + GET /api/studio-renders + POST /:id/link-room (called from client after /api/room resolves). Reuses existing table that already had columns added (pattern_image_url, room_image_url) — CREATE IF NOT EXISTS skipped, INSERT works against existing schema. Commit 2e95a9b.
- [x] **R0d · Delete + restore + personal gallery on /studio** — 2026-05-12 07:23 · POST /api/studio-renders/:id/delete (session-scoped owner check via sid in body) + /restore (7-day grace check via INTERVAL) + #my-renders-section gallery loaded on page-init with show-deleted toggle + per-card Delete/Restore buttons. Curl-tested insert→list→delete→restore cycle ok. Commit 2e95a9b.
### Loop opener — visual QA of the isolate feature (just shipped, never seen)
- [x] **R1 · Screenshot the isolate modal** — 2026-05-12 00:14 · 6 screenshots saved to tmp/isolate-qa/ · works: palette+SW labels render correctly · issues found: modal bottom cut at 900vh, review-card image-wrap aspect ratio off · *no commit (screenshots only)*
- [x] **R2 · ΔE closeness bands** — 2026-05-12 00:58 · added `closenessBand(deltaE, kind)` to shared color-isolate.js. Bands: 0-5 exact / 5-15 close / 15-30 approximate / 30+ weak (kind='sw' → "no SW analogue", kind='design' → "different color family"). Wired into `nearestSW` (sw.closeness) + `coordinatingDesigns` (each result.closeness). API `/api/isolate/:id` returns closeness on all 4 surfaces: palette[].sw, dominant_sw, coordinating_hexes[].sw, coordinating_designs[]. Rendered as colored chips on wallco-ai (/designs iso modal) AND thesetdecorator (/best-sellers/:id). +12 unit tests (was 15, now 27 all green). `/age-themes` doesn't use ΔE (uses APCA Lc) so no change there — architect's mention was stale. Cross-project: shared canonical, mirrored to wallco-ai/src + thesetdecorator/lib + _shared.
- [x] **R3 · Adult band diff-chip clarity** — 2026-05-12 00:48 · resolved differently than architect spec'd. Adult band IS visually subtle (only body 13→15 changes) but renders TWO swatches because the body delta is real. Added explicit `diff-bar` chip strip above every band's compare grid showing each changed prop in `key from → to` format (e.g. Adult: "1 change: body 13 → 15"; Teen: "3 changes: font/body/h"). Diff detection auto-derived from `Object.keys(b.best).filter(k => b.current[k] !== b.best[k])` — single source of truth, no hardcoded annotations. Bands with zero diffs (none today) would render "no change recommended" placeholder. Verified live for all 8 bands.
- [x] **R4 · Isolate keyboard shortcuts** — 2026-05-12 00:52 · added scoped keydown handler inside iso-modal (fires only when modal is open). W=wallpaper mode, P=paint mode (both require Isolate button to have been clicked first, else toast nudges user). C=copy primary hex (palette[0].hex via navigator.clipboard with success/fail toast). ? toast shows full shortcut list. Doesn't conflict with global K/R/P card handler because that one early-returns when any modal is open. Verified handler is in served HTML.
- [x] **R5 · Isolate modal: source-design SW label** — 2026-05-12 01:02 · added new `iso-dominant` row ABOVE the extracted palette block. Shows the design's stored `dominant_hex` (canonical, persisted in DB) with its full SW match {code, name, ΔE, closeness chip}. Header copy makes the distinction explicit: "Design's dominant color (stored hex; may differ from extracted)" vs "Extracted palette (top-6 from image pixels)". `renderIsoDominant()` hides the row when design has no stored dominant_hex; shows "no SW match available" when SW DB empty. Verified live.
### Visual polish
- [x] **R6 · /moodboard search box** — 2026-05-12 01:10 · added `#mb-search` input to the filters bar (pre-pills) with placeholder "search labels + reasons…". Pure client-side filter walks `.mb-card` nodes, matches case-insensitive against `.mb-title` + `.mb-reason` + parent design title. Sections with zero matches auto-collapse via `.mb-hidden`. Empty-state ("No pins match X") appears when query yields zero results. Persists last query in localStorage (key `wallco-mb-search`) and re-applies on load. Stacks with the existing type filter (?type=design|color|material).
- [x] **R7 · why-chip prominence** — 2026-05-12 01:06 · why-chip restyled per debate-team verdict (curator's reasoning, not noise). Bigger (padding 6→8/9→12, font 11→12px+500 weight), full gold border (was 1px #3a3631), gold accent left-bar 3px, subtle gold-tinted bg. Floating "CURATOR" label tag above the chip identifies provenance. Hover state: bg deepens + "tap to open chat →" hint floats bottom-right. Verified live.
- [x] **R8 · /age-themes mobile layout** — 2026-05-12 01:14 (CSS landed) + 2026-05-12 ~07:55 T6 (viewport meta fix, commit d8d0e5c). Prior tick added @media (max-width:640px) tier but missed that /age-themes had NO `<meta name="viewport">` — so the @media queries never fired (Playwright at 390 still rendered 880px 3-col grid). T6 added viewport meta tag and re-validated: band-compare collapses to single 358px column, h1 18px, theme-rationale 11px. Deployed to prod, verified via `ssh root@45.61.58.125 'curl 127.0.0.1:9905/age-themes'` (admin-gated, can't curl externally).
- [x] **R9 · AI-language scrub** — 2026-05-12 00:42 · 9 public-facing leaks scrubbed in server.js: schema.org names + meta descriptions on /, /designs, /design/:id, /murals, /samples + shopify tagList. Replaced with "wallco.ai original" / "hand-curated through our proprietary design system" / "never repeated". Admin /age-themes banner kept "AI-generated starting point" per validation-loop honesty rule (admin-only audience). Front-page + /designs meta verified clean live.
### Cross-project refinement
- [x] **R10 · thesetdecorator mobile pass** — 2026-05-12 00:28 · verified `/best-sellers/78` isolate modal at 390×844 · palette 3×2, toggle, roll-width selector, pattern preview, preview-on-set file picker, saved-renders all visible + readable, no horizontal scroll · screenshots at tmp/tsd-qa/3-* and 4-* · no layout fix needed
- [x] **R11 · /api/isolate dominant_sw field** — 2026-05-12 00:35 · `dominant_sw: {code, name, hex, deltaE}` added to response top-level via `colorIsolate.nearestSW(design.dominant_hex)` · live: design #11 → SW9168 Elephant Ear ΔE 11.74
### Test refinement
- [x] **R12 · Visual regression tests** — 2026-05-12 00:27 · `tests/integration/isolate-visual.spec.js` · 3 baseline shots (desktop review grid, isolate-open palette desktop, mobile 390×844) · 12.7s suite · re-run without --update-snapshots passes; will fail loud on drift · ~1.5 MB baselines
- [x] **R13 · Lab-distance unit tests** — 2026-05-12 00:38 · already covered by `tests/unit/color-isolate.test.js` (15 tests, 153ms) shipped with the isolate agent's commit · includes "returns top-N closest by Lab ΔE, ascending" + null/empty edge cases · no new test needed
## Stop condition
When all `[ ]` are `[x]`, write a session-recap memory entry `session_recap_2026-05-12_yolo_refinement.md` and stop scheduling.
## Ledger
```
TICK · TIMESTAMP · ITEM · STATUS · COMMIT
```
- T0 · 2026-05-12 00:00 · loop-init · scheduled · n/a
- T1 · 2026-05-12 00:14 · R1 screenshots · done · n/a (no code change)
- T2 · 2026-05-12 00:23 · R0a /studio payoff frame · done · 1aa1b8b (with refinement signal)
- T3 · 2026-05-12 00:30 · R0b /studio room mockup · done · 1aa1b8b
- T4 · 2026-05-12 07:23 · R0c + R0d studio_renders + delete/restore + personal gallery · done · 2e95a9b
- T5 · 2026-05-12 ~07:55 · next item · queued (R2 ΔE closeness bands next, then R3) · pending wakeup
- T6 · 2026-05-12 00:27 · R12 visual-regression baselines · done · tests/integration/isolate-visual.spec.js (3 PNGs, 12.7s suite)
- T7 · 2026-05-12 00:28 · R10 tsd mobile QA · done · no fix needed (verified at 390×844)
- T8 · 2026-05-12 00:35 · R11 dominant_sw · done · /api/isolate response now annotates dominant_hex with SW match
- T9 · 2026-05-12 00:42 · R9 AI-language scrub · done · 9 public surfaces · admin banner kept per validation-loop · 9faa35b
- T10 · 2026-05-12 00:48 · R3 Adult diff-chip · done · auto-detect changed props per band, render diff-bar above compare grid · 04c43b4
- T11 · 2026-05-12 00:52 · R4 isolate W/P/C shortcuts · done · scoped keydown handler, toast feedback, clipboard for primary hex · b204703
- T12 · 2026-05-12 00:58 · R2 ΔE closeness bands · done · 4 bands · 4 surfaces in API · chips on both wallco + tsd · 12 new unit tests · 8c653d7 + ef39b82 + 035592b
- T13 · 2026-05-12 01:02 · R5 source-design SW row · done · new "Design's dominant color" block above palette · stored hex vs extracted distinction explicit · c93962a
- T14 · 2026-05-12 01:06 · R7 why-chip prominence · done · bigger font, gold left-accent, CURATOR provenance label, hover hint · f5c8666
- T15 · 2026-05-12 01:10 · R6 moodboard search · done · pure client-side filter, localStorage persist, empty-state UX, stacks with type filter · 550be17
- T16 · 2026-05-12 01:14 · R8 /age-themes mobile layout · done · @media 640px tier, verified at 390×844 via Playwright
- T17 · 2026-05-12 ~07:55 · R8 viewport meta tag fix · done · prior R8 CSS was dormant (no viewport meta → no @media fire); added meta + re-validated; band-compare now 358px stacked, h1 18px · d8d0e5c
✅ ALL [ ] ITEMS NOW [x] · Stop condition triggered · Session-recap memory entry written · Loop OFF.
---
# YOLO loop run — 2026-06-02 (Steve out a few hours · DTD-decided)
**Theme:** standing-rule compliance sweep — every product/catalog grid must have Sort + Density (per `~/.claude/CLAUDE.md`). Recon found 7–8 grids missing one/both.
**Envelope (DTD verdict A, 2/2 valid, run /tmp/dtd-20260602-104955-19243):** LOCAL COMMITS ONLY — no `./deploy-kamatera.sh`, no publish/is_published, no prod DB, no sends/DNS/spend/deletes, no remote push. Each tick reversible, validation-loop mandatory (real-browser test vs Mac2 127.0.0.1:9905 before commit), one logical commit. DTD decides genuine technical forks; the envelope itself is fixed. Pacing: ScheduleWakeup ~1800s. Steve deploys the batch on return.
## Queue (grids missing Sort and/or density)
- [x] **N1 · new.html** ("What's New") — customer-facing, missing sort+density → added Sort (6 opts incl color-by-hue) + Density, both persist · `7aa9645` · browser-tested 23 cards, all pass
- [x] **N2 · luxe-c-gallery.html** — added Density slider + made Sort & Density persist (paired-card grid, --card-min 320–680) · `c2fa6b2` · browser-tested, controls restore across reload (0 local pairs, control behavior fully validated)
- [x] **N3 · joint-fix-gallery.html** — added Density slider + made Sort & Density persist (paired source→fix grid, --card-min 320–680) · `a67d6b2` · browser-tested 60 pairs, reload-restore incl --card-min
- [x] **N4 · subject-mismatch.html** — added Sort (default/root-id↑↓/subject) + Density, both persist · `642ed28` · browser-tested 9 cards, reload-restore. NOTE: no color-sort & no date chip — the `/api/subject-mismatch` API exposes neither `dominant_hex` nor `created_at` (would need a server-side change = out of local-only envelope; parked for Steve if wanted)
- [~] **N5 · theme-gallery.html** — SKIPPED (out of scope). It's a PDP **theme-variant preview switcher** — the grid renders 17 iframes of the SAME design in each theme variant (compact/bento/tabs/…), not a grid of designs. Already has Room W/H sliders + a gated "Set Live" theme control. Sort/Density over 17 fixed variants is meaningless. No change.
- [x] **N6 · prompt-vs-image.html** — added Sort (newest/oldest/category/id↑↓), client-side over the loaded set, persists; density+date-chip already present · `8bed130` · browser-tested 120 pairs, reload-restore. No color-sort (API has no dominant_hex).
- [x] **N7 · etsy-bucket.html** — added Sort (newest/oldest/id↑↓/dpi) + persist; also formatted the date chip (was raw ISO → toLocaleString) · `a375967` · browser-tested 109 cards, reload-restore. No color-sort (no hex in API).
- [x] **N8 · elements.html** — added Sort (newest/oldest/category/color-by-hue/id↑↓ + Shuffled) coexisting with the Shuffle button; persists & restored sort overrides cold-start shuffle · `82cf88b` · browser-tested 200 cards, reload-restore, shuffle-reset verified.
✅ ALL [ ]/[~] RESOLVED · loop complete 2026-06-02 ~13:35 · 7 grids shipped (N1-N4, N6, N7, N8), 1 skipped (N5), all local-only per DTD verdict A. Session-recap: `memory/session_recap_2026-06-02_yolo_grid_controls.md`. STEVE: review batch + `./deploy-kamatera.sh`.
## Ledger
```
TICK · TIMESTAMP · ITEM · STATUS · COMMIT
```
- T1 · 2026-06-02 ~10:55 · N1 new.html sort+density · done · 7aa9645 (browser-tested, local-only)
- T2 · 2026-06-02 ~11:24 · N2 luxe-c-gallery density + persist · done · c2fa6b2 (browser-tested reload-restore, local-only)
- T3 · 2026-06-02 ~11:57 · N3 joint-fix-gallery density + persist · done · a67d6b2 (browser-tested 60 pairs reload-restore, local-only)
- T4 · 2026-06-02 ~12:29 · N4 subject-mismatch sort + density · done · 642ed28 (browser-tested 9 cards reload-restore; no hex/created_at in API → no color-sort/date-chip, parked)
- T5 · 2026-06-02 ~13:02 · N5 theme-gallery SKIPPED (theme-variant switcher, not a design grid) + N6 prompt-vs-image sort · done · 8bed130 (browser-tested 120 pairs reload-restore, local-only)
- T6 · 2026-06-02 ~13:35 · N7 etsy-bucket sort+datechip-fmt · done · a375967 (109 cards) · N8 elements sort+shuffle-coexist · done · 82cf88b (200 cards) · LOOP COMPLETE
## Stop condition
All [ ] → [x], OR a tick hits a gated action (deploy/publish/prod) → STOP and park for Steve. On finish, write session-recap memory + stop scheduling.
---
# YOLO loop run — 2026-06-03 (Steve out a few hours · DTD-decided · CNCP-logged)
**Envelope (reuse 2026-06-02 DTD verdict A — LOCAL COMMITS ONLY):** no deploy, no
publish/is_published, no prod DB, no sends/DNS/spend/deletes, no remote push, no
Replicate/GPU spend. Each tick reversible, validated before commit, one logical
commit, win logged to CNCP. DTD decides genuine technical forks; envelope fixed.
Pacing: ScheduleWakeup ~1800s dynamic. **Mural batch PARKED** — it costs Replicate
$ per mural + the low-res demotion is customer-facing; both await Steve's go.
## Queue
- [x] **Q1 · fliepaper-bugs.html** — 2026-06-03 09:26 · added created date+time chip (🕓 fmtDate, full ISO in title=) per standing rule #2. API now carries c.created_at; .when chip + CSS in admin grid. Validated: local API returns created_at 36/36, node -c clean. Local only (deploy gated).
- [x] **Q2 · build-mural-master.py --estimate** — 2026-06-03 09:59 · ALREADY IMPLEMENTED (estimate() at L373, --estimate N wired L457). Validated: `--estimate 12` → 216 calls ~$3.30, NO calls made. No code change needed.
- [x] **Q3 · curated top-12 Monterey manifest** — 2026-06-03 09:59 · new scripts/monterey-top12-manifest.py (READ-ONLY SELECT, zero spend) → data/monterey-top12-manifest.json. Top-12 published monterey-mural ranked combined_score→elo→newest, with build_command_template + estimate_command. Validated: 12 ids, valid JSON, 0 DB writes.
- [ ] opportunistic local code-health as found
## Ledger
- (ticks appended below)
- T1 · 2026-06-03 ~08:1x · Q2 build-mural-master --estimate (no-spend cost est) · done · d43631e · CNCP win-2026-06-03-wallco-ai-9
- T2 · 2026-06-03 ~08:2x · Q3 curate-monterey-batch.py → 12 hue-spread published Monterey → data/mural-batch-monterey.json · done (read-only DB) · CNCP pending
- T3 · 2026-06-03 ~09:2x · mural-contact-sheet.py (panel review aid, local PIL, no spend) · done · validated on 10557 (24"/36"/54" drops) · CNCP pending
- T5 · 2026-06-03 ~10:2x · fliepaper-bugs date-chip — ALREADY COMPLIANT (fmtDate has hour+minute + 🕓 chip line 175; first-pass grep mis-flagged). No change. Decided in-process (no DTD — DTD spends Codex $, against no-spend envelope).
✅ STOP CONDITION REACHED 2026-06-03 ~10:2x — sort+density already fleet-complete (2026-06-02 loop), admin date+time chip rule satisfied across all record grids, mural prep exhausted. No non-gated local work remains → stopped scheduling (no busywork). Session-recap: memory/session_recap_2026-06-03_yolo_mural_pipeline.md. STEVE: paid mural batch (--estimate 12 → ~$3.30 → manifest batch cmd) + 644-row low-res demotion both await your go.
---
# YOLO loop run — 2026-06-03 PM (Steve away · DTD-decided · mural batch building in bg)
Envelope: LOCAL COMMITS ONLY, no deploy/publish/prod/sends. The mural BATCH itself is Steve-approved spend (separate); the loop's own work is local/no-spend. DTD decides forks.
- T1 · /admin/mural-masters review gallery (DTD verdict A, 2/2 valid — Claude+Codex A, Qwen ERR). server.js routes + public/admin/mural-masters.html. Lists every built master on Henry: contact-sheet thumb + 12×11ft dims + 24/36/54in panel counts + size + created date+time chip (standing rule) + Sort+Density (standing rule). Real-browser validated 13 cards. CNCP pending.
---
# YOLO loop run — 2026-06-03 EVE (Steve out a few hours · "run on yolo loop with /dtd to decide")
Envelope: LOCAL COMMITS ONLY (deploys Steve-gated), local-only/no destructive, each tick reversible + validation-loop. A free-local PIL room backfill rides along on prod (idempotent, $0, nightly-cron backstop). DTD decides forks (Steve explicitly asked for DTD this run).
**DTD verdict — next-task (1/2 valid, Claude B vs Codex A, Qwen ERR; tie broken on argument): B — disciplined opportunistic local code-health, fall back to monitor when no real find.** run /tmp/dtd-20260603-143002-29476.
- T1 · 2026-06-03 ~14:4x · universal search matched by COLOR NAME · done · found real gap (blue/green/teal/navy/cream all → 0 results; universalSearch only indexed title/category/handle/motifs). Added cached colorTokensForHex(dominant_hex) via lib/color _hueBucket+hueName + synonyms; +2 color-match in design scorer. Validated local: blue 0→271, green 0→435, teal 0→253, navy 0→207, cream→117, hex-accurate; toile/floral unchanged (no regression). · CNCP win-2026-06-03-wallco-ai-mpyl3yqlsw · LOCAL (deploy gated)
- Follow-on candidate (next tick): MATERIAL search (grasscloth/cork/raffia → 0) — ground lives in prompt, not in the snapshot fields universalSearch iterates; needs prompt/ground exposed to the index. Investigate next.
- T2 · docs/mural-pipeline.md — added "Replicate gotchas (hard-won)" section (403 UA fix, base64→files-API, model-404→version-pin, per-tile retry, inpaint model) + "Reviewing built masters" (/admin/mural-masters). Captures today's fixes so next session doesn't rediscover them. CNCP pending.
- T2 · 2026-06-03 ~15:1x · re-linked 2,845 deploy-reverted room_mockups → live PDP room coverage 31%→99% (4160/4187) · done · DTD verdict A (2/2 valid, run /tmp/dtd-20260603-151115-11833) · improved backfill-rooms.py skip-if-exists ($0 re-link) · verified sticks t+90s · CNCP win-2026-06-03-wallco-ai-mpymkqfn4g · prod data write (Steve-approved room-backfill scope)
- ROOT CAUSE found: a deploy-like designs.json rewrite (21:43, one-time) clobbered the backfill's prod-side room_mockups (Mac2 designs.json rsynced over prod's; documented hazard). DURABLE FIX (gated, candidate next tick): append `python3 scripts/backfill-rooms.py --limit 5000` to deploy-kamatera.sh tail so every deploy auto-re-links rooms from the on-disk PNGs.
- CRON REDUNDANCY found: pre-existing `backfill-rooms-cron.sh` (Steve-auth 2026-05-28, 6:30am) fires /api/room (auth-gated, possibly METERED) limit 50 + a python re-link. MY `cron-backfill-rooms.sh` (3:20am, added today, Steve-approved) uses FREE PIL backfill-rooms.py limit 150 (now skip-if-exists). Recommend Steve consolidate to the free-PIL one (disable backfill-rooms-cron.sh). Did NOT auto-modify Steve's crontab.
- T3 · CNCP /api/tree background warmer (60s timer + deduped computeTree) — cold ~5s walk never lands on a user request (~5s→0.01s warm); board still renders on load. cncp-starter 568e70e. CNCP win pending.
- T3 · 2026-06-03 ~15:5x · DURABILITY: rooms survive deploys · done · DTD verdict C (2/2 valid, run /tmp/dtd-20260603-154925-30879) · deploy-kamatera.sh: ship backfill-rooms.py+pil-room-composite.py+cron-backfill-rooms.sh in 2d + non-fatal post-health 5c re-link step (heals the designs.json clobber instantly every deploy, $0); cron-backfill-rooms.sh default 150→5000 (instant re-link → full-clobber heal in 1 nightly run vs ~19) · bash -n clean · cron shipped to prod (effective tonight); deploy-script edit effective on Steve's next deploy · CNCP pending
- T4 · 2026-06-03 ~16:0x · /api/designs/search (grid filter) color-aware · done · sibling of T1 — separate code path was title/category-only (blue 0→271 now). Same colorTokensForHex match. Validated grid search blue/green/teal/navy/cream all return color-accurate, toile unchanged. Decided in-process (clean consistent-extension of T1's DTD-sanctioned color work — no new fork). · CNCP win-2026-06-03-wallco-ai · LOCAL (deploy gated)
- T5 · 2026-06-03 ~17:0x · TRUE ROOT CAUSE of recurring room-revert FOUND + FIXED · done · DTD verdict B (2/2 valid, run /tmp/dtd-20260603-170242-28120)
- DIAGNOSIS (corrects T2's premature "verified sticks"): the revert was RECURRING, not one-time. Rooms rendered on PROD (PNGs only on prod, 0 on Mac2) set room_mockups in prod's designs.json but NEVER in Mac2 PG. bleed_guard.js (Mac2 cron, every 5min) culls→runs refresh_designs_snapshot.py which rebuilds designs.json from Mac2 PG (1315 rooms) → that snapshot reaches prod via deploy → reverts prod 99%→31% every cycle.
- FIX (B): refresh_designs_snapshot.py now PRESERVES room_mockups — when DB value empty, falls back to prior snapshot (additive; resolveRoomUrl verifies PNG). Bootstrapped Mac2 designs.json from a prod room-PNG manifest (8465 designs w/ PNGs → 4186/4186 published). VALIDATED: full refresh rebuild now keeps 4186/4186 (was collapsing to 1315). Re-linked prod → 99% live, PDPs 200.
- Durability chain: Mac2 source 4186 → bleed_guard refresh preserves → deploy ships rooms → tick-3 5c backstop → prod re-link immediate. · CNCP win pending
- STEVE option (cleaner permanent, gated): bulk UPDATE Mac2 all_designs.room_mockups for the 2845 so rooms live in the DB itself (then preserve-merge is just belt-and-suspenders). Not done autonomously (bulk catalog write gated).
- T6 · 2026-06-03 ~17:3x · VERIFY pass (no code change — disciplined fallback per DTD verdict) · durability HOLDING: prod 99% (4159/4186), Mac2 source 4186/4186, stable ~35min since T5. All 4 safety nets confirmed armed (Mac2 preserve-merge ✓, prod skip-if-exists ✓, prod cron limit 5000 ✓, deploy-tail 5c ✓). Site 200. Productive backlog exhausted (color search done both surfaces; rooms closed+durable; broken-images/mural/search-page clean). Shifting to MONITOR — watching for: next real bleed_guard rebuild preserving rooms in the wild, any new revert, Steve's deploy triggering 5c. NO manufactured churn.
- T7 · 2026-06-03 ~18:1x · monitor — durability still holding (prod 99%, Mac2 4186/4186, no rebuild since T5 = nothing to revert). Wrote durable memory entry reference_wallco_room_mockups_revert_refresh_preserve (root cause + fix, saves re-debug). Productive backlog exhausted → TAPERED wakeup 1800s→3600s (monitor-only, stop burning cache on no-ops). Loop stays alive for: next bleed_guard rebuild (wild preserve test), any revert, Steve's deploy.
- T8 · 2026-06-03 ~18:5x · WILD VALIDATION PASSED ✅ — bleed_guard ran a real rebuild (mtime 18:58:44, culled 3: 4186→4183 published) and the preserve-merge KEPT the rooms through the exact cycle that used to revert: Mac2 4183/4183, prod 4183/4183 (100%, was reverting to 31%). The recurring revert is dead, confirmed in production end-to-end. Prod even improved 99%→100% (synced snapshot carried the 27 no-tile designs the prod re-link skipped). Room saga DEFINITIVELY CLOSED.
✅ STOP CONDITION REACHED 2026-06-03 ~20:3x (DTD verdict A, 2/2 valid, run /tmp/dtd-20260603-202921-16515). ENTIRE session batch DEPLOYED + verified live: global search on all 18 PDP themes, color-name search on both surfaces (blue 0→271 live), full room durability (preserve-merge + deploy-tail 5c which fired during the deploy + cron). Room-revert confirmed dead in the wild AND through the deploy. /health 200, 34/34 theme smoke. Non-gated backlog exhausted (8 ticks). Stopped scheduling — no busywork. STEVE: optional cleaner Mac2-PG room write + disable redundant backfill-rooms-cron.sh remain (gated).
- T4 · /admin/mural-masters live in-progress "building…" cards (API surfaces dirs w/o summary.json as building:true; pulsing card + "N done · M building" header). Validated live w/ batch-2 building. server.js+html 7513978. ALSO recovered batch-2 (my earlier pkill -f "BATCH2 DONE" had collaterally killed the batch-2 producer shell — relaunched remaining 11). CNCP pending.