Pin the live buffer's two cost claims as assertions
Follow-on to #921, same treatment for the two remaining cost claims in the event-feed package's capacity comments.
The claims
MaxCapacity: "The live buffer grows to its capacity lazily and pays only for the events it admits."DefaultLiveBufferCapacity: "deliberately decoupled from the dedupe capacity — only event-bearing frames are buffered."
Both justify a published constraint by naming a cost or an independence. Neither was measured.
TestLiveBufferPaysOnlyForTheEventsItAdmits
Bytes (runtime.MemStats.TotalAlloc), not testing.AllocsPerRun's count, for the reason #921 paid for: make([]Event, 0, capacity) is one allocation whether the capacity is 1 or a million, so a count is identical in exactly the case that must fail. TestSustainedOverflowRetainsTheBacking next to it counts allocations because its claim is about how many happen; this claim is about how big one is.
Capacity and admitted count vary independently — a grid over admitted ∈ {0, 1, 16, 1000} × capacity ∈ {n, n+1, 10n, 10 000, MaxCapacity} — because a diagonal cannot tell "pays for its capacity" from "pays for what it admits", which is the entire claim. Every cell is compared against the smallest capacity that still holds the admitted events, so a fixed-size allocation added to newLiveBuffer moves all the cells together and stays green. The rising floor across admitted counts is the other half: the cost does move, with the events, which is what makes the invariance an observation rather than a measurement of nothing.
Events are built outside the measured region and carry no strings, so the only allocations inside it are the liveBuffer struct and append's growth of the store. The grid never overflows — a drop would charge the measurement for add's dropped-ids slices instead of the store.
TestLiveBufferCapacityIsDecoupledFromTheDedupeCapacity
Behavior rather than bytes, and the choice is not arbitrary — it follows from the first test. Because the live buffer's cost does not move with its own capacity, a byte grid over the two capacities would stay green under newLiveBuffer(cfg.dedupeCapacity, …), which is the single most likely way to break this claim. Bytes are the wrong instrument here.
What is observable is which capacity bounds which population: the buffer drops at its own configured capacity and the LRU evicts at its own, each while the other is set somewhere else. Sampled off the diagonal in both orderings (64/3, 3/64, 1/8, 8/1) plus the shipped defaults — and the defaults cell is labelled in the table as the one that discriminates nothing, since DefaultLiveBufferCapacity and DefaultDedupeCapacity are the same number.
What this test cannot reach, stated rather than papered over
Writing DefaultLiveBufferCapacity = DefaultDedupeCapacity would make the two constants formally coupled and leave every observation in the test unchanged — verified, it passes under that mutation — because untyped constants carry no evidence of where they came from. That half of the claim is a statement about intent and stays a comment. The half that is mechanical — that nothing in the wiring derives, swaps or clamps one by the other — is what the test holds.
Mutation checks
Each mutation applied to loop.go, built, both tests run, reverted. T1 = pays-only-for-admitted, T2 = decoupled.
| # | mutation | T1 | T2 |
|---|---|---|---|
| M1 | newLiveBuffer → events: make([]Event, 0, capacity) | FAIL | pass |
| M2 | newLiveBuffer → events: make([]Event, 0, capacity/2+1) (half-sized, still eager) | FAIL | pass |
| M3 | dedupe-shaped eager index map sized by capacity in newLiveBuffer | FAIL | pass |
| M4 | grow to capacity on the first add rather than in the constructor | FAIL | pass |
| M5 | control: a fixed-size (capacity-independent) allocation in newLiveBuffer | pass | pass |
| N1 | newLoop hands the dedupe capacity to the live buffer | pass | FAIL |
| N2 | newLoop hands the live buffer capacity to the dedupe | pass | FAIL |
| N3 | newLoop clamps the live buffer by the dedupe capacity | pass | FAIL |
| N4 | newLoop clamps the dedupe by the live buffer capacity | pass | FAIL |
| N5 | DefaultLiveBufferCapacity = DefaultDedupeCapacity | pass | pass — the documented limit above |
M5 is the control that matters for the byte test: an unrelated allocation must not break it, or the test would become a tripwire on every edit to newLiveBuffer. M1–M4 are four different eager-allocation shapes, including the exact one that exists in dedupe.go today.
Gates
go build ./..., go vet ./..., go test ./... -race -count=1, make go-lint (0 issues). The two new tests also pass -race -count=5.
Summary by cubic
Adds two tests pinning the event-feed capacity comments' two cost claims: the live buffer pays only for events admitted, and its capacity is decoupled from the dedupe capacity. Also expands those comments to describe the dedupe LRU as a bounded per-lane window and reference the tests.
Tests
TestLiveBufferPaysOnlyForTheEventsItAdmitsmeasures bytes across a grid of capacity × admitted count, so cost must not move with capacity and must move with admitted events; bytes rather than allocation count, sincemake([]Event, 0, capacity)is one allocation at any size.TestLiveBufferCapacityIsDecoupledFromTheDedupeCapacityasserts which capacity bounds which population rather than bytes, because the first test shows cost doesn't move with capacity, so a byte grid would stay green undernewLiveBuffer(cfg.dedupeCapacity).- Mutation-checked: nine targeted mutations fail, the fixed-size control passes, and the one mutation coupling the two default constants still passes — untyped constants carry no derivation evidence, so that half stays a comment.