14 Commits

Author SHA1 Message Date
Alexander Rozhenko
79e7a4f61f fix #2: header pill refreshes itself after swipes, undo and new batches
loadStats() only ran once at boot, so the live/fresh/new pill (and the
list sub-line) went stale until a full reload. Refresh it, debounced and
fire-and-forget, after any decision change, when a new batch lands, and
on app foreground. Adds two fe_walk_v11 regression checks + a UI-SPEC note.
2026-11-13 15:58:36 -04:00
Torres
35138bdc22 test(v1.1): fe_walk_v11 harness (89 checks, 3 staged catalogs) + polish from the walk
- app/fe_walk_v11.py: self-contained headless walk — stages rich /
  returns-only / dead-catalog Dbs, boots the scratch server on 9455
  (OPENROUTER_API_KEY unset), and verifies all ten items on the real page:
  keyboard map + guards + no-scroll, tap flow + Esc chains (deck and list
  paths), contain/blur computed styles, minimal rubric + debug toggle
  round-trip, the 0/25 -> 25/25 counter with undos, dry messaging, fresh
  pill, loud empty2 + nightly-recovery, violet bands, B1 regressions
  (flip clamps, one .topcard, no-lock storm) and the full P3 loop.
- Keyboard: ArrowDown/Backspace now no-op while a sheet is open (arrows
  work on the deck only — spec note); found by the walk.
- get_section: an empty composed section (fully drained catalog)
  recomposes on read once pool_counts shows stock again — the nightly
  import re-lights the deck without a manual forge (item 8 recovery).
