Skip to content

fix(dialog_cache): read cached_at as UTC-aware (naive/aware TypeError #1291) - #1293

Merged
axisrow merged 1 commit into
mainfrom
ao/tg_content_factory_5863f66be3-69/fix-1291-naive-cached-at
Jul 23, 2026
Merged

fix(dialog_cache): read cached_at as UTC-aware (naive/aware TypeError #1291)#1293
axisrow merged 1 commit into
mainfrom
ao/tg_content_factory_5863f66be3-69/fix-1291-naive-cached-at

Conversation

@axisrow

@axisrow axisrow commented Jul 22, 2026

Copy link
Copy Markdown
Owner

What

Fixes the latent naive/aware TypeError in the dialog-cache age computation found by audit (a "beyond scope" finding of #1234 review).

Closes #1291.

Root cause

dialog_cache.cached_at has a schema DEFAULT of datetime('now') (src/database/schema.py:316), which yields a naive string without a UTC offset. Rows inserted without an explicit cached_at therefore reached DialogCacheRepository.get_cached_at as naive datetimes, and _get_db_cached_dialogs (src/telegram/pool_dialogs.py:402) crashed on:

age_sec = (datetime.now(timezone.utc) - cached_at).total_seconds()
# TypeError: can't subtract offset-naive and offset-aware datetimes

→ the dialog warm/refresh path crashes whenever the schema DEFAULT fills cached_at. Latent only because the normal write path (replace_dialogs) emits aware isoformat() strings.

Fix

Normalize at the row→model boundary: get_cached_at now reads through parse_utc_datetime, which treats naive values as UTC. Minimal, single-method change; all consumers (pool_dialogs, web/CLI/agent dialogs handlers) benefit.

TDD cycle (per request)

  • Red (proven): test_get_db_cached_dialogs_survives_naive_cached_at — real DB row relying on the schema DEFAULT raised the exact TypeError on pre-fix code in pool_dialogs.py:402.
  • Green: after the fix, the e2e path and repo-level tests pass.

Tests

  • tests/repositories/test_dialog_cache_repository.py (new) — schema-DEFAULT row reads back UTC-aware; normal write path preserves time without drift.
  • tests/test_main_client_pool_collector_paths.py_get_db_cached_dialogs e2e against a real DB no longer raises.
pytest tests/test_dialog_cache_ttl.py tests/test_main_client_pool_collector_paths.py \
       tests/test_telegram_client_pool_collector.py tests/repositories/test_dialog_cache_repository.py
# 282 passed

ruff check clean on changed files.

Risk / follow-up

Low. This is the recurring "naive/aware datetime at the row→model boundary" bug class (cf. #1234/pool_dialogs); normalizing on read is the project's established direction from the issue.

🤖 Generated with Claude Code

…ypeError (#1291)

`dialog_cache.cached_at` has a schema DEFAULT of `datetime('now')`, which
yields a naive string without a UTC offset. Rows inserted without an
explicit cached_at therefore reached `get_cached_at` as naive datetimes,
and `_get_db_cached_dialogs` (pool_dialogs) crashed on
`datetime.now(timezone.utc) - cached_at` with TypeError.

Fix at the row→model boundary: parse through `parse_utc_datetime`, which
normalizes naive values to UTC. Latent — the normal write path already
emits aware isoformat strings, so this only triggers when the schema
DEFAULT fills cached_at.

Regression tests:
- repo-level: schema-DEFAULT row reads back UTC-aware; normal write path
  preserves time without drift.
- pool_dialogs e2e: real DB + schema-DEFAULT row no longer raises on age
  subtraction (proven red on pre-fix code with the exact TypeError).

Co-Authored-By: Claude <noreply@anthropic.com>
@axisrow

axisrow commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

📋 Review summary — all cycles

Reviewed locally in cycle-review local mode: built-in /review + Codex companion (no GitHub bots pinged).

Cycle Reviewer Finding Verdict Resolution
1 claude /review (no findings) n/a
1 codex (no findings — verdict: approve) n/a

Totals: 0 FIX, 0 SKIP, 0 UNVERIFIED. Clean first round.

Notes:

  • Codex ran adversarial-review against origin/main (merge-base 0e3a0a87); verdict approve, 0 findings. Codex noted it could not execute the focused tests in its read-only env — that path is covered by the repo's own regression tests (proven red on pre-fix code).
  • Round bound to head 225c88cf / base main @ 0e3a0a87.

@axisrow
axisrow merged commit 764bbda into main Jul 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant