fix: #150 follow-ups (drawer header contrast, Live heat sync, RX days race, IATA interval cap) - #169
Merged
Merged
Conversation
…150) Step (k) in test-nav-drawer-1064-e2e.js opens the drawer in the light and the dark theme and computes the contrast of the header title (and the close button) against the header background from computed styles. On master the light theme paints the header with --surface-2 (white) under the white --nav-text title: 1.00:1. Dark passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nav-drawer.css paints the drawer title and close button with --nav-text and --nav-text-muted, but style.css gave the header --surface-2, white in the light theme. The header now uses --nav-bg2, which the customizer already maps (navBg2) and every preset pairs with navText. Default themes: title 17.1:1 on --nav-bg2 in light and dark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#135 (#150) New steps in test-issue-125-live-toggles-early-e2e.js: - Matrix and Heat saved ON, Matrix clicked OFF while init is held: Heat must be checked and enabled, its layer shown after init, and Matrix ON/OFF after init must bring Heat back as saved. Red on master: the checkbox stays unchecked while applyLiveControlEffects() shows the layer. - The same with Heat saved OFF: Heat stays unchecked with no layer. - #135 regression: leave Live while init awaits loadNodes(), come back, then one click on each of the nine toggles must write localStorage once. api() shares the in-flight request, so both inits continue when it is answered. Green on master (fixed by #135); against master with live.js from before #135 it fails on 8 of 9 toggles with 2 writes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…off (#150) syncHeatToggleToMatrix(false) only re-enabled the checkbox, so after Matrix was switched off during init it stayed unchecked while applyLiveControlEffects() showed the heat layer. It now also sets checked from heatEnabled. Switching Matrix off after init also rebuilds the heat layer when Heat is on, so the checked box is never shown without its layer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test 13 in test-issue-124-rx-coverage-viewport.js switches days 7 -> 30, answers the days=30 coverage and leaderboard first, then releases the slow days=7 responses: the days=30 data must stay. A failed older leaderboard request must not replace a newer one either. Red on master: the days=7 leaderboard replaces the days=30 one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uest (#150) drawCoverage() and loadBoard() each take a sequence number (coverageSeq, boardSeq) next to the mount generation from #124, and a response (or a leaderboard failure) renders only if no newer request of its kind has started. An older days response can no longer overwrite newer data; the same holds for coverage requests from quick pans or rx changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#150) - TestIATAWarnIntervalClampsHugeValues: 1e10 s (also from JSON), MaxInt, 86401 s and a year must give a 24h interval. Red on master: 1e10 s overflows time.Duration to a negative interval. - TestIATADropThrottleOldestTracksStaggeredEntries and TestIATADropThrottleOldestFollowsAnEarlierDrop cover the `oldest` lower bound with staggered and out-of-order timestamps. They pass on master; they kill four mutants that survived the existing tests (oldest left at now after a sweep, set to now on every insert, and either half of the insert condition dropped). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
time.Duration(c.IATAWarnIntervalSec) * time.Second overflowed for huge values (1e10 s became a negative interval), so every dropped message was logged. IATAWarnInterval() now caps the configured value at 86400 s. Documented in config.go and config.example.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dborup
marked this pull request as ready for review
October 2, 2026 15:35
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Relates to #150
The four follow-ups from the review of the issue batch (#109–#126). Each item has a test commit followed by a fix commit. The fifth point in the issue comment (analytics warm-up vs. frontend retry) is not part of this PR.
1. Nav drawer header unreadable in the light theme
style.cssgave.nav-drawer-headerthe background--surface-2(white in light), whilenav-drawer.csspaints the title with--nav-text(white) and the close button with--nav-text-muted. The header now uses--nav-bg2, which the customizer already maps (navBg2inTHEME_CSS_MAP) and every preset pairs withnavText. No new variable, so the customizer is unchanged.test-nav-drawer-1064-e2e.jscomputes, from computed styles, the contrast of the title (≥ 4.5:1) and the close button (≥ 3:1) against the header background in light and dark.rgb(26, 26, 46)).#232340to#1a1a2e, the same colour as the top nav.2. Live: Heat checkbox vs. heat layer
syncHeatToggleToMatrix(false)now also setsht.checked = heatEnabled. Switching Matrix off after init also rebuilds the heat layer when Heat is on. Without that rebuild, the checkbox would now be checked while the layer stayed hidden.New steps in
test-issue-125-live-toggles-early-e2e.js:loadNodes(), come back, then one click on each of the nine toggles must write localStorage exactly once.api()shares the in-flight/api/nodesrequest, so both inits continue when it is answered. This step is green on master because fix(live): wire every persisted view toggle before Live init awaits #135 fixed the bug. Against master withlive.jsfrom before fix(live): wire every persisted view toggle before Live init awaits #135 (d778bc40^1) it fails with "8 of 9 toggles" and 2 writes per click, which matches the issue.3. RX Coverage: stale
daysresponsedrawCoverage()andloadBoard()each take a sequence number (coverageSeq,boardSeq) next to the mount generation from #136. A response, or a leaderboard failure, renders only if no newer request of its kind has started. As a side effect, the same now holds for coverage requests from quick pans and rx changes.test-issue-124-rx-coverage-viewport.js: switch days 7 → 30, answer the days=30 requests, then release the delayed days=7 responses. The days=30 data must stay. A failed older leaderboard request must not replace a newer one either. Red on master (the days=7 leaderboard replaces the days=30 one).4. Ingestor:
iataWarnIntervalSecoverflowIATAWarnInterval()caps the configured value at 86400 s (24 h). Before,1e10overflowedtime.Durationto a negative interval, so every drop was logged. The cap is documented inconfig.goandconfig.example.json; the field is not in the README.TestIATAWarnIntervalClampsHugeValues: 1e10 s (direct and from JSON),MaxInt, 86401 s and a year all give 24 h; 86399 s stays as is. Red on master.TestIATADropThrottleOldestTracksStaggeredEntriesandTestIATADropThrottleOldestFollowsAnEarlierDropcover theoldestlower bound with staggered and out-of-order timestamps. They pass on master, which is expected: they pin the existing optimisation and kill four mutants the old tests let survive (see below).Tests
test-nav-drawer-1064-e2e.jstest-issue-125-live-toggles-early-e2e.jslive.jsfrom before #135test-issue-124-rx-coverage-viewport.jsgo test ./...ingestor (-run IATA)TestIATAWarnIntervalClampsHugeValuesredUnchanged on master and branch:
test-frontend-helpers.jshas 2 favStar failures (known baseline).test-rx-coverage-escape.jsfails on both with "could not locate row-builder end"; it is not run in CI.test-pr-1490-live-map-gpu-animations-e2e.jscannot load@playwright/testlocally on either side; it is not in CI.Mutants
All run in copies, never in the worktree:
var(--surface)/ back tovar(--surface-2, var(--surface))ht.checked = heatEnabledht.checked = truelive.jsfrom before #135.then/ coverage.then/ board.catchwithout the sequence checkboardSeqnot bumpedTestIATAWarnIntervalClampsHugeValuesoldest = now…OldestTracksStaggeredEntriesoldest = nownow.Before…OldestFollowsAnEarlierDroplen == 0…OldestTracksStaggeredEntries(sweep count)The four
oldestmutants survived the tests on master.Perf
None of the changes is in a hot path. Item 3 adds one integer compare per response, item 2 one assignment per Matrix toggle, and item 4 one compare per dropped message.
Notes
test-all.shanddeploy.ymlare unchanged. The Kpa-clawbot guard count is still 9.scripts/check-xss-sinks.sh --diffandscripts/check-css-vars.jsare clean.🤖 Generated with Claude Code