diff --git a/prod/clean_arch/dita_v2/rust_backend.py b/prod/clean_arch/dita_v2/rust_backend.py index 5ed721e..4985e98 100644 --- a/prod/clean_arch/dita_v2/rust_backend.py +++ b/prod/clean_arch/dita_v2/rust_backend.py @@ -437,9 +437,25 @@ def _first_invalid_intent_field(intent: KernelIntent) -> Optional[tuple[str, flo return None +def _utc_isoformat(ts: Any) -> str: + """Return an RFC3339 timestamp string with UTC offset (+00:00). + + Rust's chrono::DateTime serde deserializer requires a timezone-aware + string. A naive datetime (no tzinfo) produces e.g. '2026-06-04T14:26:55.098914' + (26 chars) which chrono rejects with 'premature end of input at column 41' + (14-char JSON key prefix + 26-char value + closing quote = column 41). + """ + from datetime import timezone as _tz + if hasattr(ts, "tzinfo"): + if ts.tzinfo is None: + ts = ts.replace(tzinfo=_tz.utc) + return ts.isoformat() + return str(ts) + + def _intent_to_payload(intent: KernelIntent) -> Dict[str, Any]: return { - "timestamp": intent.timestamp.isoformat() if hasattr(intent.timestamp, "isoformat") else str(intent.timestamp), + "timestamp": _utc_isoformat(intent.timestamp), "intent_id": intent.intent_id, "trade_id": intent.trade_id, "slot_id": intent.slot_id,