{"record":{"id":"222cb51b1cd49174","repo":"666ghj/MiroFish","slug":"label-must-use-yyyy-mm-ddthh-mm-ssz","errorCode":null,"errorMessage":"{label} must use YYYY-MM-DDTHH:MM:SSZ","messagePattern":"(.+?) must use YYYY-MM-DDTHH:MM:SSZ","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":319,"sourceCode":"def _strict_non_negative_int(value: Any, label: str) -> int:\n    if type(value) is not int or value < 0:\n        raise StarHistoryError(f\"{label} must be a non-negative integer\")\n    return value\n\n\ndef _parse_github_timestamp(value: str) -> datetime:\n    try:\n        parsed = datetime.fromisoformat(value.replace(\"Z\", \"+00:00\"))\n    except ValueError as exc:\n        raise StarHistoryError(\"GitHub returned an invalid star timestamp\") from exc\n    if parsed.tzinfo is None or parsed.utcoffset() != timedelta(0):\n        raise StarHistoryError(\"GitHub star timestamp was not UTC\")\n    return parsed.astimezone(UTC)\n\n\ndef _parse_state_timestamp(value: Any, label: str) -> datetime:\n    if not isinstance(value, str) or not STATE_TIMESTAMP_RE.fullmatch(value):\n        raise StarHistoryError(f\"{label} must use YYYY-MM-DDTHH:MM:SSZ\")\n    try:\n        parsed = datetime.strptime(value, \"%Y-%m-%dT%H:%M:%SZ\").replace(tzinfo=UTC)\n    except ValueError as exc:\n        raise StarHistoryError(f\"{label} is not a valid UTC timestamp\") from exc\n    return parsed\n\n\ndef _format_state_timestamp(value: datetime) -> str:\n    normalized = _normalize_now(value)\n    return normalized.strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n\n\ndef _normalize_now(value: datetime) -> datetime:\n    if value.tzinfo is None or value.utcoffset() != timedelta(0):\n        raise StarHistoryError(\"clock must return a UTC datetime\")\n    return value.astimezone(UTC).replace(microsecond=0)\n\n","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L301-L337","documentation":"_parse_state_timestamp validates persisted-state timestamps against STATE_TIMESTAMP_RE (r'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$') and raises StarHistoryError(f'{label} must use YYYY-MM-DDTHH:MM:SSZ') when the value is not a string or does not fullmatch. This guards the history-state JSON file against format drift (fractional seconds, offsets, missing Z) before strptime runs.","triggerScenarios":"A state file containing 'generated_at': '2024-01-15T10:30:00' (no Z), '...:00.123456Z' (fractional seconds), '...+00:00' (offset instead of Z), or a non-string; also hand-edited state files.","commonSituations":"State file written by an older/newer version of the script with a different timestamp format; someone edited the JSON by hand and pasted a timezone-offset timestamp; a different tool regenerated the file with fromisoformat-style output.","solutions":["Reset the state file to let the script regenerate it from scratch (losing incremental history is often acceptable)","Or fix the offending timestamp(s) in the state file to strict 'YYYY-MM-DDTHH:MM:SSZ' form","Identify the writer that produced the bad format and route it through _format_state_timestamp"],"exampleFix":"// before (state file)\n\"generated_at\": \"2024-01-15T10:30:00.123456+00:00\"\n\n// after (state file)\n\"generated_at\": \"2024-01-15T10:30:00Z\"","handlingStrategy":"validation","validationCode":"import re\nSTATE_TIMESTAMP_RE = re.compile(r\"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$\")\n\nbad = [k for k, v in state_flat_timestamps.items() if not (isinstance(v, str) and STATE_TIMESTAMP_RE.fullmatch(v))]\nif bad:\n    raise StarHistoryError(f\"timestamps not in YYYY-MM-DDTHH:MM:SSZ: {bad}\")","typeGuard":"def is_state_timestamp(value: object) -> TypeGuard[str]:\n    return isinstance(value, str) and bool(STATE_TIMESTAMP_RE.fullmatch(value))","tryCatchPattern":"try:\n    validate_state(state)\nexcept StarHistoryError as exc:\n    if \"must use YYYY-MM-DDTHH:MM:SSZ\" in str(exc):\n        regenerate_state_file()\n    else:\n        raise","preventionTips":["Never hand-edit timestamps in the state file; regenerate the file instead","Any external writer must use strftime('%Y-%m-%dT%H:%M:%SZ') — no fractional seconds, no offsets"],"tags":["state-file","validation","datetime","format","star-history"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}