Skip to content

feat: database grid infinite scroll, honest row counts, column virtualization (0340) - #534

Merged
crs48 merged 6 commits into
mainfrom
claude/0340-grid-60fps-frontier-rows-columns-pagination-and
Jul 18, 2026
Merged

feat: database grid infinite scroll, honest row counts, column virtualization (0340)#534
crs48 merged 6 commits into
mainfrom
claude/0340-grid-60fps-frontier-rows-columns-pagination-and

Conversation

@crs48

@crs48 crs48 commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

Implements exploration 0340 (docs/explorations/0340_[x]GRID_60FPS_FRONTIER…md) — the render-side fixes measured in that doc:

  • Infinite scroll (rows): useGridDatabase replaces its fixed 500-row page with a growing window via useInfiniteQuery (pageSize 500, maxLoaded 2000), and GridSurface grows it from a reach-end sentinel. Window grows keep the grid mounted (masked loading), row models cache per node identity, and GridRow is memoized so grows re-render only new rows.
  • Honest footer: count: 'exact' folds the true total into the fused row query; the footer reads "2,000 of 10,000 rows" instead of presenting the window as the total. Client-side filtered/sorted views on capped windows are labeled "filtered within loaded rows".
  • Column virtualization: past 20 fields, GridSurface virtualizes columns (horizontal virtualizer, overscan 3, spacer cells) — vertical scrolling no longer mounts every column per overscan row.
  • useInfiniteQuery gains its first committed test coverage.

Validation (live app, Playwright Chromium, same harness as the exploration baseline)

Metric Before After
32-col vertical scroll 48fps, p95 42ms 80fps, p95 25ms (steady-state 17.6ms)
64-col 28fps, p95 92ms 75fps, p95 25ms
128-col 8.6fps, p50 142ms 60-68fps, p50 9.1ms
10k-row DB, scroll bottom stops at row 500, footer "500 rows" reaches row 2,000, footer "2,000 of 10,000 rows"
Heap after deep scroll 202MB 202MB (flat)

Changeset: @xnetjs/react minor. Changelog fragment included.

🤖 Generated with Claude Code

xNet Test and others added 6 commits July 17, 2026 18:59
useGridDatabase replaces its fixed 500-row page with a growing window
(pageSize 500, maxLoaded 2000) and exposes totalRowCount / hasMoreRows /
isFetchingMoreRows / fetchMoreRows. count:'exact' folds the true total
into the fused row query. Promotes the 0340 scratch verification into
useInfiniteQuery.test.tsx — the hook's first committed coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…tinel (0340)

Columns virtualize past 20 fields (horizontal useVirtualizer, overscan 3,
spacer cells) so vertical scrolling mounts a bounded cell window instead
of every column per overscan row - measured 8.6fps at 128 unvirtualized
columns. Footer reads 'N of M rows' from totalRowCount instead of
presenting the window size as the total, and onReachEnd fires near the
end of loaded rows for infinite scroll.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…atabase grid (0340)

DatabaseView passes totalRowCount/hasMoreRows/fetchMoreRows through to
GridSurface, and labels view filter/sort results 'filtered within loaded
rows' whenever more rows exist past the window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…(0340)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…0340)

Window grows no longer flip the grid's loading state (which unmounted the
surface to a skeleton and lost scroll position) - useGridDatabase now
reports the masked loading from useInfiniteQuery and surfaces the grow
via isFetchingMoreRows. Row models cache per node identity so a grow
rebuilds only new rows, and GridRow is memoized so unchanged visible rows
skip re-render entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…ion and infinite scroll

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
@crs48
crs48 temporarily deployed to pr-534 July 18, 2026 02:27 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

🖼️ UI changes in this PR

No visual differences detected in the changed UI.

CI run

github-actions Bot added a commit that referenced this pull request Jul 18, 2026
github-actions Bot added a commit that referenced this pull request Jul 18, 2026
@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Preview removed for PR #534.

