---
description: Stream M: standardise every listing (brand | line | variation | size), suggest merges at every level, and give rian a keyboard-driven mass confirm session
---

You are running **Stream M** of the Duty Free Professor build, as an autonomous session. Start by
running `pwd`; it must be `/srv/apps/dutyfreeprofessor`, or stop.

Read first, in this order: `.logs/planning/streams/OVERNIGHT-RULES.md` (binding), then your brief
`.logs/planning/streams/M-merging.md` (it names what already exists; build on it), `agents.md`,
`brief.md`, build plan `.logs/planning/build-plan-2026-09.md` sections 2 and 4, `main/docs/DATA-MODEL.md`,
`python3 main/scripts/items.py list --decisions` (rian's decision of 12 Sep is the mandate), the top
three entries of `.logs/handoff.md`, and `app/services/merges.py` in full before you change identity.

Then work the brief's tasks in order, M1 to M7, one at a time, each verified and committed and recorded
on `/plan` with `main/scripts/plan-set.py` (`doing` when you start, `done` with a `--note` that says
what proves it, `blocked` with why). Delegate mechanical edits to a cheaper model and verify the
diff yourself; never delegate the line key, the matching rules, or anything a person reads on the
merge page. **Never run Stream A's tasks or touch the live database.** Rehearse every migration and
backfill on `dfp-devdb` (127.0.0.1:5433) in a fresh copy of the newest nightly dump, and report the
numbers it produced, read from that database.

The one outcome that matters: when you are done, rian can open `/collectors`, go to Merge, and confirm
or reject suggested merges at every level by keyboard, each decision recorded against his account, with
the Paco Rabanne to Rabanne alias as the first case waiting for him.

## Goal, and exactly when you are done

**Goal:** the listings table, the line and variation model, matching that stops splitting the same
bottle, aliases at every level, rule-based suggestions, the merge session, and the inheritance rules,
to the verified-and-committed standard.

**You are done when ALL of the following are true**, and not before:
1. Every one of these task ids in `import/progress.json` is `done`, or is `blocked` with a
   note saying why: **M1, M2, M3, M4, M5, M6, M7**. (Check with `python3 -c "import json;d=json.load(open('import/progress.json'));print({t['id']:t['status'] for s in d['streams'] for t in s['tasks'] if t['id'] in ['M1','M2','M3','M4','M5','M6','M7']})"`.)
2. `../.venv-dev/bin/pytest tests -q` passes and `main/check.sh` prints "checks passed" on the
   current tree.
3. Every finished task has its own commit prefixed `M:` (`git log --oneline | grep "^[0-9a-f]* M:"`).
4. A handoff entry for this session exists at the top of `.logs/handoff.md` (≤25 lines: what
   landed and how it was verified with the numbers from the rehearsal, the migration id and the
   after-deploy commands in order, what is blocked and why, what rian must do), and `/checkpoint`
   has been run.
5. Anything only rian can decide is on the running list (`python3 main/scripts/items.py add
   --kind decide --by "Stream M" --blocks <task> --weight ...`) with the assumption you proceeded under.

A task you cannot finish is not a reason to keep going or to stop early: mark it `blocked`
with the reason, record the decision if one is needed, and move to the next. If all tasks
are done or blocked, finish steps 2 to 5 and stop. If eight hours have passed, mark every
unfinished task `blocked` with the note "eight-hour cap; resume with /stream-m", write the handoff,
run `/checkpoint`, and stop.

## The goal line (rian pastes this after the first turn ends)
Start the session with `/stream-m`. When that first turn ends, paste this one line:

```
/goal Stream M of the Duty Free Professor build is complete: in import/progress.json every one of the task ids M1, M2, M3, M4, M5, M6, M7 has status done, or blocked with a note saying why; main/check.sh has printed "checks passed" on the final tree; every finished task has its own commit prefixed "M:"; a handoff entry for this session is at the top of .logs/handoff.md naming the migration id and the after-deploy commands, and /checkpoint has been run; anything only rian can decide has been added to the running list with main/scripts/items.py. Or stop after 120 turns.
```
