Wheel scrolling the Proxmox overview on a 929-guest estate hitched for
200-260ms per runway rebalance. Four compounding causes, all fixed:
- The windowing runway policy rebalanced in ~53-row jumps inside a
non-passive wheel listener, so the compositor waited on a multi-frame
remount. Both windowing owners now keep a symmetric runway topped up
in dead-band batches (one bounded mutation frame per ~8 rows of
travel), every windowed-page listener is passive, and only a viewport
that leaves the mounted window entirely re-centers it in one jump.
- The Workloads viewport-sync effect tracked the windowing signals its
own measurement pass moves, so every shift re-ran row measurement
(two forced reflows) and listener binding. The measurement pass is
now untracked, matching the unified-resource sync owner; the platform
and storage windowing owners had the same latent tracking and are
untracked too.
- WorkloadPanel built its guest-id lookup from the windowed slice, so a
shift re-validated every mounted row's memo chain. The lookup now
derives from the full group and only changes when data changes.
- The CPU/memory/disk bar hooks read offsetWidth in onMount, forcing a
full-table reflow per mounted bar during every top-up. Width now
comes solely from the ResizeObserver's initial pre-paint delivery.
Prewarmed-but-hidden platform tabs also ran viewport sync per scroll
event and paid the visible surface's layout flush; hidden surfaces now
skip sync via a shared checkVisibility guard.
Measured on the 50-node/929-guest mock estate at 2560x1240: a 4-row
top-up fell from ~230ms to ~7ms, scroll-jitter oscillation produces
zero frames over 25ms, and sustained fast scrolling holds native frame
cadence with one bounded mutation frame per dead-band. The remaining
scroll-time long tasks are realtime websocket merge ticks, which the
realtime-merge lane already owns.
Contract-Neutral: Storage history behavior is documented in the staged API and storage contracts and covered by staged focused regressions; shared router references do not change agent-lifecycle, performance, or security contracts, and the proof allowlists do not yet name the focused test files.
Add a language-neutral condition key and explicit resource context to generic alert payloads so receivers can translate notifications without parsing English text.
Refs #1779
Change-source: pulse-maintainer
Align manually created Agent tokens with the runtime lifecycle minimum, expose agent:manage in custom create/edit flows, and document the backend-owned scope boundary.
Change-source: pulse-maintainer
Per-comment stamps at continuous-automation volume made the machinery
louder than the maintenance. The standing disclosure is this page: it
now says plainly that day-to-day activity may be automated and
unstamped, that the tracker's pace is part of what is disclosed, and
that asking gets a straight human answer. Support email keeps its
per-message Pulse Triage identity.
release/v6.3.2 becomes the governed branch for exactly version 6.3.2 via
the existing legacy_release_lines mechanism, so the surgical hotfix can
dispatch from its branch instead of shipping current main. Scoped to the
single version so 6.3.0/6.3.1 backfills and the 6.4 line stay on main.
Contract-Neutral: The release-note line documents an alert evaluator fix and does not change release promotion or artifact dispatch.
Change-source: pulse-maintainer
'My review' overstated per-change human review now that an autonomous
maintainer lands commits through the automated gates. Say what is
actually true: direction and responsibility are Richard's, review is of
the stream that lands, and the bar a fix must clear is his.
The 2026-08-25 evening perf pass re-profiled the remaining frontend
costs on the 50-node mock rig after d5440ff43. Idle main-thread burn on
a throttled phone (~10.5s of long tasks per 30s on the worst-case mock)
and residual warm tab-entry cost both decomposed into per-changed-row
work that ignores what actually changed: every metrics tick deep-cloned,
re-canonicalized, and fully re-merged each patched row, and both store
commits then deep-unwrapped the merged rows again through whole-row
keyed reconciles.
The server's resource delta is a JSON merge patch, so the change shape
is already known. applyResourceStateDelta now records the top-level
keys each patch touched (platformData expanded one level), the
connection store publishes them with the resource revision and unions
them across the bounded history and the hidden-tab deferral set, and
mergeCanonicalResourceDeltaSnapshot takes a fast path for changed
non-host rows whose keys stay within the pass-through metric fields,
the proxmox facet mirror, and the four platformData metric mirror
leaves: the previous display row with just those subtrees cloned in
(a manual plain-data clone — structuredClone's per-invocation setup
dominates at this size). Both commit sites write fast rows as per-key
subtree patches (nested reconcile for records, direct sets for
primitives and platformData leaves) instead of whole-row reconciles,
and the connection store commits aligned ticks per index. Any other
change shape — additions, removals, repeated patches in one frame,
structural keys, agent rows (host coalescing) — keeps the full
clone-canonicalize-merge path, and the fast output is pinned
content-equivalent to it in resourceStateAdapters tests; a websocket
store test pins the per-key change shapes, the meta-history union, and
its unknown-shape contamination.
Measured on the pulse-dev rig (VM-to-VM, 50-node/1500-resource mock,
worst-case RandomMetrics, vs two d5440ff43 baseline runs): mobile-4x
idle long tasks 10.8/10.2s -> 3.9s per 30s; warm Alerts entry 5-rep
median long-task total 3.85s -> 1.52s; mobile warm Overview return
3.8/1.7s -> 1.0s; desktop Backups entry settle 1.06/1.20s -> 0.71s;
warm Storage/Overview sub-tab switch medians flat within rep spread;
desktop cold load and /api/state size unchanged.
Browser-verified on the rig build of this tree: live ticks render
through the fast path with per-cell DOM-vs-store consistency at two
samples 30s apart, zero console errors, desktop and 390px/4x mobile.
The 2026-08-25 audit follow-up profiled the remaining frontend costs on
the 50-node mock rig. Entering a tab more than one websocket tick behind
the shared cache fell off the incremental path onto a full-estate
deep-unwrap merge — a 2.1s unwrap dominated warm Alerts entry at 4x
throttle — and the client-facing resource stream re-shipped ~3KB of
mostly-static metadata per resource on every snapshot, REST recovery,
and reconnect (governed gap resource-payload-static-metadata).
The connection store now keeps a bounded per-tick changed-id history and
serves unions from it, so an instance that mounts or resumes a few
revisions behind catches up with a delta merge over the union instead of
remerging the estate. Uncovered gaps and full-snapshot commits still
fall back to keyed full reconciliation.
Broadcast payloads dedupe the estate's distinct capability blobs into a
content-addressed state-level capabilityCatalog referenced per resource
by capabilitiesRef; default-posture resources (internal sensitivity,
cloud-summary routing, no redactions) omit policy and aiSafeSummary; and
canonicalIdentity.aliases no longer duplicates supersededIds. Ingestion
reverses all three: refs expand through the catalog as per-row clones
(reconcile mutates adopted objects in place), missing policies
synthesize the default posture so a policy:null transition patch cannot
strand a stale governed policy, and identity alias resolution consults
supersededIds explicitly. Slimming edits only the per-broadcast copy,
never stored monitor state, and the delta engine's generic top-level
field diff carries catalog changes in the same frame as the first
resource referencing a new entry.
Rig A/B on the pinned 50-node mock (same VM as the morning baseline,
single runs, +-30% variance; RandomMetrics mutates nearly every row per
tick, so this estate is the worst case for the catch-up union): mobile
4x Alerts entry settles 3.9s -> 2.0s with long tasks 5.5s -> 3.3s,
idle-30s long tasks drop 12.6s -> 10.8s mobile and 3.4s -> 2.8s
desktop, remaining steps flat within variance. Sparse-delta estates
gain more, because their catch-up unions stay small.
/api/state on the pinned mock estate drops 4.75MB -> 4.09MB (-13.9%);
the capability catalog is 7 entries totalling 2.5KB where 946 resources
previously inlined the blobs, and 806 default-posture resources shed
policy and aiSafeSummary. Browser-verified against a live build of this
tree: byte-identical UI outcomes vs the unmodified baseline across
overview/storage/docker/alerts probes at both viewports, with docker
container lifecycle actions enabled through catalog-expanded
capabilities. pulse-mobile and pulse-enterprise do not read the slimmed
fields; the AI runtime consumes the internal model, which is unchanged.
Contracts for monitoring, api-contracts, unified-resources,
performance-and-scalability, alerts, agent-lifecycle, and
storage-recovery are amended with the slimmed wire shape, the ingestion
synthesis obligations, the catch-up history, and superseded-id
resolution.
The 2026-08-25 frontend perf audit measured 21-31% idle main-thread
saturation on phones (4x throttle, 50-node mock estate) with the dominant
costs in the websocket tick pipeline rather than rendering.
useUnifiedResources deep-unwrapped the entire resource store on every
websocket tick in every realtime hook instance (1.7s per 20s idle window on
the Alerts page alone). The realtime effect now skips the store read
entirely when the tick's revision is already applied, and the merging
instance unwraps only the subtrees the delta merge will clone: flagged ids,
host-merge members, and ids absent from the shared cache.
mergeCanonicalResourceDeltaSnapshot re-cloned and re-canonicalized every
agent resource on every tick because a host-merge group could change
without its surviving member being flagged. Host-key groups now refresh
only when a member id is in the delta; a flagged id absent from the
incoming snapshot (removal, or a partner a previous coalesce folded away)
conservatively refreshes every group.
useWorkloads rebuilt every row object each refresh, churning row identity
estate-wide per metrics tick. Rows whose serialized form is unchanged now
reuse the previous object via WeakMap-cached signatures, and refreshes
that change nothing return the previous array identity. The joined
signature cache field this replaces is removed.
Remeasured (mobile 4x, dev attribution, 20s windows): Alerts-page tick
unwrap 1713ms -> 200ms, Overview app busy -27%, workload signature cost
-72%. Contracts for unified-resources, performance-and-scalability, and
storage-recovery are amended to state the group-scoped coalesce refresh
and lazy store-read obligations.