Skip to content

test(topic): fix load-flaky WS panic in cross-instance await helpers - #518

Merged
adnaan merged 2 commits into
mainfrom
flaky-xinstance-race
Jul 22, 2026
Merged

test(topic): fix load-flaky WS panic in cross-instance await helpers#518
adnaan merged 2 commits into
mainfrom
flaky-xinstance-race

Conversation

@adnaan

@adnaan adnaan commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

TL;DR — a gorilla read-deadline antipattern, not a container race

This started as an investigation into a flaky panic that looked like a testcontainer/teardown race under concurrent load. The root cause turned out to be a gorilla/websocket antipattern in two test helpers — which is why the diff is three test files, not container-lifecycle code.

Symptom

TestTopic_V8_…CrossInstance (and the awaitWSContains / awaitWSContainsRejecting helper class) intermittently panicked repeated read on failed websocket connection during the full go test ./... run — never in isolation (passed 4/4 alone).

Root cause (proven, not inferred)

The helpers looped SetReadDeadline(150ms) + ReadMessage, doing continue on any error:

for time.Now().Before(deadline) {
    trigger()
    ws.SetReadDeadline(time.Now().Add(150 * time.Millisecond))
    _, msg, err := ws.ReadMessage()
    if err != nil { continue }   // ← poisons on the first timeout
    ...
}

gorilla records a read-deadline timeout in c.readErr (via hideTempErr, which wraps but still returns the error), and there is no way to clear it. Once poisoned, every ReadMessage returns the stored error immediately, so the loop fast-spins and gorilla's readErrCount >= 1000 guard panics (conn.go:1030). This only triggers when a frame arrives slower than the 150ms deadline — i.e. under CPU saturation during the concurrent ./... run — which is exactly why it masqueraded as a load/container race.

Evidence:

  • Source: NextReader's for c.readErr == nil loop is skipped once readErr is set; SetReadDeadline doesn't touch readErr.
  • Deterministic repro (load-independent): SetReadDeadline(1ms) + retry-loop ReadMessage against a silent server panics with the exact string in <1s.
  • Negative control: a targeted high-churn container repro (topic×6 ‖ pubsub×4) did not reproduce it — ruling out churn as the cause.

Fix

A single reader goroutine (wsFrameReader) owns ReadMessage with no per-read deadline, so it never times out and never poisons the conn. The wait loop selects on the delivered-frame channel vs a re-trigger ticker vs one overall 8s deadline. awaitWSContains / awaitWSContainsRejecting collapse to thin wrappers over a shared awaitWSFrame.

wsFrameReader also clears the stale deadline connectWS leaves set for the initial-render read, and closes ws via t.Cleanup so the reader goroutine always exits.

Regression guard

TestWSFrameReader_SurvivesSlowFrame delivers a 600ms-delayed frame without panicking. Verified it discriminates: the pre-fix helper panics on that same input (throwaway control), the new helper passes.

