Normalize ALL timestamps to epoch-ms + consolidate baseline (closes #226) - #40
Merged
Conversation
Annotates all 35 bare integer('*_at') columns (18 always-ms + 17
formerly-seconds columns migrated to ms by the prior task) with
{ mode: 'timestamp_ms' }, and exempts the one dead frozen column
(users.expires_at, guest removal) with a ts-lint-ok comment so the
gate skips it.
Fixes every consumer broken by the resulting number->Date type change:
insert/update sites across server/services and server/portal switch
from Date.now()/Math.floor(.../1000) to new Date(...), and read sites
that expose a public number contract (unix-ms or unix-seconds, e.g.
observer-link exp, QBO connection status, report verification
publishedAt) convert back via .getTime()/1000 at the boundary so
external consumers (settings UI, public verify page) are unaffected.
Also fixes two call sites that only broke at runtime because they
route through untyped `any` seams (ScopedDB.insert, the dual-driver
erasure orchestrator) that tsc cannot see through, and updates all
affected test fixtures (unit + workers) accordingly.
lint:timestamps now reports only the 4 remaining text datetime('now')
columns (Task 5 scope). db:check shows no drift (mode-only change).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hkbz8jKCeiQigeqLuBNvhH
…t (match siblings)
…stamp_ms Numbered the drizzle-generated retype 0026 (not 0025) to avoid colliding with the hand-authored 0025 seconds->ms data migration, which is not tracked in the drizzle journal (mirrors the portal convention: pure data migrations occupy a file number without a journal entry, leaving an idx gap).
Adds scripts/check-ts-range.mjs (npm run check:ts-range) — samples MIN/MAX per column across a representative set of migrated tables and fails if any non-null value falls outside epoch-ms ~2015-2035. Refreshes the tenant-scoping baseline (line-shift only, no new findings) — prior timestamp-migration commits on this branch moved lines in observer-link.service.ts and qbo/api-base.ts past two pre-existing, verified-safe update-by-id queries.
…to timestamp_ms via baseline consolidation
Converts the remaining 11 text('*_at') columns (automation_logs.send_at/
delivered_at, inspections.confirmed_at, inspection_requests.scheduled_at,
discount_codes.expires_at, marketplace_templates/libraries.created_at/updated_at,
tenant_marketplace/library_imports.imported_at) from ISO-string TEXT to
integer { mode: 'timestamp_ms' }. Documents the calendar/clock exceptions
(due_date, closing_date, start_time, end_time, date) that intentionally stay TEXT.
Per the repo pre-launch policy (drizzle.config.ts), schema changes regenerate the
single migrations/0000_baseline.sql — so this collapses the prior forward
migrations (incl. the B1 timestamp work) into one clean baseline with no dead
columns. Existing data is preserved by an export -> ISO->ms transform -> reimport
of the deployed DB (validated: 2841 rows, zero loss).
Widens lint:timestamps with Rule D (text('*_at') is a violation). All time-semantic
Drizzle columns now use integer timestamp_ms; closes the acceptance criteria of InspectorHub#226.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Completes InspectorHub#226: every time-semantic Drizzle column now stores integer epoch-milliseconds with explicit
{ mode: 'timestamp_ms' }; the only TEXT time columns left are documented calendar/clock exceptions (due_date,closing_date,start_time,end_time,date).Because OpenInspection is pre-launch, this follows the repo policy (
drizzle.config.ts) of regenerating the singlemigrations/0000_baseline.sqlrather than stacking forward migrations — so the prior incremental timestamp work is collapsed into one clean baseline with no dead columns.What changed
integer('*_at')→ explicit timestamp_ms; textdatetime('now')and text-ISO'*_at'columns → integer timestamp_ms._atcolumns converted (automation_logs, inspections, inspection_requests, discount_codes, marketplace_templates/libraries, tenant_marketplace/library_imports).lint:timestampsgate (scripts/check-timestamps.mjs) with 4 rules incl. Rule D:text('*_at')is a violation; calendar/clock text columns documented as intentional exceptions.0000_baseline.sql.Verification
lintclean (timestamps gate 0 violations),db:checkno drift (81 tables), type-check clean, suite green (unit 3085 / web 1188 / workers 87).🤖 Generated with Claude Code