Make lanes.size safe to drop: defer reads + server_default for writes (PP-4506)#3481
Conversation
|
Claude finished @jonathangreen's task in 2m 19s —— View job Review — PR #3481
SummaryThis is a clean, correct implementation of release-1 of the online-migration sequence. The reasoning in the PR body holds up under scrutiny: marking both columns DetailsNit:
|
Greptile SummaryThis PR implements release-1 of a two-step online migration to remove the deprecated
Confidence Score: 5/5Safe to merge — the migration is catalog-only (instant, no table rewrite), fully reversible, and backwards-compatible with the previous release. Both the model change and the migration are mechanically correct: deferred() stops eager reads, server_default replaces the Python-side default so the ORM omits the column from inserts, and the ALTER COLUMN SET DEFAULT migration is a no-lock, instant Postgres catalog operation. No other code in the codebase references size or size_by_entrypoint on the Lane model. No files require special attention. Important Files Changed
Reviews (6): Last reviewed commit: "Some small human comment cleanup" | Re-trigger Greptile |
fd3bada to
ec69b90
Compare
82da44c to
d9b7230
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3481 +/- ##
=======================================
Coverage 93.46% 93.46%
=======================================
Files 512 512
Lines 46611 46611
Branches 6352 6352
=======================================
+ Hits 43566 43567 +1
+ Misses 1969 1968 -1
Partials 1076 1076 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
65db282 to
f82e06f
Compare
The plan to drop lanes.size / size_by_entrypoint directly fails the
backwards-compatibility gate: the previous release still maps those columns,
so its ORM SELECTs them, and dropping the columns makes those SELECTs error
("column lanes.size does not exist").
Because SQLAlchemy eagerly SELECTs every mapped column, "keeping them mapped"
(as the prior release did) is not enough to stop using them. Mark them
``deferred`` instead: they stay in the model and the schema (so
test_model_definitions_match_ddl still passes and the previous release keeps
working), but the current code no longer includes them in its default SELECT.
This is the online-migration "stop using the column" step. Once a release
containing this change has shipped, a follow-up migration can drop the
columns without breaking the then-previous release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Marking the columns ``deferred`` stops reads (the default SELECT) but not writes: ``size`` is NOT NULL with a Python-side ``default=0``, so SQLAlchemy still emitted it in every Lane INSERT (lanes are created at runtime via create_default_lanes). A follow-up migration that dropped the column would then break the still-running previous release's inserts. Move the default into the database with an ``ALTER COLUMN size SET DEFAULT 0`` migration and drop the Python-side ``default=0``. With a server_default and no Python default, SQLAlchemy omits the column from INSERTs and Postgres fills in 0, so the eventual DROP is write-safe. The migration is catalog-only (instant, no rewrite) and backwards-compatible: N-1 still writes size=0 explicitly. ``size_by_entrypoint`` is nullable with no default, so it was already omitted. Also document in CLAUDE.md that "stop using" an ORM column means stopping both reads (deferred) and writes (server_default), so this trap is avoided going forward.
e654836 to
13b75b6
Compare
jonathangreen
left a comment
There was a problem hiding this comment.
This looks good.
I pushed a couple commits to clean up some AI code review comments here. And I'm going to merge this one once all the tests pass, since @dbernstein is out on vacation and it would be nice to get this into this release.
Description
Follow-up to #3424 (merged), which removed all lane-size maintenance but left
size/size_by_entrypointeagerly mapped on theLanemodel. This is release-1 of the online-migration sequence to remove those columns: stop using them. The column drop is a stacked follow-up (release-2), gated on this shipping first."Stop using" an ORM column has two sides, and both must be handled before the column can be dropped safely:
SELECTs every mapped column, so simply "keeping them mapped" (as Migrate custom-list entry updates to Celery and remove lane-size maintenance (PP-4506) #3424 did) does not stop the current code from reading them. Both columns are markeddeferred(), which excludes them from the defaultSELECT.default=in everyINSERT.sizeisNOT NULLwithdefault=0, so it was still written on everyLaneinsert — and lanes are created at runtime (create_default_lanes: reset lanes / configure a library / create a custom lane). A follow-up migration that dropped the column would then break the still-running previous release's inserts (column "size" does not exist). This PR moves the default into the database (ALTER COLUMN size SET DEFAULT 0) and removes the Python-sidedefault=0. With aserver_defaultand no Python default, SQLAlchemy omits the column fromINSERTs and Postgres fills in0, so the eventual drop is write-safe.size_by_entrypointis nullable with no default, so it was already omitted from inserts and needs no write-side change.The
SET DEFAULTmigration is catalog-only in Postgres (instant, no table rewrite) and backwards-compatible: the previous release still writessize=0explicitly, harmlessly overriding the new default, and still readssize(the column is untouched). The columns stay in the model and the database, sotest_model_definitions_match_ddlstill passes and the previous release keeps working.Once a release containing this change has shipped, the follow-up PR can drop both columns without breaking the then-previous release.
Motivation and Context
JIRA: PP-4506
Completes the "stop using" step of the online-migration sequence for removing the lane-size columns (release-1). The column drop is release-2, gated on this shipping first, and is tracked by the
cleanup migrationlabel.How Has This Been Tested?
tests/migration/test_alembic_builtin_tests.pypasses, includingtest_model_definitions_match_ddl(model matches the migrated schema, withcompare_server_default=True) and the up/down migration round-trip.mypyclean on the Lane model.NOT NULLcolumn with the same config that, with aserver_defaultand no Python default, SQLAlchemy omits the column fromINSERTs entirely (and the insert still succeeds after the column is dropped), whereas the previousdeferred-only / Python-default=0version emitted it on every insert.Checklist