Commit Graph
4 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 172e784cb2 docs(6205): rule_moment_judgments, retrieval_migration, repo_bindings, moments, logging, design_systems comments drop citations
retrieval_migration states what it lets a tuned floor do without quoting
the operator, and its order-of-operations refusal is described as enforced
rather than as history. logging states why raw date filters fail rather
than citing the two issues that found it. The rest drop milestone, step and
record citations; step references now name the code that does the job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:32:07 -04:00
bvandeusenandClaude Fable 5 7d48eb0b1b refactor(services): one periodic-task shape, one APScheduler job shape, one token hash, one summary rule — the services pass of the shape audit (#2830, milestone 296)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / TypeScript typecheck (push) Successful in 12s
CI & Build / integration (push) Successful in 24s
CI & Build / Python tests (push) Successful in 55s
CI & Build / Build & push image (push) Successful in 24s
- background.start_periodic(interval, work, label=) replaces the three hand-rolled
  while-True/sleep/try loops in logging, auth and notifications.
- services/scheduler.ScheduledJob replaces the four private BackgroundScheduler
  copies in recurrence/version_pinning/trash/db_maintenance schedulers; public
  start_/stop_/reschedule_ surfaces unchanged.
- api_keys.hash_token is the one sha256 helper; auth.py used to inline it 5x.
- auth.is_registration_open reads via settings.get_admin_setting; notification
  prefs read via settings.get_setting; _fire_share_email uses _get_user_email.
- projects.get_project_summary / milestones.get_project_milestone_summary are
  now the one-id view of their batch siblings instead of a second copy of the
  queries; sharing.best_permission_by (was _deduplicate_by_permission) is the
  one rank-dedup, now also used by list_projects_for_user.
- backup: the row builders for every section both exporters carry are named
  functions, so a column added to one export cannot silently miss the other.
- iso() from models.base replaces the attr.isoformat()-if-attr-else-None idiom
  and db_maintenance._iso across services; backup keeps its explicit shape.
- trash.py hoists the sql_delete/timedelta imports it re-imported per function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 12:34:28 -04:00
bvandeusenandClaude Opus 5 293a14361a fix(db): bind datetimes, not strings, when filtering timestamptz columns
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 10s
CI & Build / integration (push) Successful in 16s
CI & Build / Python tests (push) Successful in 42s
CI & Build / Build & push image (push) Successful in 26s
Closes #1727 and #2257 — the same bug in two services written months apart.

AppLog.created_at is `timestamp with time zone`. asyncpg binds a Python str as
VARCHAR and Postgres has no `timestamptz >= text` operator, so both of these
raised when Postgres planned the query:

  notifications.check_due_tasks   AppLog.created_at >= today.isoformat()
  logging.get_logs                AppLog.created_at >= <raw request.args str>

#1727 was the worse of the two because a per-user `except Exception` swallowed
it: reminder emails silently never sent, and the only outward trace was an
hourly traceback in the Postgres log. It has been open since 2026-07-19 with the
diagnosis written and the fix never applied. #2257 has no swallowing handler, so
it merely breaks the admin log viewer's date filters outright.

notifications: `utc_day_start(day)` returns midnight UTC as an AWARE datetime.
Deliberately not the bare `date` the original diagnosis suggested — comparing
timestamptz to date does work via an implicit cast, but Postgres resolves that
cast in the SESSION's TimeZone, so the dedup window would drift with a server
setting nobody remembers is load-bearing.

logging: `parse_filter_datetime()` converts the query-string value to an aware
UTC datetime; unparseable input returns None so the filter is skipped rather
than 500ing the viewer. It also fixes a bug the naive fix would have introduced
— `date_to=2026-07-30` parses to midnight, so `<=` would exclude the entire day
the user asked for. Date-only upper bounds now run to 23:59:59.999999, while a
value carrying an explicit time is left as given.

The guard is the point. This class is invisible to ordinary testing: the failure
happens when Postgres plans the query, not when Python builds it, so no unit
test that doesn't execute SQL can see it. tests/test_timestamp_filters.py fails
CI on two shapes —

  1. a local bound to .isoformat() compared against a *_at column   (#1727)
  2. a str-ANNOTATED PARAMETER compared against a *_at column       (#2257)

Shape 2 is the one that matters. Nothing in logging.py looks date-ish, so a
guard built only from #1727's shape finds nothing there — which is exactly how
the second instance survived. Verified by replaying both checks against the
pre-fix files out of git: shape 1 catches `today_str`, shape 2 catches
`date_from`/`date_to`, and the current tree is clean.

Found by grepping for siblings after fixing #1727 — the third instance today of
"the second place nobody checked", after #2245.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
2026-07-30 12:53:57 -04:00
bvandeusenandClaude Opus 4.8 b255a0f90e refactor: rename package fabledassistant -> scribe (code-only)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 1m14s
Renames src/fabledassistant -> src/scribe and all imports, plus the
default DB name and DB user/password (fabled -> scribe) in config +
compose. 952 refs / 154 files. Reverses the old 'internal name stays
fabledassistant' convention.

Code-only: live databases are still physically named 'fabledassistant'.
Deployed environments must set POSTGRES_DB / POSTGRES_USER (or rename the
DB) since the defaults now resolve to 'scribe'. Repo (FabledScribe), git
host (fabledsword), MCP (fabled-git) and the image name (fabledscribe)
are intentionally unchanged.

ruff check src/ clean locally; CI (typecheck + pytest) is the gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:48:35 -04:00