# W36 — the Bag, and two live board bugs

Four Requests are bagged (#39, #40, #41, #42). This wave takes three of them plus the
vocabulary ruling; **#41 is W37** (Operator's build order, 2026-07-29).

Requests: **#39** the State-change ephemeral never clears and keeps acting · **#40** the
State select offers the State the Request is already in · **#42** `--file` reads as "send
this file as the Request" · plus the **Target → Bag** rename (Operator ruling, 2026-07-29)
and the Operator's own name missing from the index.

## The ruling, and what it costs

**Target becomes Bag. 🎯 becomes 🎒.** "A bag of Requests" — the collection an Alchemist
assembles a Milestone from. The old word collided with *build target* / *release target*
in ordinary prose, and that collision misread a live instruction on 2026-07-29.

Decisions I am taking under it, stated so they can be overruled:

1. **The verb becomes `bags`**, not `bag`. A bare `bag` is an imperative — the same trap
   `targets` fell into. `bags` is a plural noun: every Alchemist's Bag on this board. The
   answer leads with the noun phrase, `Bagged Requests in <owner/repo>`, never the bare word.
2. **Requirement ids keep their names** (`REQ-TARGET-REACTION`, `REQ-TARGETS-VERB`,
   `REQ-HAZARD-TARGET-RELOCATION-CARRY`); their titles are restated in the new vocabulary
   and the registry carries a one-line note that TARGET is the retired name of Bag. Ids are
   references — commits, ADRs, issues and plans point at them — while the glossary is where
   vocabulary lives. Renaming them dangles every existing reference to buy a grep hit.
3. **Module and symbol names follow the glossary**: `targets.rs` → `bag.rs`,
   `targets_index.rs` → `bag_index.rs`, `TARGET_EMOJI` → `BAG_EMOJI`, `targets.json` →
   `bag.json`. Code that reads in the retired word is the drift the glossary exists to stop.

## The hazard this rename creates, and the fix

**Four live Bags are 🎯 reactions right now.** A rename that only swaps the constant would
read 🎒, find none, and every one of them would vanish — silently, which is the loss class
this project refuses. And the bot **cannot** re-place a member's reaction: `create_reaction`
posts as the bot alone (the platform fact `REQ-HAZARD-TARGET-RELOCATION-CARRY` already
turns on). So a member's 🎯 can never become their 🎒.

It does not have to. The carried line is a field **the daemon writes**, and it already
means "this Alchemist bagged this Request without holding a reaction here". So the
migration is the relocation carry, run once:

> For each card in Backlog/Eval, any roster member holding 🎯 is folded into the card's
> carried line; then the bot removes their 🎯 (the one reaction write the platform allows
> on a member's behalf) and its own 🎯 seed; then it seeds 🎒.

Ordering is the carry's own: **write the card first, remove the reaction second** — a crash
between them leaves the Request bagged twice over, never dropped. Idempotent by
construction: a card with no 🎯 left asks for nothing. This is a `REQ-HAZARD-*` in its own
right — a vocabulary change that eats live state is the failure, and the test replays the
migration twice.

## Tasks

### T1 — the doc stage
- `CONTEXT.md`: Target → Bag throughout (the glossary entry, the staging post, Finalize,
  the card head block), 🎯 → 🎒, and `targets` → `bags` on the vocabulary line.
- `traceable-reqs.toml`: restate the three titles; add the retired-name note; register
  `REQ-HAZARD-BAG-EMOJI-MIGRATION` (`doc`/`impl`/`unit`) for the fold above.
- `docs/KNOWN-HAZARDS.md`: the migration entry.
- `CHANGELOG.md` language: the user-facing text says "picks" today while the model said
  "Target" — both retire to Bag, so the board and the changelog speak one word.

### T2 — the rename and the migration · `REQ-HAZARD-BAG-EMOJI-MIGRATION`
- Modules, symbols, emoji, index filename, `bags` capability (manifest + arg table +
  CONTEXT vocabulary line move together or `REQ-VOCAB-PARITY` fails).
- `bag::migrate_legacy(card, reactors, roster) -> Resolution`-shaped decision, folded into
  the reconcile's existing keep-branch so it costs no extra call: the cards are already
  read, and a card whose 🎯 count is the bot's seed alone needs no roster call.
- Tests: a live 🎯 Bag survives as a carried Bag and the 🎯 comes off; a second pass writes
  nothing; a non-Alchemist's 🎯 is left alone (inert then, inert now); the bot's own stale
  seed is cleared.

### T3 — the Operator has no name in the index
The bot owner is an Alchemist **by construction** (`reconcile::target_roster` adds them) and
holds no Alchemist role, so `role_members_named` cannot name them and the verb prints a raw
snowflake. Name them from the guild member read the roster already makes; fall back to the
id only when the member genuinely cannot be read. Rides `REQ-TARGETS-VERB`.

### T4 — #39: the State ephemeral neither clears nor stops acting
Today the select's pick answers `Acknowledge`, which leaves the ephemeral standing **with a
live select in it** — so every further pick fires another State write at a Request that has
already relocated. Fix, in the select and confirm branches both:
- Answer with `UpdateMessage`: the ephemeral's content becomes the outcome and its
  components are **removed**, so there is nothing left to click. This still answers inside
  Discord's three-second window, exactly as `Acknowledge` did.
- On success, delete the ephemeral once the card is refreshed — the refreshed card is the
  acknowledgement (`REQ-EDIT-QUIET-ON-SUCCESS`), so a lingering panel is a second answer.
  On failure it stays, carrying what broke.
- Rides `REQ-CARD-STATE-CONTROL`; the requirement's title gains the terminal-panel property.

### T5 — #40: the select offers the State the Request is already in
`state_choices()` omits Greenlit only. Read the current State from the **card's own badge
line** — the card the button sits on is in hand, so this costs no fetch — and drop it from
the options. And refuse it **by name** on arrival, because a select's values are
client-supplied and the offered vocabulary is only what a member sees (the rule Greenlit
already follows). Rides `REQ-CARD-STATE-CONTROL`.

### T6 — #42: route it, do not build it
`--file` is **spt-core's** flag on `spt shell send`; alchemy only ever sees the resulting
`shell_file` frame (`frames.rs:53`). Renaming it is doyle's surface, not mine — and the
confusion is real and measured: on 2026-07-29 I ran `spt shell send alchemy-0 --file req.txt`
expecting the file to BE the Request and it staged an attachment instead, which is the
incident this Request was minted from. Raise with doyle with that evidence; the Request
routes out rather than sitting in a Backlog that cannot deliver it.

### T7 — gate and ship
`cargo test` green · `traceable-reqs check` exit 0 · v0.13.0 published, installed, and the
**migration verified on the live board**: the Operator's four Bags still bagged, now on the
carried line, with 🎒 seeded and no 🎯 left.

## Gate

Evidence tagged in the same commit as the code; behavior verified against the installed
binary and the live board, never a green assertion alone.

## Acceptance

#39 and #40 are board acts — the Operator's read closes them. #42 closes on doyle's ruling.
The rename closes when the four live Bags survive it, which is measurable from the index
and the board without a human clicking anything.
