You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
And it is called once per session, from getSessionUsage (session-discovery.ts:951), immediately after each extraction — reached per-session via FleetManager. So warming N cold sessions performs N whole-file reads and N whole-file writes: write volume is O(N x filesize), i.e. quadratic in session count.
Measured
Against a copy of a real session-metadata/<agent>.json from a production instance (293 KB, 1,677 sessions), simulating load -> mutate -> atomic write:
per setUsage
5.71 ms
to warm all 1,677 sessions
~9.6 s, ~493 MB written
An independent measurement during the same review, on the same file at an earlier size (261 KB / 1,520 sessions), got 2.99 ms per write / 389 MB / ~4.5 s. The two differ by roughly 2x on per-write cost — almost certainly methodology (whether the read is counted, and JSON.stringify indentation) — but agree on the shape and the order of magnitude. Either way it is hundreds of MB of writes to populate a cache that holds a few hundred KB.
Reads are not the problem: a full JSON.parse + Zod safeParse of that file is ~3 ms, and ~20 ms even at 3.5 MB. This is purely write amplification.
Why it matters now
It is already happening in production on every cold start that enumerates sessions.
It blocks the persisted-usage work. Paddock is about to stop maintaining its own in-memory usage cache and call getUsage/setUsage instead (its usage.ts currently duplicates this, and archive.ts:8 already notes core is "the natural home"). Routing Paddock's writes through setUsage as it stands inherits the quadratic behaviour at a larger scale. This is a prerequisite, not a follow-up.
add batchSetUsage(agentName, entries) mirroring the existing batchSetAutoNames / batchSetPreviews / batchSetSidechains, and have the enrichment pass collect then flush once; or
give the store a write-coalescing queue so that N setters within one pass produce one file write, which fixes this for every field rather than just usage.
The second is more general and probably the better shape — the other three fields only avoid the problem because each grew a bespoke batch method. A single coalescing write path would make the batch variants redundant.
Ordering
Land #419 first (unreadable-vs-absent), then this. #426 (>= -> === plus size in the key) touches the same entry shape and can land alongside either.
autoName,previewandisSidechainall havebatchSet*methods onSessionMetadataStore.usagedoes not —batchSetUsagedoes not exist.Every
setUsagecall therefore runs the full cycle:And it is called once per session, from
getSessionUsage(session-discovery.ts:951), immediately after each extraction — reached per-session viaFleetManager. So warming N cold sessions performs N whole-file reads and N whole-file writes: write volume is O(N x filesize), i.e. quadratic in session count.Measured
Against a copy of a real
session-metadata/<agent>.jsonfrom a production instance (293 KB, 1,677 sessions), simulating load -> mutate -> atomic write:setUsageAn independent measurement during the same review, on the same file at an earlier size (261 KB / 1,520 sessions), got 2.99 ms per write / 389 MB / ~4.5 s. The two differ by roughly 2x on per-write cost — almost certainly methodology (whether the read is counted, and
JSON.stringifyindentation) — but agree on the shape and the order of magnitude. Either way it is hundreds of MB of writes to populate a cache that holds a few hundred KB.Reads are not the problem: a full
JSON.parse+ ZodsafeParseof that file is ~3 ms, and ~20 ms even at 3.5 MB. This is purely write amplification.Why it matters now
getUsage/setUsageinstead (itsusage.tscurrently duplicates this, andarchive.ts:8already notes core is "the natural home"). Routing Paddock's writes throughsetUsageas it stands inherits the quadratic behaviour at a larger scale. This is a prerequisite, not a follow-up.Ask
Either:
batchSetUsage(agentName, entries)mirroring the existingbatchSetAutoNames/batchSetPreviews/batchSetSidechains, and have the enrichment pass collect then flush once; orusage.The second is more general and probably the better shape — the other three fields only avoid the problem because each grew a bespoke batch method. A single coalescing write path would make the batch variants redundant.
Ordering
Land #419 first (unreadable-vs-absent), then this. #426 (
>=->===plus size in the key) touches the same entry shape and can land alongside either.