github-actions Bot added a commit that referenced this pull request Jul 18, 2026
@crs48
crs48 merged commit c412211 into main Jul 18, 2026
21 checks passed
@crs48
crs48 deleted the claude/0340-grid-60fps-frontier-rows-columns-pagination-and branch July 18, 2026 02:35
github-actions Bot added a commit that referenced this pull request Jul 18, 2026
crs48 added a commit that referenced this pull request Jul 18, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @xnetjs/cli@0.2.0

### Minor Changes

- [#533](#533)
[`0a4a1de`](0a4a1de)
Thanks [@crs48](https://github.com/crs48)! - Agent Passports and signed
agent audit trails (exploration 0337).
- `@xnetjs/data`: new agent schema pack — `AgentPassport`,
`AgentSession`,
`AgentAction`, `AgentApproval`, `AgentNotification` — with deterministic
id
    helpers (`agentActionId`, …) and `redactInstruction`.
- `@xnetjs/identity`: `mintAgentPassport` / `verifyAgentPassport`
(per-agent
    `did:key` + operator-delegated, attenuation-checked UCAN; wildcards
    rejected) and `rootIssuers` for delegation-chain root inspection.
- `@xnetjs/plugins`: `AgentAuditRecorder` wraps the AI surface so every
tool
call lands as an `AgentAction` node and medium+ risk calls park behind a
risk-tiered approval ceremony (chat nonce with TTL for medium;
xNet-surface
only for high/critical); ceremony tools (`xnet_approve`, `xnet_deny`,
`xnet_pending_approvals`, `xnet_undo`) and the `xnet_poll_notifications`
outbox tool; `MCPServerConfig.agentAudit` wires it into the MCP server;
`NodeStoreAPI.create` now accepts an optional deterministic `id`; new AI
    scopes `agent.approve` and `agent.notifications`.
  - `@xnetjs/cli`: `xnet agent enroll <name>` mints and stores passports
(`~/.xnet/agents`, 0600) and prints OpenClaw/Hermes config; `xnet mcp
serve
--agent <name> [--db <path>]` serves an agent-scoped session over an
    agent-signed local store.

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/identity@2.1.0
  - @xnetjs/plugins@2.1.0
  - @xnetjs/runtime@0.5.1
  - @xnetjs/sync@2.1.0
  - @xnetjs/sqlite@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/data@2.1.0

### Minor Changes

- [#533](#533)
[`0a4a1de`](0a4a1de)
Thanks [@crs48](https://github.com/crs48)! - Agent Passports and signed
agent audit trails (exploration 0337).
- `@xnetjs/data`: new agent schema pack — `AgentPassport`,
`AgentSession`,
`AgentAction`, `AgentApproval`, `AgentNotification` — with deterministic
id
    helpers (`agentActionId`, …) and `redactInstruction`.
- `@xnetjs/identity`: `mintAgentPassport` / `verifyAgentPassport`
(per-agent
    `did:key` + operator-delegated, attenuation-checked UCAN; wildcards
    rejected) and `rootIssuers` for delegation-chain root inspection.
- `@xnetjs/plugins`: `AgentAuditRecorder` wraps the AI surface so every
tool
call lands as an `AgentAction` node and medium+ risk calls park behind a
risk-tiered approval ceremony (chat nonce with TTL for medium;
xNet-surface
only for high/critical); ceremony tools (`xnet_approve`, `xnet_deny`,
`xnet_pending_approvals`, `xnet_undo`) and the `xnet_poll_notifications`
outbox tool; `MCPServerConfig.agentAudit` wires it into the MCP server;
`NodeStoreAPI.create` now accepts an optional deterministic `id`; new AI
    scopes `agent.approve` and `agent.notifications`.
  - `@xnetjs/cli`: `xnet agent enroll <name>` mints and stores passports
(`~/.xnet/agents`, 0600) and prints OpenClaw/Hermes config; `xnet mcp
serve
--agent <name> [--db <path>]` serves an agent-scoped session over an
    agent-signed local store.

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/identity@2.1.0
  - @xnetjs/sync@2.1.0
  - @xnetjs/storage@2.1.0
  - @xnetjs/sqlite@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/identity@2.1.0

### Minor Changes

- [#533](#533)
[`0a4a1de`](0a4a1de)
Thanks [@crs48](https://github.com/crs48)! - Agent Passports and signed
agent audit trails (exploration 0337).
- `@xnetjs/data`: new agent schema pack — `AgentPassport`,
`AgentSession`,
`AgentAction`, `AgentApproval`, `AgentNotification` — with deterministic
id
    helpers (`agentActionId`, …) and `redactInstruction`.
- `@xnetjs/identity`: `mintAgentPassport` / `verifyAgentPassport`
(per-agent
    `did:key` + operator-delegated, attenuation-checked UCAN; wildcards
    rejected) and `rootIssuers` for delegation-chain root inspection.
- `@xnetjs/plugins`: `AgentAuditRecorder` wraps the AI surface so every
tool
call lands as an `AgentAction` node and medium+ risk calls park behind a
risk-tiered approval ceremony (chat nonce with TTL for medium;
xNet-surface
only for high/critical); ceremony tools (`xnet_approve`, `xnet_deny`,
`xnet_pending_approvals`, `xnet_undo`) and the `xnet_poll_notifications`
outbox tool; `MCPServerConfig.agentAudit` wires it into the MCP server;
`NodeStoreAPI.create` now accepts an optional deterministic `id`; new AI
    scopes `agent.approve` and `agent.notifications`.
  - `@xnetjs/cli`: `xnet agent enroll <name>` mints and stores passports
(`~/.xnet/agents`, 0600) and prints OpenClaw/Hermes config; `xnet mcp
serve
--agent <name> [--db <path>]` serves an agent-scoped session over an
    agent-signed local store.

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/plugins@2.1.0

### Minor Changes

- [#533](#533)
[`0a4a1de`](0a4a1de)
Thanks [@crs48](https://github.com/crs48)! - Agent Passports and signed
agent audit trails (exploration 0337).
- `@xnetjs/data`: new agent schema pack — `AgentPassport`,
`AgentSession`,
`AgentAction`, `AgentApproval`, `AgentNotification` — with deterministic
id
    helpers (`agentActionId`, …) and `redactInstruction`.
- `@xnetjs/identity`: `mintAgentPassport` / `verifyAgentPassport`
(per-agent
    `did:key` + operator-delegated, attenuation-checked UCAN; wildcards
    rejected) and `rootIssuers` for delegation-chain root inspection.
- `@xnetjs/plugins`: `AgentAuditRecorder` wraps the AI surface so every
tool
call lands as an `AgentAction` node and medium+ risk calls park behind a
risk-tiered approval ceremony (chat nonce with TTL for medium;
xNet-surface
only for high/critical); ceremony tools (`xnet_approve`, `xnet_deny`,
`xnet_pending_approvals`, `xnet_undo`) and the `xnet_poll_notifications`
outbox tool; `MCPServerConfig.agentAudit` wires it into the MCP server;
`NodeStoreAPI.create` now accepts an optional deterministic `id`; new AI
    scopes `agent.approve` and `agent.notifications`.
  - `@xnetjs/cli`: `xnet agent enroll <name>` mints and stores passports
(`~/.xnet/agents`, 0600) and prints OpenClaw/Hermes config; `xnet mcp
serve
--agent <name> [--db <path>]` serves an agent-scoped session over an
    agent-signed local store.

- [#525](#525)
[`fa93e2f`](fa93e2f)
Thanks [@crs48](https://github.com/crs48)! - Add the workspace-plugin
runtime (exploration 0331): author, hot-load, and
compose plugins whose source lives in the workspace as a `PluginSource`
node.
New public surface: `PluginSourceSchema` + `readPluginSourceNode`, an
in-browser
module builder (`buildPluginModuleGraph`) with a pinned import map, the
`SandboxedPluginHost` (`activateWorkspacePlugin`) that loads plugin code
only in
  an opaque-origin iframe and registers data-declared contributions over
MessagePort RPC, a gated store RPC (`createPluginStoreRpc`,
denylist-wins), a
250ms-debounce hot reloader (`createWorkspacePluginHotReloader`),
content-hash
pinning + drift diffing (`computePluginSourceHash`,
`assessPluginUpdate`), the
  `plugin_*` agent tools (`createWorkspacePluginAgentTools`) and the
`WRITING_XNET_PLUGINS_SKILL_MD` authoring skill, and both publish paths
(`requestWorkspacePluginPublish`, `buildCommunityRegistryEntry`).
`MCPServerConfig`
gains an `extraTools` field to expose the new tools beside the
built-ins.

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/abuse@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/react@2.1.0

### Minor Changes

- [#534](#534)
[`5473a29`](5473a29)
Thanks [@crs48](https://github.com/crs48)! - `useGridDatabase` now pages
database rows through a growing window instead of a fixed 500-row page:
new `fetchMoreRows()` grows the window by `pageSize` (default 500) up to
`maxLoaded` (default 2000, configurable via options), and the result
exposes `totalRowCount` (exact matching count), `hasMoreRows`, and
`isFetchingMoreRows` so grids can render honest totals and infinite
scroll. Existing consumers keep working unchanged — rows still arrive
sorted by `sortKey` on the live query path.

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/identity@2.1.0
  - @xnetjs/plugins@2.1.0
  - @xnetjs/data-bridge@2.1.0
  - @xnetjs/history@2.1.0
  - @xnetjs/runtime@0.5.1
  - @xnetjs/sync@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/abuse@2.1.0

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/identity@2.1.0
  - @xnetjs/crypto@2.1.0
## @xnetjs/crypto@2.1.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/core@2.1.0
## @xnetjs/data-bridge@2.1.0

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/sync@2.1.0
  - @xnetjs/sqlite@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/history@2.1.0

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/sync@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/runtime@0.5.1

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/identity@2.1.0
  - @xnetjs/plugins@2.1.0
  - @xnetjs/data-bridge@2.1.0
  - @xnetjs/history@2.1.0
  - @xnetjs/sync@2.1.0
  - @xnetjs/storage@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/storage@2.1.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/sqlite@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/sync@2.1.0

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/identity@2.1.0
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
## @xnetjs/core@2.1.0


## @xnetjs/sqlite@2.1.0


## xnet-cloud@0.0.19

### Patch Changes

- Updated dependencies []:
  - @xnetjs/telemetry@0.0.1
  - @xnetjs/crypto@2.1.0
  - @xnetjs/core@2.1.0
  - @xnetjs/cloud@0.0.1
## xnet-demos@0.1.3

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`5473a29`](5473a29)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/identity@2.1.0
  - @xnetjs/react@2.1.0
  - @xnetjs/devtools@0.1.0
## @xnetjs/brain@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/vectors@0.0.1
## @xnetjs/comms@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/crypto@2.1.0
## @xnetjs/dashboard@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`5473a29`](5473a29),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/plugins@2.1.0
  - @xnetjs/react@2.1.0
  - @xnetjs/social@0.0.20
## @xnetjs/labs@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/plugins@2.1.0
## @xnetjs/licenses@0.0.20

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@2.1.0
## @xnetjs/maps@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
## @xnetjs/meetings@0.0.13

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de),
[`fa93e2f`](fa93e2f)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/plugins@2.1.0
## @xnetjs/server@0.0.19

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/identity@2.1.0
  - @xnetjs/data-bridge@2.1.0
  - @xnetjs/crypto@2.1.0
## @xnetjs/social@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
  - @xnetjs/crypto@2.1.0
## @xnetjs/unreal@0.0.20

### Patch Changes

- Updated dependencies
[[`0a4a1de`](0a4a1de)]:
  - @xnetjs/data@2.1.0
## xnet-desktop@2.1.0

Desktop shell release riding the @xnetjs/core 2.1.0 train.
Desktop-specific changes are not tracked here; see the core packages'
changelogs for what shipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant