Skip to content

Commit d8cb711

Browse files
committed
docs(resources): all four kinds have a canonical view
The rules, CLAUDE.md and the migration doc all still described `table` as the holdout and the table unit as "view layer only". Corrects the status table, and two claims that are now wrong in a way that would mislead: - "A view is read-only; the shell writes." That was a staging point during the migration, never a rule — `FileView` edited from the start, and `TableView` does now. What a view must not hold is route context, not mutations. - "`table-grid.tsx` never moved, and did not need to." True of the first pass. It moved in the second, intact, and the ordering is the lesson worth keeping: the context reads were severed *in place* first, so R6 was already 0 before a single file changed directory. The 61-file move then carried no semantic risk. Reversed, four behavioural edits would have been buried inside a rename diff. Also drops the "mothership still mounts the whole editing page" note from the open list — it mounts `TableView` against a source now, like files and logs.
1 parent 901ace8 commit d8cb711

4 files changed

Lines changed: 26 additions & 18 deletions

File tree

.claude/rules/sim-resource-views.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,12 @@ everywhere else in the app. The one exception is a folder's own `index.ts`
5454
naming its siblings, which stays relative (`./<child>`) — it is describing its
5555
own directory, not reaching across the app.
5656

57-
`table-view` is the one unit with no `<unit>.tsx`, and deliberately so: a table
58-
has no read-only surface yet, because everything that draws a grid today also
59-
writes one. It is absent from `CANONICAL_UNITS`' view list for exactly that
60-
reason, and carries the layout above so a future `TableView` lands in the shape
61-
the other three already have.
57+
All four kinds have a canonical view: `FileView`, `TableView`, `LogView`,
58+
`KnowledgeView`. A view reads **and** writes — `FileView` edits, `TableView`
59+
edits — gated on `grants.write`. "The view is read-only and the shell writes"
60+
was a staging point during the migration, never a rule.
6261

63-
A resource kind with no canonical view yet — `table` alone today — is simply **absent** from the view list in `CANONICAL_UNITS`. That is the correct state for an unmigrated kind. Do not add a flag, a shim, or a placeholder entry for it.
62+
A kind with no canonical view would simply be **absent** from the view list in `CANONICAL_UNITS` — that is the correct state for an unmigrated kind, not a flag, a shim, or a placeholder entry. Every kind has one today, so the list is full.
6463

6564
## Consume: construct the axes, then mount
6665

.cursor/rules/sim-resource-views.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ apps/sim/resources/ # kinds/source/grants/host — pure TS, N
2727
apps/sim/components/resources/<unit>/ # 'use client' — THE view, one per resource
2828
```
2929

30-
A kind with no canonical view yet — `table` alone today — is simply absent from the view list in the check’s `CANONICAL_UNITS`. Do not add a flag, shim, or placeholder for it.
30+
All four kinds have a canonical view. A kind without one would simply be absent from the view list in the check’s `CANONICAL_UNITS` not a flag, shim, or placeholder.
3131

3232
## Consume: construct, then mount
3333

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ Views are mounted against exactly **three axes**, defined in `apps/sim/resources
425425
- `grants` — what this viewer may do: `{ write, run, manage }`, plus `settled` (whether those three are final, or still resolving — a denied member and a loading one are otherwise indistinguishable). Replaces `canEdit`, `canRun`, `canAdmin`, `disableEdit/Insert/Delete`.
426426
- `host` — who owns the URL, the router, the document frame: `'page' | 'panel' | 'public'`. Replaces `embedded`. `hostOwnsUrl(host)` is the one place the "embedded views do not write nuqs keys" rule lives.
427427

428-
There is no fourth axis; agent streaming is one optional prop on `FileView`. Consumers CONSTRUCT the axes and MOUNT the view — never wrap it in a passthrough, never reach past its barrel, never reimplement its UI because it lacks a seam (add the seam), never import `@/app/workspace/[workspaceId]/**` from an anonymous surface (`app/f/**`, `app/(interfaces)/**`), and never read `useRouter`/`useParams`/`useQueryState`/`useUserPermissionsContext` inside a unit. A kind with no canonical view yet — `table` alone today — is simply absent from the view list in the check's `CANONICAL_UNITS` — no flag, shim, or placeholder. Every unit has the same layout (`<unit>.tsx` · `index.ts` · `components/<child>/` · `hooks/` · `utils/` · `types.ts`), so moving between them costs nothing.
428+
There is no fourth axis; agent streaming is one optional prop on `FileView`. Consumers CONSTRUCT the axes and MOUNT the view — never wrap it in a passthrough, never reach past its barrel, never reimplement its UI because it lacks a seam (add the seam), never import `@/app/workspace/[workspaceId]/**` from an anonymous surface (`app/f/**`, `app/(interfaces)/**`), and never read `useRouter`/`useParams`/`useQueryState`/`useUserPermissionsContext` inside a unit. All four kinds have a canonical view, and a view reads and writes (gated on `grants.write`) rather than deferring mutations to a shell. A kind without one would simply be absent from the view list in the check's `CANONICAL_UNITS` — no flag, shim, or placeholder. Every unit has the same layout (`<unit>.tsx` · `index.ts` · `components/<child>/` · `hooks/` · `utils/` · `types.ts`), so moving between them costs nothing.
429429

