---
type: plan
title: Easel coordination — the verdicts on the pack proposal and standards review 2
slug: easel-coordination
status: active
owner: rian
created: 2026-09-02
related:
  - /srv/apps/easel/.logs/planning/caddie-ui-standard-proposal.md
  - /srv/apps/easel/.logs/planning/caddie-standards-review-2.md
  - /srv/apps/caddie/.logs/planning/04-interaction-standard.md
  - /srv/apps/caddie/.logs/planning/02-tool-contract.md
  - /srv/apps/caddie/.logs/planning/05-building-a-caddie-app.md
summary: >
  Caddie's answer to the easel session's two proposals and its fourteen-version
  standards review (2026-09-02): what was adopted and where it landed, what was
  adopted with a change, what was declined and why, what is deferred, and the
  one decision left for rian. Hand this path to the easel session; its asks
  back to easel are at the end.
---

# Easel coordination — verdicts (caddie 0.4.0)

## Adopted, and where it landed

| Proposal | Verdict | Where |
|---|---|---|
| The `caddie-ui` pack as canonical, stamped like `bw-admin` | **Adopted.** Canonical copy is `/srv/apps/caddie/packs/caddie-ui/` (v1.1.0); `packs/stamp-caddie-ui.sh <workspace>` stamps, `--check` verifies byte-identity. Open question 5 answered. | 04 §6, 05 §2/§3a, D16 |
| Caddie's own Bell and StageComments become pack consumers | **Done.** Two-row shell, the pack's bell behind a 30-line adapter, the one side panel as the Discussion, `Prose`/`Body`/`Lightbox`/`Stages`. `md.tsx` and `StageComments.tsx` deleted. | caddie 0.4.0 |
| The host bar renders INTO the global row's locator | **Adopted.** | 02 §6, §10 |
| `decision` as a notification kind | **Adopted.** Caddie's approvals emit it; the pack's bell speaks it; only `mention`/`turn` are "needs you". | 04 §5 |
| Subjects are plural; anything a person can look at is one | **Adopted**, and extended: the WORK SURFACE itself is a subject — caddie's project page has a project-level conversation. Open question 3 answered: the page is a subject of whoever owns the page. | 04 §4.1, D18 |
| One discussion read per work surface | **Adopted.** `GET /api/projects/{id}/discussion`; `discussion_of()` in the reference service. | 04 §4.1 |
| Re-file a conversation (`move`) | **Adopted**, with the delete-orphan note and a rule that old deep links still land (the client resolves `#c-{id}` by comment id). | 04 §4.1 |
| Starters, breadcrumb labels, the list stays a list, the lightbox, one mode not a toggle, one panel by state, Escape across frames, the measured bottom, panel push | **Adopted** as standard text. `ThreadStarter` became a pack PIECE (it was a rule with no component, so easel hand-rolled `dp-starter`). | 04 §6, 05 §3a |
| The item in a sequence is the root of its conversation; anchored feedback (point/area, draft on press, movable after) | **Adopted** as standard text; nothing for caddie to build. | 04 §4.1 |
| The composer holds the file; markdown appended on Send | **Adopted**; the addendum's wording corrected. | 04 addendum |
| The round-closer rings twice (`turn` + outbound) | **Adopted.** | 04 §5 |
| The journey rule (a tool's landing page is the project's journey); stage prose is the team's, per project; the page speaks to the person | **Adopted.** Caddie's page draws the `Stages` rail with a read-selection distinct from the active stage, greets by first name, renders stage prose with `Prose`. | 01 §4, 05 §3a |
| The tool introduction is a walkthrough that starts and closes on the project page; the `?tour=1` / `?intro=1` / `?tour=done` hand-off; no popup gate | **Adopted** into the contract. Open question 2 answered: caddie runs the opening and the close, the tool the middle. Nothing built in caddie yet (it has no tour). | 02 §6, D20 |
| Display name in `/api/me` | **Adopted** as a kit ask (logged in caddie's `v8-feedback.md`); meanwhile caddie's `/api/whoami` carries `first_name`/`display_name`/`is_agency` from the directory (cached), derived from the username as a fallback. Open question 4 answered for caddie; the kit still owes it. | 05 §3a |
| The client parses both error shapes | **Adopted** in caddie's client (`apiError()`), and logged as a kit ask for the react-admin pack's own `bwApi.ts`. | 05 §3a |
| Background-tab rule; deploy gate; two-sessions-one-tree; null guards; content as data | **Adopted** as engineering practice. | 05 §3b |
| Stages hand-over (open question 1) | **Decided:** caddie PUSHES the client-visible stage rail on provision and every reconcile; the tool holds a read-only mirror; caddie seeds from templates; a standalone tool seeds its own in the same shape. Rejected: a live read per page view. | 02 §2, D19 |

## Adopted with a change

- **The pack changed on its way to canonical (1.0.0 → 1.1.0):** `ThreadStarter`
  added; `decision` in the bell's sentences; `domId` on `ThreadRow` and
  `ThreadReply` plus an `is-settling`/`is-target` wash so a deep link lands on
  the exact comment and settles rather than flashes; `PACK_VERSION` exported;
  `.cu-starter` added to the token roots. The README carries a changelog.
- **Resolve / edit / soft-delete** were written into caddie's reference service
  in the standard's own shape (04 §4's `resolved`, `edited_at`, `deleted_at`),
  so the eventual `bw_interaction` extraction carries them.

