record the close of §4
This commit is contained in:
@@ -193,9 +193,9 @@ malformed row turning that into a white screen loses the result at the one momen
|
||||
`config` added a new unvalidated field to an already-unvalidated tree. The work itself is safe in
|
||||
`chat_session_events`, which is why recovery must offer "restore default layout" rather than SQL._
|
||||
|
||||
**The first three are resolved — `64961d4` (the boundary) and `ef036df` (the other two).** §4 is the last
|
||||
Tier A item that was still whole; what is left of it is validate-on-write, below, which is the cheap half
|
||||
of a rule now enforced on both sides of the wire but nowhere in the database.
|
||||
**§4 is closed** — `64961d4` (the boundary), `ef036df` (validate-on-read and the `'[]'` default),
|
||||
`92b8905` (validate-on-write). "A layout is an object" is now stated in four places: the column, the
|
||||
route, the read, and the renderer's willingness to survive being handed something else anyway.
|
||||
|
||||
- [x] **Add an error boundary.** `grep -rln "componentDidCatch\|getDerivedStateFromError\|ErrorBoundary\|errorElement" src` returned **nothing**
|
||||
across the whole repo.
|
||||
@@ -231,11 +231,24 @@ of a rule now enforced on both sides of the wire but nowhere in the database.
|
||||
omitted too. `bun db:push` planned exactly the four expected `ALTER`s plus the two known-harmless
|
||||
`pk_music_now_playing` lines.
|
||||
|
||||
- [ ] **Validate on write.** The whole path is `unknown`: `useDashboardState.ts:46` →
|
||||
- [x] **Validate on write.** The whole path is `unknown`: `useDashboardState.ts:46` →
|
||||
`servers/api/dashboards/dashboards.ts:45,83` → `queries/dashboards.ts:51,97` → cast `as never` at
|
||||
`:114` to satisfy drizzle → jsonb. No zod, no CHECK on any of the three layout columns. Given
|
||||
`:114` to satisfy drizzle → jsonb. No zod, no CHECK on either layout column. Given
|
||||
`databases/CLAUDE.md`'s stance that the schema is the source of truth for _contents_, a CHECK on
|
||||
`jsonb_typeof(layout) = 'object'` is the cheap half.
|
||||
**Resolved `92b8905`** — both halves, because they do different jobs.
|
||||
`ck_dashboards_layout_object` / `ck_screens_layout_object` are the backstop: nothing reaches those
|
||||
columns without passing them, including a psql session or a future writer nobody has written yet.
|
||||
NULL stays legal — it means "none stored", which is the honest state of a dashboard created without
|
||||
a layout. But a constraint violation surfaces as a 500 that tells the caller nothing, so the PATCH
|
||||
dispatcher checks the same rule first and answers `400 "ws-layout-x" must be a layout object`.
|
||||
Deliberately **not** a full `LayoutNode` schema: this is the wrong-container class of bug — the one
|
||||
that crashes `normalizeLayout` — and a structural validator would need the client's `zoom`/`config`
|
||||
vocabulary in the database layer to say anything more.
|
||||
Verified live: `db:push` planned exactly the two `ADD CONSTRAINT`s plus the known
|
||||
`pk_music_now_playing` churn and was stable on a second run; `update … set layout = '[]'` and
|
||||
`= '3'` are both rejected by Postgres; array, number and string bodies to `ws-layout-{id}` and
|
||||
`screens/{name}` all 400, and an object still round-trips.
|
||||
|
||||
- [x] **A bare number is squatting in a framework namespace.** _(verified in the live DB)_
|
||||
`apps/Soulseek/shared.ts:12` built `screens/soulseek-zoom/${panelId}` and passed it to
|
||||
@@ -579,8 +592,7 @@ _(move items here with the commit and a one-line resolution)_
|
||||
layers, none of which was enforcing anything before: the columns stopped defaulting to a value that
|
||||
could not be a layout, the read stopped handing over one that is not, and the render stopped taking
|
||||
the whole app down when something else does. Per-item detail in §4.
|
||||
What this does **not** do is validate on write — §4's last open item. The database will still accept
|
||||
any jsonb at all; the two new guards mean it can no longer reach a renderer.
|
||||
What this did **not** do is validate on write; that followed in `92b8905`, closing §4.
|
||||
|
||||
- [x] **A layout write can no longer be quietly undone by an older one.** _(`b0a32ae` + `81ad3ef`, branch
|
||||
`agent-coordination-mvp`)_ — Tier A5 and A7, and with them the whole of §5.5, which empties Tier A.
|
||||
@@ -596,6 +608,11 @@ _(move items here with the commit and a one-line resolution)_
|
||||
`config` — the panel that was just given an agent's name goes anonymous, and the agent stops being
|
||||
addressable through it.
|
||||
|
||||
- [x] **A layout column cannot hold a non-layout.** _(`92b8905`, branch `agent-coordination-mvp`)_ —
|
||||
§4's last item, and the end of §4. A CHECK on each layout column (NULL or `jsonb_typeof = 'object'`)
|
||||
plus the same rule in the PATCH dispatcher, so the caller gets a 400 naming the key rather than a
|
||||
500 naming nothing. Detail in §4.
|
||||
|
||||
---
|
||||
|
||||
## 8. Dead code sweep
|
||||
|
||||
Reference in New Issue
Block a user