You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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.
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this matters
With
DB_BACKEND=postgres, Token Spy's/api/usageand/api/summarypaths 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
%splaceholder 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, andods/extensions/services/token-spy/db_postgres.py. No semantic or open same-file overlap was found. Existing Token Spy PRs touchingmain.pydo 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 passedpython -m py_compile ods/extensions/services/token-spy/db_postgres.py ods/extensions/services/token-spy/tests/test_postgres_query_intervals.pygit diff --checkTradeoffs 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.