# ticket — v8 substrate feedback

> Running log of friction hit while building **inside** the v8 conventions.
> **This is feedback about the substrate, not about this project** — it gets
> compiled into `/srv/.logs/planning/server-evolution-2026.md` or the ops queue
> (`/srv/.logs/ideas.md`) once the build settles.
>
> Scope discipline: only entries where the *server framework, standards library,
> or gateway* caused the friction. Bugs in this project's own code belong in
> `handoff.md`, not here.
>
> Each entry: what happened, what it cost, and a candidate fix.
> (Pattern proven 2026-07-30; it is what turns one project's
> pain into a standards fix for every later project. Delete this file if the
> project never hits substrate friction.)

## 2026-09-02 — planning session
- **No substrate convention for LLM API credentials.** Ticket is the first app
  on this box that calls the Claude API (grep of every `main/app`,
  `requirements.txt`, compose file: zero prior use). The BW-app scaffold has
  `.app.env` for app secrets, which works, but nothing says whether a per-app
  key, a shared gateway-held key with per-app caps (like the Resend pattern),
  or a proxy is the house rule. Cost: a decision made locally that the next
  AI-using app will remake. Candidate fix: one paragraph in `coding.md`
  (secrets) naming the pattern — per-app key in `.app.env`, usage logged per
  call — or a gateway endpoint mirroring the notifier's cap model.
- **Inbound email has no substrate path either.** Outbound goes through the
  gateway's Resend path; there is no receiving layer on the server. Ticket
  will stand one up app-locally (plan §4.1). If a second app wants mail in
  (the Interaction Standard's delivery seam replies, for instance), the
  webhook + sender-auth + raw-store trio is substrate-shaped. Logged for the
  evolution plan; not asking for anything yet.
