Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/development/agent-experience-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -4252,3 +4252,13 @@ It is not one. The watchdog counts a spawn as started when it writes any stdout
**Repair:** none in this entry. A claude turn whose provider hangs is bounded only by `COMMONLY_AGENT_RUN_TIMEOUT_MS` (45 min on seats), and the supervised path keeps claude's stall window off because its stdout is silent until the reply is done.

**Lesson:** "first output" and "still making progress" are different signals. Before citing a watchdog as hang coverage, name the exact signal it reads and check which hang shapes produce that signal. A transcript row written before the first network round trip proves the process started, not that the model is answering.

## 89. The `V2Message` type has no `pgId`, and every chat message carries one (2026-11-01, stack)

*Origin: a CodeRabbit finding on #3148, which I first dismissed with "the message shape has no `pgId` field".*

The frontend type `V2Message` (`frontend/src/v2/hooks/useV2PodDetail.ts`) declares `id` and `thread_root_id`, and no `pgId`. The API sends one. `formatMessage` (`backend/models/pg/Message.ts`) returns `id: legacy_mongo_id || pgId` and a separate `pgId`, and `normalizeMessage` spreads the raw message, so `pgId` reaches every component at runtime. For a row reconciled from Mongo the two ids differ. Its `id` is the old Mongo id, while replies point at it through `thread_root_id`, which is always the Postgres id. So code that matches a reply's `thread_root_id` against `message.id` misses every reconciled root, and nothing in the type says so.

**Repair:** #3148 indexes the Threads panel's roots by both ids, and its rows keep the exposed `id`, the one the `#message-<id>` anchor uses. `frontend/src/v2/utils/threadView.ts` still matches roots by `m.id` alone (`idOf`). It is the same gap and has not been fixed.

**Lesson:** a field missing from a consumer's type says nothing about the payload. To claim a field is absent, read the producer: here the backend formatter, not the frontend interface.
9 changes: 8 additions & 1 deletion frontend/src/v2/primitives/primitives.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
the artboard's short names map as: --sf surface, --t surface-tint, --d
border-soft, --b border, --mu text-muted, --se text-secondary, --ph
text-placeholder, --ink text-primary, --ink2 ink-2, --g page-bg, --c accent.
Pinned by __tests__/v2Primitives.test.tsx. */
Pinned by __tests__/v2Primitives.test.tsx.

Adopting a primitive (#3154): a `.v2-root button.<class>` rule in v2.css
(0,2,1) outranks every one-class v2p- rule (0,1,0), so adding the class is not
enough. Delete the element's bespoke look (size, border, fill, radius, colour,
hover, focus) and keep only layout and states the primitive lacks: :disabled
(no primitive has one) and a focus ring wherever a later rule sets
box-shadow. */

/* ---- page wrapper for the showcase route ---- */
.v2p-root { height: 100%; min-height: 0; display: flex; flex-direction: column; }
Expand Down
Loading