2026-11-13 14:04:11 -04:00
Torres
08f945a029 feat(v1.1): item 10 — Second Look band in violet (bold fill + border)
.band.sl re-tinted to the confirmed violet palette (#c4b5fd text,
rgba(124,58,237,.22) fill, rgba(167,139,250,.65) border, weight 800);
wildcard stays amber for contrast. The card band mirrors into the
dossier body (new #dband, static variant of the pill) on return and
wildcard listings; new-slot dossiers show no band. bandHTML/bandLabel
split reuses the same labels on both surfaces.
2026-11-13 13:54:01 -04:00
Torres
a1455aade4 feat(v1.1): items 7-8 — fresh counter pill + loud 'No more new bikes!' empty state
Item 7: /api/stats gains fresh (actives with no swipe row — the deck's
new-pool predicate verbatim); the header pill reads 'N live · M fresh'
(new badge unchanged); old APIs without fresh render no segment.

Item 8: sections.pool_counts() answers can-the-forge-serve-anything from
the composer's own candidate SQLs (stock answer, LAST_TWO not applied)
and rides every section_state body. The FE adds #empty2 ('No more new
bikes!' + 08:30 line + undo note): shown whenever the pile/buffer drain
and pool is 0/0/0 (report masked), on a zero-item dry forge too; undo
hides it; legacy .empty untouched. UpdateUI repaints the caption per
hydrate; the stats key-set selfcheck gains fresh.
2026-11-13 13:42:08 -04:00
Torres
0d2e5a592f feat(v1.1): item 6 — dry-catalog messaging (forged batches with 0 fresh are labeled)
section_state now mirrors the composed recipe at body.recipe; the forge
note appends 'catalog fully reviewed' when the batch has zero fresh cards.
The FE shows the BACKLOG sentence in the report (dryCap) and in the forge
status line whenever recipe.new===0 with cards served; a non-dry forge
behaves exactly as before. No new fetch loops.
2026-11-13 13:39:22 -04:00
Torres
98d345ceee fix(v1.1): item 5 — section counter keys off in-section events (2/2 -> 3/2 bug)
A card is decided only when a swipe event carries THIS section's id;
the lifetime swipes.action a second look wears into its section no longer
paints it as pre-decided. progress/undecided, report counts (latest
in-section event per listing) and maybe_exhaust all use the new
section_decided_ids() set; read path only, no writes. Every section_state
item carries decided_this_section; the FE counts server truth unless a
local intent is in flight, and sectDecided is clamped to sectTotal
everywhere (commit + paintSect) so the pill can never read past N/N.

Semantics note: completing a section now means striking EVERY item in it
(returns re-struck on their second look) — the exhaust selfcheck was
updated to strike all items, matching the deck's real flow. Undo-on-a-
return residual (event stays after the DELETE) is the accepted Q5 clamp-
only behavior, covered by a dedicated selfcheck case.
2026-11-13 13:38:18 -04:00
Torres
ac613e680a feat(v1.1): item 4 — minimal rubric (gauge + %) and rubric_debug 'why' toggle
- prefs API accepts the new rubric_debug key (off|on), the only new runtime
  write in v1.1; every section_state body now carries prefs.rubric_debug.
- fillRank renders the tank gauge + rounded % by default; the breakdown
  lines, audit footer and the quiet listing-enrichment fetch run only when
  the pref is on. List rows and the card face stay rubric-free (unchanged).
- Trends 'Actions' gains a 'Why breakdown: off | on' row in the setMode
  style; updateSectionUI repaints it on every section hydrate.
2026-11-13 13:31:21 -04:00
Torres
e67f8a0cda feat(v1.1): items 1-3 — keyboard map, info-first tap flow, photos = fit + blurred backdrop
Item 1: ArrowLeft/Right/Up drive nope/like/maybe through commit(); ArrowDown
and Backspace (kept alias) drive undo(); Esc closes the top open sheet only
(viewer -> dossier -> deck, inert on report). Text inputs/TEXTAREA/SELECT/
contentEditable swallow keys; arrow defaults are prevented (no page scroll).

Item 2: card center tap now opens the dossier (bike data first); side taps
keep flipping photos; the direct card -> viewer door is retired. The deck
dossier records its pile entry; the hero tap opens the viewer with a
backToDetail chain so Esc walks viewer -> dossier -> deck (repeatable).

Item 3: deck card + dossier hero photos switch from cover to contain over a
soft blurred backdrop of the same image (option C, demo panel C); thumb and
fullscreen viewer untouched; nophoto paths render no backdrop.
2026-11-13 13:30:09 -04:00
Torres
4630813644 b1: frontend fix — viewer segment bars render flat inside #vsegs (no nested .segments); fe_walk_b1: deterministic headless §11 evidence harness (fixture DB 701-706, staged local photos, real pointers: flips/clamps/viewer/zoom/pull-close/rotation/fast-chain/report/forge/list/trends) 2026-11-11 00:20:16 -04:00
Torres
fff9f05bae b1: frontend §11 — tap zones (sides flip clamped, center fullscreen, ⓘ wins), segment bars + band top:22 amendment, fullscreen viewer (swipe nav clamp, pinch 1-4x + double-tap zoom, ✕/pull-down close, same-position return), repeat rotation lead (last+1)%n, photo_idx on swipe commits, photo preload, sw cache v3 2026-11-11 00:08:04 -04:00
Torres
1e4d84017a frontend: fix second-look returns filtered out of the swipe buffer (decision===null filter dropped them; returns must enter the deck to be re-struck) 2026-11-10 23:38:55 -04:00
Torres
b6e1851b11 frontend: report-screen exhaustion fix — local decision map drives section progress; show report on local exhaust with rate-limited resync (verified headless: full 25-card section loop, forge, trends, tanks) 2026-11-10 23:28:06 -04:00
Torres
04463cadcd P3: personalization core — event log + taste engine + section engine + agent pass + API + frontend
- db.py: guarded P3 tables (swipe_events/sections/section_items/taste_profile/
  agent_runs), one-time event seeding from swipes, append_event round math
- taste.py: deterministic taste engine (action x round x recency weights,
  n/(n+3) shrink, ramp w=min(.85,N/60), percentile norm, agent adjustments
  +/-10, points + source-labeled breakdown + tank bands)
- sections.py: compose/read/exhaust/forge — 2 wildcards + <=5 returns
  (<=2 nopes, surprising only) + remainder new, <=4/family, >=3 price
  bands w/ repair, returns maybe>like>nope, last-two-section exclusion,
  ondemand/strict modes
- agentpass.py: mock (deterministic) / live (OpenRouter, one retry) /
  fallback; strict payload schema; --print-summary/--dry-run
- api.py: GET /api/section, POST /api/section/forge, GET /api/trends,
  POST /api/agent/run, POST /api/prefs; P3 payload fields (points, tank,
  slot, round_next, points_breakdown); events stamped with section_id
- frontend: section buffer + progress pill, report screen + forge + mode
  toggle, WILDCARD/SECOND LOOK bands, tank gauges (list + dossier), dossier
  Why-this-rank, real Trends tab, /api/deck fallback for pre-P3 API, sw v2
- selfcheck: 9 new P3 checks (25/25 green)
2026-11-10 23:18:26 -04:00
Torres
57fae0df49 app: no-build PWA frontend (fidelity port) + image mirror
- app/static/index.html: single-file app — DOM/CSS/stack engine ported
  verbatim from reference/mockup-001-fidelity.html (DEPTH/SC/TY/DIM, drag/
  fly/undo, one .topcard, no-lock commits, stamps, dossier sheet,
  pull-to-close, empty state); production deltas only (UI-SPEC §7): deck
  buffer + cursor refill (40/page), optimistic swipe persistence with
  2s/5s/10s/15s retry queue + toast, badge-once-per-session, real list
  filters + search (server-side), real Matches screen, /img/{id} everywhere
  with placeholder fallback, SW registration, safe areas, desktop centering
- manifest.json + sw.js (precache shell, network-first API, cache-first imgs)
- icons: 192/512/maskable/apple-touch-180, dark tile with the brand
  accent-gradient mark (Pillow)
- app/imgfetch.py: local mirror, hunt's Chrome-120 UA, ~1s pacing,
  skip-existing, .part writes atomic, per-item failure isolation,
  fetched/skipped/failed summary; verified: --limit 15 -> 15 fetched, full
  run 5 more, re-run 0 fetched 20 skipped (20/20 mirrored)
2026-11-10 21:21:27 -04:00