---
description: "Stream AW3: pictures at three levels (Adam's folder classified into a manifest, provenance columns on brands, product lines and product variants, one display cascade with the level exposed, the stage and import commands, Wikidata logos and Open Food Facts line promotion, image_tier for AW2, the /images page by level)"
---

You are running **Stream AW3** of the Duty Free Professor away run of 19 to 20 September 2026, as
an autonomous session. The design is in the brief; do not redesign it. Where the brief is silent,
choose the option that leaves a row empty rather than guessing a picture, and write the choice in
your handoff.

**Start by checking your ground.** `pwd` must be
`/srv/apps/dutyfreeprofessor/.claude/worktrees/collectors-live-page-plan-8951e2` on branch
`claude/collectors-live-page-plan-8951e2`; `git log --oneline -1` must show `05941b4` or later.
If either is wrong, stop and say so. `.venv-dev` and `main/web/node_modules` are symlinked here.

Read first, in this order: your brief `.logs/planning/streams/AW3-images.md`, the away plan
`.logs/planning/streams/AWAY-2026-09-19.md` (sections 1, 2 and 7 bind you),
`.logs/planning/streams/OVERNIGHT-RULES.md`, `agents.md`, `brief.md`, then the docs the tasks
need: `main/docs/DATA-MODEL.md` ("Facts, not expression", "What a merge inherits"),
`main/docs/COLLECTORS.md` (L2, the imagery posture), `main/docs/VOCABULARY.md`,
`main/docs/RUNBOOK.md` (Migrations, Backups and restore, the dev database), `main/docs/QUALITY.md`
metric 16. Then the code the brief names: `services/images.py`, `image_ask.py`, `catalog_queries.py`
(the image reads), `seo.py` (the image and logo emission), `merges.py` (the image inheritance),
`main.py` (`mount_site`, `cache_headers`), `access.py` (`PUBLIC_ALWAYS`), `cli.py` (`cmd_images`,
`cmd_backfill`), `Thumb.tsx`, `ImagesPage.tsx`, and the tests that pin them.

Adam's pictures live only in the main checkout at
`/srv/apps/dutyfreeprofessor/notes/images for the site/`: read from that absolute path, never move
it, never commit a picture. The runtime home is the main checkout's `uploads/` (gitignored, mounted
at `/srv/uploads`); the worktree's `uploads/` is not mounted anywhere.

Then work the tasks in order, AW3.1 to AW3.5, one at a time, each verified, committed with the
`AW3:` prefix. Register the tasks on `/plan` first, one per task:

```
python3 main/scripts/plan-set.py AW3.1 todo "Stream AW3" --add --stream AW3 --stream-title "AW3 · Pictures at three levels" --title "Survey and manifest"
python3 main/scripts/plan-set.py AW3.2 todo "Stream AW3" --add --stream AW3 --title "Storage, provenance and the cascade"
python3 main/scripts/plan-set.py AW3.3 todo "Stream AW3" --add --stream AW3 --title "Stage, import, and every reader on the cascade"
python3 main/scripts/plan-set.py AW3.4 todo "Stream AW3" --add --stream AW3 --title "Wider legitimate coverage"
python3 main/scripts/plan-set.py AW3.5 todo "Stream AW3" --add --stream AW3 --title "The /images page, coverage, docs"
```

then `python3 main/scripts/plan-set.py AW3.n doing "Stream AW3"` when you start one and
`python3 main/scripts/plan-set.py AW3.n done "Stream AW3" --note "<what proves it>"` when it is
verified. Rehearse the migration (up, down, up) and every data move on `dfp-devdb`
(`127.0.0.1:5433`) holding a fresh restore of the newest dump in `backups/`, and report the numbers
that copy produced. A bug you fix becomes a test in `main/tests/` written as the real record that
failed, with what it cost in the docstring. `main/check.sh` must print "checks passed" before each
commit; one task, one commit.

**Hard boundaries beyond the usual.** You never deploy and never write to staging's or production's
database: the migration, `backfill image_sources` and `images import` are commands you hand the
orchestrator in the handoff, run after deploy D2. `images stage` you run yourself, from the
worktree with `--uploads /srv/apps/dutyfreeprofessor/uploads`, and you commit the manifest with
its `url` fields (AW5 reads the hero addresses from it). You never run a collection. The only
network you may use is the Pernod URL downloads `images stage` makes for chosen entries and one
`images logos --limit 3 --check` dry run against the dev copy, one request per second, the bot
user agent, both inside `.logs/runs/window-2026-09-19-images.md`, which you write and announce
before the first request and close with the counts. You never edit `docker-compose.yml`,
`.env`, `.app.env`, `featured.py` or `airport_featured.py` (AW2 reads your `image_tier`), the
collectors, the identity rules or `decisions/`. Never a bare "product" in code, labels or prose: product variant, product line,
brand, picture level. Client-facing copy has no em dashes and never the words "cheap" or "free".

Tell rian as you go with `srv-gw notify --from "AW3" "<one line>"`: on start (`AW3 starting: 5
tasks, pictures at three levels`), after each task with the count (`AW3.2 done (2/5): ...`), on
blocked, and at hand-back. Never put a secret or a tokened URL in a message. If the command fails,
note it in the handoff and carry on.

When you are blocked on something only rian can decide, do not stop: add it to the running list
(`python3 main/scripts/items.py add --kind decide --by "Stream AW3" --blocks AW3.n --weight
costly|blocking --title ... --detail ... --option ... --assumption ...`) with the options, the
assumption you are proceeding under, and what you would have to redo, then carry on with
everything that does not depend on it. The brief's "Questions for rian" are already assumed; raise
them as items only if the work turns one critical.

If a task turns out to need more than about three hours, split it, record the split with a note,
and keep the part that lands. When the brief is done, prepend the handoff entry to
`.logs/handoff.md` (25 lines or fewer, state not summary: the migration id, the after-D2 command
order with `--check` first, coverage before and after by level from the copy, the manifest's
chosen and unassigned counts, the OFF key bug and its test, what AW2 reads and where, what you need
from rian), add the CHANGELOG line, run the project `/checkpoint`, send the hand-back line, and
stop. The orchestrator deploys; you do not.

```
/goal Stream AW3 is complete: every task AW3.1 to AW3.5 is done on /plan, 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 "AW3:"; import/images/adam-2026-09-19.json exists and is tracked, no image file is committed; the migration was rehearsed up, down, up on dfp-devdb and its id is in the handoff with the after-D2 command order; services/imagery.py exposes resolve() and image_tier() with the seven tiers; nothing was deployed, staging's database was never written, no collection was run. Or stop after 120 turns.
```
