Priority: medium Complexity: medium Status: done
GoalRecord and AttemptEntryRecord store timestamps as strings:
@dataclass
class GoalRecord:
started_at: str | None
finished_at: str | None
Consequences:
parse_iso_datetime, parse_iso_datetime_flexible) is scattered throughout the codebasestarted_at: datetime | Noneserde.py when reading from JSONserde.py when writing to JSONdatetime operationsGoalRecord.started_at and finished_at are typed as datetime | NoneAttemptEntryRecord and EffectiveGoalRecordparse_iso_datetime_flexible consolidated to the serde boundary (serde.py + entry points in aggregation.py)# type: ignore suppressions on datetime codemake verify passes (304/304)started_at flows into JSON output — each will need .isoformat()