← back to Dw Photo Capture
5x REPORT: TK-11947 capture rebuild — 51/51, Cody SHIP IT, deploy gated
7d98690702d46aafab93f9cffcf78f36eeb6a3bf · 2026-09-20 12:08:07 -0700 · steve
Files touched
Diff
commit 7d98690702d46aafab93f9cffcf78f36eeb6a3bf
Author: steve <steve@designerwallcoverings.com>
Date: Sun Sep 20 12:08:07 2026 -0700
5x REPORT: TK-11947 capture rebuild — 51/51, Cody SHIP IT, deploy gated
---
5x/REPORT.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/5x/REPORT.md b/5x/REPORT.md
new file mode 100644
index 0000000..4d3b3e2
--- /dev/null
+++ b/5x/REPORT.md
@@ -0,0 +1,46 @@
+# /5x REPORT — TK-11947 · #twoShotCam live-adjust ordered two-photo capture
+
+Target: `http://localhost:9890/` (local dw-photo-capture, Basic auth) · repo `~/Projects/dw-photo-capture`
+Feature: replace native-camera handoff for the FRONT/BACK two-photo flow with an in-page live view —
+live WB + Brightness/Sat/Hue baked at the shutter, ordered front→back with a luminosity ghost of Photo 1.
+
+## Sweep ledger
+
+| sweep | what | result | commit |
+|-------|------|--------|--------|
+| 1 | generic /3x six-way runner | mismatch — runner probes a different app's controls; `/` is auth-gated; **found the real bug: was probing :9912 (commercialrealestate), not :9890 (dwphoto)** | — |
+| 1b | build state, targeted harness authored | wrong server (:9912) → element not found | — |
+| 2 | targeted fake-camera harness on :9890, **after Cody FIX FIRST fixes** | **44/44 PASS** iPhone(390×844) + iPad(1024×1366) | `1878910` |
+
+## Cody gate #1 (commit 480017e) → FIX FIRST — 3 real defects, all fixed in 1878910
+1. **Camera lifecycle** — `openTwoShotCam` had no busy-guard → fast double-tap raced two `getUserMedia` (orphaned hot stream); a failed camera-flip left `_tsLive` stale-true so the shutter baked/saved a **frozen frame** as a real photo.
+ → Fix: `_tsOpening` guard on open + `_tsAcquiring` guard in `startTsStream` (both try/finally); `_tsLive=false` + shutter disabled until a fresh live frame; flip reverts to the known-good lens on failure.
+2. **Resolution vs server cap** — dropped `downscale()`, captured up to 4096×3072 with no ceiling → two busy-pattern JPEGs could 413 the server's 25MB `/api/create-item` cap.
+ → Fix: `tsCapture` clamps longest edge to 2000px (aspect preserved, bake runs on the clamped canvas).
+3. **Flip mid-pair** — flipping lens between front/back ghosted front-cam against rear-cam (nonsensical alignment).
+ → Fix: `#tsFlip` hidden on the BACK phase (lens locked for the pair).
+
+## Sweep 2 — targeted verification (44/44 PASS, both viewports)
+Every check on iPhone + iPad: twoShotCam present & hidden-until-opened · **order enforced** (BACK request downgraded to FRONT) · **double-tap → exactly 1 getUserMedia** (race guard holds) · live camera plays · `_tsLive` true only after a live frame · 3 color sliders · shutter 105×105px & enabled-only-when-live · flip visible FRONT / **hidden BACK** · step chip FRONT/1 · FRONT capture sets `_frontPhoto` & advances to BACK · ghost source loaded & **ghost canvas rendered** · **captured longest edge = 2000px** (cap holds) · BACK capture sets `_backPhoto` & closes · **camera stream stopped on close (no leak)** · **0 console/page errors**.
+
+Harness: `5x/verify-twoshot.mjs` (global Playwright + system Chrome, `--use-fake-device-for-media-stream`). Results: `5x/twoshot-result.json`.
+
+## Explicitly DEFERRED to Steve's on-device /5x (cannot be proven headless)
+- (1) true edge-to-edge fill + shutter vs iOS home indicator (URL bar collapsed/expanded)
+- (7) overlay/tap alignment under `html{zoom:1.35}` on **real WebKit** (headless Chromium ≠ iOS Safari)
+- (10) bottom-edge swipe never triggering the iOS home gesture
+
+## Cody gate #2 (commit 1878910)
+<pending — appended on completion>
+
+## Cody gate #2 (commit 1878910) → SHIP IT (grudging)
+All 3 findings CONFIRMED-FIXED. Required per CLAUDE.md negative-test rule: the harness only tested the happy path (fake camera always succeeds). Added a fail-path test + 2 one-line hardenings (conditional shutter-arm; flip double-tap guard) → commit 635c96e.
+
+## Sweep 3 — 51/51 PASS (44 happy-path + 6 fail-path + 1 desync), iPhone+iPad
+Fail-path PROVEN: injected getUserMedia rejection → shutter disabled, _tsLive false (no frozen-frame save), camFacing reverts, toast fires, recovers when camera returns. Double flip-tap → one flip (no desync).
+
+## FINAL JOINT VERDICT (DTD + Cody)
+Cody: SHIP IT. Empirical: 51/51. eslint: 0. → CODE is ship-ready. The DEPLOY to photo.designerwallcoverings.com is a hard external-publish gate → **HOLD-FOR-STEVE**: memo drafted to pending-approval (2026-09-20-TK-11947-deploy-dwphoto-twoshot-live-capture.md). Paid DTD panel skipped ($0) — the gate dictates HOLD-FOR-STEVE regardless of any panel vote; running 5 LLMs to confirm a foregone gated conclusion would be token-waste.
+
+## Empirical test gate note
+The capture flow is getUserMedia-based; /cta + /screenrecord drive real browsers but do not grant a fake camera, so they cannot exercise #twoShotCam. The targeted fake-camera harness (real Chromium, 2 viewports, injected failure) IS the domain-appropriate empirical drive per the skill's substitution clause. /cta breadth on the non-capture grid/add-modal remains optionally available.
← 635c96e Cody re-gate #2 hardening: conditional shutter-arm + flip do
·
back to Dw Photo Capture
·
auto-data-snapshot: 2026-09-20T12:15:15 (2 data files) — dat 39c872f →