{"record":{"id":"24a992f28bc5877b","repo":"666ghj/MiroFish","slug":"reconstruction-daily-must-be-a-list","errorCode":null,"errorMessage":"reconstruction.daily must be a list","messagePattern":"reconstruction\\.daily must be a list","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":392,"sourceCode":"    if not isinstance(reconstruction, dict):\n        raise StarHistoryError(\"reconstruction must be an object\")\n    _expect_keys(\n        reconstruction,\n        {\"method\", \"generated_at\", \"daily\"},\n        \"reconstruction\",\n    )\n    reconstruction_method = reconstruction[\"method\"]\n    if reconstruction_method not in {\n        \"current_stargazers_starred_at\",\n        \"aggregate_snapshot_only\",\n    }:\n        raise StarHistoryError(\"unsupported reconstruction method\")\n    generated_at = _parse_state_timestamp(\n        reconstruction[\"generated_at\"], \"reconstruction.generated_at\"\n    )\n    daily = reconstruction[\"daily\"]\n    if not isinstance(daily, list):\n        raise StarHistoryError(\"reconstruction.daily must be a list\")\n    if reconstruction_method == \"aggregate_snapshot_only\" and daily:\n        raise StarHistoryError(\"aggregate-only history cannot contain reconstructed dates\")\n\n    previous_day: date | None = None\n    previous_stars = 0\n    for index, raw_point in enumerate(daily):\n        if not isinstance(raw_point, dict):\n            raise StarHistoryError(\"reconstruction point must be an object\")\n        _expect_keys(raw_point, {\"date\", \"stars\"}, \"reconstruction point\")\n        raw_date = raw_point[\"date\"]\n        if not isinstance(raw_date, str):\n            raise StarHistoryError(\"reconstruction date must be a string\")\n        try:\n            point_day = date.fromisoformat(raw_date)\n        except ValueError as exc:\n            raise StarHistoryError(\"reconstruction date is invalid\") from exc\n        if point_day.isoformat() != raw_date:\n            raise StarHistoryError(\"reconstruction date is not canonical\")","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L374-L410","documentation":"Raised by validate_state() when reconstruction['daily'] is not a JSON array. 'daily' holds the reconstructed per-day star count points, each an object with 'date' and 'stars'; anything other than a list (dict, string, number, null) fails immediately before per-point validation.","triggerScenarios":"validate_state(state) where reconstruction.daily is an object keyed by date (e.g. {\"2024-01-01\": 10}) instead of a list of points, or a null/string value from a partial hand edit.","commonSituations":"Converting the daily data to a date-keyed map for convenience and forgetting to convert back; merging state files with a tool that changed the array to an object; older producers that emitted a different structure.","solutions":["Make daily a JSON array of {\"date\": \"YYYY-MM-DD\", \"stars\": <int>} objects (it may be empty for aggregate_snapshot_only)","If using a date-keyed map internally, convert it to a list sorted by date before writing state","Regenerate the state with the current script rather than hand-transforming it"],"exampleFix":"// before\n\"daily\": {\"2024-01-01\": 10, \"2024-01-02\": 25}\n// after\n\"daily\": [{\"date\": \"2024-01-01\", \"stars\": 10}, {\"date\": \"2024-01-02\", \"stars\": 25}]","handlingStrategy":"type-guard","validationCode":"if not isinstance(state[\"reconstruction\"].get(\"daily\"), list):\n    daily = [] if state[\"reconstruction\"].get(\"daily\") is None else sorted(\n        [{\"date\": d, \"stars\": s} for d, s in state[\"reconstruction\"][\"daily\"].items()],\n        key=lambda p: p[\"date\"],\n    )","typeGuard":"def is_daily_list(value) -> bool:\n    return isinstance(value, list) and all(\n        isinstance(p, dict) and set(p) == {\"date\", \"stars\"} for p in value\n    )","tryCatchPattern":"try:\n    validate_state(state)\nexcept StarHistoryError as exc:\n    if \"reconstruction.daily must be a list\" in str(exc):\n        # normalize a date-keyed map to a sorted list, then re-validate\n        ...","preventionTips":["Serialize daily as a sorted array, never a date-keyed object","Run validate_state in CI on any committed state file","Keep one canonical serializer for the state document"],"tags":["validation","json","state-file"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}