# Rehearsal: the review area's three tabs and the price block (Stream K10, 17 Sep)

Where: `dfp-devdb` (127.0.0.1:5433) only, database `dfp_k10`, a fresh restore of
`backups/dfp-2026-09-17-post-chain.dump`. Staging and production were never contacted; no
collection ran; nothing was deployed. Code: `claude/review-area` in its own worktree.

## The three tabs, read end to end off that database

**Tab 1, How decisions are made.** `docs/REVIEW-PROCESS.md` version 3 (2026-09-17) read from the
host: 7 sections, 22,488 characters rendered -- the standing rules, then the certain boundary,
the grouping defaults, what a proposal must carry, what the person spot-checks, the value order
and the file. **13 passes, 938 proposals waiting**: format words 257 across 117 brands, drink
words 188/92, lists together 159/80, cask words 154/80, brand trailers 91/91, connectors 37/24,
region words 14/11, brand partial 12/7, shade shapes 10/5, pack words 8/6, audience 4/3, noise
3/3, age words 1/1.

**Tab 2, Folding and splitting. 3,913 things waiting:**

| level | waiting | pairs | with a rule's reason | values | first row |
|---|---|---|---|---|---|
| Brands | 165 | 74 | 0 | 91 | Rabanne + Paco Rabanne |
| **Product lines** | **2,572** | 2,572 | 683 | 0 | Lady Million + Lady Million Royal |
| Attributes and wordings | 164 | 0 | 0 | 164 | a Rouge Dior shade |
| Product variants | 1,012 | 1,012 | 0 | 0 | Dylan Purple 5cl + Versace Dylan Purple EDP |

So **product line work outnumbers brand work sixteen to one**, which was rian's worry and is now
the first thing on the tab. Adding the proposals table to the suggestions table would have printed
**3,255** at line level instead of 2,572; a rule's reading of a pair is a reason ON that pair.

**Tab 3, Publish candidates. 2,081 waiting**: 364 brands, 1,701 product lines, 16 places. Ciroc
leads the brands ("11 variants priced across 2 or more places"), Aventus the lines ("3 variants
compared, the widest across 3 places"), Athens the places ("251 variants priced here"). Page one
shows 100 and page seventeen is now reachable; "glenfiddich" narrows 2,081 to 17 pages.

**Nothing written.** After reading all three tabs and every level, the session held no new, dirty
or deleted rows, and a test says the same.

## The price block, on CHANEL Bleu de (6 variants, 18 listings on the busiest)

| state | before | now |
|---|---|---|
| nothing chosen | "Choose a quantity to see its prices" and no chips at all | all 6 variants offered in the block |
| a bottle, no airports | "Sold at 2 airports we track", names linking away | Bogota 49.00 USD and Panama 49.00 USD, both seen 11 Sep, printed here |
| airports chosen (LHR) | "Not stocked at LHR", the airports named | the same, and both prices open underneath |
| a shop not chosen | unreachable without clearing the airports | one closed disclosure away |

Every price carries its date in all four; no "From $X"; a catalogue-only shop prices no page in
any state; and the served body (`seo.py`) and the SPA were changed together, as they must be.

## Found by rehearsing, and fixed
1. The runtime image copies `app/`, alembic and the built SPA -- **not `docs/`** -- so a tab that
   reads `REVIEW-PROCESS.md` would have found nothing on staging. The Dockerfile now copies that
   one doc; the rest of `docs/` stays out of the image.
2. `markdown.py` had no table support, so section 2's grouping defaults -- the block a person
   opens the tab to read -- rendered as one run-on paragraph with the `|---|` still in it.
3. The index candidates panel asked for the first hundred and said "the rest follow once these are
   decided": the first hundred of 1,701 product lines, so finding one page meant deciding a
   hundred others first.
4. The price block offered only the variants stocked at the shopper's chosen airports, which is an
   empty list when no airport is chosen -- the exact state rian was looking at when he said there
   was "no ability to choose it right there in that section".
