666ghj/MiroFish · error · StarHistoryError
chart coordinates must be ordered
Error message
chart coordinates must be ordered
What it means
Raised in `_monotone_x_path` (scripts/star_history.py:788) when a chart point's x is strictly smaller than the previous point's x. Monotone-X interpolation requires non-decreasing x; equal x values are tolerated (the later point replaces the earlier one), but a regression means the input sequence zig-zags and the cubic tangents would be undefined.
Source
Thrown at scripts/star_history.py:788
if value > 0:
return 1
return 0
def _monotone_x_path(points: Sequence[tuple[float, float]]) -> str:
"""Return a D3 curveMonotoneX-equivalent SVG path.
D3 uses Steffen monotonic interpolation: interior tangents are limited so a
smooth cubic cannot overshoot a monotonic run. This small implementation
keeps the Star History curve shape without adding a JavaScript dependency.
"""
normalized: list[tuple[float, float]] = []
for x, y in points:
if not math.isfinite(x) or not math.isfinite(y):
raise StarHistoryError("chart coordinates must be finite")
if normalized and x < normalized[-1][0]:
raise StarHistoryError("chart coordinates must be ordered")
if normalized and x == normalized[-1][0]:
normalized[-1] = (x, y)
else:
normalized.append((x, y))
if not normalized:
return ""
start_x, start_y = normalized[0]
commands = [f"M{_format_float(start_x)},{_format_float(start_y)}"]
if len(normalized) == 1:
return "".join(commands)
if len(normalized) == 2:
end_x, end_y = normalized[1]
commands.append(f"L{_format_float(end_x)},{_format_float(end_y)}")
return "".join(commands)
secants = [View on GitHub (pinned to b5b53acc57)
Solutions
- Sort the points before calling the path builder: `pts = sorted(pts, key=lambda p: p[0])` — duplicate-x entries are then handled by the function itself.
- If `render_svg` raises it, inspect the state's `reconstruction.daily` dates and `snapshots[].at` for out-of-order entries and regenerate the state from a clean backfill.
- Avoid hand-merging state files from different runs; use the library's update path which keeps snapshots monotonic.
- Add a quick assertion when preparing state: `dates = [p['date'] for p in state['reconstruction']['daily']]; assert dates == sorted(dates)`.
Example fix
# before: unsorted points path = _monotone_x_path(points) # after: order guaranteed (duplicate x kept, last wins) points = sorted(points, key=lambda p: p[0]) path = _monotone_x_path(points)
Defensive patterns
Strategy: validation
Validate before calling
def non_decreasing_x(points) -> bool:
return all(points[i][0] <= points[i + 1][0] for i in range(len(points) - 1))
if not non_decreasing_x(points):
points = sorted(points, key=lambda p: p[0])
path = _monotone_x_path(points) Try / catch
try:
svg = render_svg(state, theme)
except StarHistoryError as exc:
if "must be ordered" in str(exc):
raise ValueError("state has out-of-order chart points; regenerate state") from exc
raise Prevention
- Keep daily dates and snapshot timestamps ordered: use the library's update functions instead of merging state files by hand.
- When calling the path helper directly, sort by x first — equal x values are handled (last wins), decreasing x is not.
- After any state manipulation, assert daily dates are sorted: `d == sorted(d)`.
When it happens
Trigger: `render_svg` building points whose x (a monotonic function of the point's datetime) decreases — e.g. state where a reconstruction `daily` entry is dated after a later snapshot, or direct callers passing unsorted tuples. Duplicate x is fine (`x == normalized[-1][0]` replaces the last point); only `x < normalized[-1][0]` raises.
Common situations: State files whose `reconstruction.daily` dates and `snapshots[].at` overlap out of order (usually from hand-merging two state files); forks that reorder `_chart_points`; direct use of the helper with unsorted data.
Related errors
- chart coordinates must be finite
- unsupported SVG theme
- generated SVG contains a forbidden element
- generated SVG contains an unsafe attribute value
- generated SVG must be strict UTF-8
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/c745f1c6e34b13bd.
Report an issue: GitHub.