## Declined

- **`client_closed_round_at` in the status report (02 §5).** The report body
  is frozen at the six states + counts + one line + seq (D9); the moment caddie
  grows a per-tool field the contract has failed. "Feedback complete" is the
  client saying the ball is with the agency — the tool records it and reports
  `waiting_agency`; presenting again reports `waiting_client`. The rule (a
  tool never infers "they are done" from silence) is in 02 §5 and D17. Easel
  keeps `feedback_completed_at` as its own; nothing to change there.

## Deferred

- **`Highlight`, `Tour`, `InlineThread` as pack pieces.** They have one
  consumer. They stay in easel as the pack candidates the review lists; the
  second tool with a walkthrough lifts them into `packs/caddie-ui/` — at
  which point the rule "no coach-mark bubbles; the panel is always there"
  gets a component to point at.
- **`bw_interaction` as a vendorable drop-in.** Caddie's
  `app/services/interaction.py` is now complete for 04 §3–4 and is the
  extraction source; the extraction itself is M2 work alongside
  `caddie_tool.py`.
- **Migrating punchlist to the pack.** Asked in `06-punchlist-coordination.md`
  (addendum 2026-09-02); punchlist's session does it.

## Left for rian

- **Anonymous commenters** (easel's `caddie-rebuild-scope.md` §5): "anonymous
  is a first-class commenter, never a member" fits both standards, but it
  decides a schema and needs the owner's word before anything is built on it.
- The two substrate items already in `/srv/.logs/ideas.md`
  (`srv-gw exec`, a mockup-serving subdomain) — not caddie's.

## Asks back to the easel session

1. **Re-stamp the pack from caddie's canonical copy** and delete easel's
   hand-rolled starter:
   ```bash
   /srv/apps/caddie/packs/stamp-caddie-ui.sh /srv/apps/easel
   /srv/apps/caddie/packs/stamp-caddie-ui.sh /srv/apps/easel --check
   ```
   Then replace `dp-starter` with the pack's `ThreadStarter`, and pass
   `domId` on rows so notification deep links settle on the comment.
   From here, a change that is right for easel goes to
   `/srv/apps/caddie/packs/caddie-ui/` (bump `PACK_VERSION`, README changelog
   line), then re-stamps — never into easel's copy.
2. **Emit `decision`** where a direction is picked or a point approved (the
   review's own ask), instead of `turn`/`status`.
3. **Report the round-closer as `waiting_agency`**, not as a new field; keep
   `feedback_completed_at` in easel.
4. **Hold `project_stages` as you do** until the contract's provision sends
   the rail (02 §2); then read the mirror and drop the seeding.
5. The `?tour=1` / `?intro=1` / `?tour=done` hand-off is now the contract's
   text (02 §6) — keep the URLs as they are.
6. Nothing else changes for easel today; the standards say what easel already
   does.
