Streaming residency is O(window) at process level — contradicts the documented O(one-chunk) claim #95
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Surfaced by the GER40 research deep-dive fieldtest (
docs/specs/fieldtest-research-breakout-deepdive.md).The docs (C12 cycle-0041 realization; the test
aura-ingest/tests/streaming_seam.rs :: residency_is_bounded_by_one_chunk_independent_of_window_length) make aload-bearing claim: streaming residency is O(one chunk), so "a 20-year window
streams in the same memory as a one-day one".
Measured, against real GER40 M1 (verified by re-reading the transcripts):
the aura-level predicate
resident_records <= 1024DOES hold at every windowlength — but process peak RSS (
VmHWM) grows ~linearly with the window:Isolation run — 4 raw
M1FieldSources, NO harness, NO sinks — streaming8.6M records over 7 years still peaks at 125 MiB (sinks add the rest: the
full breakout +
drain_tracereaches 210 MiB, but that part is expected traceaccumulation). So the growth is source-/data-server-side, not the recorders.
The
streaming_seamtest only measures the auraM1FieldSourcering, not theunderlying
data-serverchunk/decode retention, so it passes green while theprocess-level promise is false. A researcher who budgets RAM on the doc's
promise (one chunk ≈ tens of KiB) is off by 100–1000×; a real multi-symbol
sweep over decades would OOM where the docs say it streams flat.
Repro:
cargo run --release --manifest-path fieldtests/research-breakout-deepdive/Cargo.toml --bin t1c_residency_scaling→ the
VmHWMcolumn grows monotonically with the record count whileaura-resident<=1024?staystrue.Recommend (debug): either the
data-serverdecoded chunks/buffers areretained across pulls and must be released (root cause likely in
Brummel/data-server), OR the residency claim must be narrowed in thedocs/test to "aura-level ring residency" (all the predicate actually proves) and
the true per-window process cost documented. Minor adjacent friction:
resident_records()lives on the concreteM1FieldSource, not the publicSourcetrait, so aBox<dyn Source>consumer cannot probe residency withoutdowncasting.
Diagnosed + resolved (doc-truth correction)
Root cause confirmed (adversarially verified, high confidence; reproduced fresh:
6 MiB @ 1mo → 173 MiB @ ~10y, linear):
FileCache(src/cache.rs) retains every touched file'sparsed chunks (
HashMap<FileKey, Arc<Vec<Arc<[M1Parsed]>>>>, keyedsymbol/year/month/format). The only eviction isrelease_symbolat symbolrefcount→0 (run end);
M1FieldSourceholds aSymbolGuardfor the whole pass,so nothing is evicted behind the cursor → live retention is O(records-touched).
sizeof(M1Parsed) = 56 B(7×8); VmHWM−baseline converges onrecords × 56 B(3.06M × 56 = 171 MiB ≈ measured 173). No mmap, no raw-buffer retention, not an
allocator artifact (loader drops the raw
Vec<u8>after parse).resident_records()predicate is honestly O(one chunk) — it measuresthe source ring, which is structurally blind to the
FileCachebeneath. Sothe predicate holding and VmHWM growing are not contradictory; they measure
different quantities.
This is not a broken design promise. The true property (per-source ring ≤ one
chunk) is real and tested. The over-claim was the process-level gloss layered on
top of it —
INDEX.md("a 20-year window streams in the same memory as a one-dayone") and
0041("resident memory is flat across the horizon"). The 0041 specalready scoped it correctly at its "Data-server cache file retention" friction note
("owned by that lib, not this cycle"); the summary prose simply widened past that
scope.
No clean always-on code fix exists — structurally, not for effort. The
whole-symbol retention is the replay-many optimization (load-once,
close+volumesharing one parse via the field-agnostic
FileKey). Any unconditional evictor thatbounds a single forward pass must drop files a lagging sim still needs, breaking
load-once. Single-pass vs replay-many residency policies must be split by intent.
Resolution (working tree, to land with this issue's close)
Narrowed the docs/comments from the false whole-process claim to the true
per-source-ring property, naming the
FileCacheper-window retention as the real(desirable, replay-amortized) process cost:
docs/design/INDEX.md— C12 realization glossdocs/specs/0041-source-ingestion-seam.md— example comment + residency criterioncrates/aura-ingest/src/lib.rs—M1FieldSource+resident_recordsdoc-commentscrates/aura-ingest/tests/streaming_seam.rs— residency-test comments (the assertis correct and unchanged; only its labelling was process-vs-ring confused)
The deferred capability (an opt-in non-retaining streaming read path, only needed if
a genuine single-pass-over-decades consumer appears — the World is replay-many and
wants the retention) is parked as Brummel/data-server#2 (
idea).Adjacent friction noted in the OP (
resident_records()on concreteM1FieldSource,not the
Sourcetrait) left as a separate small follow-up.