20260915 - Draw the axes over what the node can see, not over what it saw - #89
Merged
Merged
Conversation
… saw The Tracker page set no range on either axis, and the route rendered the template with no context at all, so the page never learned what the node was configured to see. Autoscaling is not a neutral default here. On fairforest B this morning, 97% of detections were a single interfering tone at 28 Hz, and the Doppler axis collapsed to a sliver around it: the plot looked full and said nothing. Two nodes, or one node an hour apart, were drawn at different scales and could not be compared. The ambiguity bounds are the only honest range. They come from the node's own blah2 config, which retina-gui already reads for other pages, and the delay bounds arrive in bins and become kilometres through the sample rate. Anything the config does not state stays None and that axis autoscales exactly as it does today. A guessed range misrepresents the node just as autoscaling does, only more confidently, so half a span is not half an axis and delay bins without a sample rate are not an axis at all. An unreadable config still renders the page: the axes are a nicety and losing them must not lose the plot. uirevision already preserves a viewer's own zoom, so the node's span is where the axis starts rather than somewhere it is dragged back to. Also: the window a viewer asks for is what they get only if the node has that much history to give, which it does not after a restart and does not once the sidecar's point ceiling ages the oldest points out. A wider Doppler span reaches that ceiling sooner. The count now says how much is actually held when it falls short, because a short record and a quiet sky are the same picture. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sweeping the spans found it on the tracker side and the same typo reaches here: dopplerMin above dopplerMax would draw the axis backwards, and a zero-width pair would collapse it. Either way a viewer gets a confident picture of nothing, where autoscaling at least shows the data. Both halves must be present and the high one above the low one. Everything else falls back to autoscale, which is the honest answer when the node has not described itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
The Tracker page set no
rangeon either axis, andindex()rendered the template with no context at all, so the page never learned what the node was configured to see.Autoscaling is not a neutral default here. On fairforest B this morning, 97% of the detections were a single interfering tone at 28 Hz, so the Doppler axis collapsed to a sliver around it. The plot looked full and told you nothing about the node's coverage. Two nodes, or the same node an hour apart, get drawn at different scales and cannot be compared. And when the fleet moves to ±300 Hz, the change would be invisible, because the axis was never showing ±200 in the first place.
Where the numbers come from
The node's own blah2
process.ambiguityblock, via the merged configretina-guialready reads for the home, config and calibrate pages. Delay arrives in bins and becomes kilometres throughcapture.fs, since a bin is only a distance once the sample rate says how wide it is.What happens when they are missing
Anything the config does not state stays
None, and that axis autoscales exactly as it does today:ambiguityblock, so both axes autoscaledopplerMinwithoutdopplerMax, so half a span is not half an axisfs, so no delay axis rather than a confident axis over a guessed cell widthThat last one is the point: the axes are a nicety, and losing them must not lose the plot. A guessed range misrepresents the node just as autoscaling does, only more confidently.
uirevisionalready preserves a viewer's own zoom across updates, so the node's span is where the axis starts rather than somewhere the view is dragged back to.Also here: how much history is actually held
The window a viewer asks for is what they get only if the node has that much to give. It does not after a restart, and it does not once the sidecar's point ceiling starts ageing the oldest points out, which a wider Doppler span reaches sooner because it raises the detection rate.
The count line now says how much is really held when it falls short of the request, for example
4,312 detections shown · 38m of 4h held. A short record and a quiet sky are otherwise the same picture. This is computed from the data the page already has, by comparing the span it holds against the window it asked for, so it needs no change to the sidecar's stream. A precise dropped-point count would, and is not here.Verification
ruff checkclean, dead-code gate clean, 888 passed.ruff format --checkis not clean, and is not clean onmaineither: it wants to rewrite single to double quotes across 56 files. This repo's.pre-commit-config.yamldeliberately carries only the dead-code hook, so reformatting is out of scope for this change and would bury it.Eight new tests in
tests/test_tracker_routes.pycover the bounds being read, ±1000 Hz carried through unchanged, delay bins converted through the sample rate, and each of the four ways the bounds can be absent. The last one parses theAXESliteral out of the rendered page rather than matching a substring, so it fails if the shape changes rather than only if the numbers do.Pairs with
retina-tracker #35, which reads the same bounds on the sidecar side and holds arriving detections to them. Neither depends on the other: this one reads the node config directly, so it works against the current sidecar release.
🤖 Generated with Claude Code