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

  1. Sort daily by date ascending and deduplicate dates before writing state
  2. When merging, keep the point with the correct cumulative value for each date
  3. 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

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


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/4d165deece95c30d. Report an issue: GitHub.