v4.2.0: bench presentation + docs uplift to typestates pattern#29
v4.2.0: bench presentation + docs uplift to typestates pattern#29
Conversation
…ily cron Aligns the docs build with the typestates pattern: - jiro4989/setup-nim-action: nim-version: '2.2.8' (was 'stable'). Pinning prevents silent breakage when nim/devel drifts. - Replaces in-place nim.cfg patching with `nimble install nim -y`, which packages the compiler API as an importable nimble pkg -- required by mkdocstrings-nim. Cleaner than manual header copies. IMP-2: the broken-include-path issue documented for `nimble install compiler` does NOT apply here; `nimble install nim` produces a pkgs2/nim-* directory with a working layout. - Daily cron at 05:17 UTC: keeps the published charts fresh even on weeks devel doesn't push (the bench data lives in latest.json on gh-pages and is fetched by the chart at page-load; cron rebuilds the docs site so any new bench data shows up daily). - New "Create watch directories" step ensures docs/overrides exists for the new mkdocs custom_dir before pip install runs. Local verification: actionlint + python yaml.safe_load both pass. Live workflow_dispatch verification deferred to post-PR run. Part of v4.2.0 omnibus.
…st.json
Two surface-level fixes for the bench snapshot pipeline:
1. [skip ci] on the snapshot commit. The bench workflow auto-commits
docs/assets/bench-results/latest.json after each devel push. The
loop-prevention layers (paths-ignore on bench.yml + bot-actor
guard) were two-of-three; this is the third, matching the project
convention. Without it, certain edge cases (workflow_dispatch
re-runs, paths-ignore evaluation order quirks) could trigger a
recursive bench run.
2. Defensive fallback latest.json. When merge_bmf fails or is
cancelled on devel, the chart page currently 404s silently. New
step writes a placeholder JSON with _status: "fallback" and
_reason embedding steps.merge.outcome so the chart can render a
meaningful "last attempt failed" state. Loop-safe (also has [skip
ci]). Positioned after the cost-gate-guarded Bencher upload so
missing bench PR label still permits the fallback snapshot.
Diagnostic (T-D1-1): root cause of the missing latest.json on
gh-pages identified. Run 25398191987 (most recent devel push) shows
Merge BMF JSON SUCCEEDED, but Track base branch benchmarks with
Bencher FAILED with: "Failed to validate the model for the
throughput_ops_ms Measure Threshold: Invalid threshold model:
Invalid model, no boundary provided". The Bencher failure
short-circuited the job and the Snapshot to docs assets step never
ran. gh-pages has no docs/assets/bench-results/latest.json at all
(404 on raw fetch). The defensive fallback as scoped here catches
merge_bmf failures specifically; the Bencher-threshold issue is a
separate config defect (mismatched --threshold-measure /
--threshold-{upper,lower}-boundary pairing in the Track base branch
step) and lands in a sibling thread. The combination — [skip ci]
plus fallback — makes future incidents observable rather than
silent, even when the precise failure mode isn't merge_bmf.
Live workflow_dispatch verification deferred to first post-merge
devel run; bash unit test of the heredoc passes locally
(bash -n exit 0, shellcheck clean with shebang, all required JSON
keys present, _commit absent per IMP-6).
Loop-prevention guards intact:
- paths-ignore on bench.yml (devel auto-snapshot doesn't fire bench)
- bot-actor guard (skip if actor == github-actions[bot])
- [skip ci] (this commit, on both snapshot + fallback messages)
Part of v4.2.0 omnibus.
The repo migrated to mkdocs + mike + mkdocstrings-nim in v4.0.x but left behind 17 stale HTML/CSS/JS files under json/ and the nimdoc.cfg that drove the nim doc generation. CI no longer regenerates these artifacts; they're a bit-rotten relic. Audit: - json/: 17 files, 312K total (HTML, CSS, JS, .idx index files for the lockfreequeues module + submodules) - nimdoc.cfg: 6 lines (threads/project/index flags + git.url pointing at branch=master, which is itself stale) - Inbound references: none. grep across *.md, *.yml, *.yaml, *.cfg, *.nim, *.nimble, *.txt found zero references to either json/ or nimdoc. No CI workflow (docs.yml, release.yml, bench.yml, build.yml) invokes `nim doc` or `--project`. The `--project lockfreequeues` strings in bench*.yml are bencher CLI flags, unrelated to nim doc. - Past releases: v4.0.0 and v4.1.0 ship zero release assets, so there is no json.tar.gz download URL pattern to preserve. Adds .gitignore entries to prevent accidental regeneration if a contributor runs nim doc locally. Reconciled with the existing /htmldocs/ entry under a new "Legacy nim doc artifacts (removed in v4.2.0)" heading. mkdocs build --strict verified clean (3.05s build, no warnings under --strict, exit 0) post-deletion. Part of v4.2.0 omnibus (bench polish + docs migration).
Adds infra to enable later doc migration work without breaking the build at any intermediate commit: - mkdocs-include-markdown-plugin: lets guide pages embed shared fragments (CHANGELOG snippets, license blocks). - theme.custom_dir: docs/overrides — empty for now; reserved for template overrides if needed. - theme.features += navigation.expand — sidebar shows full tree without click-to-expand. - show_attribution: false on the nim mkdocstrings handler — drops "Generated by mkdocstrings" footer per typestates style. - docs-requirements.txt: pins click<8.3.0 (mkdocs compatibility) and adds mkdocs-include-markdown-plugin>=6.0. Nav restructure deferred to a later commit (after new guide pages land) to keep mkdocs build --strict GREEN at every commit boundary. Part of v4.2.0 omnibus.
The `Track base branch benchmarks with Bencher` step on devel has been failing on every push since the Track 6 threshold work landed (most recently run 25398191987 on 2026-05-05) with: Failed to validate the model for the throughput_ops_ms Measure Threshold: Invalid threshold model: Invalid model, no boundary provided The CLI invocation as written matches the documented bencher.dev two-measure pattern (latency upper-boundary + throughput lower-boundary in a single `bencher run`, terminated by `--thresholds-reset`), but the Bencher CLI is rejecting it in production. The leading hypothesis is that clap argparse absorbs the trailing `--threshold-lower-boundary` into the first measure block (latency) rather than the second (throughput), so throughput ends up with a model that has no boundary. The failed Bencher step short-circuited the job before `Snapshot to docs assets` ran, so docs/assets/bench-results/latest.json on gh-pages remained stale (or empty), which is why the v4.2.0 chart work would have rendered the defensive fallback (added in 341e0b6) instead of real numbers. Fix: Option C — mark the threshold step `continue-on-error: true` so a threshold-validation failure no longer blocks the downstream snapshot step. Functionally we lose nothing in the short term: per Track 6 Task 6.4 the threshold gating itself is dormant until the 10-run calibration soak completes post-merge, and at present there is no sample history for Bencher to compare against anyway. A TODO comment in the workflow records the post-release follow-up: - try giving each measure both upper AND lower boundaries explicitly, - or split into two separate `bencher run` invocations, - or pin bencherdev/bencher to a specific tag once Bencher confirms the bug or the expected multi-measure syntax. This complements 341e0b6's defensive fallback (defense-in-depth): - 341e0b6: defensive snapshot fallback for any future merge_bmf-style failure. - This commit: stops the current Bencher-step failure from short- circuiting the job, so the regular snapshot path works and v4.2.0 ships with real data. Live verification deferred to first post-merge devel run. Refs PR 6 commit 8c1290d (feat(bench): latency thresholds + p999/max measures + K=5000) for the original threshold design. Part of v4.2.0 omnibus.
Restructures the docs tree to the typestates pattern: standalone guide content lives under docs/guide/, API reference pages stay under docs/api/. Moved (with git mv to preserve history): - docs/safety-model.md -> docs/guide/safety-model.md - docs/slot-ownership-typestates.md -> docs/guide/slot-ownership-typestates.md - docs/examples.md -> docs/guide/examples.md Updated inbound link references in: - README.md (docs/safety-model.md and docs/slot-ownership-typestates.md links retargeted under docs/guide/) - docs/api/unbounded_sipmuc.md (../slot-ownership-typestates.md -> ../guide/slot-ownership-typestates.md) - docs/api/unbounded_mupmuc.md (same) - docs/api/unbounded_mupsic.md (same) The intra-guide link from safety-model.md to slot-ownership-typestates.md remains a same-directory relative link and works unchanged. mkdocs.yml nav: minimal update to keep mkdocs build --strict GREEN at this commit boundary -- only the three moved entries (Safety Model, Slot Ownership Typestates, Examples) were retargeted to their new guide/ paths. The full nav restructure (tabs, Guide-first top-level grouping per the typestates pattern) lands in a later commit (B1b) once the new guide pages also exist. Part of v4.2.0 omnibus.
…rary colors
Replaces the single-chart-with-toggle-legend rendering with a more
legible multi-panel layout matching the docs page restructure:
- Hero panel at the top (#bench-hero): one representative shape
(preference: mpmc/4p4c -> mpmc/2p2c -> mpsc/4p1c -> spsc/1p1c ->
fallback-by-coverage) showing lockfreequeues vs alternatives as
hand-rendered DOM bars (a11y + theming wins; see bench-charts.js
comments).
- Per-topology throughput panels (SPSC, MPSC, MPMC bounded, MPMC
unbounded), one uPlot instance per panel with its own log/linear
toggle and per-library legend.
- Latency panel placeholder (#bench-latency) — rendering lands in
the next commit (A2).
Library color discipline: lockfreequeues family gets a single brand
indigo (Material #3f51b5 bounded, #5c6bc0 unbounded); each comparison
library gets a stable distinct Material hue. LIBRARY_COLORS const is
marker-bracketed for the contract-test parser (CONTRACT-TEST-PARSED-
{START,END} LIBRARY_COLORS). Unknown libraries fall through to a
fallback palette with a one-shot console.warn pointing at the map.
Blocking-on-full libraries (Threading.Channels, system Channel)
render as dashed lines + asterisk in legend on uPlot panels and as
dotted-border bars on the hero. BLOCKING_LIBRARIES const is also
marker-bracketed.
Empty-state handling: when latest.json reports _status: "fallback"
(see 341e0b6 / 1c5ec4a) the chart falls through to example.json,
shows a yellow status banner with the upstream cause, and continues
to render. When both sources fail, panels show a clear
"snapshot pending" message instead of an empty grid.
Hash routing supported via DOM IDs: #bench-hero,
#bench-throughput-{spsc,mpsc,mpmc-bounded,mpmc-unbounded},
#bench-latency. The bootstrap nudges scrollIntoView once panels
are populated so an initial load with #bench-throughput-spsc lands
on the rendered panel rather than above it.
Mobile-responsive: chart containers are width 100% / max-width 100%;
hero rows collapse to single column under 768px; iPhone SE width
gets horizontal scroll on uPlot plots rather than illegible squeeze.
window.lockfreequeuesBench public surface: NOT introduced. Research
confirmed the prior code did not expose any window global, and the
existing contract test does not require one. The IIFE remains the
only public boundary; the contract surface is the bracketed
LIBRARY_COLORS / BLOCKING_LIBRARIES constants for future test
extension in A4.
Part of v4.2.0 omnibus. Followed by A2 (latency panel) and A3 (hero
polish) in a later commit.
The chart code added in 10243ea (A1) supports a 3-tier fallback chain: latest.json (live) -> example.json (fixture) -> error banner This commit lands the middle tier. Without it, the docs benchmarks page shows the red "snapshot pending" error banner whenever live data isn't available - a poor first-impression for v4.2.0 readers. Provenance: BMF JSON merged from the five per-binary artifacts of workflow run 25369126487 (https://github.com/elijahr/lockfreequeues/actions/runs/25369126487), a successful bench run on 2026-05-05 09:42:58Z covering 48 slugs across spsc / mpsc / mpmc bounded / mpmc unbounded topologies. Library coverage: lockfreequeues_{sipsic,sipmuc,mupsic,mupmuc} + their unbounded variants, moodycamel, nim_channel, nim_channels. The cross-language comparison adapters (loony, boost_lockfree_*, crossbeam_*, threading_channels) are not included because they only run on the bench-comparison.yml nightly cron, which has not yet produced a successful merged BMF on devel. The fallback chart renders correctly without them and will pick up the full set once the live latest.json is published. The fixture is intentionally REPRESENTATIVE, not authoritative - the chart prepends a yellow status banner explaining "Showing representative data from example.json. Live snapshot was unavailable ({reason}). The chart will refresh once the next bench run on devel publishes latest.json." Re-merging was required because bench.yml uploads per-binary BMF fragments (bench-bench_{spsc,mpsc,mpmc,unbounded,latency}-bmf), not a single merged.json artifact. Procedure documented in benchmarks/README.md ("Refreshing the example fixture") for future regenerations. Part of v4.2.0 omnibus.
The sipmuc.md page is the canonical API reference template introduced when sipmuc landed (v3.x). The other three bounded variants (sipsic, mupsic, mupmuc) had stub pages with just an mkdocstrings-nim handler invocation — no examples, no typestate diagrams, no cross-links. This commit brings them up to parity: - Variant identification in the SPSC/MPSC/SPMC/MPMC quadrant. - mkdocstrings-nim handler invocation (existing). - 1-2 worked examples per variant, validated against actual init signatures in src/lockfreequeues/<variant>.nim. - Typestate diagram where applicable (mupsic / mupmuc have producer / consumer binding states; sipsic does not). - Cross-links to ../guide/safety-model.md and ../guide/slot-ownership-typestates.md. Source-of-truth verified at: - src/lockfreequeues/sipsic.nim:28 initSipsic[N, T] - src/lockfreequeues/mupsic.nim:81 initMupsic[N, P, T] - src/lockfreequeues/mupmuc.nim:90 initMupmuc[N, P, C, T] Examples verified to compile under nim check. Part of v4.2.0 omnibus.
Skeleton structure for the new guide pages that the v4.2.0 docs migration introduces. Prose comes in a follow-up commit (C3 / G4); this commit lands just the page structure to keep the diff reviewable. New files: - docs/guide/getting-started.md (install + first SPSC queue) - docs/guide/core-concepts.md (bounded/unbounded/quadrant/capacity) - docs/guide/bounded-vs-unbounded.md (when to choose each) - docs/guide/memory-management.md (memory model + DEBRA) - docs/guide/performance-tuning.md (capacity, thread placement, compile) - docs/contributing.md (top-level OSS contributing) Each skeleton has H1, brief intent, section headings, placeholder code blocks, and internal cross-links. Sections are intentionally short pending the C3 prose pass. Nav restructure (linking these pages into the top-level Guide grouping) lands in a subsequent commit (B1b) so this commit's diff stays scoped. Part of v4.2.0 omnibus.
Moves the docs site to the typestates-pattern nav layout now that the new guide pages (b7e82cd) and expanded API pages (3ed149b) exist on disk: - Top-level Guide grouping (was: scattered top-level entries): Getting Started -> Core Concepts -> Bounded vs Unbounded -> Slot Ownership Typestates -> Safety Model -> Memory Management -> Performance Tuning -> Examples - API Reference grouping unchanged in members; ordering already pedagogical (sipsic -> sipmuc -> mupsic -> mupmuc, then unbounded variants). - Top-level Contributing entry pointed at docs/contributing.md (the in-tree contributing page, not the 9-line root CONTRIBUTING.md which serves as a stub for OSS scanners). - watch: directive gains docs/guide so mkdocs serve picks up changes in the new guide tree during dev. mkdocs build --strict GREEN; the "pages not in nav" INFO notes emitted by --strict during the C2 skeleton commit are now resolved. Part of v4.2.0 omnibus.
…anels A1 (10243ea) introduced 4 throughput panels but the routing data left mpsc_unbounded out, so its 3 slugs in example.json (84225f7) landed in the fixture but never rendered. spsc_unbounded was folded into the mpmc_unbounded panel, which doesn't reflect what the panel name promises. Fix: pair bounded + unbounded within each core-topology panel: #bench-throughput-spsc: spsc + spsc_unbounded #bench-throughput-mpsc: mpsc + mpsc_unbounded #bench-throughput-mpmc-bounded: mpmc only #bench-throughput-mpmc-unbounded: mpmc_unbounded only MPMC keeps the bounded/unbounded split because the bounded panel already carries comparison libraries (crossbeam, moodycamel, boost, loony, channels) and mixing unbounded would muddle that comparison. SPSC and MPSC have far fewer comparison libraries so the bounded + unbounded co-location stays readable. Library color discipline already separates lockfreequeues bounded (#3f51b5) from unbounded (#5c6bc0), so visual mixing is unambiguous. Adds a routing contract test that parses THROUGHPUT_PANELS from bench-charts.js, asserts the expected topology -> panel mapping, verifies every topology routes to exactly one panel (no double- render), and cross-checks that every topology in example.json is covered by some panel (so future fixture additions can't silently disappear). Verified: - node --check on bench-charts.js exits 0. - mkdocs build --strict GREEN. - Contract test 10/10 PASS (was 9/9; +1 routing test). - Hand-traced: example.json's 3 mpsc_unbounded slugs now route to the mpsc panel; example.json's 1 spsc_unbounded slug routes to the spsc panel. Part of v4.2.0 omnibus.
Replaces the placeholder _(Coming in v4.2.0)_ markers in the b7e82cd skeletons with substantive prose, runnable code examples, and curated cross-links. Pages filled in: - docs/guide/getting-started.md (install + first SPSC queue + pitfalls) - docs/guide/core-concepts.md (SPSC/MPSC/MPMC quadrant; bounded vs unbounded; capacity model) - docs/guide/bounded-vs-unbounded.md (decision guidance + backpressure + trade-offs) - docs/guide/memory-management.md (acquire/release; cache-line padding; ARC/ORC; DEBRA reclamation) - docs/guide/performance-tuning.md (capacity, thread placement, batch sizing, compile settings) - docs/contributing.md (build, test, code style, PR process, license; supersedes root CONTRIBUTING.md as a 9-line tooling stub) All Nim code blocks pass `nim check --path:src --threads:on`. mkdocs build --strict GREEN. Voice matches the typestates-pattern guide pages (safety-model.md, slot-ownership-typestates.md). Part of v4.2.0 omnibus.
A1 (10243ea) left the latency panel as a placeholder. This commit fills it in. Visualization: stepped-line ladder, x-axis = percentile bucket [p50, p95, p99, p999, max], y-axis = nanoseconds (log scale, because latency tail dynamics span 3-4 decades). One line per library, colors from LIBRARY_COLORS. Bounded 1p1c variants (sipsic, sipmuc, mupsic, mupmuc) are the canonical latency sources; cross-language alternatives appear if their adapters emit latency measures. Log y-axis chosen because linear scale compresses p50 / p95 against the noise floor and obscures the tail behavior that matters for production sizing. Empty state: if no latency slugs are present (e.g. running off the fallback fixture without bench_latency data), the panel shows a clear "latency measurements unavailable in this dataset" message rather than an empty grid. Verified: - node --check on bench-charts.js exits 0. - mkdocs build --strict GREEN. - Contract test 10/10 PASS. - example.json's 4 bounded 1p1c slugs render as 4 lines. Part of v4.2.0 omnibus.
Refines the hero panel rendering (#bench-hero) introduced in 10243ea. The follow-up items from A1's report: - Hero shows the chosen topology's bounded variant only; bounded-vs-unbounded comparisons live in the per-topology panels below. Hero is for "lockfreequeues vs alternatives at this canonical shape," not a bounded/unbounded survey. - Legend always emits a stable structure; blocking libraries carry a "(blocking)" badge in the legend row, replacing A1's conditional inline footnote. - Tooltip now shows: library, value ± stddev, units, shape context. - Y-axis labeled "throughput (ops/ms)". - Alternatives sorted by descending throughput, so the strongest alternative sits next to lockfreequeues for easy comparison. Verified: - node --check on bench-charts.js exits 0. - mkdocs build --strict GREEN. - Contract test 10/10 PASS. Part of v4.2.0 omnibus.
…BRARIES, DOM IDs, fixture)
Extends benchmarks/tests/test_bench_charts_contract.py with four new
tests pinning the surfaces introduced across G2 (A1) and G5 (A2, A3).
Per Phase 3.2 CRIT-4, regexes are value-anchored — robust against
marker-comment drift and reformatter reflow of `Object.freeze({...})`.
New tests:
- test_dom_containers_present_in_benchmarks_md: pins all 7 DOM
container IDs (bench-status, bench-hero, four throughput panels,
bench-latency); asserts each appears exactly once.
- test_library_colors_map_covers_fixture: every library family in
SAMPLE_BMF has a LIBRARY_COLORS entry; all hex values are 6-char
lowercase; the lockfreequeues_* family has all 8 expected members
(4 bounded + 4 unbounded).
- test_blocking_libraries_const_matches_contract: BLOCKING_LIBRARIES
literal equals EXPECTED_BLOCKING_LIBRARIES = {threading_channels,
nim_channel} exactly. Defensive regression guard against
accidental additions.
- test_example_json_validates_against_schema: BMF slug grammar; no
`_status` / `_reason` placeholder keys; reasonable size (10 <
slug_count < 200); every measure carries a finite numeric value.
SAMPLE_BMF fixture extended to cover all 6 topology axes (spsc, mpsc,
mpmc, spsc_unbounded, mpsc_unbounded, mpmc_unbounded) plus the full
latency percentile suite for one bounded 1p1c slug. Existing
test_chart_assets_present extended with one assertion for
example.json. Existing 10 tests unchanged. Total: 14 tests.
Per the CRIT-1 resolution on the impl plan (no `git rebase -i`),
these tests land AFTER the implementation in commit-stack order. The
authoring sequence was test-first (mental model), with the test spec
embedded in the design doc and the implementation reviewed against
those expectations. Mutation-tested locally to confirm each new test
fails when its target surface is broken (drop a LIBRARY_COLORS
entry, rename a DOM id, etc.).
Part of v4.2.0 omnibus.
Terminal v4.2.0 polish on the user-facing benchmark surfaces. README BENCHMARKS block (between the existing markers): - Headline number from example.json (the canonical bench fixture) - 4-row variant comparison table (Sipsic / Sipmuc / Mupsic / Mupmuc at one canonical shape each) - Link to the live chart at latest/benchmarks/ docs/benchmarks.md: - New "How to read these numbers" section: topology axis, shape axis, bounded vs unbounded, asterisk semantics, why MPMC 4p4c is harder than SPSC 1p1c. Cross-links to Guide pages. - New "When to pick lockfreequeues" section: use-case advice grounded in measured numbers, with explicit trade-off notes for when it's the wrong choice. Bug fix from A4 fact-check: example.json contains `nim_channels` (plural — adapter ID for system Channel on some platforms) which had no LIBRARY_COLORS entry, falling back to FALLBACK_PALETTE + console.warn. Added entry pointed at same color as nim_channel. Same blocking-on-full semantics, so added to BLOCKING_LIBRARIES too. Contract test expected set updated to match. Verified: - node --check on bench-charts.js exits 0. - mkdocs build --strict GREEN. - Contract test 14/14 PASS. Part of v4.2.0 omnibus.
Phase 4.6.3 green mirage audit identified two CI gaps:
1. No automated JS syntax check on docs/assets/bench-charts.js.
mkdocs --strict treats the file as an opaque static asset, so
a typo only surfaces at runtime in the browser console. Added
`node --check` step before `mkdocs build`.
2. The `verify mike asset path` step only checked HTTP 200 + JSON
parse. If bench.yml is silently broken (or the defensive
fallback fires repeatedly), latest.json would carry
`_status: "fallback"` indefinitely and the docs build would
stay green. Extended the verify step to:
- Always emit `::warning::` if `_status == "fallback"`
- Fail the step (`::error::`) only when the run is the daily
`schedule` cron — that gives the maintainer a daily nudge
without breaking unrelated docs PRs.
Live verification deferred to first post-PR push (the new step
will run automatically on the next docs.yml trigger).
Verified:
- actionlint clean.
- yaml.safe_load on docs.yml succeeds.
- bash -n on the new shell body is clean.
- contract test 14/14 PASS (no test surface affected).
- mkdocs build --strict GREEN.
Part of v4.2.0 omnibus.
Phase 4.6.3 green mirage audit identified that the existing
panel-routing test is regex-extract-only — it pins which topology
literals appear in THROUGHPUT_PANELS, but never simulates the
routing decision. A mutation flipping || to && (silently dropping
every spsc slug from the chart) would PASS the test.
Fix: build a Python-side mirror of the routing decision. Test
parses each panel's `includes` predicate body, translates the JS
expression into an evaluable Python callable under a strict token
whitelist (topology|===|!==|==|!=|&&|\|\||string-literal|paren),
and asserts predicate behaviour against an explicit
EXPECTED_ROUTING dict that pins:
spsc -> bench-throughput-spsc
spsc_unbounded -> bench-throughput-spsc
mpsc -> bench-throughput-mpsc
mpsc_unbounded -> bench-throughput-mpsc
mpmc -> bench-throughput-mpmc-bounded
mpmc_unbounded -> bench-throughput-mpmc-unbounded
Each topology must route to exactly one panel id, every panel
predicate is probed against every topology (positive + negative),
and an unknown topology must be rejected by every panel.
Mutation-tested locally:
- || -> && in the spsc panel: spsc routes to [], test FAILS
as expected.
- swap spsc_unbounded <-> mpsc_unbounded across panels:
spsc_unbounded routes to mpsc panel, test FAILS as expected.
Verified:
- contract test 14/14 PASS.
- node --check on bench-charts.js exits 0.
- mkdocs build --strict exits 0.
Part of v4.2.0 omnibus.
The Phase 4.6 audit flagged that CHANGELOG.md's [Unreleased] block only documented the legacy nim-doc artifact removal — the chart overhaul, guide migration, prose pass, Bencher fix, and mkdocs nav restructure were missing. Fixes that, so the next release tag ships with notes a reader can actually use. Grouped into Added / Changed (matching existing keepachangelog conventions), summarising the 17-commit branch: - Added: multi-panel chart layout, hero/latency panels, library color discipline, 5 new guide pages + contributing, narrative sections, README hybrid block, example.json fixture, 4 new contract tests, defensive bench fallback. - Changed: guide pages moved to docs/guide/, API page expansions, mkdocs nav restructure to typestates Guide-first pattern, mkdocs.yml typestates alignment, docs.yml CI updates, bench.yml loop-prevention strengthening, Bencher threshold band-aid. Part of v4.2.0 omnibus.
|
✅ Momus review posted — verdict APPROVE, 0 findings
|
There was a problem hiding this comment.
Code Review
This pull request significantly overhauls the project's documentation and benchmarking infrastructure. Key changes include the introduction of a comprehensive guide track covering core concepts and performance tuning, expanded API reference pages with usage examples, and a new multi-panel interactive benchmark chart system. The update also adds robust contract tests for the charting logic and removes legacy documentation artifacts in favor of a restructured MkDocs configuration. I have no feedback to provide as there were no review comments to assess.
|
/ai-review |
There was a problem hiding this comment.
This PR overhauls the benchmark chart presentation (multi-panel layout, hero panel, latency ladder) and migrates the docs to a typestates-pattern mkdocs+mike pipeline. It also folds in CI fixes including a defensive fallback snapshot, Bencher continue-on-error band-aid, and JS syntax checking. The main issue is that the new latency panel rendering pipeline has zero contract test coverage despite establishing CONTRACT-TEST-PARSED marker infrastructure that was never wired in, leaving a regression blind spot.
Severity tally: 1 Low.
Low
- BOT-A2 (
docs/assets/bench-charts.js:1005): renderAllEmpty drops the hero panel heading but keeps throughput panel headings
Noteworthy
- The test_throughput_panel_routing test's predicate-evaluation strategy (parsing JS lambda bodies into Python evaluables) is a genuinely robust defense against green-mirage regressions that regex-only tests would miss.
- The defensive fallback step in bench.yml with triple-layered loop prevention (paths-ignore + bot-actor + [skip ci]) is well-documented and architecturally sound.
Verdict: APPROVE.
Commands
- Comment
/ai-reviewor mention @axiomantic-momus[bot] to request a re-review of the latest changes. - Reply to a finding with
won't fix,by design, ornot a bugto decline it. - Reply with
instead, ...to propose an alternative fix.
Powered by Momus running deepseek/deepseek-v4-pro via openrouter.ai.
| 'was unavailable (' + reason + '). The chart will refresh once ' + | ||
| 'the next bench run on devel publishes latest.json.'; | ||
| } else if (status === 'error') { | ||
| message = | ||
| 'Bench snapshot pending — the most recent attempt to merge ' + | ||
| 'benchmark results was unavailable (' + reason + | ||
| '). Live data will appear here on the next successful run.'; | ||
| } else { | ||
| message = 'Bench snapshot status: ' + status + ' (' + reason + ').'; | ||
| } | ||
| host.appendChild(el('p', null, message)); | ||
| } | ||
|
|
||
| function renderAllEmpty(reason) { | ||
| const heroHost = document.getElementById('bench-hero'); | ||
| if (heroHost) { |
There was a problem hiding this comment.
BOT-A2 — Low (quality)
renderAllEmpty drops the hero panel heading but keeps throughput panel headings
When the fallback chain fully fails, renderAllEmpty renders the hero panel (id='bench-hero') with just a
'Bench snapshot pending — ...' message, omitting the
heading that renderHero always emits (at minimum 'Throughput at a glance'). By contrast, renderAllEmpty does emit
panel titles for each THROUGHPUT_PANELS entry. This creates an inconsistent UX where the hero section heading vanishes on error while throughput sections keep their headings. The fix is a single line: add el('h3', { class: 'bench-hero-heading' }, 'Throughput at a glance') before the error
in renderAllEmpty.
| 'was unavailable (' + reason + '). The chart will refresh once ' + | |
| 'the next bench run on devel publishes latest.json.'; | |
| } else if (status === 'error') { | |
| message = | |
| 'Bench snapshot pending — the most recent attempt to merge ' + | |
| 'benchmark results was unavailable (' + reason + | |
| '). Live data will appear here on the next successful run.'; | |
| } else { | |
| message = 'Bench snapshot status: ' + status + ' (' + reason + ').'; | |
| } | |
| host.appendChild(el('p', null, message)); | |
| } | |
| function renderAllEmpty(reason) { | |
| const heroHost = document.getElementById('bench-hero'); | |
| if (heroHost) { | |
| In renderAllEmpty, after clearing heroHost.innerHTML, add: | |
| heroHost.appendChild(el('h3', { class: 'bench-hero-heading' }, 'Throughput at a glance')); | |
| before the 'Bench snapshot pending' <p>. |
When the snapshot fallback chain fully fails, renderAllEmpty was emitting just an error <p> for the hero panel while still emitting <h4> titles for each throughput panel — an inconsistent layout where the hero heading vanishes on error but section headings stay. Add the standard 'Throughput at a glance' <h3> before the error message so the page structure is identical between healthy and empty states. Addresses Momus BOT-A2 (Low).
There was a problem hiding this comment.
This v4.2.0 omnibus PR delivers a major benchmark chart presentation overhaul (hero panel, multi-panel throughput/latency layout, library color discipline), a docs migration to the typestates-pattern mkdocs+mike pipeline with 5 new guide pages, and several CI/pipeline fixes (defensive fallback snapshot, daily cron for doc freshness, JS syntax gate, [skip ci] loop prevention, and Bencher continue-on-error band-aid). The code is well-structured with thorough contract tests for the chart surface area (DOM IDs, library colors, blocking libraries, panel routing predicates, fixture schema). Two low-severity concerns identified: the Bencher continue-on-error masks all failure modes, not just the targeted upstream CLI issue; and there is a small test gap for the JS fallback chain detection logic that could be covered using the existing JS↔Python contract-test pattern.
No findings.
Noteworthy
- The panel routing contract test (
test_throughput_panel_routing) is a standout: it parses JS predicates from source, translates them to evaluable Python callables, and asserts behavioral correctness against an EXPECTED_ROUTING dict — catching operator flips (e.g.||→&&) that literal-extraction tests would miss. - The defensive fallback snapshot in bench.yml with its 3-layer loop prevention (paths-ignore + bot-actor guard + [skip ci]) and retry-3 push pattern is a well-considered reliability addition.
Verdict: APPROVE.
Commands
- Comment
/ai-reviewor mention @axiomantic-momus[bot] to request a re-review of the latest changes. - Reply to a finding with
won't fix,by design, ornot a bugto decline it. - Reply with
instead, ...to propose an alternative fix.
Powered by Momus running deepseek/deepseek-v4-pro via openrouter.ai.
## v4.2.0 omnibus: bench presentation overhaul + docs migration to typestates pattern This branch ships the v4.2.0 release-blocker work: a full overhaul of the benchmark chart presentation, a migration of the documentation site to the typestates-pattern mkdocs+mike pipeline (replacing the bit-rotten `nim doc` artifacts), and a handful of CI/pipeline fixes folded in along the way. ### What this ships **Chart presentation core (the user-facing wins):** - Hero panel: headline "10.6x faster than system Channel at MPMC 4p4c" surfaced as a labeled tooltip, sorted-alternatives legend, dedicated styling. - Multi-panel layout: separate panels for SPSC, SPMC, MPSC, MPMC plus a latency ladder, replacing the prior single-chart grid. - Library color discipline: lockfreequeues vs nim_channels vs reference baselines now have stable, accessible color assignments enforced by a single `LIBRARY_COLORS` map. - Latency panel (`#bench-latency`): log-y stepped ladder rendering p50/p99/p999 distributions per scenario. - Hero number sourced from `example.json` (BMF fixture from artifact 25369126487, 2026-05-05). **Docs migration to typestates pattern:** - 5 new full guide pages plus prose-rich expansions of existing API pages (Sipsic, Sipmuc, Mupsic, Mupmuc). - mkdocs nav restructured under top-level Guide grouping; existing guide pages migrated into `docs/guide/`. - README BENCHMARKS hybrid block: chart-rendering markers paired with a current-numbers table. - Narrative sections in `benchmarks.md` describing the methodology, BMF schema, and how to refresh the example fixture. ### CI / pipeline fixes folded in - Bencher threshold `continue-on-error` band-aid that unblocks `latest.json` snapshots when the threshold model boundary trips. - Defensive fallback step in `bench.yml` that emits a `_status: "fallback"` `latest.json` so the chart never goes blank. - `[skip-ci]` tag on snapshot auto-commits to prevent CI loops. - Daily cron in `docs.yml` to keep mike-published charts fresh even on quiet weeks. - `node --check` JS syntax gate so chart-script regressions fail PR CI rather than at runtime in the browser. - Fallback-status freshness alert: docs.yml's verify step warns when the deployed `latest.json` carries `_status: "fallback"` for too long, and fails on cron. ### Cleanup Legacy `json/` directory and `nimdoc.cfg` removed. These were `nim doc` artifacts the mkdocs+mike pipeline supplanted in v4.0.x and have been bit-rotten since. ### Authoring-order note for the test commits The CRIT-1 resolution in the implementation plan ruled out `git rebase -i` for this stack, so the test commits land **after** their corresponding implementation commits in commit-stack order. The mental model was test-first: the test specifications were embedded in the design doc and each implementation commit was reviewed against them before being accepted. The commit stack reflects landing-order, not authoring-order. Reviewers should not read the absence of a preceding test commit as the absence of a test spec. ### 20-commit stack outline Read in this order: 1. `ea18e1f` ci(docs): pin Nim 2.2.8, install nim package for compiler API, add daily cron 2. `341e0b6` ci(bench): add [skip-ci] to snapshot commit + defensive fallback latest.json 3. `8326fc7` chore(docs): remove legacy nim doc artifacts (json/, nimdoc.cfg) 4. `c7cb1d3` docs: align mkdocs config with typestates pattern (additive-only) 5. `1c5ec4a` ci(bench): fix Bencher threshold model boundary configuration 6. `977953a` docs: move existing guide pages into docs/guide/ 7. `10243ea` docs: chart presentation core — hero panel + multi-panel layout + library colors 8. `84225f7` docs: add example.json BMF fixture for chart fallback rendering 9. `3ed149b` docs: expand sipsic/mupsic/mupmuc API pages to match sipmuc structure 10. `b7e82cd` docs: scaffold 6 guide page skeletons (typestates-pattern) 11. `32dcd2f` docs: restructure mkdocs nav with top-level Guide grouping 12. `1f8a827` docs: route mpsc_unbounded (and audit spsc_unbounded) to consistent panels 13. `5e1fdc1` docs: prose pass on guide pages (C2 skeletons -> full content) 14. `eac2150` docs: render latency panel (#bench-latency) — log-y stepped ladder 15. `3a7ae75` docs: polish hero panel — labeling, tooltip, alternatives sort, legend 16. `c27ca64` test(bench): pin chart contract surfaces (LIBRARY_COLORS, BLOCKING_LIBRARIES, DOM IDs, fixture) 17. `76d1cf4` docs: README hybrid benchmarks block + narrative + nim_channels color 18. `f133b21` ci(docs): JS syntax check + bench-fallback freshness alert 19. `d12ae35` test(bench): make panel routing test catch logical regressions 20. `656974c` docs: complete CHANGELOG [Unreleased] for v4.2.0 omnibus ### Hard constraints upheld - No new vendored assets. - No CDN dependencies. - BMF schema unchanged (the fixture validates against the existing schema). - Cost gate intact (Bencher continue-on-error fallback writes a sentinel, not an unbounded retry). - Loop-prevention guards intact: `paths-ignore`, bot-actor check, and `[skip-ci]` tag all preserved. ### What's deliberately deferred These are out-of-scope for this omnibus and land in a follow-up release-prep PR: - `nimble.lock` regeneration. - Version bump to 4.2.0 in `lockfreequeues.nimble`. - CHANGELOG cut from `[Unreleased]` to `[4.2.0] - YYYY-MM-DD`. - mike alias coordination after the release tag lands. The release-prep checklist artifact tracks all of the above.
Eliminates the race where docs.yml deployed mike with no (or stale) latest.json because it ran in parallel with bench.yml. Now bench.yml's bench-upload job dispatches docs.yml after it commits the snapshot, so the next docs deploy is guaranteed to pick up the fresh JSON. The 'Verify mike asset path' step in docs.yml was checking bench.yml's output from inside the docs workflow — wrong concern boundary. The chart's example.json fallback (PR #29) renders an explicit empty state on transient 404, so the hard-fail wasn't needed. Bench freshness alerting belongs in bench.yml where the daily cron also lives. bench-upload now needs 'actions: write' to dispatch docs.yml via the GitHub API.
Bump version 4.1.0 → 4.2.0 in lockfreequeues.nimble. Move the [Unreleased] CHANGELOG block (PR #29's bench-presentation work plus this PR's bench-tightening + depth-pass work) to [4.2.0] - 2026-05-06. Create a new empty [Unreleased] block above. Highlights of v4.2.0 (full detail in CHANGELOG): - 5 new comparison libraries (atomic_queue, rigtorp×2, flume, kanal, liblfds) wired through the bench matrix; folly_pcq dropped per transitive-include + C++20 audit (strict-floor 16/17, breach documented for v4.3.0 follow-up). - First-class SPMC topology axis; sipmuc adapters rerouted from MPMC to SPMC. Bencher.dev threshold history for sipmuc slugs reset accordingly. - Topology-based adapter dispatcher (Option C) replaces name-based variant dispatch. - Harness-side schedYield-escalating backoff unblocks oversubscribed unbounded shapes on under-provisioned CI runners. Canonical queue-side fix deferred to v4.3.0 (Constraint #7). - uPlot bars for throughput panels; dark-mode-aware canvas reflow. - Inline glossary + "Why MPMC is harder than SPSC" prose in docs/benchmarks.md. - bench-comparison.yml retired; Rust cdylib consolidated under benchmarks/rust/comparison/. Release tag (v4.2.0) is a post-merge action handled separately.
v4.2.0 omnibus: bench presentation overhaul + docs migration to typestates pattern
This branch ships the v4.2.0 release-blocker work: a full overhaul of the benchmark chart presentation, a migration of the documentation site to the typestates-pattern mkdocs+mike pipeline (replacing the bit-rotten
nim docartifacts), and a handful of CI/pipeline fixes folded in along the way.What this ships
Chart presentation core (the user-facing wins):
LIBRARY_COLORSmap.#bench-latency): log-y stepped ladder rendering p50/p99/p999 distributions per scenario.example.json(BMF fixture from artifact 25369126487, 2026-05-05).Docs migration to typestates pattern:
docs/guide/.benchmarks.mddescribing the methodology, BMF schema, and how to refresh the example fixture.CI / pipeline fixes folded in
continue-on-errorband-aid that unblockslatest.jsonsnapshots when the threshold model boundary trips.bench.ymlthat emits a_status: "fallback"latest.jsonso the chart never goes blank.[skip ci]tag on snapshot auto-commits to prevent CI loops.docs.ymlto keep mike-published charts fresh even on quiet weeks.node --checkJS syntax gate so chart-script regressions fail PR CI rather than at runtime in the browser.latest.jsoncarries_status: "fallback"for too long, and fails on cron.Cleanup
Legacy
json/directory andnimdoc.cfgremoved. These werenim docartifacts the mkdocs+mike pipeline supplanted in v4.0.x and have been bit-rotten since.Authoring-order note for the test commits
The CRIT-1 resolution in the implementation plan ruled out
git rebase -ifor this stack, so the test commits land after their corresponding implementation commits in commit-stack order. The mental model was test-first: the test specifications were embedded in the design doc and each implementation commit was reviewed against them before being accepted. The commit stack reflects landing-order, not authoring-order. Reviewers should not read the absence of a preceding test commit as the absence of a test spec.20-commit stack outline
Read in this order:
ea18e1fci(docs): pin Nim 2.2.8, install nim package for compiler API, add daily cron341e0b6ci(bench): add [skip ci] to snapshot commit + defensive fallback latest.json8326fc7chore(docs): remove legacy nim doc artifacts (json/, nimdoc.cfg)c7cb1d3docs: align mkdocs config with typestates pattern (additive-only)1c5ec4aci(bench): fix Bencher threshold model boundary configuration977953adocs: move existing guide pages into docs/guide/10243eadocs: chart presentation core — hero panel + multi-panel layout + library colors84225f7docs: add example.json BMF fixture for chart fallback rendering3ed149bdocs: expand sipsic/mupsic/mupmuc API pages to match sipmuc structureb7e82cddocs: scaffold 6 guide page skeletons (typestates-pattern)32dcd2fdocs: restructure mkdocs nav with top-level Guide grouping1f8a827docs: route mpsc_unbounded (and audit spsc_unbounded) to consistent panels5e1fdc1docs: prose pass on guide pages (C2 skeletons -> full content)eac2150docs: render latency panel (#bench-latency) — log-y stepped ladder3a7ae75docs: polish hero panel — labeling, tooltip, alternatives sort, legendc27ca64test(bench): pin chart contract surfaces (LIBRARY_COLORS, BLOCKING_LIBRARIES, DOM IDs, fixture)76d1cf4docs: README hybrid benchmarks block + narrative + nim_channels colorf133b21ci(docs): JS syntax check + bench-fallback freshness alertd12ae35test(bench): make panel routing test catch logical regressions656974cdocs: complete CHANGELOG [Unreleased] for v4.2.0 omnibusHard constraints upheld
paths-ignore, bot-actor check, and[skip ci]tag all preserved.What's deliberately deferred
These are out-of-scope for this omnibus and land in a follow-up release-prep PR:
nimble.lockregeneration.lockfreequeues.nimble.[Unreleased]to[4.2.0] - YYYY-MM-DD.The release-prep checklist artifact tracks all of the above.