Verification

  • Full go test ./... — green
  • go test -race -run 'TestTopic|TestWSFrameReader' -count=2 — 0 data races, 0 panics (matches CI's -race job; no double-reader-on-one-conn since each test awaits one conn once)
  • Topic tests ×8 under all-core CPU saturation — 0 panics (the exact condition that exposed the flake)

Context

Surfaced while wiring release-script tests into CI (#513 / #517); split out as its own PR since it's an unrelated, pre-existing flake on main.

🤖 Generated with Claude Code

TestTopic_V8_…CrossInstance (and its awaitWSContains/awaitWSContainsRejecting
helper class) intermittently panicked "repeated read on failed websocket
connection" under the full `go test ./...` run, never in isolation.

Root cause is a gorilla/websocket antipattern, not container/load contention
(a targeted high-churn repro did NOT trigger it). The helpers looped
SetReadDeadline(150ms) + ReadMessage, doing `continue` on any error. gorilla
records a read-deadline TIMEOUT in c.readErr via hideTempErr — poisoning the
connection — and there is no way to clear it. Once poisoned, every ReadMessage
returns the stored error immediately, so the loop fast-spins and gorilla's
readErrCount>=1000 guard panics. This only bites when a frame arrives slower
than the 150ms deadline, i.e. under CPU saturation during the concurrent
`./...` run, which is why it looked like a load/container race.

Fix: a single reader goroutine (wsFrameReader) owns ReadMessage with NO
per-read deadline, so it never times out and never poisons the conn; the wait
loop selects on the delivered-frame channel vs a re-trigger ticker vs one 8s
overall deadline. awaitWSContains/awaitWSContainsRejecting collapse to thin
wrappers over a shared awaitWSFrame. wsFrameReader also clears the stale
deadline connectWS leaves set, and closes ws via t.Cleanup so the goroutine
always exits.

TestWSFrameReader_SurvivesSlowFrame pins the contract: it delivers a
600ms-delayed frame without panicking (verified the pre-fix helper panics on
the same input, so the guard discriminates).

Verified: full `go test ./...` green; topic tests pass x8 under all-core CPU
saturation (0 panics) — the exact condition that exposed the flake.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ui2cwpeGkrUfRt8rh2FgGG
@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review

Solid fix — read through the diff and the full call sites in topic_cross_instance_test.go / topic_wildcard_test.go. The root-cause analysis in the PR description checks out against the code: wsFrameReader never calls SetReadDeadline with a non-zero deadline, so it can't hit gorilla's "poisoned after any read error" trap, and TestWSFrameReader_SurvivesSlowFrame is a genuinely discriminating regression test (600ms delay vs. the old 150ms per-read deadline).

Strengths

  • Correctly diagnoses that the bug is a gorilla/websocket antipattern (read-deadline timeout permanently poisons c.readErr, no way to clear it, fast-spin → readErrCount>=1000 panic) rather than a container/load race — and backs it with a negative control (targeted churn repro didn't reproduce it).
  • wsFrameReader clearing the stale deadline connectWS leaves behind (ws.SetReadDeadline(time.Time{})) before the blocking read is the right fix — I checked connectWS in broadcast_test.go:99 and confirmed it does set a 5s deadline for the initial-render read that would otherwise linger.
  • t.Cleanup(func() { _ = ws.Close() }) guarantees the reader goroutine unblocks and close(frames) runs, so no leak beyond test scope.
  • Verified every current call site (topic_cross_instance_test.go, topic_wildcard_test.go) only calls awaitWSContains/awaitWSContainsRejecting once per connection — important, see the note below.
  • Comment density matches the file's existing style (this codebase already documents gorilla's read-poisoning behavior at length in neighboring tests), so it's consistent with repo convention, not excessive.

One footgun worth a one-line guard or comment

wsFrameReader spawns a goroutine that owns ws.ReadMessage() for the lifetime of the test (via t.Cleanup). gorilla/websocket does not support concurrent reads on one connection. If a future test calls awaitWSContains/awaitWSContainsRejecting (or wsFrameReader directly) a second time on the same *websocket.Conn before it's closed — e.g. to wait for two sequential frames — it will spawn a second goroutine reading the same conn concurrently with the first, which is a data race gorilla explicitly doesn't support. Nothing in the current diff enforces "at most one call per connection" beyond doc comments. Not a bug today (verified no existing call site does this), but since this helper will likely get reused for new cross-instance tests, consider either:

  • a doc-comment callout on awaitWSContains/awaitWSContainsRejecting ("call at most once per connection — wraps the conn in a dedicated reader goroutine"), or
  • returning the frames channel from a wsFrameReader-wrapping helper so a second wait on the same conn reuses the existing reader instead of spawning another.

Given the PR is scoped as a targeted flake fix, a comment addition is probably sufficient rather than reworking the API.

Minor

  • frames := make(chan string, 16) with a default:-drop on full buffer is a reasonable choice for these tests (retriggers redrive delivery), just flagging that a burst of >16 unread frames would silently drop the wanted one — extremely unlikely at this test cadence, not a real concern.

Test coverage / correctness: no issues found. TestWSFrameReader_SurvivesSlowFrame correctly avoids connectWS (its server intentionally doesn't send an immediate initial render) and directly dials, which is appropriate.

No security or production-code concerns — this PR only touches test helpers/files.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

✅ Performance Benchmark Results

Status: No significant regressions detected

Benchmark Comparison
                                                 │ testdata/benchmarks/baseline.txt │  current-bench.txt   │
                                                 │              sec/op              │    sec/op      vs base   │
DispatchWithState_Cached-8                                             243.8n ± ∞ ¹
E2EUserJourney-8                                                       257.0µ ± ∞ ¹
E2ETodoApp-8                                                           26.17µ ± ∞ ¹
E2ERangeOperations/add-items-8                                         9.541µ ± ∞ ¹
E2ERangeOperations/remove-items-8                                      5.600µ ± ∞ ¹
E2ERangeOperations/reorder-items-8                                     7.037µ ± ∞ ¹
E2ERangeOperations/update-items-8                                      6.930µ ± ∞ ¹
E2EMultipleSessions/sessions-1-8                                       2.781µ ± ∞ ¹
E2EMultipleSessions/sessions-10-8                                      28.64µ ± ∞ ¹
E2EMultipleSessions/sessions-100-8                                     303.0µ ± ∞ ¹
SpecificationCompliance-8                                              1.960µ ± ∞ ¹
ErrorPaths/invalid-template-syntax-8                                   1.856m ± ∞ ¹
ErrorPaths/missing-field-8                                             2.928µ ± ∞ ¹
ErrorPaths/nil-data-8                                                  3.994µ ± ∞ ¹
ErrorPaths/empty-template-8                                            1.942m ± ∞ ¹
TemplateExecute/initial-render-8                                       1.898m ± ∞ ¹
TemplateExecute/subsequent-render-8                                    3.025µ ± ∞ ¹
TemplateExecuteUpdates/no-changes-8                                    2.238µ ± ∞ ¹
TemplateExecuteUpdates/small-update-8                                  2.263µ ± ∞ ¹
TemplateExecuteUpdates/large-update-8                                  6.789µ ± ∞ ¹
TemplateComplexity/simple-fields-8                                     6.258µ ± ∞ ¹
TemplateComplexity/with-conditionals-8                                 4.250µ ± ∞ ¹
TemplateComplexity/with-ranges-8                                       8.797µ ± ∞ ¹
TemplateComplexity/deeply-nested-8                                     8.939µ ± ∞ ¹
TemplateConcurrent/goroutines-1-8                                      3.531µ ± ∞ ¹
TemplateConcurrent/goroutines-10-8                                     3.345µ ± ∞ ¹
TemplateConcurrent/goroutines-100-8                                    4.314µ ± ∞ ¹
Template_Execute-8                                                     3.230µ ± ∞ ¹
Template_ExecuteUpdates-8                                              2.414µ ± ∞ ¹
UserJourney-8                                                          880.1µ ± ∞ ¹
TreeNodeCreation/flat-8                                                483.1n ± ∞ ¹
TreeNodeCreation/nested-small-8                                        3.350µ ± ∞ ¹
TreeNodeCreation/nested-medium-8                                       7.878µ ± ∞ ¹
TreeNodeCreation/nested-large-8                                        23.90µ ± ∞ ¹
TreeNodeMarshalJSON/flat-8                                             4.074µ ± ∞ ¹
TreeNodeMarshalJSON/nested-small-8                                     46.27µ ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-8                                    170.8µ ± ∞ ¹
WrapperInjection/full-html-8                                           2.955µ ± ∞ ¹
WrapperInjection/fragment-8                                            1.912µ ± ∞ ¹
ExtractWrapperContent-8                                                1.897µ ± ∞ ¹
ContextOperations/with-statics-8                                       2.265µ ± ∞ ¹
ContextOperations/without-statics-8                                    2.185µ ± ∞ ¹
TreeNodeClone/flat-8                                                   304.1n ± ∞ ¹
TreeNodeClone/nested-small-8                                           2.227µ ± ∞ ¹
TreeNodeClone/nested-medium-8                                          6.915µ ± ∞ ¹
TreeNodeToMap/flat-8                                                   694.1n ± ∞ ¹
TreeNodeToMap/nested-small-8                                           4.671µ ± ∞ ¹
TreeNodeToMap/nested-medium-8                                          14.39µ ± ∞ ¹
GenerateRandomID-8                                                     93.57n ± ∞ ¹
CalculateStructureFingerprint_Small-8                                  179.6n ± ∞ ¹
CalculateStructureFingerprint_Medium-8                                 3.568µ ± ∞ ¹
CalculateStructureFingerprint_Large-8                                  28.42µ ± ∞ ¹
CalculateStructureFingerprint_DeepNested-8                             3.450µ ± ∞ ¹
CalculateStructureFingerprint_Range100-8                               238.7n ± ∞ ¹
CalculateStructureFingerprint_Range1000-8                              239.4n ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-8                             289.1n ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-8                         214.3n ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-8                            4.603µ ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-8                        3.536µ ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-8                             36.37µ ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-8                         28.49µ ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-8                           4.429µ ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-8                       3.549µ ± ∞ ¹
ExecuteTemplateWithContext_Struct-8                                    1.882µ ± ∞ ¹
ExecuteTemplateWithContext_Map-8                                       2.030µ ± ∞ ¹
Precompute/eager_all_methods-8                                         7.748µ ± ∞ ¹
Precompute/referenced_only-8                                           955.5n ± ∞ ¹
Precompute/all_referenced-8                                            8.011µ ± ∞ ¹
CompareTreesNoChanges-8                                                132.4n ± ∞ ¹
CompareTreesSmallChange-8                                              59.75n ± ∞ ¹
CompareTreesLargeChange/10-8                                           190.8n ± ∞ ¹
CompareTreesLargeChange/100-8                                          1.297µ ± ∞ ¹
CompareTreesLargeChange/1000-8                                         25.17µ ± ∞ ¹
RangeDiffUpdate-8                                                      2.221µ ± ∞ ¹
RangeDiffInsert-8                                                      2.215µ ± ∞ ¹
RangeDiffRemove-8                                                      2.224µ ± ∞ ¹
RangeDiff_TreeNode_Update-8                                            26.59µ ± ∞ ¹
RangeDiff_TreeNode_Reorder-8                                           13.13µ ± ∞ ¹
RangeDiff_TreeNode_LargeList-8                                         321.6µ ± ∞ ¹
PrepareTreeForClient/with-statics-8                                    2.025n ± ∞ ¹
PrepareTreeForClient/without-statics-8                                 921.3n ± ∞ ¹
ClientNeedsStatics_SameStructure-8                                     6.454n ± ∞ ¹
ClientNeedsStatics_DifferentStructure-8                                6.133n ± ∞ ¹
ClientNeedsStatics_DeepNested-8                                        6.447n ± ∞ ¹
ClientNeedsStatics_Range-8                                             6.600n ± ∞ ¹
ClientNeedsStatics_NilOld-8                                            1.986n ± ∞ ¹
WireSize_WithStatics-8                                                 5.345µ ± ∞ ¹
WireSize_WithoutStatics-8                                              5.227µ ± ∞ ¹
WireSizeComparison/small_5_with_statics-8                              1.482µ ± ∞ ¹
WireSizeComparison/small_5_without_statics-8                           1.179µ ± ∞ ¹
WireSizeComparison/medium_20_with_statics-8                            5.284µ ± ∞ ¹
WireSizeComparison/medium_20_without_statics-8                         5.089µ ± ∞ ¹
WireSizeComparison/large_100_with_statics-8                            25.45µ ± ∞ ¹
WireSizeComparison/large_100_without_statics-8                         25.94µ ± ∞ ¹
Parse/simple-8                                                         2.327µ ± ∞ ¹
Parse/conditional-8                                                    3.764µ ± ∞ ¹
Parse/range-8                                                          3.485µ ± ∞ ¹
Parse/nested-8                                                         4.166µ ± ∞ ¹
Parse/complex-8                                                        7.498µ ± ∞ ¹
BuildTree/simple-8                                                     371.7n ± ∞ ¹
BuildTree/conditional-true-8                                           750.2n ± ∞ ¹
BuildTree/conditional-false-8                                          467.3n ± ∞ ¹
BuildTree/range-small-8                                                2.742µ ± ∞ ¹
BuildTreeScale/small-10-8                                              7.808µ ± ∞ ¹
BuildTreeScale/medium-100-8                                            72.15µ ± ∞ ¹
BuildTreeScale/large-1000-8                                            733.5µ ± ∞ ¹
NodeRender-8                                                           81.89n ± ∞ ¹
TreeToHTML/simple-8                                                    139.2n ± ∞ ¹
TreeToHTML/nested-8                                                    250.7n ± ∞ ¹
TreeToHTML/with-ranges-8                                               224.6n ± ∞ ¹
TreeToHTMLScale/small-10-8                                             853.2n ± ∞ ¹
TreeToHTMLScale/medium-100-8                                           7.146µ ± ∞ ¹
TreeToHTMLScale/large-1000-8                                           73.11µ ± ∞ ¹
IsVoidElement-8                                                        91.54n ± ∞ ¹
NodeRenderComplex-8                                                    230.5n ± ∞ ¹
ParseActionFromHTTP-8                                                  1.968µ ± ∞ ¹
ParseActionFromWebSocket-8                                             827.0n ± ∞ ¹
PrepareUpdate/without-errors-8                                        0.3640n ± ∞ ¹
PrepareUpdate/with-errors-8                                            17.39n ± ∞ ¹
SerializeUpdate-8                                                      998.0n ± ∞ ¹
PrepareAndSerialize/simple-update-8                                    1.014µ ± ∞ ¹
PrepareAndSerialize/with-metadata-8                                    1.308µ ± ∞ ¹
ParseActionScale/small-http-8                                          1.950µ ± ∞ ¹
ParseActionScale/small-ws-8                                            787.2n ± ∞ ¹
ParseActionScale/medium-http-8                                         2.657µ ± ∞ ¹
ParseActionScale/medium-ws-8                                           1.501µ ± ∞ ¹
ParseActionScale/large-http-8                                          4.011µ ± ∞ ¹
ParseActionScale/large-ws-8                                            2.914µ ± ∞ ¹
SerializeUpdateScale/simple-8                                          944.4n ± ∞ ¹
SerializeUpdateScale/nested-8                                          2.069µ ± ∞ ¹
SerializeUpdateScale/multiple-fields-8                                 1.547µ ± ∞ ¹
ConcurrentConnections/100_connections-8                                19.76µ ± ∞ ¹
ConcurrentConnections/1000_connections-8                               143.9µ ± ∞ ¹
RegisterUnregister-8                                                   2.698µ ± ∞ ¹
GetByGroup-8                                                           276.4n ± ∞ ¹
CloseConnection-8                                                      1.224µ ± ∞ ¹
MemoryUsage-8                                                          40.35µ ± ∞ ¹
BroadcastToGroup-8                                                     15.73µ ± ∞ ¹
BufferSizes/buf_10-8                                                   275.6n ± ∞ ¹
BufferSizes/buf_50-8                                                   172.5n ± ∞ ¹
BufferSizes/buf_100-8                                                  152.7n ± ∞ ¹
BufferSizes/buf_500-8                                                  175.3n ± ∞ ¹
BufferSizes/buf_1000-8                                                 175.7n ± ∞ ¹
ConcurrentRegistrations-8                                              2.708µ ± ∞ ¹
GetByGroupExcept-8                                                     297.9n ± ∞ ¹
DispatchWithState_Cached-4                                                             467.4n ± ∞ ¹
E2EUserJourney-4                                                                       526.2µ ± ∞ ¹
E2ETodoApp-4                                                                           49.24µ ± ∞ ¹
E2ERangeOperations/add-items-4                                                         20.62µ ± ∞ ¹
E2ERangeOperations/remove-items-4                                                      12.99µ ± ∞ ¹
E2ERangeOperations/reorder-items-4                                                     15.50µ ± ∞ ¹
E2ERangeOperations/update-items-4                                                      15.49µ ± ∞ ¹
E2EMultipleSessions/sessions-1-4                                                       5.473µ ± ∞ ¹
E2EMultipleSessions/sessions-10-4                                                      54.95µ ± ∞ ¹
E2EMultipleSessions/sessions-100-4                                                     565.5µ ± ∞ ¹
SpecificationCompliance-4                                                              3.884µ ± ∞ ¹
ErrorPaths/invalid-template-syntax-4                                                   1.529m ± ∞ ¹
ErrorPaths/missing-field-4                                                             5.474µ ± ∞ ¹
ErrorPaths/nil-data-4                                                                  4.174µ ± ∞ ¹
ErrorPaths/empty-template-4                                                            1.567m ± ∞ ¹
RangeFullSwap_Simple_N10-4                                                             127.1µ ± ∞ ¹
RangeFullSwap_Simple_N100-4                                                            1.143m ± ∞ ¹
RangeFullSwap_Simple_N1000-4                                                           10.85m ± ∞ ¹
RangeFullSwap_DynamicBranch_N10-4                                                      229.2µ ± ∞ ¹
RangeFullSwap_DynamicBranch_N100-4                                                     2.210m ± ∞ ¹
RangeFullSwap_DynamicBranch_N1000-4                                                    20.82m ± ∞ ¹
RecursiveRender-4                                                                      2.143m ± ∞ ¹
RecursiveUpdate-4                                                                      12.83m ± ∞ ¹
OpaqueHTMLBaseline-4                                                                   919.3µ ± ∞ ¹
SystemCard/Counter/Dashboard/session-memory-4                                          34.97µ ± ∞ ¹
SystemCard/Counter/Dashboard/update-4                                                  17.17µ ± ∞ ¹
SystemCard/Counter/Dashboard/state-clone-4                                             707.3n ± ∞ ¹
SystemCard/Counter/Dashboard/payload-size-4                                            17.21µ ± ∞ ¹
SystemCard/Todo_App/session-memory-4                                                   408.0µ ± ∞ ¹
SystemCard/Todo_App/update-4                                                           497.8µ ± ∞ ¹
SystemCard/Todo_App/state-clone-4                                                      13.12µ ± ∞ ¹
SystemCard/Todo_App/payload-size-4                                                     492.1µ ± ∞ ¹
SystemCard/Social_Feed/session-memory-4                                                1.172m ± ∞ ¹
SystemCard/Social_Feed/update-4                                                        1.194m ± ∞ ¹
SystemCard/Social_Feed/state-clone-4                                                   50.42µ ± ∞ ¹
SystemCard/Social_Feed/payload-size-4                                                  1.216m ± ∞ ¹
SystemCard/Chat/Collab/session-memory-4                                                1.753m ± ∞ ¹
SystemCard/Chat/Collab/update-4                                                        1.261m ± ∞ ¹
SystemCard/Chat/Collab/state-clone-4                                                   59.98µ ± ∞ ¹
SystemCard/Chat/Collab/payload-size-4                                                  1.261m ± ∞ ¹
TemplateExecute/initial-render-4                                                       1.584m ± ∞ ¹
TemplateExecute/subsequent-render-4                                                    5.910µ ± ∞ ¹
TemplateExecuteUpdates/no-changes-4                                                    4.644µ ± ∞ ¹
TemplateExecuteUpdates/small-update-4                                                  4.700µ ± ∞ ¹
TemplateExecuteUpdates/large-update-4                                                  12.53µ ± ∞ ¹
TemplateComplexity/simple-fields-4                                                     11.55µ ± ∞ ¹
TemplateComplexity/with-conditionals-4                                                 7.987µ ± ∞ ¹
TemplateComplexity/with-ranges-4                                                       18.95µ ± ∞ ¹
TemplateComplexity/deeply-nested-4                                                     18.38µ ± ∞ ¹
TemplateConcurrent/goroutines-1-4                                                      6.173µ ± ∞ ¹
TemplateConcurrent/goroutines-10-4                                                     6.240µ ± ∞ ¹
TemplateConcurrent/goroutines-100-4                                                    6.408µ ± ∞ ¹
Template_Execute-4                                                                     6.212µ ± ∞ ¹
Template_ExecuteUpdates-4                                                              4.961µ ± ∞ ¹
TopicFanoutByN/N=1-4                                                                   481.9n ± ∞ ¹
TopicFanoutByN/N=5-4                                                                   1.402µ ± ∞ ¹
TopicFanoutByN/N=10-4                                                                  3.245µ ± ∞ ¹
TopicFanoutByN/N=50-4                                                                  19.92µ ± ∞ ¹
TopicFanoutByN/N=100-4                                                                 42.65µ ± ∞ ¹
TopicPatternScanByP/P=1-4                                                              371.1n ± ∞ ¹
TopicPatternScanByP/P=10-4                                                             1.570µ ± ∞ ¹
TopicPatternScanByP/P=100-4                                                            13.19µ ± ∞ ¹
UserJourney-4                                                                          1.615m ± ∞ ¹
TreeNodeCreation/flat-4                                                                650.3n ± ∞ ¹
TreeNodeCreation/nested-small-4                                                        4.588µ ± ∞ ¹
TreeNodeCreation/nested-medium-4                                                       13.77µ ± ∞ ¹
TreeNodeCreation/nested-large-4                                                        42.34µ ± ∞ ¹
TreeNodeMarshalJSON/flat-4                                                             5.715µ ± ∞ ¹
TreeNodeMarshalJSON/nested-small-4                                                     42.02µ ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-4                                                    126.6µ ± ∞ ¹
WrapperInjection/full-html-4                                                           5.646µ ± ∞ ¹
WrapperInjection/fragment-4                                                            3.691µ ± ∞ ¹
WrapperInjection/string-fallback-tokenizer-4                                           3.406µ ± ∞ ¹
ExtractWrapperContent-4                                                                3.538µ ± ∞ ¹
ContextOperations/with-statics-4                                                       3.758µ ± ∞ ¹
ContextOperations/without-statics-4                                                    3.763µ ± ∞ ¹
TreeNodeClone/flat-4                                                                   536.7n ± ∞ ¹
TreeNodeClone/nested-small-4                                                           3.867µ ± ∞ ¹
TreeNodeClone/nested-medium-4                                                          11.41µ ± ∞ ¹
TreeNodeToMap/flat-4                                                                   1.009µ ± ∞ ¹
TreeNodeToMap/nested-small-4                                                           6.871µ ± ∞ ¹
TreeNodeToMap/nested-medium-4                                                          21.22µ ± ∞ ¹
GenerateRandomID-4                                                                     108.6n ± ∞ ¹
CalculateStructureFingerprint_Small-4                                                  247.5n ± ∞ ¹
CalculateStructureFingerprint_Medium-4                                                 4.488µ ± ∞ ¹
CalculateStructureFingerprint_Large-4                                                  32.43µ ± ∞ ¹
CalculateStructureFingerprint_DeepNested-4                                             5.073µ ± ∞ ¹
CalculateStructureFingerprint_Range100-4                                               318.6n ± ∞ ¹
CalculateStructureFingerprint_Range1000-4                                              325.7n ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-4                                             410.1n ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-4                                         305.5n ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-4                                            6.269µ ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-4                                        4.683µ ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-4                                             46.25µ ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-4                                         33.38µ ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-4                                           5.207µ ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-4                                       4.113µ ± ∞ ¹
ExecuteTemplateWithContext_Struct-4                                                    3.603µ ± ∞ ¹
ExecuteTemplateWithContext_Map-4                                                       3.859µ ± ∞ ¹
Precompute/eager_all_methods-4                                                         4.828µ ± ∞ ¹
Precompute/referenced_only-4                                                           457.3n ± ∞ ¹
Precompute/all_referenced-4                                                            4.953µ ± ∞ ¹
CompareTreesNoChanges-4                                                                218.9n ± ∞ ¹
CompareTreesSmallChange-4                                                              109.2n ± ∞ ¹
CompareTreesLargeChange/10-4                                                           325.3n ± ∞ ¹
CompareTreesLargeChange/100-4                                                          2.321µ ± ∞ ¹
CompareTreesLargeChange/1000-4                                                         41.84µ ± ∞ ¹
RangeDiffUpdate-4                                                                      4.811µ ± ∞ ¹
RangeDiffInsert-4                                                                      4.922µ ± ∞ ¹
RangeDiffRemove-4                                                                      4.901µ ± ∞ ¹
RangeDiff_TreeNode_Update-4                                                            164.5µ ± ∞ ¹
RangeDiff_TreeNode_Reorder-4                                                           116.2µ ± ∞ ¹
RangeDiff_TreeNode_LargeList-4                                                         1.871m ± ∞ ¹
PrepareTreeForClient/with-statics-4                                                    2.371n ± ∞ ¹
PrepareTreeForClient/without-statics-4                                                 1.629µ ± ∞ ¹
ClientNeedsStatics_SameStructure-4                                                     9.374n ± ∞ ¹
ClientNeedsStatics_DifferentStructure-4                                                8.748n ± ∞ ¹
ClientNeedsStatics_DeepNested-4                                                        9.375n ± ∞ ¹
ClientNeedsStatics_Range-4                                                             9.068n ± ∞ ¹
ClientNeedsStatics_NilOld-4                                                            1.870n ± ∞ ¹
WireSize_WithStatics-4                                                                 9.311µ ± ∞ ¹
WireSize_WithoutStatics-4                                                              9.018µ ± ∞ ¹
WireSizeComparison/small_5_with_statics-4                                              2.653µ ± ∞ ¹
WireSizeComparison/small_5_without_statics-4                                           2.262µ ± ∞ ¹
WireSizeComparison/medium_20_with_statics-4                                            9.211µ ± ∞ ¹
WireSizeComparison/medium_20_without_statics-4                                         9.029µ ± ∞ ¹
WireSizeComparison/large_100_with_statics-4                                            41.63µ ± ∞ ¹
WireSizeComparison/large_100_without_statics-4                                         42.87µ ± ∞ ¹
RangeDiff_Stream_Append_Small-4                                                        8.387µ ± ∞ ¹
RangeDiff_Stream_Append_Medium-4                                                       73.70µ ± ∞ ¹
RangeDiff_Stream_Append_Large-4                                                        9.614m ± ∞ ¹
RangeDiff_Stream_Update_Small-4                                                        8.170µ ± ∞ ¹
RangeDiff_Stream_Update_Medium-4                                                       74.07µ ± ∞ ¹
RangeDiff_Stream_Update_Large-4                                                        10.19m ± ∞ ¹
RangeDiff_Stream_Reorder_Small-4                                                       7.529µ ± ∞ ¹
RangeDiff_Stream_Reorder_Medium-4                                                      67.19µ ± ∞ ¹
RangeDiff_Stream_Reorder_Large-4                                                       8.095m ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Small-4                                               11.05µ ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Medium-4                                              77.91µ ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Large-4                                               9.556m ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Small-4                                               9.340µ ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Medium-4                                              75.08µ ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Large-4                                               10.14m ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Small-4                                              8.173µ ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Medium-4                                             71.03µ ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Large-4                                              8.179m ± ∞ ¹
RangeDiff_LegacyPartialDelta_Update_WireSize-4                                         626.4n ± ∞ ¹
Parse/simple-4                                                                         4.621µ ± ∞ ¹
Parse/conditional-4                                                                    7.314µ ± ∞ ¹
Parse/range-4                                                                          6.574µ ± ∞ ¹
Parse/nested-4                                                                         8.120µ ± ∞ ¹
Parse/complex-4                                                                        14.44µ ± ∞ ¹
BuildTree/simple-4                                                                     671.3n ± ∞ ¹
BuildTree/conditional-true-4                                                           1.300µ ± ∞ ¹
BuildTree/conditional-false-4                                                          856.3n ± ∞ ¹
BuildTree/range-small-4                                                                4.092µ ± ∞ ¹
BuildTreeScale/small-10-4                                                              11.20µ ± ∞ ¹
BuildTreeScale/medium-100-4                                                            101.5µ ± ∞ ¹
BuildTreeScale/large-1000-4                                                            901.3µ ± ∞ ¹
NodeRender-4                                                                           108.5n ± ∞ ¹
TreeToHTML/simple-4                                                                    207.5n ± ∞ ¹
TreeToHTML/nested-4                                                                    338.1n ± ∞ ¹
TreeToHTML/with-ranges-4                                                               318.3n ± ∞ ¹
TreeToHTMLScale/small-10-4                                                             1.291µ ± ∞ ¹
TreeToHTMLScale/medium-100-4                                                           10.70µ ± ∞ ¹
TreeToHTMLScale/large-1000-4                                                           110.6µ ± ∞ ¹
IsVoidElement-4                                                                        97.71n ± ∞ ¹
NodeRenderComplex-4                                                                    301.2n ± ∞ ¹
ParseActionFromHTTP-4                                                                  2.793µ ± ∞ ¹
ParseActionFromWebSocket-4                                                             506.4n ± ∞ ¹
PrepareUpdate/without-errors-4                                                        0.3124n ± ∞ ¹
PrepareUpdate/with-errors-4                                                            31.50n ± ∞ ¹
SerializeUpdate-4                                                                      1.199µ ± ∞ ¹
PrepareAndSerialize/simple-update-4                                                    1.236µ ± ∞ ¹
PrepareAndSerialize/with-metadata-4                                                    1.855µ ± ∞ ¹
ParseActionScale/small-http-4                                                          2.810µ ± ∞ ¹
ParseActionScale/small-ws-4                                                            495.8n ± ∞ ¹
ParseActionScale/medium-http-4                                                         3.431µ ± ∞ ¹
ParseActionScale/medium-ws-4                                                           1.056µ ± ∞ ¹
ParseActionScale/large-http-4                                                          4.835µ ± ∞ ¹
ParseActionScale/large-ws-4                                                            2.438µ ± ∞ ¹
SerializeUpdateScale/simple-4                                                          1.197µ ± ∞ ¹
SerializeUpdateScale/nested-4                                                          2.293µ ± ∞ ¹
SerializeUpdateScale/multiple-fields-4                                                 1.794µ ± ∞ ¹
ConcurrentConnections/1000_connections-4                                               237.6µ ± ∞ ¹
RegisterUnregister-4                                                                   4.650µ ± ∞ ¹
GetByGroup-4                                                                           445.3n ± ∞ ¹
CloseConnection-4                                                                      3.676µ ± ∞ ¹
MemoryUsage-4                                                                          89.16µ ± ∞ ¹
BroadcastToGroup-4                                                                     21.44µ ± ∞ ¹
BufferSizes/buf_10-4                                                                   376.4n ± ∞ ¹
BufferSizes/buf_50-4                                                                   192.8n ± ∞ ¹
BufferSizes/buf_100-4                                                                  174.2n ± ∞ ¹
BufferSizes/buf_500-4                                                                  170.0n ± ∞ ¹
BufferSizes/buf_1000-4                                                                 171.9n ± ∞ ¹
ConcurrentRegistrations-4                                                              4.612µ ± ∞ ¹
GetByGroupExcept-4                                                                     553.3n ± ∞ ¹
geomean                                                                2.307µ          8.977µ        ? ² ³
¹ need >= 6 samples for confidence interval at level 0.95
² benchmark set differs from baseline; geomeans may not be comparable
³ ratios must be >0 to compute geomean

                                                 │ testdata/benchmarks/baseline.txt │   current-bench.txt    │
                                                 │               B/op               │     B/op       vs base │
DispatchWithState_Cached-8                                              80.00 ± ∞ ¹
E2EUserJourney-8                                                      246.0Ki ± ∞ ¹
E2ETodoApp-8                                                          22.64Ki ± ∞ ¹
E2ERangeOperations/add-items-8                                        9.184Ki ± ∞ ¹
E2ERangeOperations/remove-items-8                                     5.366Ki ± ∞ ¹
E2ERangeOperations/reorder-items-8                                    6.617Ki ± ∞ ¹
E2ERangeOperations/update-items-8                                     6.617Ki ± ∞ ¹
E2EMultipleSessions/sessions-1-8                                      2.743Ki ± ∞ ¹
E2EMultipleSessions/sessions-10-8                                     27.38Ki ± ∞ ¹
E2EMultipleSessions/sessions-100-8                                    273.7Ki ± ∞ ¹
SpecificationCompliance-8                                             1.827Ki ± ∞ ¹
ErrorPaths/invalid-template-syntax-8                                  382.9Ki ± ∞ ¹
ErrorPaths/missing-field-8                                            2.899Ki ± ∞ ¹
ErrorPaths/nil-data-8                                                 7.144Ki ± ∞ ¹
ErrorPaths/empty-template-8                                           405.5Ki ± ∞ ¹
TemplateExecute/initial-render-8                                      409.3Ki ± ∞ ¹
TemplateExecute/subsequent-render-8                                   2.962Ki ± ∞ ¹
TemplateExecuteUpdates/no-changes-8                                   2.149Ki ± ∞ ¹
TemplateExecuteUpdates/small-update-8                                 2.149Ki ± ∞ ¹
TemplateExecuteUpdates/large-update-8                                 5.065Ki ± ∞ ¹
TemplateComplexity/simple-fields-8                                    4.571Ki ± ∞ ¹
TemplateComplexity/with-conditionals-8                                3.899Ki ± ∞ ¹
TemplateComplexity/with-ranges-8                                      7.378Ki ± ∞ ¹
TemplateComplexity/deeply-nested-8                                    7.550Ki ± ∞ ¹
TemplateConcurrent/goroutines-1-8                                     2.962Ki ± ∞ ¹
TemplateConcurrent/goroutines-10-8                                    2.962Ki ± ∞ ¹
TemplateConcurrent/goroutines-100-8                                   2.963Ki ± ∞ ¹
Template_Execute-8                                                    3.118Ki ± ∞ ¹
Template_ExecuteUpdates-8                                             2.267Ki ± ∞ ¹
UserJourney-8                                                         920.9Ki ± ∞ ¹
TreeNodeCreation/flat-8                                               1.234Ki ± ∞ ¹
TreeNodeCreation/nested-small-8                                       7.875Ki ± ∞ ¹
TreeNodeCreation/nested-medium-8                                      23.91Ki ± ∞ ¹
TreeNodeCreation/nested-large-8                                       72.00Ki ± ∞ ¹
TreeNodeMarshalJSON/flat-8                                            3.472Ki ± ∞ ¹
TreeNodeMarshalJSON/nested-small-8                                    27.29Ki ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-8                                   89.06Ki ± ∞ ¹
WrapperInjection/full-html-8                                          6.930Ki ± ∞ ¹
WrapperInjection/fragment-8                                           6.266Ki ± ∞ ¹
ExtractWrapperContent-8                                               5.883Ki ± ∞ ¹
ContextOperations/with-statics-8                                      7.266Ki ± ∞ ¹
ContextOperations/without-statics-8                                   7.266Ki ± ∞ ¹
TreeNodeClone/flat-8                                                  1.078Ki ± ∞ ¹
TreeNodeClone/nested-small-8                                          7.266Ki ± ∞ ¹
TreeNodeClone/nested-medium-8                                         22.03Ki ± ∞ ¹
TreeNodeToMap/flat-8                                                  2.109Ki ± ∞ ¹
TreeNodeToMap/nested-small-8                                          14.06Ki ± ∞ ¹
TreeNodeToMap/nested-medium-8                                         42.54Ki ± ∞ ¹
GenerateRandomID-8                                                      24.00 ± ∞ ¹
CalculateStructureFingerprint_Small-8                                   88.00 ± ∞ ¹
CalculateStructureFingerprint_Medium-8                                  904.0 ± ∞ ¹
CalculateStructureFingerprint_Large-8                                 4.016Ki ± ∞ ¹
CalculateStructureFingerprint_DeepNested-8                            1.781Ki ± ∞ ¹
CalculateStructureFingerprint_Range100-8                                104.0 ± ∞ ¹
CalculateStructureFingerprint_Range1000-8                               104.0 ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-8                              184.0 ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-8                          112.0 ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-8                            1000.0 ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-8                         928.0 ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-8                            4.109Ki ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-8                        4.039Ki ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-8                          1.875Ki ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-8                      1.805Ki ± ∞ ¹
ExecuteTemplateWithContext_Struct-8                                    1003.0 ± ∞ ¹
ExecuteTemplateWithContext_Map-8                                      1.151Ki ± ∞ ¹
Precompute/eager_all_methods-8                                        1.570Ki ± ∞ ¹
Precompute/referenced_only-8                                            440.0 ± ∞ ¹
Precompute/all_referenced-8                                           1.570Ki ± ∞ ¹
CompareTreesNoChanges-8                                                 288.0 ± ∞ ¹
CompareTreesSmallChange-8                                               144.0 ± ∞ ¹
CompareTreesLargeChange/10-8                                            288.0 ± ∞ ¹
CompareTreesLargeChange/100-8                                         1.875Ki ± ∞ ¹
CompareTreesLargeChange/1000-8                                        18.94Ki ± ∞ ¹
RangeDiffUpdate-8                                                     13.77Ki ± ∞ ¹
RangeDiffInsert-8                                                     13.77Ki ± ∞ ¹
RangeDiffRemove-8                                                     13.77Ki ± ∞ ¹
RangeDiff_TreeNode_Update-8                                           32.67Ki ± ∞ ¹
RangeDiff_TreeNode_Reorder-8                                          20.62Ki ± ∞ ¹
RangeDiff_TreeNode_LargeList-8                                        439.0Ki ± ∞ ¹
PrepareTreeForClient/with-statics-8                                     0.000 ± ∞ ¹
PrepareTreeForClient/without-statics-8                                1.875Ki ± ∞ ¹
ClientNeedsStatics_SameStructure-8                                      0.000 ± ∞ ¹
ClientNeedsStatics_DifferentStructure-8                                 0.000 ± ∞ ¹
ClientNeedsStatics_DeepNested-8                                         0.000 ± ∞ ¹
ClientNeedsStatics_Range-8                                              0.000 ± ∞ ¹
ClientNeedsStatics_NilOld-8                                             0.000 ± ∞ ¹
WireSize_WithStatics-8                                                4.271Ki ± ∞ ¹
WireSize_WithoutStatics-8                                             4.528Ki ± ∞ ¹
WireSizeComparison/small_5_with_statics-8                              1017.0 ± ∞ ¹
WireSizeComparison/small_5_without_statics-8                          1.017Ki ± ∞ ¹
WireSizeComparison/medium_20_with_statics-8                           4.271Ki ± ∞ ¹
WireSizeComparison/medium_20_without_statics-8                        4.528Ki ± ∞ ¹
WireSizeComparison/large_100_with_statics-8                           19.10Ki ± ∞ ¹
WireSizeComparison/large_100_without_statics-8                        20.93Ki ± ∞ ¹
Parse/simple-8                                                        5.125Ki ± ∞ ¹
Parse/conditional-8                                                   5.867Ki ± ∞ ¹
Parse/range-8                                                         5.703Ki ± ∞ ¹
Parse/nested-8                                                        6.078Ki ± ∞ ¹
Parse/complex-8                                                       8.375Ki ± ∞ ¹
BuildTree/simple-8                                                      672.0 ± ∞ ¹
BuildTree/conditional-true-8                                          1.297Ki ± ∞ ¹
BuildTree/conditional-false-8                                           968.0 ± ∞ ¹
BuildTree/range-small-8                                               3.862Ki ± ∞ ¹
BuildTreeScale/small-10-8                                             11.30Ki ± ∞ ¹
BuildTreeScale/medium-100-8                                           107.3Ki ± ∞ ¹
BuildTreeScale/large-1000-8                                           1.045Mi ± ∞ ¹
NodeRender-8                                                            56.00 ± ∞ ¹
TreeToHTML/simple-8                                                     64.00 ± ∞ ¹
TreeToHTML/nested-8                                                     144.0 ± ∞ ¹
TreeToHTML/with-ranges-8                                                72.00 ± ∞ ¹
TreeToHTMLScale/small-10-8                                              544.0 ± ∞ ¹
TreeToHTMLScale/medium-100-8                                          3.634Ki ± ∞ ¹
TreeToHTMLScale/large-1000-8                                          65.42Ki ± ∞ ¹
IsVoidElement-8                                                         0.000 ± ∞ ¹
NodeRenderComplex-8                                                     248.0 ± ∞ ¹
ParseActionFromHTTP-8                                                 6.799Ki ± ∞ ¹
ParseActionFromWebSocket-8                                              656.0 ± ∞ ¹
PrepareUpdate/without-errors-8                                          0.000 ± ∞ ¹
PrepareUpdate/with-errors-8                                             32.00 ± ∞ ¹
SerializeUpdate-8                                                       648.0 ± ∞ ¹
PrepareAndSerialize/simple-update-8                                     672.0 ± ∞ ¹
PrepareAndSerialize/with-metadata-8                                     848.0 ± ∞ ¹
ParseActionScale/small-http-8                                         6.791Ki ± ∞ ¹
ParseActionScale/small-ws-8                                             648.0 ± ∞ ¹
ParseActionScale/medium-http-8                                        6.955Ki ± ∞ ¹
ParseActionScale/medium-ws-8                                            760.0 ± ∞ ¹
ParseActionScale/large-http-8                                         7.885Ki ± ∞ ¹
ParseActionScale/large-ws-8                                           1.578Ki ± ∞ ¹
SerializeUpdateScale/simple-8                                           648.0 ± ∞ ¹
SerializeUpdateScale/nested-8                                         1.282Ki ± ∞ ¹
SerializeUpdateScale/multiple-fields-8                                  968.0 ± ∞ ¹
ConcurrentConnections/100_connections-8                               3.516Ki ± ∞ ¹
ConcurrentConnections/1000_connections-8                              35.16Ki ± ∞ ¹
RegisterUnregister-8                                                  1.182Ki ± ∞ ¹
GetByGroup-8                                                            896.0 ± ∞ ¹
CloseConnection-8                                                       248.0 ± ∞ ¹
MemoryUsage-8                                                         95.83Ki ± ∞ ¹
BroadcastToGroup-8                                                    4.000Ki ± ∞ ¹
BufferSizes/buf_10-8                                                    113.0 ± ∞ ¹
BufferSizes/buf_50-8                                                    54.00 ± ∞ ¹
BufferSizes/buf_100-8                                                   47.00 ± ∞ ¹
BufferSizes/buf_500-8                                                   36.00 ± ∞ ¹
BufferSizes/buf_1000-8                                                  36.00 ± ∞ ¹
ConcurrentRegistrations-8                                             1.210Ki ± ∞ ¹
GetByGroupExcept-8                                                      896.0 ± ∞ ¹
DispatchWithState_Cached-4                                                              80.00 ± ∞ ¹
E2EUserJourney-4                                                                      272.6Ki ± ∞ ¹
E2ETodoApp-4                                                                          24.65Ki ± ∞ ¹
E2ERangeOperations/add-items-4                                                        11.16Ki ± ∞ ¹
E2ERangeOperations/remove-items-4                                                     7.063Ki ± ∞ ¹
E2ERangeOperations/reorder-items-4                                                    8.418Ki ± ∞ ¹
E2ERangeOperations/update-items-4                                                     8.418Ki ± ∞ ¹
E2EMultipleSessions/sessions-1-4                                                      3.011Ki ± ∞ ¹
E2EMultipleSessions/sessions-10-4                                                     30.06Ki ± ∞ ¹
E2EMultipleSessions/sessions-100-4                                                    300.2Ki ± ∞ ¹
SpecificationCompliance-4                                                             1.967Ki ± ∞ ¹
ErrorPaths/invalid-template-syntax-4                                                  334.6Ki ± ∞ ¹
ErrorPaths/missing-field-4                                                            3.039Ki ± ∞ ¹
ErrorPaths/nil-data-4                                                                 2.227Ki ± ∞ ¹
ErrorPaths/empty-template-4                                                           362.1Ki ± ∞ ¹
RangeFullSwap_Simple_N10-4                                                            62.12Ki ± ∞ ¹
RangeFullSwap_Simple_N100-4                                                           583.1Ki ± ∞ ¹
RangeFullSwap_Simple_N1000-4                                                          6.108Mi ± ∞ ¹
RangeFullSwap_DynamicBranch_N10-4                                                     113.3Ki ± ∞ ¹
RangeFullSwap_DynamicBranch_N100-4                                                    1.069Mi ± ∞ ¹
RangeFullSwap_DynamicBranch_N1000-4                                                   11.87Mi ± ∞ ¹
RecursiveRender-4                                                                     1.027Mi ± ∞ ¹
RecursiveUpdate-4                                                                     8.946Mi ± ∞ ¹
OpaqueHTMLBaseline-4                                                                  204.4Ki ± ∞ ¹
SystemCard/Counter/Dashboard/session-memory-4                                         18.96Ki ± ∞ ¹
SystemCard/Counter/Dashboard/update-4                                                 7.487Ki ± ∞ ¹
SystemCard/Counter/Dashboard/state-clone-4                                              168.0 ± ∞ ¹
SystemCard/Counter/Dashboard/payload-size-4                                           7.487Ki ± ∞ ¹
SystemCard/Todo_App/session-memory-4                                                  166.5Ki ± ∞ ¹
SystemCard/Todo_App/update-4                                                          237.9Ki ± ∞ ¹
SystemCard/Todo_App/state-clone-4                                                     4.135Ki ± ∞ ¹
SystemCard/Todo_App/payload-size-4                                                    237.9Ki ± ∞ ¹
SystemCard/Social_Feed/session-memory-4                                               519.7Ki ± ∞ ¹
SystemCard/Social_Feed/update-4                                                       627.9Ki ± ∞ ¹
SystemCard/Social_Feed/state-clone-4                                                  19.89Ki ± ∞ ¹
SystemCard/Social_Feed/payload-size-4                                                 628.5Ki ± ∞ ¹
SystemCard/Chat/Collab/session-memory-4                                               732.9Ki ± ∞ ¹
SystemCard/Chat/Collab/update-4                                                       611.4Ki ± ∞ ¹
SystemCard/Chat/Collab/state-clone-4                                                  22.03Ki ± ∞ ¹
SystemCard/Chat/Collab/payload-size-4                                                 611.5Ki ± ∞ ¹
TemplateExecute/initial-render-4                                                      365.5Ki ± ∞ ¹
TemplateExecute/subsequent-render-4                                                   3.102Ki ± ∞ ¹
TemplateExecuteUpdates/no-changes-4                                                   2.422Ki ± ∞ ¹
TemplateExecuteUpdates/small-update-4                                                 2.422Ki ± ∞ ¹
TemplateExecuteUpdates/large-update-4                                                 5.337Ki ± ∞ ¹
TemplateComplexity/simple-fields-4                                                    4.711Ki ± ∞ ¹
TemplateComplexity/with-conditionals-4                                                4.039Ki ± ∞ ¹
TemplateComplexity/with-ranges-4                                                      9.009Ki ± ∞ ¹
TemplateComplexity/deeply-nested-4                                                    9.087Ki ± ∞ ¹
TemplateConcurrent/goroutines-1-4                                                     3.102Ki ± ∞ ¹
TemplateConcurrent/goroutines-10-4                                                    3.102Ki ± ∞ ¹
TemplateConcurrent/goroutines-100-4                                                   3.103Ki ± ∞ ¹
Template_Execute-4                                                                    3.258Ki ± ∞ ¹
Template_ExecuteUpdates-4                                                             2.547Ki ± ∞ ¹
TopicFanoutByN/N=1-4                                                                    232.0 ± ∞ ¹
TopicFanoutByN/N=5-4                                                                    400.0 ± ∞ ¹
TopicFanoutByN/N=10-4                                                                   920.0 ± ∞ ¹
TopicFanoutByN/N=50-4                                                                 4.227Ki ± ∞ ¹
TopicFanoutByN/N=100-4                                                                8.539Ki ± ∞ ¹
TopicPatternScanByP/P=1-4                                                               256.0 ± ∞ ¹
TopicPatternScanByP/P=10-4                                                              992.0 ± ∞ ¹
TopicPatternScanByP/P=100-4                                                           8.000Ki ± ∞ ¹
UserJourney-4                                                                         940.5Ki ± ∞ ¹
TreeNodeCreation/flat-4                                                               1.234Ki ± ∞ ¹
TreeNodeCreation/nested-small-4                                                       7.875Ki ± ∞ ¹
TreeNodeCreation/nested-medium-4                                                      23.91Ki ± ∞ ¹
TreeNodeCreation/nested-large-4                                                       72.00Ki ± ∞ ¹
TreeNodeMarshalJSON/flat-4                                                            4.979Ki ± ∞ ¹
TreeNodeMarshalJSON/nested-small-4                                                    36.43Ki ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-4                                                   116.8Ki ± ∞ ¹
WrapperInjection/full-html-4                                                          6.930Ki ± ∞ ¹
WrapperInjection/fragment-4                                                           6.266Ki ± ∞ ¹
WrapperInjection/string-fallback-tokenizer-4                                          4.938Ki ± ∞ ¹
ExtractWrapperContent-4                                                               5.883Ki ± ∞ ¹
ContextOperations/with-statics-4                                                      7.266Ki ± ∞ ¹
ContextOperations/without-statics-4                                                   7.266Ki ± ∞ ¹
TreeNodeClone/flat-4                                                                  1.078Ki ± ∞ ¹
TreeNodeClone/nested-small-4                                                          7.266Ki ± ∞ ¹
TreeNodeClone/nested-medium-4                                                         22.03Ki ± ∞ ¹
TreeNodeToMap/flat-4                                                                  2.109Ki ± ∞ ¹
TreeNodeToMap/nested-small-4                                                          14.06Ki ± ∞ ¹
TreeNodeToMap/nested-medium-4                                                         42.54Ki ± ∞ ¹
GenerateRandomID-4                                                                      24.00 ± ∞ ¹
CalculateStructureFingerprint_Small-4                                                   88.00 ± ∞ ¹
CalculateStructureFingerprint_Medium-4                                                  904.0 ± ∞ ¹
CalculateStructureFingerprint_Large-4                                                 4.016Ki ± ∞ ¹
CalculateStructureFingerprint_DeepNested-4                                            1.781Ki ± ∞ ¹
CalculateStructureFingerprint_Range100-4                                                104.0 ± ∞ ¹
CalculateStructureFingerprint_Range1000-4                                               104.0 ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-4                                              152.0 ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-4                                          80.00 ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-4                                             968.0 ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-4                                         896.0 ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-4                                            4.078Ki ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-4                                        4.008Ki ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-4                                            952.0 ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-4                                        880.0 ± ∞ ¹
ExecuteTemplateWithContext_Struct-4                                                    1002.0 ± ∞ ¹
ExecuteTemplateWithContext_Map-4                                                      1.150Ki ± ∞ ¹
Precompute/eager_all_methods-4                                                        1.570Ki ± ∞ ¹
Precompute/referenced_only-4                                                            440.0 ± ∞ ¹
Precompute/all_referenced-4                                                           1.570Ki ± ∞ ¹
CompareTreesNoChanges-4                                                                 288.0 ± ∞ ¹
CompareTreesSmallChange-4                                                               144.0 ± ∞ ¹
CompareTreesLargeChange/10-4                                                            288.0 ± ∞ ¹
CompareTreesLargeChange/100-4                                                         1.875Ki ± ∞ ¹
CompareTreesLargeChange/1000-4                                                        18.94Ki ± ∞ ¹
RangeDiffUpdate-4                                                                     17.17Ki ± ∞ ¹
RangeDiffInsert-4                                                                     17.17Ki ± ∞ ¹
RangeDiffRemove-4                                                                     17.17Ki ± ∞ ¹
RangeDiff_TreeNode_Update-4                                                           90.48Ki ± ∞ ¹
RangeDiff_TreeNode_Reorder-4                                                          66.15Ki ± ∞ ¹
RangeDiff_TreeNode_LargeList-4                                                        995.4Ki ± ∞ ¹
PrepareTreeForClient/with-statics-4                                                     0.000 ± ∞ ¹
PrepareTreeForClient/without-statics-4                                                1.875Ki ± ∞ ¹
ClientNeedsStatics_SameStructure-4                                                      0.000 ± ∞ ¹
ClientNeedsStatics_DifferentStructure-4                                                 0.000 ± ∞ ¹
ClientNeedsStatics_DeepNested-4                                                         0.000 ± ∞ ¹
ClientNeedsStatics_Range-4                                                              0.000 ± ∞ ¹
ClientNeedsStatics_NilOld-4                                                             0.000 ± ∞ ¹
WireSize_WithStatics-4                                                                5.659Ki ± ∞ ¹
WireSize_WithoutStatics-4                                                             5.949Ki ± ∞ ¹
WireSizeComparison/small_5_with_statics-4                                             1.407Ki ± ∞ ¹
WireSizeComparison/small_5_without_statics-4                                          1.493Ki ± ∞ ¹
WireSizeComparison/medium_20_with_statics-4                                           5.659Ki ± ∞ ¹
WireSizeComparison/medium_20_without_statics-4                                        5.949Ki ± ∞ ¹
WireSizeComparison/large_100_with_statics-4                                           24.03Ki ± ∞ ¹
WireSizeComparison/large_100_without_statics-4                                        25.89Ki ± ∞ ¹
RangeDiff_Stream_Append_Small-4                                                       4.898Ki ± ∞ ¹
RangeDiff_Stream_Append_Medium-4                                                      40.95Ki ± ∞ ¹
RangeDiff_Stream_Append_Large-4                                                       4.219Mi ± ∞ ¹
RangeDiff_Stream_Update_Small-4                                                       5.375Ki ± ∞ ¹
RangeDiff_Stream_Update_Medium-4                                                      44.42Ki ± ∞ ¹
RangeDiff_Stream_Update_Large-4                                                       4.635Mi ± ∞ ¹
RangeDiff_Stream_Reorder_Small-4                                                      4.820Ki ± ∞ ¹
RangeDiff_Stream_Reorder_Medium-4                                                     42.29Ki ± ∞ ¹
RangeDiff_Stream_Reorder_Large-4                                                      4.479Mi ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Small-4                                              5.961Ki ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Medium-4                                             42.06Ki ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Large-4                                              4.223Mi ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Small-4                                              5.603Ki ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Medium-4                                             44.66Ki ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Large-4                                              4.636Mi ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Small-4                                             4.954Ki ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Medium-4                                            43.35Ki ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Large-4                                             4.731Mi ± ∞ ¹
RangeDiff_LegacyPartialDelta_Update_WireSize-4                                          192.0 ± ∞ ¹
Parse/simple-4                                                                        5.148Ki ± ∞ ¹
Parse/conditional-4                                                                   5.891Ki ± ∞ ¹
Parse/range-4                                                                         5.727Ki ± ∞ ¹
Parse/nested-4                                                                        6.102Ki ± ∞ ¹
Parse/complex-4                                                                       8.398Ki ± ∞ ¹
BuildTree/simple-4                                                                      688.0 ± ∞ ¹
BuildTree/conditional-true-4                                                          1.312Ki ± ∞ ¹
BuildTree/conditional-false-4                                                           984.0 ± ∞ ¹
BuildTree/range-small-4                                                               3.781Ki ± ∞ ¹
BuildTreeScale/small-10-4                                                             11.02Ki ± ∞ ¹
BuildTreeScale/medium-100-4                                                           104.1Ki ± ∞ ¹
BuildTreeScale/large-1000-4                                                           1.030Mi ± ∞ ¹
NodeRender-4                                                                            56.00 ± ∞ ¹
TreeToHTML/simple-4                                                                     64.00 ± ∞ ¹
TreeToHTML/nested-4                                                                     144.0 ± ∞ ¹
TreeToHTML/with-ranges-4                                                                72.00 ± ∞ ¹
TreeToHTMLScale/small-10-4                                                              544.0 ± ∞ ¹
TreeToHTMLScale/medium-100-4                                                          3.633Ki ± ∞ ¹
TreeToHTMLScale/large-1000-4                                                          65.41Ki ± ∞ ¹
IsVoidElement-4                                                                         0.000 ± ∞ ¹
NodeRenderComplex-4                                                                     248.0 ± ∞ ¹
ParseActionFromHTTP-4                                                                 6.556Ki ± ∞ ¹
ParseActionFromWebSocket-4                                                              456.0 ± ∞ ¹
PrepareUpdate/without-errors-4                                                          0.000 ± ∞ ¹
PrepareUpdate/with-errors-4                                                             64.00 ± ∞ ¹
SerializeUpdate-4                                                                       896.0 ± ∞ ¹
PrepareAndSerialize/simple-update-4                                                     920.0 ± ∞ ¹
PrepareAndSerialize/with-metadata-4                                                   1.310Ki ± ∞ ¹
ParseActionScale/small-http-4                                                         6.540Ki ± ∞ ¹
ParseActionScale/small-ws-4                                                             440.0 ± ∞ ¹
ParseActionScale/medium-http-4                                                        6.751Ki ± ∞ ¹
ParseActionScale/medium-ws-4                                                            608.0 ± ∞ ¹
ParseActionScale/large-http-4                                                         7.759Ki ± ∞ ¹
ParseActionScale/large-ws-4                                                           1.508Ki ± ∞ ¹
SerializeUpdateScale/simple-4                                                           896.0 ± ∞ ¹
SerializeUpdateScale/nested-4                                                         1.759Ki ± ∞ ¹
SerializeUpdateScale/multiple-fields-4                                                1.438Ki ± ∞ ¹
ConcurrentConnections/1000_connections-4                                              35.17Ki ± ∞ ¹
RegisterUnregister-4                                                                  1.433Ki ± ∞ ¹
GetByGroup-4                                                                            896.0 ± ∞ ¹
CloseConnection-4                                                                       248.0 ± ∞ ¹
MemoryUsage-4                                                                         120.7Ki ± ∞ ¹
BroadcastToGroup-4                                                                    4.000Ki ± ∞ ¹
BufferSizes/buf_10-4                                                                    117.0 ± ∞ ¹
BufferSizes/buf_50-4                                                                    59.00 ± ∞ ¹
BufferSizes/buf_100-4                                                                   51.00 ± ∞ ¹
BufferSizes/buf_500-4                                                                   42.00 ± ∞ ¹
BufferSizes/buf_1000-4                                                                  40.00 ± ∞ ¹
ConcurrentRegistrations-4                                                             1.437Ki ± ∞ ¹
GetByGroupExcept-4                                                                      896.0 ± ∞ ¹
geomean                                                                           ²                  ? ³ ² ⁴
¹ need >= 6 samples for confidence interval at level 0.95
² summaries must be >0 to compute geomean
³ benchmark set differs from baseline; geomeans may not be comparable
⁴ ratios must be >0 to compute geomean

                                                 │ testdata/benchmarks/baseline.txt │   current-bench.txt   │
                                                 │            allocs/op             │  allocs/op    vs base │
DispatchWithState_Cached-8                                              4.000 ± ∞ ¹
E2EUserJourney-8                                                       5.083k ± ∞ ¹
E2ETodoApp-8                                                            496.0 ± ∞ ¹
E2ERangeOperations/add-items-8                                          222.0 ± ∞ ¹
E2ERangeOperations/remove-items-8                                       124.0 ± ∞ ¹
E2ERangeOperations/reorder-items-8                                      157.0 ± ∞ ¹
E2ERangeOperations/update-items-8                                       157.0 ± ∞ ¹
E2EMultipleSessions/sessions-1-8                                        54.00 ± ∞ ¹
E2EMultipleSessions/sessions-10-8                                       540.0 ± ∞ ¹
E2EMultipleSessions/sessions-100-8                                     5.394k ± ∞ ¹
SpecificationCompliance-8                                               41.00 ± ∞ ¹
ErrorPaths/invalid-template-syntax-8                                   3.667k ± ∞ ¹
ErrorPaths/missing-field-8                                              57.00 ± ∞ ¹
ErrorPaths/nil-data-8                                                   57.00 ± ∞ ¹
ErrorPaths/empty-template-8                                            3.814k ± ∞ ¹
TemplateExecute/initial-render-8                                       3.910k ± ∞ ¹
TemplateExecute/subsequent-render-8                                     61.00 ± ∞ ¹
TemplateExecuteUpdates/no-changes-8                                     46.00 ± ∞ ¹
TemplateExecuteUpdates/small-update-8                                   46.00 ± ∞ ¹
TemplateExecuteUpdates/large-update-8                                   123.0 ± ∞ ¹
TemplateComplexity/simple-fields-8                                      115.0 ± ∞ ¹
TemplateComplexity/with-conditionals-8                                  87.00 ± ∞ ¹
TemplateComplexity/with-ranges-8                                        182.0 ± ∞ ¹
TemplateComplexity/deeply-nested-8                                      176.0 ± ∞ ¹
TemplateConcurrent/goroutines-1-8                                       61.00 ± ∞ ¹
TemplateConcurrent/goroutines-10-8                                      61.00 ± ∞ ¹
TemplateConcurrent/goroutines-100-8                                     61.00 ± ∞ ¹
Template_Execute-8                                                      63.00 ± ∞ ¹
Template_ExecuteUpdates-8                                               48.00 ± ∞ ¹
UserJourney-8                                                          12.81k ± ∞ ¹
TreeNodeCreation/flat-8                                                 17.00 ± ∞ ¹
TreeNodeCreation/nested-small-8                                         119.0 ± ∞ ¹
TreeNodeCreation/nested-medium-8                                        362.0 ± ∞ ¹
TreeNodeCreation/nested-large-8                                        1.091k ± ∞ ¹
TreeNodeMarshalJSON/flat-8                                              52.00 ± ∞ ¹
TreeNodeMarshalJSON/nested-small-8                                      358.0 ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-8                                    1.087k ± ∞ ¹
WrapperInjection/full-html-8                                            37.00 ± ∞ ¹
WrapperInjection/fragment-8                                             28.00 ± ∞ ¹
ExtractWrapperContent-8                                                 28.00 ± ∞ ¹
ContextOperations/with-statics-8                                        93.00 ± ∞ ¹
ContextOperations/without-statics-8                                     93.00 ± ∞ ¹
TreeNodeClone/flat-8                                                    13.00 ± ∞ ¹
TreeNodeClone/nested-small-8                                            93.00 ± ∞ ¹
TreeNodeClone/nested-medium-8                                           282.0 ± ∞ ¹
TreeNodeToMap/flat-8                                                    18.00 ± ∞ ¹
TreeNodeToMap/nested-small-8                                            120.0 ± ∞ ¹
TreeNodeToMap/nested-medium-8                                           363.0 ± ∞ ¹
GenerateRandomID-8                                                      1.000 ± ∞ ¹
CalculateStructureFingerprint_Small-8                                   5.000 ± ∞ ¹
CalculateStructureFingerprint_Medium-8                                  65.00 ± ∞ ¹
CalculateStructureFingerprint_Large-8                                   305.0 ± ∞ ¹
CalculateStructureFingerprint_DeepNested-8                              70.00 ± ∞ ¹
CalculateStructureFingerprint_Range100-8                                7.000 ± ∞ ¹
CalculateStructureFingerprint_Range1000-8                               7.000 ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-8                              6.000 ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-8                          7.000 ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-8                             66.00 ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-8                         67.00 ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-8                              306.0 ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-8                          307.0 ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-8                            71.00 ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-8                        72.00 ± ∞ ¹
ExecuteTemplateWithContext_Struct-8                                     29.00 ± ∞ ¹
ExecuteTemplateWithContext_Map-8                                        36.00 ± ∞ ¹
Precompute/eager_all_methods-8                                          15.00 ± ∞ ¹
Precompute/referenced_only-8                                            5.000 ± ∞ ¹
Precompute/all_referenced-8                                             15.00 ± ∞ ¹
CompareTreesNoChanges-8                                                 2.000 ± ∞ ¹
CompareTreesSmallChange-8                                               2.000 ± ∞ ¹
CompareTreesLargeChange/10-8                                            2.000 ± ∞ ¹
CompareTreesLargeChange/100-8                                           2.000 ± ∞ ¹
CompareTreesLargeChange/1000-8                                          902.0 ± ∞ ¹
RangeDiffUpdate-8                                                       16.00 ± ∞ ¹
RangeDiffInsert-8                                                       16.00 ± ∞ ¹
RangeDiffRemove-8                                                       16.00 ± ∞ ¹
RangeDiff_TreeNode_Update-8                                             128.0 ± ∞ ¹
RangeDiff_TreeNode_Reorder-8                                            22.00 ± ∞ ¹
RangeDiff_TreeNode_LargeList-8                                         1.038k ± ∞ ¹
PrepareTreeForClient/with-statics-8                                     0.000 ± ∞ ¹
PrepareTreeForClient/without-statics-8                                  2.000 ± ∞ ¹
ClientNeedsStatics_SameStructure-8                                      0.000 ± ∞ ¹
ClientNeedsStatics_DifferentStructure-8                                 0.000 ± ∞ ¹
ClientNeedsStatics_DeepNested-8                                         0.000 ± ∞ ¹
ClientNeedsStatics_Range-8                                              0.000 ± ∞ ¹
ClientNeedsStatics_NilOld-8                                             0.000 ± ∞ ¹
WireSize_WithStatics-8                                                  53.00 ± ∞ ¹
WireSize_WithoutStatics-8                                               52.00 ± ∞ ¹
WireSizeComparison/small_5_with_statics-8                               18.00 ± ∞ ¹
WireSizeComparison/small_5_without_statics-8                            17.00 ± ∞ ¹
WireSizeComparison/medium_20_with_statics-8                             53.00 ± ∞ ¹
WireSizeComparison/medium_20_without_statics-8                          52.00 ± ∞ ¹
WireSizeComparison/large_100_with_statics-8                             217.0 ± ∞ ¹
WireSizeComparison/large_100_without_statics-8                          216.0 ± ∞ ¹
Parse/simple-8                                                          47.00 ± ∞ ¹
Parse/conditional-8                                                     68.00 ± ∞ ¹
Parse/range-8                                                           63.00 ± ∞ ¹
Parse/nested-8                                                          73.00 ± ∞ ¹
Parse/complex-8                                                         130.0 ± ∞ ¹
BuildTree/simple-8                                                      14.00 ± ∞ ¹
BuildTree/conditional-true-8                                            27.00 ± ∞ ¹
BuildTree/conditional-false-8                                           18.00 ± ∞ ¹
BuildTree/range-small-8                                                 90.00 ± ∞ ¹
BuildTreeScale/small-10-8                                               266.0 ± ∞ ¹
BuildTreeScale/medium-100-8                                            2.516k ± ∞ ¹
BuildTreeScale/large-1000-8                                            25.76k ± ∞ ¹
NodeRender-8                                                            3.000 ± ∞ ¹
TreeToHTML/simple-8                                                     4.000 ± ∞ ¹
TreeToHTML/nested-8                                                     7.000 ± ∞ ¹
TreeToHTML/with-ranges-8                                                5.000 ± ∞ ¹
TreeToHTMLScale/small-10-8                                              16.00 ± ∞ ¹
TreeToHTMLScale/medium-100-8                                            109.0 ± ∞ ¹
TreeToHTMLScale/large-1000-8                                           1.017k ± ∞ ¹
IsVoidElement-8                                                         0.000 ± ∞ ¹
NodeRenderComplex-8                                                     5.000 ± ∞ ¹
ParseActionFromHTTP-8                                                   30.00 ± ∞ ¹
ParseActionFromWebSocket-8                                              13.00 ± ∞ ¹
PrepareUpdate/without-errors-8                                          0.000 ± ∞ ¹
PrepareUpdate/with-errors-8                                             1.000 ± ∞ ¹
SerializeUpdate-8                                                       10.00 ± ∞ ¹
PrepareAndSerialize/simple-update-8                                     11.00 ± ∞ ¹
PrepareAndSerialize/with-metadata-8                                     15.00 ± ∞ ¹
ParseActionScale/small-http-8                                           30.00 ± ∞ ¹
ParseActionScale/small-ws-8                                             13.00 ± ∞ ¹
ParseActionScale/medium-http-8                                          40.00 ± ∞ ¹
ParseActionScale/medium-ws-8                                            23.00 ± ∞ ¹
ParseActionScale/large-http-8                                           63.00 ± ∞ ¹
ParseActionScale/large-ws-8                                             46.00 ± ∞ ¹
SerializeUpdateScale/simple-8                                           10.00 ± ∞ ¹
SerializeUpdateScale/nested-8                                           19.00 ± ∞ ¹
SerializeUpdateScale/multiple-fields-8                                  16.00 ± ∞ ¹
ConcurrentConnections/100_connections-8                                 200.0 ± ∞ ¹
ConcurrentConnections/1000_connections-8                               2.000k ± ∞ ¹
RegisterUnregister-8                                                    13.00 ± ∞ ¹
GetByGroup-8                                                            1.000 ± ∞ ¹
CloseConnection-8                                                       3.000 ± ∞ ¹
MemoryUsage-8                                                           620.0 ± ∞ ¹
BroadcastToGroup-8                                                      101.0 ± ∞ ¹
BufferSizes/buf_10-8                                                    3.000 ± ∞ ¹
BufferSizes/buf_50-8                                                    2.000 ± ∞ ¹
BufferSizes/buf_100-8                                                   2.000 ± ∞ ¹
BufferSizes/buf_500-8                                                   2.000 ± ∞ ¹
BufferSizes/buf_1000-8                                                  2.000 ± ∞ ¹
ConcurrentRegistrations-8                                               11.00 ± ∞ ¹
GetByGroupExcept-8                                                      1.000 ± ∞ ¹
DispatchWithState_Cached-4                                                             4.000 ± ∞ ¹
E2EUserJourney-4                                                                      5.685k ± ∞ ¹
E2ETodoApp-4                                                                           556.0 ± ∞ ¹
E2ERangeOperations/add-items-4                                                         252.0 ± ∞ ¹
E2ERangeOperations/remove-items-4                                                      152.0 ± ∞ ¹
E2ERangeOperations/reorder-items-4                                                     186.0 ± ∞ ¹
E2ERangeOperations/update-items-4                                                      186.0 ± ∞ ¹
E2EMultipleSessions/sessions-1-4                                                       60.00 ± ∞ ¹
E2EMultipleSessions/sessions-10-4                                                      600.0 ± ∞ ¹
E2EMultipleSessions/sessions-100-4                                                    5.988k ± ∞ ¹
SpecificationCompliance-4                                                              44.00 ± ∞ ¹
ErrorPaths/invalid-template-syntax-4                                                  3.992k ± ∞ ¹
ErrorPaths/missing-field-4                                                             60.00 ± ∞ ¹
ErrorPaths/nil-data-4                                                                  47.00 ± ∞ ¹
ErrorPaths/empty-template-4                                                           4.154k ± ∞ ¹
RangeFullSwap_Simple_N10-4                                                            1.155k ± ∞ ¹
RangeFullSwap_Simple_N100-4                                                           10.52k ± ∞ ¹
RangeFullSwap_Simple_N1000-4                                                          105.7k ± ∞ ¹
RangeFullSwap_DynamicBranch_N10-4                                                     1.891k ± ∞ ¹
RangeFullSwap_DynamicBranch_N100-4                                                    17.83k ± ∞ ¹
RangeFullSwap_DynamicBranch_N1000-4                                                   178.7k ± ∞ ¹
RecursiveRender-4                                                                     20.45k ± ∞ ¹
RecursiveUpdate-4                                                                     75.45k ± ∞ ¹
OpaqueHTMLBaseline-4                                                                  5.229k ± ∞ ¹
SystemCard/Counter/Dashboard/session-memory-4                                          244.0 ± ∞ ¹
SystemCard/Counter/Dashboard/update-4                                                  139.0 ± ∞ ¹
SystemCard/Counter/Dashboard/state-clone-4                                             5.000 ± ∞ ¹
SystemCard/Counter/Dashboard/payload-size-4                                            139.0 ± ∞ ¹
SystemCard/Todo_App/session-memory-4                                                  3.015k ± ∞ ¹
SystemCard/Todo_App/update-4                                                          3.919k ± ∞ ¹
SystemCard/Todo_App/state-clone-4                                                      78.00 ± ∞ ¹
SystemCard/Todo_App/payload-size-4                                                    3.918k ± ∞ ¹
SystemCard/Social_Feed/session-memory-4                                               7.791k ± ∞ ¹
SystemCard/Social_Feed/update-4                                                       8.951k ± ∞ ¹
SystemCard/Social_Feed/state-clone-4                                                   203.0 ± ∞ ¹
SystemCard/Social_Feed/payload-size-4                                                 8.961k ± ∞ ¹
SystemCard/Chat/Collab/session-memory-4                                               12.88k ± ∞ ¹
SystemCard/Chat/Collab/update-4                                                       11.41k ± ∞ ¹
SystemCard/Chat/Collab/state-clone-4                                                   423.0 ± ∞ ¹
SystemCard/Chat/Collab/payload-size-4                                                 11.41k ± ∞ ¹
TemplateExecute/initial-render-4                                                      4.259k ± ∞ ¹
TemplateExecute/subsequent-render-4                                                    64.00 ± ∞ ¹
TemplateExecuteUpdates/no-changes-4                                                    54.00 ± ∞ ¹
TemplateExecuteUpdates/small-update-4                                                  54.00 ± ∞ ¹
TemplateExecuteUpdates/large-update-4                                                  131.0 ± ∞ ¹
TemplateComplexity/simple-fields-4                                                     118.0 ± ∞ ¹
TemplateComplexity/with-conditionals-4                                                 90.00 ± ∞ ¹
TemplateComplexity/with-ranges-4                                                       206.0 ± ∞ ¹
TemplateComplexity/deeply-nested-4                                                     196.0 ± ∞ ¹
TemplateConcurrent/goroutines-1-4                                                      64.00 ± ∞ ¹
TemplateConcurrent/goroutines-10-4                                                     64.00 ± ∞ ¹
TemplateConcurrent/goroutines-100-4                                                    64.00 ± ∞ ¹
Template_Execute-4                                                                     66.00 ± ∞ ¹
Template_ExecuteUpdates-4                                                              56.00 ± ∞ ¹
TopicFanoutByN/N=1-4                                                                   6.000 ± ∞ ¹
TopicFanoutByN/N=5-4                                                                   10.00 ± ∞ ¹
TopicFanoutByN/N=10-4                                                                  18.00 ± ∞ ¹
TopicFanoutByN/N=50-4                                                                  62.00 ± ∞ ¹
TopicFanoutByN/N=100-4                                                                 114.0 ± ∞ ¹
TopicPatternScanByP/P=1-4                                                              6.000 ± ∞ ¹
TopicPatternScanByP/P=10-4                                                             24.00 ± ∞ ¹
TopicPatternScanByP/P=100-4                                                            204.0 ± ∞ ¹
UserJourney-4                                                                         13.23k ± ∞ ¹
TreeNodeCreation/flat-4                                                                17.00 ± ∞ ¹
TreeNodeCreation/nested-small-4                                                        119.0 ± ∞ ¹
TreeNodeCreation/nested-medium-4                                                       362.0 ± ∞ ¹
TreeNodeCreation/nested-large-4                                                       1.091k ± ∞ ¹
TreeNodeMarshalJSON/flat-4                                                             68.00 ± ∞ ¹
TreeNodeMarshalJSON/nested-small-4                                                     465.0 ± ∞ ¹
TreeNodeMarshalJSON/nested-medium-4                                                   1.410k ± ∞ ¹
WrapperInjection/full-html-4                                                           37.00 ± ∞ ¹
WrapperInjection/fragment-4                                                            28.00 ± ∞ ¹
WrapperInjection/string-fallback-tokenizer-4                                           14.00 ± ∞ ¹
ExtractWrapperContent-4                                                                28.00 ± ∞ ¹
ContextOperations/with-statics-4                                                       93.00 ± ∞ ¹
ContextOperations/without-statics-4                                                    93.00 ± ∞ ¹
TreeNodeClone/flat-4                                                                   13.00 ± ∞ ¹
TreeNodeClone/nested-small-4                                                           93.00 ± ∞ ¹
TreeNodeClone/nested-medium-4                                                          282.0 ± ∞ ¹
TreeNodeToMap/flat-4                                                                   18.00 ± ∞ ¹
TreeNodeToMap/nested-small-4                                                           120.0 ± ∞ ¹
TreeNodeToMap/nested-medium-4                                                          363.0 ± ∞ ¹
GenerateRandomID-4                                                                     1.000 ± ∞ ¹
CalculateStructureFingerprint_Small-4                                                  5.000 ± ∞ ¹
CalculateStructureFingerprint_Medium-4                                                 65.00 ± ∞ ¹
CalculateStructureFingerprint_Large-4                                                  305.0 ± ∞ ¹
CalculateStructureFingerprint_DeepNested-4                                             70.00 ± ∞ ¹
CalculateStructureFingerprint_Range100-4                                               7.000 ± ∞ ¹
CalculateStructureFingerprint_Range1000-4                                              7.000 ± ∞ ¹
FingerprintAlgorithms/small/MD5-previous-4                                             5.000 ± ∞ ¹
FingerprintAlgorithms/small/FNV1a128-current-4                                         6.000 ± ∞ ¹
FingerprintAlgorithms/medium/MD5-previous-4                                            65.00 ± ∞ ¹
FingerprintAlgorithms/medium/FNV1a128-current-4                                        66.00 ± ∞ ¹
FingerprintAlgorithms/large/MD5-previous-4                                             305.0 ± ∞ ¹
FingerprintAlgorithms/large/FNV1a128-current-4                                         306.0 ± ∞ ¹
FingerprintAlgorithms/deep-20/MD5-previous-4                                           65.00 ± ∞ ¹
FingerprintAlgorithms/deep-20/FNV1a128-current-4                                       66.00 ± ∞ ¹
ExecuteTemplateWithContext_Struct-4                                                    29.00 ± ∞ ¹
ExecuteTemplateWithContext_Map-4                                                       36.00 ± ∞ ¹
Precompute/eager_all_methods-4                                                         15.00 ± ∞ ¹
Precompute/referenced_only-4                                                           5.000 ± ∞ ¹
Precompute/all_referenced-4                                                            15.00 ± ∞ ¹
CompareTreesNoChanges-4                                                                2.000 ± ∞ ¹
CompareTreesSmallChange-4                                                              2.000 ± ∞ ¹
CompareTreesLargeChange/10-4                                                           2.000 ± ∞ ¹
CompareTreesLargeChange/100-4                                                          2.000 ± ∞ ¹
CompareTreesLargeChange/1000-4                                                         902.0 ± ∞ ¹
RangeDiffUpdate-4                                                                      19.00 ± ∞ ¹
RangeDiffInsert-4                                                                      19.00 ± ∞ ¹
RangeDiffRemove-4                                                                      19.00 ± ∞ ¹
RangeDiff_TreeNode_Update-4                                                           2.445k ± ∞ ¹
RangeDiff_TreeNode_Reorder-4                                                          1.623k ± ∞ ¹
RangeDiff_TreeNode_LargeList-4                                                        24.05k ± ∞ ¹
PrepareTreeForClient/with-statics-4                                                    0.000 ± ∞ ¹
PrepareTreeForClient/without-statics-4                                                 2.000 ± ∞ ¹
ClientNeedsStatics_SameStructure-4                                                     0.000 ± ∞ ¹
ClientNeedsStatics_DifferentStructure-4                                                0.000 ± ∞ ¹
ClientNeedsStatics_DeepNested-4                                                        0.000 ± ∞ ¹
ClientNeedsStatics_Range-4                                                             0.000 ± ∞ ¹
ClientNeedsStatics_NilOld-4                                                            0.000 ± ∞ ¹
WireSize_WithStatics-4                                                                 31.00 ± ∞ ¹
WireSize_WithoutStatics-4                                                              32.00 ± ∞ ¹
WireSizeComparison/small_5_with_statics-4                                              14.00 ± ∞ ¹
WireSizeComparison/small_5_without_statics-4                                           15.00 ± ∞ ¹
WireSizeComparison/medium_20_with_statics-4                                            31.00 ± ∞ ¹
WireSizeComparison/medium_20_without_statics-4                                         32.00 ± ∞ ¹
WireSizeComparison/large_100_with_statics-4                                            117.0 ± ∞ ¹
WireSizeComparison/large_100_without_statics-4                                         118.0 ± ∞ ¹
RangeDiff_Stream_Append_Small-4                                                        111.0 ± ∞ ¹
RangeDiff_Stream_Append_Medium-4                                                       831.0 ± ∞ ¹
RangeDiff_Stream_Append_Large-4                                                       80.12k ± ∞ ¹
RangeDiff_Stream_Update_Small-4                                                        106.0 ± ∞ ¹
RangeDiff_Stream_Update_Medium-4                                                       826.0 ± ∞ ¹
RangeDiff_Stream_Update_Large-4                                                       80.15k ± ∞ ¹
RangeDiff_Stream_Reorder_Small-4                                                       103.0 ± ∞ ¹
RangeDiff_Stream_Reorder_Medium-4                                                      823.0 ± ∞ ¹
RangeDiff_Stream_Reorder_Large-4                                                      80.14k ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Small-4                                               127.0 ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Medium-4                                              847.0 ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Large-4                                              80.15k ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Small-4                                               114.0 ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Medium-4                                              834.0 ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Large-4                                              80.16k ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Small-4                                              105.0 ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Medium-4                                             825.0 ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Large-4                                             80.16k ± ∞ ¹
RangeDiff_LegacyPartialDelta_Update_WireSize-4                                         7.000 ± ∞ ¹
Parse/simple-4                                                                         48.00 ± ∞ ¹
Parse/conditional-4                                                                    69.00 ± ∞ ¹
Parse/range-4                                                                          64.00 ± ∞ ¹
Parse/nested-4                                                                         74.00 ± ∞ ¹
Parse/complex-4                                                                        131.0 ± ∞ ¹
BuildTree/simple-4                                                                     15.00 ± ∞ ¹
BuildTree/conditional-true-4                                                           28.00 ± ∞ ¹
BuildTree/conditional-false-4                                                          19.00 ± ∞ ¹
BuildTree/range-small-4                                                                82.00 ± ∞ ¹
BuildTreeScale/small-10-4                                                              237.0 ± ∞ ¹
BuildTreeScale/medium-100-4                                                           2.217k ± ∞ ¹
BuildTreeScale/large-1000-4                                                           22.77k ± ∞ ¹
NodeRender-4                                                                           3.000 ± ∞ ¹
TreeToHTML/simple-4                                                                    4.000 ± ∞ ¹
TreeToHTML/nested-4                                                                    7.000 ± ∞ ¹
TreeToHTML/with-ranges-4                                                               5.000 ± ∞ ¹
TreeToHTMLScale/small-10-4                                                             16.00 ± ∞ ¹
TreeToHTMLScale/medium-100-4                                                           109.0 ± ∞ ¹
TreeToHTMLScale/large-1000-4                                                          1.017k ± ∞ ¹
IsVoidElement-4                                                                        0.000 ± ∞ ¹
NodeRenderComplex-4                                                                    5.000 ± ∞ ¹
ParseActionFromHTTP-4                                                                  26.00 ± ∞ ¹
ParseActionFromWebSocket-4                                                             9.000 ± ∞ ¹
PrepareUpdate/without-errors-4                                                         0.000 ± ∞ ¹
PrepareUpdate/with-errors-4                                                            1.000 ± ∞ ¹
SerializeUpdate-4                                                                      14.00 ± ∞ ¹
PrepareAndSerialize/simple-update-4                                                    15.00 ± ∞ ¹
PrepareAndSerialize/with-metadata-4                                                    22.00 ± ∞ ¹
ParseActionScale/small-http-4                                                          26.00 ± ∞ ¹
ParseActionScale/small-ws-4                                                            9.000 ± ∞ ¹
ParseActionScale/medium-http-4                                                         39.00 ± ∞ ¹
ParseActionScale/medium-ws-4                                                           22.00 ± ∞ ¹
ParseActionScale/large-http-4                                                          67.00 ± ∞ ¹
ParseActionScale/large-ws-4                                                            50.00 ± ∞ ¹
SerializeUpdateScale/simple-4                                                          14.00 ± ∞ ¹
SerializeUpdateScale/nested-4                                                          26.00 ± ∞ ¹
SerializeUpdateScale/multiple-fields-4                                                 16.00 ± ∞ ¹
ConcurrentConnections/1000_connections-4                                              2.000k ± ∞ ¹
RegisterUnregister-4                                                                   15.00 ± ∞ ¹
GetByGroup-4                                                                           1.000 ± ∞ ¹
CloseConnection-4                                                                      3.000 ± ∞ ¹
MemoryUsage-4                                                                          819.0 ± ∞ ¹
BroadcastToGroup-4                                                                     101.0 ± ∞ ¹
BufferSizes/buf_10-4                                                                   3.000 ± ∞ ¹
BufferSizes/buf_50-4                                                                   2.000 ± ∞ ¹
BufferSizes/buf_100-4                                                                  2.000 ± ∞ ¹
BufferSizes/buf_500-4                                                                  2.000 ± ∞ ¹
BufferSizes/buf_1000-4                                                                 2.000 ± ∞ ¹
ConcurrentRegistrations-4                                                              13.00 ± ∞ ¹
GetByGroupExcept-4                                                                     1.000 ± ∞ ¹
geomean                                                                           ²                 ? ³ ² ⁴
¹ need >= 6 samples for confidence interval at level 0.95
² summaries must be >0 to compute geomean
³ benchmark set differs from baseline; geomeans may not be comparable
⁴ ratios must be >0 to compute geomean

                                               │ testdata/benchmarks/baseline.txt │  current-bench.txt   │
                                               │             bytes/op             │   bytes/op     vs base   │
WireSize_WithStatics-8                                                294.0 ± ∞ ¹
WireSize_WithoutStatics-8                                             251.0 ± ∞ ¹
WireSizeComparison/small_5_with_statics-8                             104.0 ± ∞ ¹
WireSizeComparison/small_5_without_statics-8                          61.00 ± ∞ ¹
WireSizeComparison/medium_20_with_statics-8                           294.0 ± ∞ ¹
WireSizeComparison/medium_20_without_statics-8                        251.0 ± ∞ ¹
WireSizeComparison/large_100_with_statics-8                         1.303Ki ± ∞ ¹
WireSizeComparison/large_100_without_statics-8                      1.261Ki ± ∞ ¹
RangeFullSwap_Simple_N10-4                                                          1.061Ki ± ∞ ¹
RangeFullSwap_Simple_N100-4                                                         10.82Ki ± ∞ ¹
RangeFullSwap_Simple_N1000-4                                                        111.9Ki ± ∞ ¹
RangeFullSwap_DynamicBranch_N10-4                                                   1.812Ki ± ∞ ¹
RangeFullSwap_DynamicBranch_N100-4                                                  18.42Ki ± ∞ ¹
RangeFullSwap_DynamicBranch_N1000-4                                                 188.9Ki ± ∞ ¹
WireSize_WithStatics-4                                                                294.0 ± ∞ ¹
WireSize_WithoutStatics-4                                                             251.0 ± ∞ ¹
WireSizeComparison/small_5_with_statics-4                                             104.0 ± ∞ ¹
WireSizeComparison/small_5_without_statics-4                                          61.00 ± ∞ ¹
WireSizeComparison/medium_20_with_statics-4                                           294.0 ± ∞ ¹
WireSizeComparison/medium_20_without_statics-4                                        251.0 ± ∞ ¹
WireSizeComparison/large_100_with_statics-4                                         1.303Ki ± ∞ ¹
WireSizeComparison/large_100_without_statics-4                                      1.261Ki ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Small-4                                              52.00 ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Medium-4                                             54.00 ± ∞ ¹
RangeDiff_Stream_Append_WireSize_Large-4                                              58.00 ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Small-4                                              45.00 ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Medium-4                                             47.00 ± ∞ ¹
RangeDiff_Stream_Update_WireSize_Large-4                                              51.00 ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Small-4                                             99.00 ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Medium-4                                            999.0 ± ∞ ¹
RangeDiff_Stream_Reorder_WireSize_Large-4                                           116.1Ki ± ∞ ¹
RangeDiff_LegacyPartialDelta_Update_WireSize-4                                        33.00 ± ∞ ¹
geomean                                                               296.4           594.4        ? ² ³
¹ need >= 6 samples for confidence interval at level 0.95
² benchmark set differs from baseline; geomeans may not be comparable
³ ratios must be >0 to compute geomean

                  │ current-bench.txt │
                  │   update_bytes    │
RecursiveUpdate-4         212.0 ± ∞ ¹
¹ need >= 6 samples for confidence interval at level 0.95

                     │ current-bench.txt │
                     │  full_html_bytes  │
OpaqueHTMLBaseline-4        23.56k ± ∞ ¹
¹ need >= 6 samples for confidence interval at level 0.95

                                            │ current-bench.txt │
                                            │   payload-bytes   │
SystemCard/Counter/Dashboard/payload-size-4         60.00 ± ∞ ¹
SystemCard/Todo_App/payload-size-4                3.539Ki ± ∞ ¹
SystemCard/Social_Feed/payload-size-4             13.51Ki ± ∞ ¹
SystemCard/Chat/Collab/payload-size-4             1.288Ki ± ∞ ¹
geomean                                           1.378Ki
¹ need >= 6 samples for confidence interval at level 0.95

Thresholds

  • ⚠️ Warning: Regressions >10% on critical benchmarks
  • ❌ Failure: Regressions >20% on critical benchmarks
  • Critical benchmarks: Benchmark(E2E|Template|CompareTrees|RangeDiff|PrepareTree).*

See benchmarking guide for details.

Address the review-bot note on #518: wsFrameReader dedicates a goroutine to
ws.ReadMessage for the connection's lifetime, and gorilla/websocket forbids
concurrent reads, so calling the await helpers twice on one connection would
spawn a second concurrent reader (a data race). No current caller does this;
the doc callouts on wsFrameReader / awaitWSContains / awaitWSContainsRejecting
keep a future reuse from tripping it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ui2cwpeGkrUfRt8rh2FgGG
@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Summary

Test-only fix (3 files, +134/-44) for a load-flaky WS panic in cross-instance test helpers. Root-cause analysis is thorough and the evidence (deterministic repro, negative container-churn control, discriminating regression test) is convincing — this reads like a genuine gorilla/websocket antipattern fix, not a guess.

What it does

Replaces the SetReadDeadline(150ms/400ms) + ReadMessage retry-loop in awaitWSContains/awaitWSContainsRejecting with a single dedicated reader goroutine (wsFrameReader) that does a deadline-free blocking read and streams frames over a channel. awaitWSFrame then multiplexes on that channel vs. a re-trigger ticker vs. an 8s overall timeout. This avoids poisoning gorilla's readErr state, which is exactly what caused the fast-spin → readErrCount>=1000 panic under CPU load.

Strengths

  • Correct diagnosis and fix. SetReadDeadline timeouts do get recorded in gorilla's sticky readErr (via hideTempErr), and there's no API to clear it — a deadline-free single reader is the right fix, not a workaround.
  • Regression coverage that actually discriminates. TestWSFrameReader_SurvivesSlowFrame sends a 600ms-delayed frame (longer than the old 150ms deadline) and confirms the old helper panics on this exact input while the new one doesn't — this is a real regression guard, not just a happy-path test.
  • Comments earn their keep per CLAUDE.md's "only add a comment when the WHY is non-obvious" — the wsFrameReader doc comment explaining the readErrCount mechanism is exactly the kind of hidden-constraint knowledge that would otherwise get relearned the hard way.
  • Confirmed single-reader-per-connection invariant holds today — I checked every current call site (topic_cross_instance_test.go, topic_wildcard_test.go) and each ws value is passed to awaitWSContains/awaitWSContainsRejecting exactly once, so there's no live double-reader risk.
  • Clearing the stale deadline left by connectWS's initial-render read (broadcast_test.go:105) before the blocking read is a nice catch — without it the first frame read would inherit a 5s deadline that could itself poison the conn under load.

Minor observations (non-blocking)

  • "Call at most once per connection" is enforced only by comment, not code. A future caller invoking awaitWSContains twice on the same ws (e.g., to await two sequential frames) would start a second reader goroutine and hit gorilla's "concurrent read" restriction — a data race -race would catch, but only if that CI job runs on the new test. Given this is a low-traffic internal test helper, relying on the doc comment is a reasonable tradeoff; just flagging it since it's the one invariant not self-enforcing.
  • Redundant Close(). Existing call sites already defer ws.Close(); wsFrameReader additionally registers t.Cleanup(func() { _ = ws.Close() }), so ws gets closed twice per test. Harmless (errors are discarded) but worth knowing it's there.
  • Silent frame drop on full buffer. The non-blocking select { case frames <- ...: default: } send will drop a frame if the channel (buffered 16) is full and the consumer is behind. Fine given the re-trigger semantics these tests rely on (at-least-once delivery via republish), just noting it's a deliberate at-least-once design, not exactly-once.
  • TestWSFrameReader_SurvivesSlowFrame adds ~2.6s (600ms send delay + 2s hold-open) to the suite. Negligible against the 300s pre-commit timeout, but worth knowing if test wall-clock time becomes a concern later.

Risk assessment

Scope is limited to test helpers/test files — no production code touched, so blast radius is minimal even if something is off. The PR body's verification section (full suite green, -race with -count=2, CPU-saturated repeated runs) covers exactly the conditions that exposed the original flake.

Nice, well-documented diagnosis-driven fix. No blocking issues found.

@adnaan
adnaan merged commit da23f8d into main Jul 22, 2026
7 checks passed
@adnaan
adnaan deleted the flaky-xinstance-race branch July 22, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant