{"slug":"dw-photo-capture","total":559,"limit":100,"offset":0,"since":null,"commits":[{"hash":"e79f317","date":"2026-09-26 18:48:26 -0700","author":"Steve Abrams","subject":"Merge-fix: themes-e2e back to 80/80 on the merged release + Cody fixes (TK-12343)","body":"- live-shot.js: never hijack a MULTIPLE (bulk library) picker — the gallery '➕ Multiple' input stays native (one\n  shutter tap had become an unreviewed live /api/photos write and bulk upload was lost). e2e: expectNativeMulti on\n  #galAddMulti (f-luxe-gold find) + --negative-multi fault run goes red.\n- f-swipe-deck findSimilarFromStack: the input is attached (hidden) before .click() so live-shot opens the live back\n  camera; it also passed a dataURL to recognizePhoto (which reads a File) — now passes the File.\n- theme-bar.js: header z-index 100 → 80 so it sits under every engine overlay (it covered the gallery's ‹ Back on iPhone).\n- square-crop.js: the engine's own crop open (2 rAFs after load, re-selects Free) could land after our 1:1 tap under\n  load → 1620×664 'square'; now waits for it and holds 1:1, and marks #cropov[data-square] when settled.\n- themes-e2e.cjs: the 6 merged-tip failures were harness races, not UI regressions — photoTap now waits for the camera\n  view itself (the camera-clarity engine un-hides #twoShotCam only once the higher-res stream plays), liveScan tolerates a\n  scan that already locked+closed, and a click whose 'stable' check starves under the fake 4K preview is verified by our\n  own hit-test before tapping (an interceptor still fails). Default concurrency 4.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"5544c11","date":"2026-09-26 17:27:26 -0700","author":"Steve Abrams","subject":"Themes: separate 'Square crop' choice beside every FRONT Adjust (engine editor on the front, 1:1 preset, Apply+Use writes the square back via the existing adjustShot path — existing auto/free crop untouched); e2e proves a square front lands (frontCrop=adjusted, w==h) on the engine sheet + a bound form; harness knows the crop overlay's own Cancel (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"9c0628a","date":"2026-09-26 17:21:59 -0700","author":"Steve Abrams","subject":"p-sticker-book: all 4 jobs e2e — Update with a scanned photo now binds THAT item (was an empty pref), grid cards get Update photos (bind → live back camera → Push); unified line-icon stickers; the empty black lens circle is a camera icon with a gentle pulse; full-bleed at 430px (was a framed card); floating Home pill + top links replaced by the shared header; .phone overflow clip so the sticky header stays put (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"cd10536","date":"2026-09-26 17:19:47 -0700","author":"Steve Abrams","subject":"p-hold-to-talk: all 4 jobs e2e. DTD Q1=B: the tap job grid is the hero, press-and-hold mic is secondary. The probe's 'Add/Update open no camera' was real (both went to pretend-viewfinder lead screens): Add now opens the live back camera on the tap; Update = pick the item → Update photos (binds it, live camera, Push); Sample = waiting list with Scan / Label+Photo identify → highlighted → ✓ Received; floating Home pill + footer links replaced by the shared header; no focus ring on load; centred layout (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"1a24518","date":"2026-09-26 17:16:27 -0700","author":"Steve Abrams","subject":"p-todays-inbox: all 4 jobs e2e — all four jobs always on the inbox (the Sample row vanished when nothing was due, Add was only a bare FAB); the camera FAB / Update This open the live back camera immediately (Update binds the item first); Samples gets Scan + Label+Photo identify that selects the matching waiting sample; floating '…' + FAB docked into a real bottom bar with safe-area; no focus ring on the date headline; one line-icon system; shared header (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"0143441","date":"2026-09-26 17:13:25 -0700","author":"Steve Abrams","subject":"p-mode-dial: all 4 jobs e2e — every shutter mode now opens the live back camera on the tap (Find was a plain results page, Sample opened a list with no camera); Adjust no longer fires an orphan two-shot (→ white balance); stray glow orbs tamed to .08, empty framing box shows the mode, 48px pills / 12px gaps, 4 mode pills fit without scrolling; one line-icon system; shared header (fixed .app overflow-x:hidden → clip so the sticky header can't scroll away) (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"27a7cc1","date":"2026-09-26 17:09:13 -0700","author":"Steve Abrams","subject":"p-scan-and-go: all 4 jobs e2e. Root-caused the GD 'empty black oval' + the whole page looking dimmed: the theme reused the ENGINE's #scanStatus id and .scan-frame class — the engine's scanner status wrote into the home page, and its 4000px scan-frame shadow dimmed everything; both renamed. Sample Just Arrived now really matches the incoming list and marks it received (was a fake 'Printing your sticker…' with no write); Update opens the form before binding (open() was wiping the bind); Photo / Label+Photo modes open the live back camera on the one Scan tap; parchment CTA distinct from copper corners; no focus ring on load; shared header. Harness: duplicate element ids now fail the run (caught f-bottom-tabs' #toast too — renamed) (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"5fd7a3d","date":"2026-09-26 17:03:07 -0700","author":"Steve Abrams","subject":"Camera: crystal-clear preview/capture + Figma-matched adjuster strip (TK-12343)","body":"Clarity (Steve: \"camera... cannot be pixelated when viewing\"):\n- Live scan camera + two-shot capture camera each request a graduated,\n  highest-sensible-first 4:3 resolution chain from getUserMedia (was a bare\n  {facingMode, width:1280} on the scanner with no fallback tier for two-shot\n  between 4096x3072 and a size-less facingMode).\n- acquire-camera.js logs the ACTUAL negotiated track.getSettings() so the\n  fallback chain is verifiable, not just hoped-for.\n- tsCapture() now tries ImageCapture.takePhoto() for the full sensor-resolution\n  still (can exceed the negotiated video track on iOS/Android), falling back\n  to the proven <video>-frame path on any failure/unsupported browser.\n\nAdjusters — matches the four-horsemen Figma spec (node 28:2 \"Camera / Adjuster\nStrip\", SPEC.md sec 3): dark glass pill, 48px targets, yellow #FFD60A accents,\n76px focus reticle, fading hint chip. Per the spec's own wiring rule (\"hidden\n[torch] or emulated in software [zoom, brightness] — never show a control that\ndoes nothing\"):\n- Zoom (1x/2x/3x) ALWAYS renders — native track.applyConstraints when the\n  device supports it, else a centered digital crop applied identically at\n  preview- and capture-time (also wired into the scanner's OCR frame grab).\n- Exposure ALWAYS renders on the two-shot camera — the existing CapturePipeline\n  software bake already applies it to every frame regardless of hardware, so\n  it is never actually dead; hardware exposureCompensation is a best-effort\n  assist layered on top. The compact strip's slider is EV units (-2..2) mapped\n  onto the same _tsTune.exposure state the full ts-toolpanel slider uses, so\n  both stay in sync.\n- Torch hides when the device has no torch capability (no software equivalent).\n- Tap-to-focus reuses the existing white-balance tap gesture: the 76px yellow\n  reticle ALWAYS shows as visual feedback; the actual pointsOfInterest command\n  only fires when supported. A top hint chip fades on first tap, reappears\n  after 8s idle.\n- #tsQuick is a left-edge vertical rail (not the spec's literal bottom bar) —\n  this engine's <video> is a full-screen overlay (unlike the Luxe Gold\n  mockup's smaller preview box with the shutter safely below it), and a\n  bottom bar's real footprint is ~1.35x bigger than its authored CSS px here\n  (this app runs under html{zoom:1.35}, which getBoundingClientRect/hit-testing\n  reflect but getComputedStyle does not) — a bottom bar sized for 48px targets\n  ends up covering the shutter. The vertical rail (matching the scanner's\n  already-proven #scQuick pattern) sits clear of every existing overlay.\n\nTests: scripts/tk12343-camera-clarity-test.mjs (Chromium fake-device x2 +\nWebKit iPhone-Pro-Max-profile smoke test + app-control-gate.cjs regression),\n16/16 passing, $0 local.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"4041490","date":"2026-09-26 16:59:04 -0700","author":"Steve Abrams","subject":"f-split-screen: all 4 jobs e2e (vendor pick → live back camera → details → Save; Update from a Find card binds the product then opens the camera; Fix opens the camera immediately; scan strip runs the lookup); fake always-on 'LIVE' viewfinder collapsed to a real 4-button camera strip; dead 'Adjust' (camera with nowhere to land) removed; centred thumb-zone job grid; shared header + step dots (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"7bc5032","date":"2026-09-26 16:56:18 -0700","author":"Steve Abrams","subject":"f-bottom-tabs: all 4 jobs e2e (Fix → typed code binds the product and opens the live back camera, Find gets a real Scan button, Sample scan highlights the waiting sample to receive, Label+Photo identify on the Sample tab); fake 'Recently fixed: Damask — Gold' placeholder removed; true full-bleed; shared header replaces the per-tab step/links row; one line-icon system (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"99efdb1","date":"2026-09-26 16:53:34 -0700","author":"Steve Abrams","subject":"f-scan-first: all 4 jobs e2e (scan results now actually run the lookup, Update binds the found item then opens the live back camera, Photo lands in the Add form, honest 'Just look' details instead of hardcoded stock text); shared header replaces the old top row/links; one line-icon system; full-bleed 430px; engine sheet ✕ pinned as a 48px target so Save never strands you (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"f698ab4","date":"2026-09-26 16:49:01 -0700","author":"Steve Abrams","subject":"f-swipe-deck: all 4 jobs e2e (New opens the live back camera, extracted mfr# carried into the field deck, Save reaches the done screen, Update only says Updated after the push succeeds, Sample scan matches the incoming list, honest check-in copy); shared header rebuilt to the Four Horsemen spec (60px frosted, Back/Step N of M/Home/Classic); f-luxe-gold rebuilt to v21 frames (today card from /api/captures, 80px job buttons, 128px labelled shutter, Maison confirm card, Saved summary that only claims dw_unified when it committed) (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"580a1a9","date":"2026-09-26 16:35:12 -0700","author":"Steve Abrams","subject":"f-luxe-gold: all 4 jobs e2e (Add opens the live back camera on tap, Update picks item → camera → Push, scan results actually run, Sample = incoming list → identify → Received); shared ThemeBar header (Back/Home/Classic + step dots), live-shot.js (every photo input → live back camera), full-bleed 430px, gold Playfair wordmark, no dead gap; scripts/themes-e2e.cjs gate (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"ce35d89","date":"2026-09-26 16:34:49 -0700","author":"Steve Abrams","subject":"DWEngine: separate largest-square auto-crop (squareCropImage) — largest square inside the detected product box, slid clear of label boxes; existing native-aspect crop unchanged; $0 test scripts/square-crop-test.cjs 14/14 (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"212ae0a","date":"2026-09-26 16:15:09 -0700","author":"Steve Abrams","subject":"DWEngine: clear the real stale key (dwphoto_camFacing) so phones already stuck on selfie reset to back camera; gate: flip is per-page, never persisted (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"1488bc2","date":"2026-09-26 16:05:49 -0700","author":"Steve Abrams","subject":"DWEngine: always open the BACK camera; a flip lasts for the page only (persisted camFacing turned every later photo in /app + all themes into a selfie after one flip tap) (TK-12343)","body":"Camera test (fake device, all 10 /t/ themes): after fix every real camera open requests facingMode environment; only explicit flip buttons request user.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"df59bf1","date":"2026-09-26 13:06:29 -0700","author":"Steve Abrams","subject":"DWEngine: credential-safe fetch guard in the shared engine so /app and all /t/ themes survive user:pass@ bookmarks (9 of 10 themes lacked it) (TK-12343 review of TK-12348)","body":"Repro before: /t/f-scan-first, /t/p-todays-inbox via user:pass@ URL -> relative fetch throws, 0 API calls, silent empty page.\nAfter: all 10 themes + /app make their API calls; /app side-by-side vs main 55/56 same (1 diff = main-side WebKit load-failed noise).\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"bc3f0bb","date":"2026-09-26 15:35:26 -0700","author":"Steve Abrams","subject":"f-swipe-deck: UX refinement pass — centering, premature warning, savecheck preview (TK-12348)","body":"Screenshotted every screen not yet visually reviewed (find-detail, camera-live,\nreview, brand, field-deck x2, savecheck, sample-match) and fixed three real\nrough edges found:\n\n- .screen-area used align-items:flex-start (needed so long screens like Find's\n  chip list / the field deck can scroll), which left short-content screens\n  (detail, review, savecheck) top-heavy with a lot of dead space below the\n  card — the mockup itself vertically centers. Switched to\n  align-items:safe center: centers short content, falls back to top-aligned +\n  scrollable the moment content is taller than the viewport. Best of both.\n- The review screen bound data-dw-out=\"status\", which showed twoPhotoGate()'s\n  \"pick or type the mfr#/SKU\" warning in red BEFORE the user could possibly\n  act on it (mfr is only collected later, in the brand grid + field deck).\n  Removed that binding from the review screen only — the gate is still shown\n  for real on the field deck and Save-this? screens where it's actionable.\n- \"Save this?\" was a bare white card until Preview was tapped (the mockup's\n  own version shows the swatch + brand immediately). Now shows the captured\n  front photo + chosen brand/mfr# right away, with Preview/Commit's real\n  output filling in underneath once run.\n- Added a neutral swatch background-color fallback so a slow/missing product\n  image doesn't render as a jarring black box.\n\nVerified: still 40/40 Playwright checks after the changes; re-screenshotted\nthe three fixed screens to confirm visually (centered card, no premature\nwarning, populated savecheck preview).\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"},{"hash":"59daed6","date":"2026-09-26 14:30:48 -0700","author":"Steve Abrams","subject":"theme f-bottom-tabs: ⌂/Classic-app links and every select are 44px targets (WebKit menulist ignored min-height); shot Adjust/Retake 44px (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"cd58737","date":"2026-09-26 14:30:48 -0700","author":"Steve Abrams","subject":"theme p-mode-dial: count badge white-on-red reaches 4.5:1 (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"0c3dfb5","date":"2026-09-26 14:30:48 -0700","author":"Steve Abrams","subject":"theme p-hold-to-talk: footer/caption text ≥4.5:1 on the dark camera page; Home pill on dark screens gets an opaque backing (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"8c323a5","date":"2026-09-26 14:30:48 -0700","author":"Steve Abrams","subject":"theme p-todays-inbox: muted text + accent ink reach 4.5:1; shot Adjust/Retake are 44px (engine .shot-acts rule leaked 38px) (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"f497707","date":"2026-09-26 14:30:48 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: white sticker text ≥4.5:1 (darker teal/rose/honey/olive) and a readable wordmark on the grey page (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"de0ca8d","date":"2026-09-26 13:59:27 -0700","author":"Steve Abrams","subject":"theme f-split-screen: filter chips are real buttons (keyboard/AT reachable, aria-pressed, 44px) and Find loads the default TWIL list on entry — caught by the unified control gate (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"ef61f5c","date":"2026-09-26 13:18:44 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: load the photo queue for need/live/done/all (those four filters were always empty) — caught by the unified control gate (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"24891e1","date":"2026-09-26 12:51:36 -0700","author":"Steve Abrams","subject":"f-swipe-deck: adopt engine's new SORTS registry + similarTo(item) (TK-12348)","body":"The engine picked up DWEngine.SORTS (Newest/Color/Style/SKU/Title/Price up/\nPrice down, per Steve's standing product-grid rule) and DWEngine.similarTo\n(item) after this theme's first commit. Update to match:\n\n- Sort <select> now renders from E.SORTS instead of a stale hardcoded\n  3-option list, default 'newest' per the new engine default.\n- Swipe-up \"Find Similar\" now calls E.similarTo(item) on the CARD currently\n  showing (reads its own image via /api/imgproxy, no new photo needed) —\n  falls back to the old camera-capture path only when the card has no\n  image yet (e.g. an unphotographed \"new\" sheet item).\n\nVerified: 40/40 Playwright checks (was 38, +2 new: full sort-key set present,\nfind-similar hits /api/recognize via similarTo without prompting the camera).\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"},{"hash":"36fb162","date":"2026-09-26 12:43:07 -0700","author":"Steve Abrams","subject":"Add f-swipe-deck theme: Figma v5 Swipe Deck on DWEngine (TK-12348)","body":"Full working app at public/t/f-swipe-deck.html built on the shared\nDWEngine, keeping the mockup's swipe/dial gestures and gold/blush palette.\nAll required controls wired to real engine actions: search + voice + 11\nfilters + sort + stack/grid density, LiveScan (code/logo/pattern), the\ntwo-shot camera with pre-shot sliders, post-shot Editor (captured photo\nand existing pid), Gallery, the 10-field Add/Update SKU form (mic per\nfield, voice-fill-all, white balance, measure, +10 photos/+6 videos,\npreview/commit/push), fav/skip/enhance/photos/shoot per item, and\ncheck-sample-in (incoming list + markReceived). Reduced-motion handled,\ntouch-action scoped to swipeable cards, --dw-* tokens verified >=4.5:1.\n\nFixed along the way (all theme-local, no engine changes):\n- render<->search infinite loop when a filter legitimately returns 0 results\n- attachSwipe's pointer-capture swallowing clicks/typing on buttons/inputs\n  nested inside a swipeable card (shot tiles, swatch, field inputs)\n- shot-tile <img> only existed in the DOM once a photo existed, so the\n  engine's own live DOM updates after each shutter press had nothing to\n  write into\n- brand grid read the vendor <select>'s options before CaptureForm.bind()\n  had populated them; now fetches via E.vendors() before rendering\n- field-deck values were lost once bindForm() re-scanned the next screen\n  (one field card at a time); now all 10 stay mounted (one visible) and\n  are mirrored into the engine's own hidden defaults before Preview/Commit\n- header nav row absolutely positioned over the centered wordmark, clipping\n  it at 390px; switched to a flex row\n\nVerified: 38/38 Playwright checks (Chromium 320/390/820/1280px + real\nWebKit iPhone 13 / iPad Pro device profiles), 0 console/page errors, no\nhorizontal overflow, all tap targets >=44px.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"},{"hash":"f6f494f","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme p-hold-to-talk: remove TEMPORARY Color/Style/Price sort shim, sort from DWEngine.SORTS; Similar via similarTo (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"2e3e7e8","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme p-todays-inbox: drop client price sort, SORTS-driven + persisted sort; Similar via similarTo; Done only on a real mark-received ok (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"fc9ac80","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme f-bottom-tabs: SORTS-driven sort; Similar via DWEngine.similarTo; Received toast no longer claims a print (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"d060a54","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme f-split-screen: SORTS-driven sort; per-item Similar uses DWEngine.similarTo on the item image (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"feb8935","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme p-scan-and-go: SORTS-driven sort; per-item Similar via DWEngine.similarTo (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"b715ddb","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme f-scan-first: SORTS-driven sort; Similar via DWEngine.similarTo; never show Done on a failed mark-received (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"6b346de","date":"2026-09-26 12:41:09 -0700","author":"Steve Abrams","subject":"theme p-mode-dial: sort options from DWEngine.SORTS (default Newest, stale key falls back) (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"9bdf5a8","date":"2026-09-26 12:41:08 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: sort options from DWEngine.SORTS (default Newest); polaroid Similar via DWEngine.similarTo (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"ea4f607","date":"2026-09-26 12:40:03 -0700","author":"Steve Abrams","subject":"theme f-luxe-gold: build Figma v20 Luxe Gold on DWEngine (TK-12348)","body":"7 screens (Welcome, Capture, Maison, Particulars, Saved, Search, Sample) wired\nto DWEngine: Camera.twoShot (11 pre-shot sliders), CaptureForm bind/start with\ndata-dw-field/action/mic/out, vendor cards → real vendor registry, search with\n11 filters + sort + density, per-card Enhance/Photos/Shoot/Fav/Skip/Similar,\nEditor.open (captured + {pid}), Identify.checkIn (sample receiving), LiveScan,\nvoice search. Verified 33/33 with Playwright (fake camera) + 0 console errors\n+ no overflow at 320/390/820/1280.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"7148c05","date":"2026-09-26 12:35:26 -0700","author":"Steve Abrams","subject":"engine: DWEngine.SORTS (newest/color/style/sku/title/price-asc/price-desc + ready) in items(); /app sort select renders from it (default Newest); DWEngine.similarTo(item) via /api/imgproxy; gate +10 checks (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"1444863","date":"2026-09-26 12:30:26 -0700","author":"Steve Abrams","subject":"theme: p-hold-to-talk — real hold-to-talk voice via DWEngine.voiceQuery (TK-12348)","body":"Home keeps the v12 mockup's hold-to-talk mic + caption pill + ring, wired to\nreal Web Speech via DWEngine.voiceQuery() (pointer + keyboard Space hold,\nshort-hold recovery, graceful degrade with no Web Speech). Browse screen adds\nall 11 filters, sort (incl. a page-side shim for Color/Style/Price beyond the\nengine's ready|title|sku), density, search+mic+scan+similar, and per-item\nactions; detail screen turns actions into chips. Add/Update use the engine's\nbuilt-in CaptureForm modal (two-shot camera, WB, measure, voice fill, 10\nmic'd fields); Received Today is a custom incoming-list + markReceived\nscreen. Full --dw-* + --dw-cam-* + --dw-warn token palette set.\n\nVerify: 70/70 Playwright checks (Chromium + WebKit iPhone/iPad), 0 console\nerrors, no horizontal overflow at 320/390/820/1280, all tap targets >=44px.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"b8b58cd","date":"2026-09-26 12:30:14 -0700","author":"Steve Abrams","subject":"theme: PS v10 Today's Inbox app at public/t/p-todays-inbox.html (TK-12348)","body":"Full working DWEngine-backed app matching the Today's Inbox mockup: inbox\nhome (samples/needs-photos/find/more rows), all 11 filters with sort +\ndensity, item detail (similar/enhance/photos/shoot/fav/skip), a\nCaptureForm-bound Add/Update SKU form (Vendor/Shots/Details/Review\nsections, front+back two-shot camera with pre-shot sliders, +10 photos/+6\nvideos, white balance, measure, voice fill, 10 fields with mics,\npreview/commit/push), sample check-in (waiting/received tabs via\nincoming()+markReceived), find flow (scan/talk/type), and a FAB with a\nlong-press speed dial (scan/label+photo/speak/look up SKU). Themed via\n--dw-* tokens (brass/kraft palette, Newsreader+Manrope). Fixes the\nmockup's low-contrast brass text (accent-ink, never white) and moves\nrender()'s splice() out of the render path.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"eb5ab67","date":"2026-09-26 12:27:26 -0700","author":"Steve Abrams","subject":"theme: add f-bottom-tabs (Figma v12 Bottom Tabs) on dw-engine.js","body":"Full working app at public/t/f-bottom-tabs.html: bottom tab bar (New/Fix/\nFind/Sample, aria-current), CaptureForm.bind() sheet reused by both New\nand Fix (Add + Update modes), live two-shot camera with pre-shot sliders,\npost-shot Editor (captured photo + {pid}), LiveScan, Identify (label+photo\nand look-up), Gallery, White Balance, Measure, per-item action sheet\n(Enhance/Photos/Shoot/Fav/Skip), 11-filter Find tab with sort+density,\nincoming-samples check-in with Waiting|Received segment. Full --dw-*\npalette (incl. --dw-warn) set on :root; camera overlays left on engine\ndefaults (--dw-cam-*). Verified: 50/50 Playwright checks.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"d5dc819","date":"2026-09-26 12:27:05 -0700","author":"Steve Abrams","subject":"Fix: printing is an explicit tap, never auto-fired after receive (TK-12348)","body":"Done screen was calling DWEngine.printSticker(recordId,'sku') automatically\nright after a successful markReceived. print-sticker flags the LIVE\nFileMaker record for the Zebra poller (FM_WRITE=1), so — matching /app's\nsample popup — it must only ever fire on an explicit user tap.\n\nDone screen now shows \"🖨 Print SKU sticker\" / \"🖨 Print address sticker\"\n(>=44px) alongside \"Scan the next one\"; each calls\nDWEngine.printSticker(recordId, 'sku'|'address') only when tapped, using\nthe recordId that was actually used for the just-completed markReceived.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"7738a1e","date":"2026-09-26 12:26:39 -0700","author":"Steve Abrams","subject":"theme f-split-screen: Figma v24 Split Screen full app on DWEngine, 45/45 verified (TK-12348)","body":"Built + verified by the f-split-screen theme builder; its first commit was swept into another builder's\ncommit and correctly unwound (8b45e85), leaving this file untracked — committed here by explicit path,\nbyte-identical to the verified version (b8cdd5a).\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"8b45e85","date":"2026-09-26 12:26:00 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: full contrast-verified token set + washi scroll affordance (TK-12348)","body":"Follow-up to engine 79d201e (non-camera overlays now route colour through\n--dw-* tokens, light themes verified >=4.5:1):\n- Set the complete kraft-paper token set on :root, incl. the new --dw-warn.\n  Lightened --dw-accent to #B8874A and darkened --dw-muted/--dw-ok so every\n  ink/muted/accent-ink/danger/warn/ok pairing clears 4.5:1 against surface,\n  surface-2 and field (verified programmatically, all pairs >=4.5:1).\n- Fixed 3 hardcoded white-on-gold text spots (bigbtn-primary, washi-tab.on,\n  pbadge.new) that would have failed contrast under the new accent.\n- Washi-tape filter row (11 tabs, only ~4 fit @390px): added a wrapper with\n  a fade-edge scroll affordance, a visible thumb scrollbar, and a\n  focus->scrollIntoView handler so keyboard Tab reaches every tab, not just\n  the ones on-screen.\n\nRe-verified 56/56 (was 48/48): added a real push-to-/api/photos assertion\nfor Update mode (via the engine's CaptureForm.shot native-snap seam, not\njust \"endpoint reachable\"), plus washi-scroll/keyboard-reachability checks.\nScreenshots re-taken; form shot now shows the Add form (paper card, dark\nink, brass borders) instead of the camera overlay atop it.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"4ebee13","date":"2026-09-26 12:24:33 -0700","author":"Steve Abrams","subject":"Fix: Confirm screen never guesses a FileMaker recordId (TK-12348)","body":"\"Yes, received\" previously fell back to dw_sku as the markReceived\nrecordId when no match was known. /api/mark-received writes LIVE\nFileMaker by recordId, so a guessed id either fails silently (a false\n\"done\") or, if it ever collides with a real recordId, stamps the wrong\nrecord.\n\nNow \"Sample came in\" resolves a real match via DWEngine.incoming(),\nusing the same matching rule as /app's matchIncoming (dw_sku exact, or\nmfr code exact/prefix after stripping non-alnum). Only a matched\nsample's real recordId is ever passed to markReceived. No match -> the\nbutton reads \"Not on the incoming list\" and routes to the real\nCheck-sample-in list (DWEngine.Identify.checkIn()) instead of posting.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"1da71f2","date":"2026-09-26 12:22:35 -0700","author":"Steve Abrams","subject":"engine: a published photo whose auto-crop failed/timed out/found no box is never published silently — in-form choice (✂ Adjust crop | Publish full photo), cropNeeded event, per-photo approval; gate +2 checks, numeric FM recordId fixture (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"09392f0","date":"2026-09-26 12:21:42 -0700","author":"Steve Abrams","subject":"theme: add p-scan-and-go.html (PS v7 Scan & Go) wired to DWEngine","body":"Teal viewfinder home with copper corner brackets + reduced-motion scanline,\nLabel/Photo/Label+Photo mode toggle, camera flip, voice search. Find screen\nwith all 11 filters, sort, density, Look-up-SKU, Add New. Per-item action\nrow (Similar/Enhance/Photos/Shoot/Fav/Skip) on match + find-detail. Samples\nchecklist (incoming + markReceived). Uses the engine's default Add/Update\nform, Camera.twoShot, Editor, Gallery, LiveScan, Identify overlays, themed\nvia the full --dw-* palette (light content) + --dw-cam-* (dark camera\nchrome). Fixes the mockup's dead add-camera screen — Add It as New now\nreaches the live two-shot camera. 50/50 Playwright checks pass.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"e7d8a99","date":"2026-09-26 12:18:51 -0700","author":"Steve Abrams","subject":"FileMaker writes: refuse non-numeric recordIds on /api/mark-received + /api/print-sticker (live + test stub) (TK-12348)","body":"A theme build passed dw_sku as a guessed recordId to mark-received. FileMaker Data API recordIds are\ndigits, so anything else is now a 400 — no client can stamp a LIVE record it didn't resolve. The --test\nstub enforces the same rule so theme verification scripts go red on guessed ids.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"96f984b","date":"2026-09-26 12:18:38 -0700","author":"Steve Abrams","subject":"theme(p-mode-dial): full parchment palette pass on the finalized engine tokens (TK-12348)","body":"Engine commit 79d201e routes every non-camera overlay colour through --dw-*\ntokens now. Set the full documented set (--dw-bg/-surface/-surface-2/-field/\n-ink/-muted/-line/-ok/-danger/-warn) to a contrast-checked parchment palette\n(WCAG AA >=4.5:1 for ink/muted/ok/danger/warn against all three surfaces they\ncan land on), keeping --dw-accent/--dw-accent-ink dynamic per mode dial.\nCamera-feed overlays (#twoShotCam etc.) intentionally left untouched — they\nkeep the engine's own --dw-cam-* dark chrome by design.\n\nRe-verified: 54/54 Playwright checks (was 50), including a new Update-mode\nPush -> /api/photos check (native photo picker -> resolve-product -> push)\nand live in-page contrast audits (>=4.5:1) of the Add/Update form, the\nLabel+Photo (Identify) modal, and the Gallery. Re-screenshotted the Add form.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"e9946db","date":"2026-09-26 12:17:08 -0700","author":"Steve Abrams","subject":"Add theme app public/t/f-scan-first.html (Figma v10 Scan First, TK-12348)","body":"Full working DW capture app built on the shared engine (window.DWEngine):\n4-step scan-first flow (Scan -> Found it -> Confirm -> Done) plus a new\nResults step (search + 11 filters + sort + density). Every required\ncontrol wired to real engine calls: LiveScan, Identify (label+photo/\nlook-up/check-in), CaptureForm default modal (Add/Update, vendor select,\nfront+back shots, WB, measure, voice fill, 10 fields+mics, preview/\ncommit/push), Editor (captured photo + {pid}), Gallery, toggleFav, skip,\nrecognizePhoto (Similar), camera flip, markReceived, printSticker.\nTheme tokens (incl. --dw-cam-* and --dw-warn) set on :root to match the\nnavy/teal v10 mockup; camera overlays stay dark per engine contract.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"e7f7398","date":"2026-09-26 12:16:29 -0700","author":"Steve Abrams","subject":"engine: preview/commit/push await in-flight auto-crops (≤8s cap, '✂ Finishing crop…', buttons locked) so a full frame with a label is never published early; CaptureForm.ready(); gate +2 checks (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"79d201e","date":"2026-09-26 12:12:39 -0700","author":"Steve Abrams","subject":"engine: route every non-camera overlay colour through --dw-* tokens (defaults = /app hex, pixel diff 0%), add --dw-warn; gate: light-theme contrast checks (>=4.5:1) + wave-0b baseline table (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"516f63f","date":"2026-09-26 12:07:25 -0700","author":"Steve Abrams","subject":"Wave 0b: auto-crop to the product (cached /api/extract, ≤8s, full-frame fallback), never publish the label, read BOTH sides (back wins), Adjust re-crops the original from the auto box; crop box fixed under html zoom; Pattern button tappable; gate +w0b checks (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"0b34b7f","date":"2026-09-26 12:06:26 -0700","author":"Steve Abrams","subject":"theme(p-mode-dial): build full working app for PS v8 Mode Dial (TK-12348)","body":"Home = navy mode-dial camera screen (NEW/UPDATE/FIND/SAMPLE pills, scroll-snap,\nper-mode accent on the shutter using ink text not white for contrast) plus a\ntool strip (Scan, Label+Photo, Look Up SKU, Similar, Speak, Add New, Check\nSample In) and Adjust/Flip pills. FIND mode's hint becomes a live search field\nwith a mic and hold-to-talk on the shutter. A themed Results screen adds all\n11 filter chips (contrast-checked against the mockup's white-on-accent issue),\nsort, density, search, and per-item Enhance/Photos/Shoot/Fav/Skip. NEW/UPDATE\nroute into the engine's own two-shot camera + Add/Update form (10 fields +\nmics, WB, measure, +10 photos/+6 videos, preview/commit/push), themed via\n--dw-accent/--dw-accent-ink switching live with the dial. SAMPLE routes to\nIdentify.checkIn() and a themed \"Received\" confirmation screen driven by the\nengine's 'received' event.\n\nVerified: 50/50 Playwright checks (Chromium fake camera + WebKit iPhone/iPad),\n0 console errors, no horizontal overflow at 320/390/820/1280, tap targets\n>=44px. Screenshots in the job tmp dir.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"a5ca650","date":"2026-09-26 12:04:20 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: fix homeFab overlapping back-links (unreachable controls)","body":"The persistent top-left home fab covered the more/find/browse screens'\nown back-link buttons, making them unclickable in Playwright (and by a\nreal user's first tap). Drop the redundant per-screen back-links and\nrely on the single homeFab; verify 48/48 PASS.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"04f993e","date":"2026-09-26 11:59:15 -0700","author":"Steve Abrams","subject":"create-item: honour client sides[] and keep label_photo in the capture record only (never a Shopify image) — wave 0b (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"596e975","date":"2026-09-26 11:55:28 -0700","author":"Steve Abrams","subject":"theme p-sticker-book: kraft-paper Sticker Book app on DWEngine (TK-12348)","body":"Home booth (LiveScan scan) drops a polaroid draggable onto 4 stickers\n(New/Update/Find/Sample); second sticker sheet adds Similar/Fav/Enhance/\nLabel+Photo/Look-up-SKU/Received. Browse screen wires washi-tape filter\ntabs (need/live/done/new/twil/all/any/shop/similar/fav/recent), search+mic,\nsort+density (localStorage), and per-card Enhance/Photos/Shoot/Fav/Skip.\nAll writes go through DWEngine (CaptureForm/LiveScan/Identify/Editor/\nGallery); tokens themed via --dw-* per the brief's kraft/paper palette.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"5faf726","date":"2026-09-26 11:53:45 -0700","author":"Steve Abrams","subject":"engine: camera-feed overlays keep dark chrome under light themes (--dw-cam-* tokens); /app unchanged, gate 53/53 + demo 7/7 (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"0237365","date":"2026-09-26 11:50:41 -0700","author":"Steve Abrams","subject":"gate: no unhandled rejections on failed checks (negative mode exits 1 cleanly); eslint: browser globals for Playwright harnesses (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"59fefcc","date":"2026-09-26 11:47:17 -0700","author":"Steve Abrams","subject":"Engine demo page /t/_engine-demo (different layout, DWEngine only) + CaptureForm.addPhoto/addVideo/shot; gate --demo 7/7 PASS (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"1562b4a","date":"2026-09-26 11:45:59 -0700","author":"Steve Abrams","subject":"Extract /app client logic into shared engine public/js/dw-engine.js (window.DWEngine); /app runs on it","body":"Engine owns every overlay (two-shot camera, editor+crop, WB, measure, live scan, gallery,\nsample popup, label+photo identify, Add/Update form, lightbox, toast): markup + tokenised CSS\n(--dw-*) injected once, plus actions, components, CaptureForm data-dw-* binding and an event bus.\n/app keeps its header/grid/home chooser and talks to the engine. Gate: 53/53 PASS before and\nafter; eslint index.html 13 errors -> 0. (TK-12348)\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"ede0906","date":"2026-09-26 11:42:02 -0700","author":"Steve Abrams","subject":"extract: return validated product_box + label_boxes from the same Gemini call (wave 0b auto-crop groundwork) (TK-12348)","body":"normBox clamps/orders boxes and drops degenerate ones (<4% of frame) so a bad box degrades to no-crop.\nBoxes are removed from fields so the client field merge only sees strings. --test stub returns fixed boxes.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"fe7f1e0","date":"2026-09-26 11:39:19 -0700","author":"Steve Abrams","subject":"Front page: rebuild / (public/pick.html) to Figma spec — 10 working themes only","body":"- 5 Figma + 5 Photoshop theme cards (radiogroup per group, roving arrow-key\n  focus, Enter/Space select), Continue -> /t/<slug>, \"Use the classic app\" -> /app\n- Real Playwright screenshots of each mockup's first screen as thumbnails\n  (scripts/make-pick-thumbs.cjs, public/pick-thumbs/*.jpg, 21-46KB JPEGs)\n- localStorage `dwTheme` persistence: returning user gets WELCOME BACK eyebrow,\n  preselected + scrolled-into-view card, \"Last used\" pill, Continue pre-enabled\n- Mobile fixed-viewport layout (sideways-scrolling card rows, no page scroll)\n  vs tablet/landscape-iPad 5-col grid with page scroll, centered max-width 820px\n- Inter webfont, prefers-reduced-motion respected, 44px+ tap targets\n- server.js: minimal bounded static route for /pick-thumbs/<key>.jpg (same\n  allow-list pattern as the existing /themes/ route)\n\nTK-12348\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"1d19cb0","date":"2026-09-26 11:37:43 -0700","author":"Steve Abrams","subject":"app-control-gate.cjs: Playwright gate driving every /app control with a fake camera (PASS/FAIL JSON, --negative, --demo) (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"a216773","date":"2026-09-26 11:34:02 -0700","author":"Steve Abrams","subject":"server: bounded /t/<slug> route for engine-themed apps (allow-listed slugs, basic-auth) (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"00ae3d3","date":"2026-09-26 11:33:52 -0700","author":"Steve Abrams","subject":"Bring themes-ux-check.cjs into the engine branch (TK-12348)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"b560bc2","date":"2026-09-26 11:26:35 -0700","author":"Steve Abrams","subject":"TWIL grid: cache+pre-gzip /api/twil per INDEX rebuild, loading/error state instead of '0 items'; stub FileMaker routes in --test (TK-12348)","body":"- /api/twil built once (sort+stringify+gzip ~0.5s on 253k) and served as stored bytes; was rebuilt per request and crawled to ~65s under load\n- loadTwil tracks idle/loading/ok/error; grid shows Loading / Try again rather than '0 TWIL items'\n- --test now stubs /api/mark-received, print-sticker, sample-request, wallpaper-details/search so test clicks can't write real FileMaker\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"6286a2f","date":"2026-09-26 11:15:25 -0700","author":"Steve Abrams","subject":"Swipe picker: Pick this one opens the theme full screen (Back / Esc / Go to the app), Open-your-pick button reopens it; fix filter wiring catching the pick button (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"28a1391","date":"2026-09-26 11:07:23 -0700","author":"Steve Abrams","subject":"Swipe picker: one trackpad swipe/wheel flick = one theme (Safari skipped two); app chooser shows once per tab, not on every load (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"24bc0c3","date":"2026-09-26 10:58:06 -0700","author":"Steve Abrams","subject":"Front screen: one-at-a-time swipe theme picker (Figma v1-v25 + Photoshop Kid-Simple v7-v16); capture app moves to /app (TK-12343)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"6e2c3f2","date":"2026-09-26 10:42:20 -0700","author":"Steve Abrams","subject":"Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Auto) + accents, smart Suggested action, full UX (TK-12346)","body":"Themed card chooser with icons, descriptions, 1-4/Enter shortcuts, incoming-samples\nbadge, last-used fallback suggestion, ARIA radiogroups, reduced-motion. Tokens scoped\nto #homeScreen; theme/accent persisted in localStorage.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF"},{"hash":"4ace5d4","date":"2026-09-26 10:43:25 -0700","author":"Steve Abrams","subject":"Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Photoshop board, behind basic-auth (TK-12344)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk"},{"hash":"ac13489","date":"2026-09-26 08:19:15 -0700","author":"Steve Abrams","subject":"Untrack runtime build counter data/build.json and gitignore it","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017oAgztBQGK3Yw8zA83NEnJ"},{"hash":"6e16998","date":"2026-09-26 07:41:59 -0700","author":"Steve Abrams","subject":"TK-12090: add verify-only prod vision check paste script","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01VizMhiDcRGXSVT356UUdHr"},{"hash":"436c44b","date":"2026-09-26 04:44:30 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T04:44:27 (1 data files) — data/color-dots.json","body":""},{"hash":"d7887da","date":"2026-09-26 03:43:42 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T03:43:38 (1 data files) — data/color-dots.json","body":""},{"hash":"655426a","date":"2026-09-25 13:56:00 -0700","author":"Steve Abrams","subject":"TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page","body":"Relative fetch() on a Basic-Auth page threw on user:pass@host bookmarks.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX"},{"hash":"9b15829","date":"2026-09-25 13:55:59 -0700","author":"Steve Abrams","subject":"TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page","body":"Relative fetch() on a Basic-Auth page threw on user:pass@host bookmarks.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX"},{"hash":"7aecde5","date":"2026-09-25 13:12:39 -0700","author":"Steve Abrams","subject":"Editor fits iPhone width: narrow-screen layout (wheel above sliders, Use Photo full-width, Crop/Reset/Cancel row)","body":"html zoom 1.35 leaves ~289 CSS px on a 390px phone; sliders/values and the action row overflowed\nthe right edge (scrollWidth 323 > 289). Now 0 overflow, headless-verified; desktop unchanged (<=600px only).\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01TZynS56oLsqJTcschug1a7"},{"hash":"69d5016","date":"2026-09-25 12:22:23 -0700","author":"Steve Abrams","subject":"Front/Back tiles: tap a taken photo to adjust it in the Enhance/Crop editor; Adjust + Retake buttons below each tile (TK-12256)","body":"Editor/crop overlay raised above the add modal (z 130) so it opens from the tiles.\nAdjusted pixels replace the local shot only — nothing uploads until Create.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01TZynS56oLsqJTcschug1a7"},{"hash":"a2e8198","date":"2026-09-25 11:24:41 -0700","author":"Steve Abrams","subject":"5x sweep 5: report — sweeps converge at cap, 3 app defects fixed, env SIGTERM open","body":"TK-12228\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"0e8aa0e","date":"2026-09-25 11:08:38 -0700","author":"Steve Abrams","subject":"5x sweep 4: history evidence screenshot viewport-only (Firefox 32767px full-page limit)","body":"TK-12228\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"bf95f56","date":"2026-09-25 11:00:40 -0700","author":"Steve Abrams","subject":"5x sweep 3: hung-camera e2e mode (all engines), WebKit stub fix, sweep aborts if server dies","body":"TK-12228\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"4fd7dee","date":"2026-09-25 10:48:37 -0700","author":"Steve Abrams","subject":"5x sweep 2: camera-timeout retry tap now opens the snap camera (as the toast promises)","body":"- index.html: after the live camera times out (8s), the next Photo 1/2 tap goes to the native <input capture>\n  inside the fresh tap's user activation instead of re-running a hung getUserMedia forever (pre-existing since\n  TK-12124; reproduced 4/4 in WebKit with a cold mock camera). Toast names Photo 1 or Photo 2.\n- e2e: asserts whichever capture path the engine takes (LIVE shutter, or timeout toast -> snap file chooser ->\n  shotAdd); WARM_CAMERA=1 forces LIVE; cam.html check fails loudly if the phone camera never goes live.\n- 5x/tools/sweep.sh sweep driver.\n\nTK-12228\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"b49fdf9","date":"2026-09-25 10:06:54 -0700","author":"Steve Abrams","subject":"deploy: exclude tracked schu-publish-audit.jsonl (identical on remote) from rsync to stop delete-guard false positive","body":""},{"hash":"15beb44","date":"2026-09-25 10:03:22 -0700","author":"Steve Abrams","subject":"5x sweep 1: favicon on captures/batch/cam, consistent missing-side rule, 3-engine e2e + lazy-img scroll","body":"- captures/batch/cam: declare <link rel=icon> (was /favicon.ico 404 console error; captures new, batch/cam pre-existing)\n- /api/captures missing_back + captures.html missing()/sort/.miss: one rule — a front/back item lacking a side;\n  single-shot photo-only items (remote cam) no longer inflate the count (was 5 vs real 1)\n- e2e: ENGINE=chromium|webkit|firefox with per-engine fake camera; scroll lazy thumbs into view before asserting\n- 5x/tools: console probe, history scroll check, index toolbar clickthrough, missing-side regression check\n\nTK-12228\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"d1a0b78","date":"2026-09-25 09:38:47 -0700","author":"Steve Abrams","subject":"TK-12228: every captured photo, front and back, displays in the app","body":"- index.html: front/back tiles show the captured photo immediately; Preview shows\n  both sides (and counts them, was \"0 photo(s)\"); Created + Update results show the\n  server-stored copies; tap to enlarge; links to the new Capture History.\n- server.js: create-item/photo/photos persist every photo under photos/ with its side\n  in the filename (create-item now also on a failed create) and index one record per\n  item in data/captures.jsonl; responses return the stored URLs. New /captures page +\n  /api/captures merge that log with batch manifests and legacy vendor-log uploads.\n- captures.html: history grid, front+back per card (missing side shown as a gap),\n  date+time chip, sort + density slider persisted in localStorage, lightbox.\n- batch.html: FRONT (PSku) + BACK (Info) thumbs side by side, front shown on capture,\n  no more 8s blob revoke. cam.html: last remote shot shown on the phone.\n- --test seam (DWP_TEST_DIR): rebased data/photos, Shopify/dw_unified/FM writes and\n  paid OCR stubbed; scripts/e2e-front-back-display.cjs drives it (19 checks).\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P"},{"hash":"e82585f","date":"2026-09-25 09:03:04 -0700","author":"Steve Abrams","subject":"deploy: exclude .claude/ from rsync so agent worktree logs on remote aren't deleted","body":""},{"hash":"126f917","date":"2026-09-25 08:59:08 -0700","author":"Steve","subject":"Fix grainy Shopify product photos: raise server-side JPEG normalize cap+quality","body":"TK-12224. Root cause: normalizeImage() (server.js) runs every uploaded camera\nphoto through ImageMagick before it's attached to the live Shopify product\n(createNewItem / /api/photo / /api/photos all pipe through normB64). It was\ndownscaling to <=1600x1600 at quality 85 -- a SECOND, lower-quality JPEG\ngeneration stacked on top of the client's own capture (which already caps to\n2000px @ quality 0.92 in index.html/cam.html, or native-res @ 0.92 in\nbatch.html). On busy, high-frequency wallcovering/fabric patterns that shows\nup as visible JPEG blocking/mosquito noise -- exactly the \"grainy\" symptom.\n\nFix: raise the resize cap to 3000x3000 (a no-op for size against every\nclient's actual output, still guards oversized/HEIC originals) and the\nquality factor to 92 (matches the client's own export quality, removing the\ndouble-compression quality loss). Auto-orient/HEIC normalization for OCR is\nunchanged.\n\nClient-side getUserMedia constraints, canvas capture sizing, and JPEG export\nquality were already correct (4096x3072 ideal, videoWidth/videoHeight-sized\ncanvases, 0.90-0.92 export quality) from prior TK-12115/12124/12127/12128\nwork -- this was the one remaining lossy step, confirmed by tracing\n/api/photo, /api/photos, and /api/create-item to normB64() -> normalizeImage()."},{"hash":"afa2777","date":"2026-09-25 04:38:16 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-25T04:38:13 (1 data files) — data/color-dots.json","body":""},{"hash":"14a6623","date":"2026-09-25 03:37:14 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-25T03:37:11 (1 data files) — data/color-dots.json","body":""},{"hash":"8cceebc","date":"2026-09-24 23:44:42 -0700","author":"Steve Abrams","subject":"TK-12205: untrack agent worktree gitlink auto-snapshotted into main; ignore .claude/worktrees/","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"05c1b61","date":"2026-09-24 23:32:45 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T23:32:41 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac","body":""},{"hash":"d47866f","date":"2026-09-24 23:02:11 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T23:02:07 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac","body":""},{"hash":"99b4c9a","date":"2026-09-24 21:00:10 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T21:00:07 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac","body":""},{"hash":"e99e554","date":"2026-09-24 20:29:43 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T20:29:39 (2 data files) — .claude/worktrees/agent-a841f65dcd871d6ac data/build.json","body":""},{"hash":"67566bd","date":"2026-09-24 17:19:56 -0700","author":"Steve Abrams","subject":"TK-12162: mint checks vendor catalog reservations + confirms the number is free LIVE (FileMaker + Shopify)","body":"The mint's sources are all mirrors (shopify_products last synced 09-23) and none read the\nvendor scrape catalog, which pre-assigns dw_skus (tres_tintas_catalog: DWTS-900001..901506).\nSo a mint could hand out a reserved number, or the same number twice before a sync.\n\n- adds vendor_registry.catalog_table reservations to the used-number set\n- JS Pattern is TEXT in FileMaker (no reliable max), so the chosen number is verified free by an\n  exact live FileMaker find + Shopify SKU prefix search, stepping past taken numbers (max 25);\n  if a live source can't answer, the mint still returns but carries a flag\n- tested read-only on prod: 901507 taken=true, 987654 taken=false, DWTT-72290 taken=true,\n  Tres Tintas mint -> DWTS-901514, clear of both reserved ranges\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"2bc55d4","date":"2026-09-24 17:00:53 -0700","author":"Steve Abrams","subject":"TK-12162: 582 FileMaker masters created for live Tres Tintas products (DWTS); 10 Thibaut records mis-moved earlier restored to DWTT","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"30fe09a","date":"2026-09-24 16:44:23 -0700","author":"Steve Abrams","subject":"TK-12162: fix my collision - 7 Tres Tintas sq-ft listings DWTS-900000..006 -> DWTS-901507..513 (900001-006 reserved in tres_tintas_catalog)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"b1582b8","date":"2026-09-24 16:38:25 -0700","author":"Steve Abrams","subject":"TK-12162: 1168 Tres Tintas Shopify variant SKUs DWTB- -> DWTS- (undo log)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>"},{"hash":"825c8b2","date":"2026-09-24 16:24:30 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T16:24:12 (2 data files) — ops/tres-tintas-dwts-2026-09-24/__pycache__/shop-tb.cpython-314.pyc ops/tres-tintas-dwts-2026-09-24/shop-tb-restore.jsonl","body":""}]}