430430
Enforced by `bun run check:resources` (strict: `check:resources:strict`), which ratchets counters for wrappers, imports past a barrel, cross-tree imports, unsanctioned props, token-as-`workspaceId`, and context leaks. Escape hatches — reason mandatory, on the line directly above: `// boundary-resource-wrapper:`, `// boundary-resource-internal:`, `// boundary-resource-tree:`, `// boundary-resource-prop:`. Full rules in `.claude/rules/sim-resource-views.md`.
431431

apps/sim/components/resources/MIGRATING-RESOURCES.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ This is the migration plan.
1313
| Resource | Canonical view | Consumers today | Notes |
1414
| --- | --- | --- | --- |
1515
| **file** | `components/resources/file-view` | Files page, mothership panel, `/f/[token]` | Done. The reference implementation, and the only kind with a public surface. |
16-
| **table** | *view layer only* (`components/resources/table-view`) | tables page + mothership, via the editing shell that mounts its parts | Moved out of the route tree; no standalone read-only view has a consumer yet. |
17-
| **knowledge** | | knowledge page, mothership panel | No public consumer yet. |
18-
| **log** | | logs page, mothership panel, tables page | `LogDetailsContent` is already shared; it just leaks context. |
16+
| **table** | `components/resources/table-view` | tables page + mothership panel | Done. The view reads and writes; the route keeps `page`/`loading`/`error` and a ~50-line client shell. |
17+
| **knowledge** | `components/resources/knowledge-view` | knowledge page, mothership panel | Read surface done; the editing shell still lives in the route tree. |
18+
| **log** | `components/resources/log-view` | logs page, mothership panel, tables page | Done. The tables page mounts it directly for the execution slideout. |
1919
| **workflow** | *deliberately excluded* || Not a document. See "Why workflow is not a resource". |
2020
| **folder** | *not a resource* || Organisational structure inside files/knowledge, not a thing you render. |
2121

@@ -118,11 +118,17 @@ a pure `resolveCellRender()` returning a typed `CellRenderKind` union and a dumb
118118

119119
The move and the axes landed together. Two corrections to the plan below, learned by doing it:
120120

121-
- **`table-grid.tsx` never moved, and did not need to.** It reads `useParams()`,
122-
`useUserPermissionsContext()` and ten mutation hooks — it *is* the shell. Only what
123-
it renders moved out from under it: 18 files, ~3.4k lines, at ~100% rename
124-
similarity. Splitting the grid was never a prerequisite for giving the view layer
125-
an address.
121+
- **`table-grid.tsx` did not move in the first pass, and did not need to.** It read
122+
`useParams()`, `useUserPermissionsContext()` and ten mutation hooks — it *was* the
123+
shell. Only what it renders moved out from under it: 18 files, ~3.4k lines, at
124+
~100% rename similarity. Splitting the grid was never a prerequisite for giving the
125+
view layer an address.
126+
127+
It moved in the second pass, intact, once the context reads were severed in place
128+
first. That ordering is the lesson: with the router, params and permission context
129+
already gone, R6 was 0 *before* a single file changed directory, so the 61-file
130+
move carried no semantic risk. Doing it the other way round would have buried four
131+
behavioral edits inside a rename diff.
126132
- **The move needed four unblocking changes first**, each worth landing alone:
127133
`StatusBadge` out of `logs/utils` (it dragged the block registry into every table
128134
cell), `ChatMessageContext` read from its definition, `RemoteTableSelection` lifted
@@ -131,8 +137,11 @@ The move and the axes landed together. Two corrections to the plan below, learne
131137
the write path regardless of `isEditing`.
132138

133139
Still open: the public surface (a token-scoped rows route plus a seed — see step 5),
134-
the mothership panel (still mounts the whole editing page — a product decision, not a
135-
refactor), and the row page-size split documented on `TABLE_VIEW_PAGE_SIZE`.
140+
and the row page-size split documented on `TABLE_VIEW_PAGE_SIZE`.
141+
142+
The mothership panel no longer mounts the editing page. It mounts `TableView` against
143+
a source, exactly as it does for files and logs — which also stopped it writing
144+
`?sort` / `?dir` / `?table-view` into the host page's address bar.
136145

137146
### Original sequencing — three PRs, not one
138147

0 commit comments

Comments
 (0)