Skip to content

fix(token-spy): bind PostgreSQL hour intervals - #2993

Open
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/token-spy-postgres-hour-intervals
Open

fix(token-spy): bind PostgreSQL hour intervals#2993
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/token-spy-postgres-hour-intervals

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Why this matters

With DB_BACKEND=postgres, Token Spy's /api/usage and /api/summary paths generated invalid parameterized interval SQL. PostgreSQL deployments could fail every recent-usage query even though the equivalent SQLite path worked.

Root cause and invariant

Both queries placed the psycopg %s placeholder inside a quoted SQL literal: INTERVAL '%s hours'. Psycopg placeholders must not be quoted; the driver substitutes a value expression, not text inside a literal. The invariant is that the hour count remains a bound parameter while PostgreSQL receives a typed interval expression.

The predicates now use NOW() - (%s * INTERVAL '1 hour') for both detail and summary queries.

Overlap check

Searched open and closed PRs for token spy postgres interval hours, psycopg interval placeholder, and ods/extensions/services/token-spy/db_postgres.py. No semantic or open same-file overlap was found. Existing Token Spy PRs touching main.py do not modify the PostgreSQL backend.

Regression coverage

A driver-independent database-boundary test loads the real module with a minimal psycopg shim, records cursor executions from both public query functions, and asserts the placeholder is outside the interval literal with exact bound parameters. This runs without a live PostgreSQL service while validating the SQL handed to psycopg.

Validation

  • pytest -q ods/extensions/services/token-spy/tests/test_postgres_query_intervals.py — 1 passed
  • python -m py_compile ods/extensions/services/token-spy/db_postgres.py ods/extensions/services/token-spy/tests/test_postgres_query_intervals.py
  • git diff --check

Tradeoffs and rollback

The expression is standard PostgreSQL interval arithmetic and preserves integer parameter binding; result windows are unchanged. Static cursor validation proves SQL construction, not a live TimescaleDB round trip. Rollback is a code-only revert with no schema or data change.

@tang-vu

tang-vu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Batch compatibility receipt (2026-08-23)

Validated merge order: #2989 ? #2990 ? #2993 ? #2991 ? #2992 ? #2994 ? #2995 ? #2996 ? #2997 ? #2998. The changes are independently useful; this order only reconciles shared model-router and magic-link files.

Synthetic integration head: origin/batch/quality-ten-20260822-round2-integration at 91eb730d. The only textual conflict was the two model-router tests inserting at the same class boundary; the integration resolution retains both contracts. Magic-link changes merged cleanly.

Combined validation on that exact head:

  • remote-provider egress contract: 16 passed
  • Token Spy suites: 22 passed, 1 skipped (live PostgreSQL availability)
  • model-router suite: 55 passed
  • APE suite: 29 passed
  • dashboard OAuth + magic-link suites: 118 passed, 2 platform skips
  • Brave Search loopback E2E: all checks passed
  • git diff --check: passed

All required GitHub checks are green across the batch. #2992 initially hit a transient openSUSE repository/mirror failure while installing rsync; a clearly labeled empty retry commit reran the unchanged tree, and openSUSE plus the full matrix 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

Development

Successfully merging this pull request may close these issues.

1 participant