---
description: "Stream AW5: the launch surface (the page-status badge for the owner and admins with the four words indexable, noindex, unlisted and hidden; ten sample articles flagged as samples with the tags column and the import commands; the article centre at /articles server-rendered with ItemList JSON-LD and noindex until approved; email capture verified end to end on a restored copy and the export procedure in the runbook)"
---

You are running **Stream AW5** of the Duty Free Professor away run of 19 to 20 September 2026, as
an autonomous session (or as the orchestrator's workflow, one subagent per task). The design is in
the brief; do not redesign it. Where the brief is silent, choose the option that keeps the public
from ever seeing an owner's mark and a sample from ever reaching production, 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`; `git branch
--show-current` must print `claude/collectors-live-page-plan-8951e2`; `git log --oneline -20`
must include `05941b4` or later (and shows which `AW1:` to `AW4:` commits have landed). If any of
these 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/AW5-launch-surface.md` (the work
list; every path and function it names is real), `.logs/planning/streams/AWAY-2026-09-19.md`
(sections 1, 2, 4 and 7 bind you), `.logs/planning/streams/OVERNIGHT-RULES.md`, `agents.md`,
`brief.md`, then the docs the tasks need: `main/docs/SEO.md`, `main/docs/ACCOUNTS.md`
(permissions and levels), `main/docs/RUNBOOK.md` (Content), `main/docs/VOCABULARY.md`, and the
top entry of `.logs/handoff.md` plus AW3's hand-back (the hero image addresses). Then the code of
your area: `main/app/services/publish.py`, `seo.py` (the articles section and `STATIC_HEADS`),
`access.py`, `accounts.py`, `editorial.py`, `cli_editorial.py`, `subscribers.py`, and the tests
that pin them (`tests/test_publish.py`, `test_seo_article.py`, `test_site_routes.py`,
`test_access.py`, `test_route_inventory.py`, `test_articles.py`, `test_subscribers.py`).

**Register the tasks on /plan first**, one line each, then work them in order, AW5.1 to AW5.5:

```
python3 main/scripts/plan-set.py AW5.1 todo "Stream AW5" --add --stream AW5 --stream-title "AW5 · The launch surface" --session /stream-aw5 --title "Page status: the four words, the read, the badge"
python3 main/scripts/plan-set.py AW5.2 todo "Stream AW5" --add --stream AW5 --title "Ten sample articles, the sample and tags columns, the import commands"
python3 main/scripts/plan-set.py AW5.3 todo "Stream AW5" --add --stream AW5 --title "The article centre: /articles server-rendered, the grid, tags, related lines"
python3 main/scripts/plan-set.py AW5.4 todo "Stream AW5" --add --stream AW5 --title "Email capture verified end to end on the copy, the export procedure"
python3 main/scripts/plan-set.py AW5.5 todo "Stream AW5" --add --stream AW5 --title "Rehearsal and hand-back"
```

Each task: `python3 main/scripts/plan-set.py AW5.<n> doing "Stream AW5"` when you start; write
the short plan in the handoff first for AW5.1 and AW5.3 (multi-file); build it; `main/check.sh`
must print "checks passed"; one commit prefixed `AW5:` with a subject line and a body that says
what it prevents or what it cost; then `python3 main/scripts/plan-set.py AW5.<n> done "Stream AW5"
--note "<what proves it>"`. A bug you fix becomes a test in `main/tests/` written as the real row
that failed, with what it cost in the docstring.

**Rehearse on a copy, never on staging.** Restore the newest dump in `backups/` to `dfp-devdb`
(127.0.0.1:5433) as a fresh database; run the migration up, down, up there; import and publish
the ten samples there; run the email-capture checks there. Report the numbers that database
produced. Close any inherited `running` collection row in the copy by status, as earlier streams
did.

**Hard boundaries beyond the usual.** You never deploy: the orchestrator deploys D4 after your
hand-back, when the deploy gate is open. You never write to staging's or production's database.
You never run a collection and you make **no network request at all**: no image is fetched from
any host, no robots.txt is read; a hero image is either one AW3 already serves or none. You never
commit a file under `uploads/`, `notes/` or `.logs/runs/`. You never edit `.app.env`, `.env`,
`.bw-auth.env`, `app/vendor/*`, `web/src/vendor/*`, `main/check.sh` or `docs-check.sh`. The
page-status badge is never emitted by `seo.py` or any served body; a sample article is never
imported without `--sample`; no client-facing sentence carries an em dash, "cheap" or "free";
never a bare "product" (product line, product variant).

Tell rian as you go with `srv-gw notify --from "AW5" "<one line>"`: on start (`"AW5 starting: 5
tasks, launch surface"`), after each task done with the count (`"AW5.2 done (2/5): ten samples
written, flagged, commands listed"`), on blocked, and at hand-back (`"AW5 done: 5/5, check green,
handoff written; D4 may deploy"`). Never put a secret, an address from the subscribers table or a
URL with a token 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 AW5" --blocks AW5.<n> --weight
costly --title ... --detail ... --option ... --assumption ...`) with the options, the assumption
you are proceeding under and what you would have to redo, mark it critical or not in your
hand-back, and carry on with everything that does not depend on it. The three questions in the
brief already carry their assumptions; raise them as items only if the code forces a different
answer.

If a task turns out to need more than about three hours, split it, record the split on /plan 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-deploy
backfill (`backfill level_permissions`), the ten import commands and the publish line for the
orchestrator to run on staging after D4, the launch step (`articles unpublish --samples`), the
numbers from the copy, what rian must decide, and "AW5 green and ready". Add the CHANGELOG lines
under `## Unreleased`. Then stop; the orchestrator deploys.

```
/goal Stream AW5 is complete: every task AW5.1 to AW5.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 "AW5:"; the rehearsal in AW5.5 has been run on a restored copy and its numbers are in the handoff with the import commands and the launch step; the migration's down_revision is the head alembic heads printed before it was written and alembic heads prints exactly one head on the final tree; the page-status read answers the four words and is refused to anonymous and member-level callers; no served body contains the badge; the ten samples are flagged; /articles renders server-side and is noindex until named in INDEXED_PAGES; nothing was deployed, staging's database was never written, no collection ran and no network request was made. Or stop after 120 turns.
```
