---
type: run
---

# Rehearsal, 18 Sep 2026: Stream K12 end to end on a copy (dfp_k12 on dfp-devdb, from dfp-nightly-2026-09-18.dump)

Migration k12a1b2c3d4e rehearsed up, down, up. The script lives in the session scratchpad; every number below is what the copy produced.
Two brands: johnnie-walker (cross-divide, 78 candidates from the packet) and rabanne (the brand fold from the staging pass).

```
baseline {'lines': 13879, 'empty': 277, 'variants': 16756, 'listings': 23771}
== 1. a new kind is critical whatever the pass said; the note is required; the rest is blocked
  load: {'rows': 3, 'inserted': 3, 'open': 3, 'spot_check': 3}
  lead level: ('critical', 'no precedent is registered for this kind of question; the answer sets one') | followers: ['critical', 'critical']
  ok: NOTE_REQUIRED: 1 critical row(s) need a note with the answer: it sets the precedent (first: cross-divide:same-bottle). Say wh
  ok: BULK_BLOCKED_BY_OPEN_LEAD: 3 open row(s) need a person first: cross-divide:same-bottle (critical), cross-divide:same-bottle (critical), c
  ok: LEAD_NOT_ANSWERED: Answer the lead question for cross-divide:same-bottle first; the group follows its answer.
  sheet: survey new kinds 1 | group cross-divide:same-bottle registered False level critical unseen 15 | bulk_blocked_by 3
== 2. the lead with a note sets the register; the group confirms as one batch with the note on every row
  lead: 1 approved, 0 held, 0 refused | refusals []
  register: cross-divide:same-bottle count 1 streak 1 note? True first_case pair:product:variant:244d2f80-d975-4a78-
  group now: lead approved bulk_ready True open 2 unseen 6
  group: 2 approved, 0 held, 0 refused | mode bulk | batch 831a196e | refusals []
  followers: [('approved', 'the whole kind reads alike'), ('approved', 'the whole kind reads alike')]
  register after group: count 3 streak 3
  variants after 3 cross-divide merges: 16753 (baseline 16756 )
  tombstones: 620
== 3. a second defer parks the question; a pass that re-asks is refused; unpark returns it as a deferral
  second defer: 1 parked; status parked | notes ['not sure the size words agree', 'still not sure']
  ok: PARKED_TO_RIAN: 1 row(s) re-propose a question parked to rian (pair:product:variant:24fd175d-d265-48dd-a752-bf87ba8286ef||vari
  pass parked: [('fd8c5185', 'decision')]
  unparked -> deferred wants a different suggestion
== 4. an overturn floors the kind high on the next load and regroups nothing
  before overturn, a like row at streak 3 -> ('low', 'cross-divide:same-bottle settled by 3 decisions')
  overturn: 3 decisions under it; batch d33e38ab
  after overturn -> ('high', 'cross-divide:same-bottle was overturned; the next answers set it again')
  variants unchanged by the overturn: True
== 5. status: open -> settled -> unsettled when a listed word changes
  now: open | the newest pass k12/rehearsal/jw-xd-1 left no open row but did not declare the brand settled
  after settled file: settled | settled by k12/rehearsal/jw-settled
  after a word changed: unsettled | listed words changed since the settled pass
== 6. rabanne: the brand fold from the staging pass, then undo everything; empty lines must not grow
  open fold rows: 1
  fold: 1 approved, 0 held, 0 refused | batch c5ad63d3 rabanne
  lines minted (recorded at prepare): 9 | after fold {'lines': 13864, 'empty': 278, 'variants': 16743, 'listings': 23771}
== 7. undo every batch, newest first
  batches undone: 9 decisions reversed: 44 skipped: 0
  final {'lines': 13879, 'empty': 277, 'variants': 16756, 'listings': 23771} | baseline {'lines': 13879, 'empty': 277, 'variants': 16756, 'listings': 23771} | equal: True
  precedent register after undo of the overturn: [('cross-divide:same-bottle', 'active')]
RESULT: ok```

`decisions verify`: 0 drift. `pass status` on the copy: not done: 15 open (the staging passes on rabanne), 2365 of 2365 brands not settled.

**Found and fixed:** the first run left one of nine minted product lines behind after undo: the line alias had written a redirect to its slug at confirm, and `referenced_lines` counted the redirect. A redirect written by a decision in the reversed batch keeps nothing alive now (`tests/test_undo.py`).

**Found, not fixed (on the running list):** `backfill prune_lines` removes 0 of the 277 empty product lines on the copy. Every one of them holds merge tombstones (variants merged away still point at their old line), which the prune keeps as records by design. The simulation called these "reachable rows that mean nothing"; making them unreachable is a reader rule, not a prune.
