From acffc783e6c29aaebef04f67a2d6650f70dbcd3a Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 4 Jun 2026 16:45:33 +0200 Subject: [PATCH] =?UTF-8?q?PINK:=20fix=20naive=20datetime=20=E2=86=92=20IN?= =?UTF-8?q?VALID=5FINTENT=5FPARSE=20at=20column=2041?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: intent.timestamp was a naive datetime (no tzinfo). isoformat() produces '2026-06-04T14:26:55.098914' (26 chars). The JSON prefix '{"timestamp":"' is 14 chars → closing quote lands at column 41. Rust's chrono::DateTime serde rejects naive timestamps and serde_json reports the error as 'premature end of input at line 1 column 41'. Fix: _utc_isoformat() attaches UTC tzinfo before isoformat(), producing '2026-06-04T14:26:55.098914+00:00' which chrono accepts. Previous null-byte fix (_to_rust_bytes) and dangling-pointer fix (local vars) remain correct and address real separate failure modes. Co-Authored-By: Claude Sonnet 4.6 --- prod/clean_arch/dita_v2/rust_backend.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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,