# caddie — changelog

Newest first. The version at `/api/meta` and in the SPA footer is how you
confirm a deploy landed.

## 0.4.3 — new passwords from the owner (2026-09-10)

- Re-vendored the BW Auth pack. Admin, People: the owner can give a member a new
  password (the "New password" button), shown once with a copy button for your own
  email; nothing is emailed and they are signed out everywhere. It works for
  accounts used only in this app; broader accounts are reset from
  auth.bowden.works/admin. Adding a person with no BW account can also create them
  with a generated password instead of an invite email. Refusals from the auth
  service now say why instead of a bare HTTP 400.

## 0.4.2 — password reset lands back on the app (2026-09-07)

- Re-vendored the BW-Auth React pack: the sign-in screen's "Forgot password?" link
  now carries `?next=<this app's root>`, so a reset started here returns to
  caddie (signed in) instead of the central account page. Auth-core change;
  nothing caddie-specific.

## 0.4.1 — the shell revalidates (2026-09-02)

- `index.html` is served with `Cache-Control: no-cache`. Found by the visual
  pass on 0.4.0: a plain visit to `/` kept rendering the previous bundle
  while a cache-busted URL showed the new one. The shell names the hashed
  bundles, so a cached shell after a deploy points at files the image no
  longer has (0.3.2 stopped carrying old bundles). Same gap in the
  scaffolder's template `main.py` — logged in `v8-feedback.md`.

## 0.4.0 — up to the standards caddie publishes (2026-09-02)

The easel build's two proposals and its 14-rule standards review, read and
decided (`.logs/planning/07-easel-coordination.md` has the verdicts). Caddie
now wears the chrome it asks every tool to wear, and its conversation layer
carries the whole of 04 §3–4.

- **The `caddie-ui` pack is canonical, and lives here** — `packs/caddie-ui/`
  (v1.1.0), stamped into any app by `packs/stamp-caddie-ui.sh <workspace>`
  and verified byte-for-byte with `--check`. Pack changes on the way in:
  `ThreadStarter`, the `decision` kind in the bell, `domId` + the settle wash
  for deep links, `PACK_VERSION`.
- **Caddie's own chrome is the pack's**: the two-row shell (global row with
  brand · locator · bell · account menu; the project page's own row with the
  Timeline/Reference navigator and the one panel toggle), the one side panel
  as the Discussion, the pack's bell, `Prose` for stage and reference bodies,
  the `Stages` rail, a lightbox for attachments. `md.tsx` and
  `StageComments.tsx` are gone.
- **The Discussion lists every subject** — the project as a whole, then each
  visible stage — as a card with its conversation inline under Reply, or a
  starter when nobody has spoken. A card goes to its stage; stage rows carry
  only a count chip. Filter all / open / resolved; re-file a conversation
  between subjects; edit your own words; remove (soft) your own or, as the
  agency, anyone's.
- **04 §3–4 on the backend**: the project is a subject
  (`POST /api/projects/{id}/comments`); one discussion read per page
  (`GET /api/projects/{id}/discussion`); resolve / reopen
  (`POST /api/threads/{id}/resolve`) with the notifications a thread raised
  flagged `resolved` and a `resolved` event to the people in it; edit
  (`PUT /api/comments/{id}`), soft delete (`DELETE`), move
  (`POST /api/threads/{id}/move`). Migration `0003_conversation_state`.
- **Labels are breadcrumbs** (`{project} › {stage}`), and an approval rings
  as a `decision`, not `status` — it closes a loop, so it is never "needs you".
- **The page speaks to the person**: `/api/whoami` carries `first_name`,
  `display_name`, `is_agency` (from the directory, cached; derived from the
  username when the directory has nothing). "Hi Dana — one thing needs you."
- **The client reads both error shapes** (`apiError()`), so the middleware's
  "viewing as someone else, read-only" sentence reaches the person instead of
  "Request failed (403)".
- Attachments ride on project comments too: `/api/attachments/{subject}`
  takes a stage OR a project, visibility re-checked through whichever owns it.
- `tests/test_discussion.py` (10 tests); the M1 gate and the interaction tests
  updated for breadcrumbs and `decision`.

## 0.3.2 — the image stops carrying stale bundles (2026-08-24)

- Added `main/.dockerignore`. The runtime stage COPYs `app/` and *then* the
  freshly built SPA over it, and Docker COPY **merges** into an existing
  directory — so every host-side `npm run build` was leaving its old
  `index-*.js`/`.css` inside the image alongside the real one. `index.html`
  always pointed at the right pair, so nothing was ever mis-served; the dead
  weight and the ambiguity are what's gone.

## 0.3.1 — the deep link actually lands (2026-08-24)

- A bell row's `?stage=…#c-…` now **opens that stage and scrolls to that
  comment**, which settles out of a wash rather than flashing. The anchor only
  exists once comments load, so the jump waits for the data, not the mount.
- **`tests/test_m1_gate.py`** walks the whole M1 gate as one narrative, so a
  later change that breaks it fails here instead of in front of a client.

## 0.3.0 — the agency's own surfaces (2026-08-24)

- **Comment attachments.** Paste a screenshot straight into the composer, or
  use the paperclip. Allow-list + magic-byte check + stored under a uuid name;
  a file's URL is **not** a capability — every read re-checks the owning
  stage, so the exact link in the wrong hands still 404s.
- **The dictionary picker.** Adding a data point is a *search*, results carry
  their usage count, and "create it" is the secondary action that near-matches
  interrupt (D15). The type vocabulary is served by the API so the picker can't
  drift from what the server accepts.
- **Reference sections are editable** — write it internal, publish it when it's
  right. `PUT`/`DELETE` added; the credential lint warns and never blocks.
- A `select` field's `options` now travel with its value, so the editor never
  has to fetch the definition to draw itself.

## 0.2.1 — the Interaction kit (2026-08-24)

Threads, server-side mentions, one bell, the 04 §5 event shape stored whole so
the shared inbox is a repoint rather than a migration.

## 0.2.0 — the spine (2026-08-24)

Projects, concurrent stages, the field dictionary, reference sections,
approvals, activity, templates. Postgres + Alembic.

## 0.1.0 — scaffold

`new-bw-app.sh` baseline: BW sign-in, levels, invites, View As, access matrix.
