Repository navigation
Record when each rotation card last changed: rotation_cards.last_changed_at - #3048
Merged
jakebromberg merged 3 commits intoOct 7, 2026
Conversation
Schema constraint shape reportno new constraints detected in this diff (uniqueIndex, .unique(), SET NOT NULL, CHECK, FK) |
jakebromberg
force-pushed
the
orchestrator/record-when-each-rotation-card-last-changed-rotati
branch
from
October 7, 2026 22:25
b34d2bd to
e5c1810
Compare
jakebromberg
deleted the
orchestrator/record-when-each-rotation-card-last-changed-rotati
branch
October 8, 2026 02:35
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.
Closes #2734
Adds
rotation_cards.last_changed_at timestamptz NULL, kept by database triggers onrotation, and serves it onGET /library/rotation/cards.What changes
0188): nullable, no default, no backfill. A migration-time value would claim every card changed on deploy day, so a card readsnulluntil a rotation write touches it.--custommigration0189): one function,wxyc_schema.stamp_rotation_card_last_changed(), which stampsnow()onOLD.card_idandNEW.card_id(nulls ignored), and two row triggers onwxyc_schema.rotation:AFTER INSERT OR DELETEAFTER UPDATE OF card_id, kill_date ... WHEN (OLD.card_id IS DISTINCT FROM NEW.card_id OR OLD.kill_date IS DISTINCT FROM NEW.kill_date). The guard keeps therotation-etlupsert, which listskill_date = excluded.kill_dateon every row it updates, from re-stamping a card whose membership did not change.wxyc_schemaexplicitly, and the migration carries theCOMMENT ON COLUMN, the@no-analyze-needed/@no-precondition-neededsuppressions, and a note on the opposite-direction move deadlock (A to B racing B to A can abort one with 40P01; accepted, not engineered around).listRotationCardsFromDBselectslast_changed_at.addRotationCardandrenameRotationCardnow.returning({ id, bin, number, name })typed asRotationCardWire, so the POST and PATCH card responses stay exactly{ id, bin, number, name }as the contract declares (last_changed_atrides the list item only).tests/mocks/database.mock.tsgains the column on therotation_cardsdouble.Notes for the reviewer
deploy-auto.ymlrun succeeds after merging (or run Manual Build & Deploy within 24 hours).legacy-linkage-resolve, the release-id backfills,linkRotationToAlbum) touches neithercard_idnorkill_date, so theUPDATE OFtrigger never fires for them.Tests
last_changed_at; both card write paths pin their.returning(...)projection to the four wire columns.rotation-card-last-changed.spec.js): insert with and without a card; A to B stamps both; kill; unkill;SET kill_date = kill_datestamps nothing; an unrelated-column UPDATE stamps nothing; row delete stamps the card; deleting a card that holds killed rows succeeds and uncards them;GETreturnsnullthen an ISO instant.rotation-cards.spec.jspins the POST and PATCH response keys. "Stamps nothing" tests pre-set a sentinel timestamp, sincenow()cannot be pinned from Jest.test:unit, typecheck, lint, format check,lint:migrations,check-bulk-update-analyze --strict,check:db-mock-sync,check:sql-claim-docs,check:auth-tables-doc,check-cross-cache-identity-flags,check-precondition-guards,check-legacy-entry-id-writes,check-lml-caller-classificationall pass. The full integration tier ran against an isolated Compose project with a fresh DB (which also applies the migration chain from scratch); three suites needed feature flags set in the local.envand pass with them.