mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Register resource-payload static-metadata coverage gap
The browser performance audit measured the client-facing resource stream as a primary scalability cost at estate scale: a 4.73MB single-frame snapshot at 1,508 resources, ~3KB of mostly-static metadata per resource (only 10 distinct capabilities blobs across the whole estate, identity alias history, aiSafeSummary prose, and policy routing shipped to every browser), and ~1s of blocked main thread per delta on desktop hardware. Slimming the stream is a wire-format change with consumers beyond frontend-modern (pulse-mobile OTA compatibility, Pro surfaces, AI runtime), so it is registered as a triaged coverage gap for an owned slice instead of an opportunistic patch. Evidence record carries the measured payload composition.
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
# Resource payload static-metadata bloat (browser performance audit, 2026-08-24)
|
||||
|
||||
## Context
|
||||
|
||||
A read-only browser performance audit (2026-08-23/24, production build served by
|
||||
the dev backend against the 50-node / 929-guest / 1,508-resource mock estate)
|
||||
measured the client-facing resource stream as a primary scalability cost:
|
||||
|
||||
- The full state snapshot is **4.73 MB** of JSON in a single websocket frame
|
||||
(`/api/state` REST recovery returns the same payload). `resources` accounts
|
||||
for 4.63 MB — ~3 KB average per resource.
|
||||
- Idle on the Proxmox overview, the browser main thread was blocked for
|
||||
**12.0 s out of every 45 s** (individual long tasks of 0.8–1.4 s roughly
|
||||
every 3–4 s, aligned with resource delta frames of up to ~500 KB) on an
|
||||
unthrottled M-series desktop. Under a 4x CPU throttle (mid-range phone
|
||||
class), tab taps landing inside those windows blocked for multiple seconds.
|
||||
|
||||
## Measured payload composition (per-field bytes across 1,508 resources)
|
||||
|
||||
| Field | Bytes | Notes |
|
||||
| --- | --- | --- |
|
||||
| `canonicalIdentity` | 0.82 MB | 12 aliases incl. 7 superseded hash ids on a typical VM; identity history ships on every snapshot |
|
||||
| `proxmox` + `platformData` | 1.36 MB | platform payloads |
|
||||
| `capabilities` | 0.34 MB | only **10 distinct blobs** across all 1,508 resources — duplicated per resource, including human-readable `description` strings |
|
||||
| `aiSafeSummary` | 0.14 MB | AI-oriented prose on every resource, shipped to every browser client |
|
||||
| `policy` | 0.12 MB | near-constant routing metadata per resource |
|
||||
|
||||
The websocket delta path is already field-level (JSON merge patches in
|
||||
`internal/websocket/state_delta.go`), so delta size is driven by estate scale,
|
||||
not by a diffing defect. The static-metadata weight is paid on every full
|
||||
snapshot, REST recovery, reconnect, and mobile tab resume.
|
||||
|
||||
## Why this is a governed gap rather than a quick fix
|
||||
|
||||
Slimming the stream means changing the client-facing resource shape (for
|
||||
example: a capabilities catalog referenced by id instead of inlined blobs,
|
||||
identity history behind a detail endpoint instead of inline aliases, and
|
||||
audience-scoped fields so `aiSafeSummary`/`policy` do not ship to browser
|
||||
sessions that never read them). That is a wire-format change with consumers
|
||||
beyond frontend-modern — pulse-mobile (OTA-before-server-release constraint),
|
||||
Pro/enterprise surfaces, and the AI runtime — and payload fields are not
|
||||
contract-neutral under the governance rules. It needs an owned slice with
|
||||
contract updates and cross-client verification, not an opportunistic patch.
|
||||
|
||||
## Companion fixes already landed separately
|
||||
|
||||
- Nav tab identity stabilization (`frontend-modern/src/components/shared/stableNavTabs.ts`)
|
||||
so websocket ticks no longer recreate every nav button.
|
||||
- `preloadDynamicChunks: false` in `frontend-modern/vite.config.ts` so cold
|
||||
start no longer fetches and compiles all ~3.1 MB of lazy chunks up front.
|
||||
- Per-tab scoped hydration and realtime gating on the Proxmox surface
|
||||
(`17bb2b3b7`, Performance lane).
|
||||
@@ -9690,7 +9690,44 @@
|
||||
"subsystem_ids": []
|
||||
}
|
||||
],
|
||||
"coverage_gaps": [],
|
||||
"coverage_gaps": [
|
||||
{
|
||||
"id": "resource-payload-static-metadata",
|
||||
"summary": "The client-facing resource stream ships ~3KB of mostly-static metadata per resource (duplicated capabilities blobs with only 10 distinct values across 1,508 resources, canonicalIdentity alias/superseded-id history, aiSafeSummary prose, and policy routing) on every snapshot, REST recovery, and reconnect. At 50-node scale the snapshot is a single 4.73MB websocket frame and browser main-thread cost per delta reaches ~1s even on desktop hardware. Slimming the stream is a wire-format change with consumers beyond frontend-modern (pulse-mobile OTA compatibility, Pro surfaces, AI runtime), so it needs an owned slice with contract updates and cross-client verification.",
|
||||
"owner": "project-owner",
|
||||
"status": "triaged",
|
||||
"recorded_at": "2026-08-24",
|
||||
"lane_ids": [
|
||||
"L6",
|
||||
"L10",
|
||||
"L13"
|
||||
],
|
||||
"subsystem_ids": [
|
||||
"api-contracts",
|
||||
"performance-and-scalability",
|
||||
"unified-resources"
|
||||
],
|
||||
"proposed_resolution": "lane-expansion",
|
||||
"coverage_impact": 6,
|
||||
"evidence": [
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "docs/release-control/v6/internal/records/resource-payload-static-metadata-2026-08-24.md",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/stores/websocket.ts",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "internal/websocket/state_delta.go",
|
||||
"kind": "file"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"candidate_lanes": [],
|
||||
"work_claims": [],
|
||||
"open_decisions": [],
|
||||
|
||||
Reference in New Issue
Block a user