Current work — 2026-09-16
Prerequisite #1668 / PR #1672 is complete after independent adversarial review and green CI. The browser now carries the admitted storage mode from a matching estimate into the run. Required disk-backed input, output or scratch failures refuse the run before fallback buffering. Stale estimates cannot admit another selection. Actual worker-handler and component contracts cover these boundaries; they are not memory measurements.
The empirical requirement remains open. The earlier 2026-09-13 browser-worker experiment used 206.61 MiB of pinned input and 206.36 MiB output, with 50.56 MiB of WASM linear-memory capacity against a 130.8 MiB estimate at a 16 MiB sort budget. These are historical measurements of that configuration, not current-head memory acceptance. They do not measure JavaScript heap, browser RSS or UI-default memory, and they do not provide a registered regression gate.
The cache default has since changed in #1781 / #1792: 4 KiB input blocks and separate 64 KiB verification blocks. Exact output, refusal checks, memory accounting and pinned performance evidence support that change; they do not close this empirical memory requirement. Use the current configuration when measuring total browser memory. #1162 owns country-scale native/browser performance; #1420 owns large-map delivery and device acceptance.
Parent epic: #1449 (evidence gap named while closing section D's streaming-memory bullet)
The gap
Nothing in the repository measures that delivering a large map holds flat memory. The guarantee rests on a model.
Until 2026-07-31 it rested on a measurement. builder/app/src/lib/device/memory.test.ts drove the real sendCatalogMap pipeline over TOTAL = 300 * 1024 * 1024 bytes and watched the process heap; its header stated the claim it existed for:
The claim #903 refuses to take on faith: memory during a 300 MB map upload stays flat.
It was deleted in 026c8248 ("refactor(maps): cut over to the cell catalog", #1047), together with the sendCatalogMap path it drove. Nothing replaced the measurement, because the cell-catalog architecture answers the same question a different way:
builder/app/src/lib/assemble/bridge.test.ts's estimateMemory group asserts that DACH fits the sunk path and is refused resident, that the engine is priced by the sort budget rather than the selection, and that the no-OPFS fallback honestly refuses a country.
builder/app/src/components/coverage/DownloadStep.svelte.test.ts covers the mandatory preflight that consumes that estimate.
Both are arithmetic over the wasm estimator. They allocate nothing and run sub-millisecond.
Why that is not the same evidence
A modelled budget and an empirical heap measurement are different classes of evidence. The current tests prove that the estimator says the right thing and that the preflight obeys it. They cannot fail if the implementation buffers a whole map while the model says it should not — the estimator would still return its number, the preflight would still gate on it, and every assertion would still pass.
So the property "a large map delivery holds flat memory" is currently unasserted. That is a coverage question, not a cost question.
Why it is not part of TS4b
TS4b (#1502) is a cost-reduction slice. It closed the section-D bullet as no current subject — correctly, because the suite the bullet named is gone — and naming this gap was in its scope. Filling it is not: the pipeline the old test drove no longer exists, so a replacement is new test design against the assembler and the OPFS store, at a level (real browser, or a host harness with a real heap) that the epic's sections E and F are about. Folding new coverage into a slice whose success criterion is a smaller runtime is how a cost slice quietly becomes a feature slice.
What a replacement has to decide
- Where it runs.
happy-dom under vitest has no OPFS and no honest heap. A real-browser level (section E) or a Node harness driving the assembler directly are the two candidates.
- What it watches.
process.memoryUsage().heapUsed was the old probe and it is not available in a browser; performance.measureUserAgentSpecificMemory() is, behind cross-origin isolation.
- What "flat" means. The old test asserted against a fixed ceiling over a fixed payload. The cell catalog's working set scales with the sort budget, so the claim needs restating before it can be measured.
- What it costs. The old test moved 300 MiB in ~4 s. Section D's own policy says a large throughput or memory assertion belongs in a performance suite, not in the required per-PR tier.
Definition of done
A test at some level fails if a map delivery buffers materially more than the estimator says it will, and the registry entry that owns it declares the tier it runs in.
Current work — 2026-09-16
Prerequisite #1668 / PR #1672 is complete after independent adversarial review and green CI. The browser now carries the admitted storage mode from a matching estimate into the run. Required disk-backed input, output or scratch failures refuse the run before fallback buffering. Stale estimates cannot admit another selection. Actual worker-handler and component contracts cover these boundaries; they are not memory measurements.
The empirical requirement remains open. The earlier 2026-09-13 browser-worker experiment used 206.61 MiB of pinned input and 206.36 MiB output, with 50.56 MiB of WASM linear-memory capacity against a 130.8 MiB estimate at a 16 MiB sort budget. These are historical measurements of that configuration, not current-head memory acceptance. They do not measure JavaScript heap, browser RSS or UI-default memory, and they do not provide a registered regression gate.
The cache default has since changed in #1781 / #1792: 4 KiB input blocks and separate 64 KiB verification blocks. Exact output, refusal checks, memory accounting and pinned performance evidence support that change; they do not close this empirical memory requirement. Use the current configuration when measuring total browser memory. #1162 owns country-scale native/browser performance; #1420 owns large-map delivery and device acceptance.
Parent epic: #1449 (evidence gap named while closing section D's streaming-memory bullet)
The gap
Nothing in the repository measures that delivering a large map holds flat memory. The guarantee rests on a model.
Until 2026-07-31 it rested on a measurement.
builder/app/src/lib/device/memory.test.tsdrove the realsendCatalogMappipeline overTOTAL = 300 * 1024 * 1024bytes and watched the process heap; its header stated the claim it existed for:It was deleted in
026c8248("refactor(maps): cut over to the cell catalog", #1047), together with thesendCatalogMappath it drove. Nothing replaced the measurement, because the cell-catalog architecture answers the same question a different way:builder/app/src/lib/assemble/bridge.test.ts'sestimateMemorygroup asserts that DACH fits the sunk path and is refused resident, that the engine is priced by the sort budget rather than the selection, and that the no-OPFS fallback honestly refuses a country.builder/app/src/components/coverage/DownloadStep.svelte.test.tscovers the mandatory preflight that consumes that estimate.Both are arithmetic over the wasm estimator. They allocate nothing and run sub-millisecond.
Why that is not the same evidence
A modelled budget and an empirical heap measurement are different classes of evidence. The current tests prove that the estimator says the right thing and that the preflight obeys it. They cannot fail if the implementation buffers a whole map while the model says it should not — the estimator would still return its number, the preflight would still gate on it, and every assertion would still pass.
So the property "a large map delivery holds flat memory" is currently unasserted. That is a coverage question, not a cost question.
Why it is not part of TS4b
TS4b (#1502) is a cost-reduction slice. It closed the section-D bullet as no current subject — correctly, because the suite the bullet named is gone — and naming this gap was in its scope. Filling it is not: the pipeline the old test drove no longer exists, so a replacement is new test design against the assembler and the OPFS store, at a level (real browser, or a host harness with a real heap) that the epic's sections E and F are about. Folding new coverage into a slice whose success criterion is a smaller runtime is how a cost slice quietly becomes a feature slice.
What a replacement has to decide
happy-domunder vitest has no OPFS and no honest heap. A real-browser level (section E) or a Node harness driving the assembler directly are the two candidates.process.memoryUsage().heapUsedwas the old probe and it is not available in a browser;performance.measureUserAgentSpecificMemory()is, behind cross-origin isolation.Definition of done
A test at some level fails if a map delivery buffers materially more than the estimator says it will, and the registry entry that owns it declares the tier it runs in.