Skip to content

Mixed dated and undated records in one file crash ingest on a naive/aware datetime comparison #12

Description

@Nitjsefnie

Description

backend/parse.py's _build_ctx_turns sorts records using a key that falls back to datetime.min when a record has no timestamp:

r["ts"] or datetime.min

datetime.min is naive, while the timestamps parsed from transcripts are timezone-aware. Python refuses to order a naive datetime against an aware one, so the comparison raises TypeError: can't compare offset-naive and offset-aware datetimes.

The failure needs a single file that contains both a record with a usable timestamp and a record without one. With every record timestamped, the fallback never evaluates. With none timestamped, every key is datetime.min and the comparison is naive-to-naive. Only the mixed case reaches the crash, which is why it has not been seen — no current fixture produces it.

The blast radius is ingest rather than a request: this runs while building context turns, so the affected file fails to ingest rather than degrading.

Expected Behavior

A record with a missing timestamp sorts deterministically against timestamped records without raising — either by using an aware minimum (datetime.min.replace(tzinfo=timezone.utc)), or by partitioning undated records explicitly rather than relying on a sentinel comparing correctly.

Reproduction Steps

  1. Construct a transcript file containing at least two records, where one has a parseable timestamp and one has none.
  2. Ingest that file.
  3. Observe TypeError: can't compare offset-naive and offset-aware datetimes raised from the sort in _build_ctx_turns.

Environment / Context

Pre-existing; not introduced by the issue #8 lint burn-down, which left the expression unchanged. No test fixture currently contains a mixed-timestamp file, so the suite passes with the defect present.

Discovered During

The issue #8 lint and type-check backlog burn-down, reported under PITFALLS_NOTED while working through backend/parse.py. Deliberately not fixed there — the burn-down's remit was clearing findings without altering parser semantics, and changing how undated records sort is a behaviour change.

Suggested Fix

Unverified. Replacing the sentinel with datetime.min.replace(tzinfo=timezone.utc) is the smallest change and makes the comparison well-defined, placing undated records first.

Worth deciding explicitly whether "first" is the intended ordering, rather than inheriting it from whichever sentinel is convenient — if undated records should instead sort last, or be excluded from context turns entirely, the sentinel choice is the wrong lever. Either way this alters stored output for mixed files, so it likely warrants a PARSER_VERSION bump so affected transcripts are reparsed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions