666ghj/MiroFish · error · StarHistoryError
reconstruction dates must be strictly increasing
Error message
reconstruction dates must be strictly increasing
What it means
Raised by validate_state() when daily points are not strictly increasing by date — i.e. a date is <= the previous date (duplicates and backwards ordering both fail). Strict ordering is required because each point is a cumulative star total for that UTC day.
Source
Thrown at scripts/star_history.py:415
previous_stars = 0
for index, raw_point in enumerate(daily):
if not isinstance(raw_point, dict):
raise StarHistoryError("reconstruction point must be an object")
_expect_keys(raw_point, {"date", "stars"}, "reconstruction point")
raw_date = raw_point["date"]
if not isinstance(raw_date, str):
raise StarHistoryError("reconstruction date must be a string")
try:
point_day = date.fromisoformat(raw_date)
except ValueError as exc:
raise StarHistoryError("reconstruction date is invalid") from exc
if point_day.isoformat() != raw_date:
raise StarHistoryError("reconstruction date is not canonical")
stars = _strict_non_negative_int(raw_point["stars"], "reconstruction stars")
if index == 0 and stars <= 0:
raise StarHistoryError("first reconstruction point must have stars")
if previous_day is not None and point_day <= previous_day:
raise StarHistoryError("reconstruction dates must be strictly increasing")
if index > 0 and stars <= previous_stars:
raise StarHistoryError("reconstruction stars must be strictly increasing")
if point_day >= generated_at.date():
raise StarHistoryError("reconstruction must contain only completed UTC dates")
previous_day = point_day
previous_stars = stars
snapshots = state["snapshots"]
if not isinstance(snapshots, list):
raise StarHistoryError("snapshots must be a list")
previous_snapshot: datetime | None = None
first_snapshot: datetime | None = None
for raw_snapshot in snapshots:
if not isinstance(raw_snapshot, dict):
raise StarHistoryError("snapshot must be an object")
_expect_keys(raw_snapshot, {"at", "stars"}, "snapshot")
snapshot_at = _parse_state_timestamp(raw_snapshot["at"], "snapshot.at")
_strict_non_negative_int(raw_snapshot["stars"], "snapshot stars")View on GitHub (pinned to b5b53acc57)
Solutions
- Sort daily by date ascending and deduplicate dates before writing state
- When merging, keep the point with the correct cumulative value for each date
- Add a unit test that asserts strict date monotonicity on generated state
Example fix
# before
"daily": [{"date": "2024-01-02", ...}, {"date": "2024-01-01", ...}]
# after
points = sorted(points, key=lambda p: p["date"]) # dedupe first, then write Defensive patterns
Strategy: validation
Validate before calling
daily.sort(key=lambda p: p["date"])
dedup = {p["date"]: p for p in daily}
daily = [dedup[d] for d in sorted(dedup)] Type guard
def dates_strictly_increasing(daily: list) -> bool:
return all(
daily[i]["date"] < daily[i + 1]["date"] for i in range(len(daily) - 1)
) Try / catch
try:
validate_state(state)
except StarHistoryError as exc:
if "reconstruction dates must be strictly increasing" in str(exc):
# sort + dedupe by date, then re-validate
... Prevention
- Always sort daily by date before writing state
- Never merge daily arrays by concatenation
- Deduplicate on date when combining sources
When it happens
Trigger: validate_state(state) where daily contains two points with the same date, or the list is unsorted (e.g. sorted by stars or built from an unordered dict).
Common situations: Building daily from a date-keyed dict without sorting by date; merging two state files by concatenation; deduplication logic that leaves duplicate dates.
Related errors
- snapshot timestamps must be strictly increasing
- {label} must use YYYY-MM-DDTHH:MM:SSZ
- {label} is not a valid UTC timestamp
- {label} contains missing or unknown fields
- history state must be a JSON object
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/4d165deece95c30d.
Report an issue: GitHub.