fix: validate_schema() honors ck naming_convention on lease CHECK#102
Merged
Conversation
A MetaData carrying a SQLAlchemy `ck` naming_convention re-templates the package's explicitly-named lease CheckConstraint (the given name fills the %(constraint_name)s token), so the live constraint is named e.g. `ck_<table>_<table>_lease_ck`, not `<table>_lease_ck`. The CHECK probe hard-coded the literal name, never found the re-templated one, and raised a spurious "missing CHECK constraint" on a valid schema for every deployment using the SQLAlchemy/Alembic-recommended convention. _validate_check_constraints_sync now derives the expected name from the Table object via _resolve_check_constraint_name (identify the lease constraint by its normalized predicate, use its convention-resolved .name), falling back to the literal name only when the table carries no matching constraint. Explicitly named indexes are unaffected (ix/uq keys only re-template auto-named indexes). - tests: convention-resolved name honored, missing-under-convention, literal fallback (unit), and an end-to-end Postgres pass under a ck convention. - docs/operations/alembic.md: replace the misleading op.f(literal) caveat with an introspect-the-rendered-name recipe. - architecture/dlq.md: record the convention-awareness invariant. - planning/releases/0.10.2.md: release notes. - planning: remove stale draft duplicate of the shipped #99 bundle from active/ (canonical copy already in archive/). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
lesnik512
added a commit
that referenced
this pull request
Jun 17, 2026
#102 made the CHECK probe predict the constraint name off the Table object, which under a `ck` naming_convention resolves to the doubled `ck_<table>_<table>_lease_ck`. But a hand-written migration (`op.create_check_constraint('<table>_lease_ck', ...)`) creates the literal name verbatim — Alembic op functions don't apply target_metadata's convention — so the probe demanded a name the migration never produces and false-failed a valid schema. The live name is unpredictable from the package side; only the predicate is stable. _validate_check_constraints_sync now matches the lease CHECK by predicate, not name: it passes if any live CHECK enforces `(acquired_token IS NULL) = (acquired_at IS NULL)` under any name, and otherwise reports `missing CHECK constraint enforcing '<predicate>'`. Removes _resolve_check_constraint_name and the now-unused CheckConstraint import. A drifted predicate now reads as "missing" (the correct one is absent); the Alembic-blind remediation pointer still fires. - tests: predicate matched under the convention-doubled name, under the literal name, missing-describes-predicate, drifted-reads-as-missing (unit), plus an end-to-end Postgres pass for convention metadata + a literally-named CHECK. - docs/operations/alembic.md: the CHECK name doesn't matter; match the predicate. - architecture/dlq.md: record the match-by-predicate invariant. - planning/releases/0.10.3.md: release notes. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
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.
Problem
validate_schema()raised a spuriousRuntimeErrorfor any deployment whoseMetaDatacarries a SQLAlchemycknaming_convention:…even with a perfectly valid schema.
Root cause. SQLAlchemy re-templates an explicitly-named
CheckConstraintthrough ackconvention — the given name fills the%(constraint_name)stoken — so the live constraint is named e.g.ck_outbox_faststream_outbox_faststream_lease_ck, notoutbox_faststream_lease_ck. The CHECK probe hard-coded the literalf"{table.name}_lease_ck", never matched the re-templated name, and reported "missing". Confirmed empirically: under ackconvention the constraint resolves to theck_…name, while the indexes keep their literal names (theix/uqkeys only re-template auto-named indexes).Fix
_validate_check_constraints_syncnow derives the expected name from theTableobject via a new_resolve_check_constraint_name— it identifies the lease constraint by its normalized predicate and returns its convention-resolved.name, falling back to the literal name only when the table carries no matching constraint (reflected/hand-builtTable). The expectation now always matches what SQLAlchemy / Alembic emit from your metadata, convention or not.Tests
ck-conventionMetaData,create_alls it, assertsvalidate_schema()does not raise.Full suite: 525 passed, 100% coverage; lint (
ruff+ty) clean; docs build clean.Docs / housekeeping (same PR)
docs/operations/alembic.md— replaced the now-misleadingop.f('outbox_lease_ck')caveat (it forced a literal name the probe no longer expects under a convention) with an introspect-the-rendered-name recipe.architecture/dlq.md— recorded the convention-awareness invariant in thevalidate_schema()mechanics section.planning/releases/0.10.2.md— release notes (patch: bugfix only, opt-in path, no API change).planning/changes/active/— removed a staledraftduplicate of the already-shipped+archived fix: actionable error for Alembic-blind schema drift #99 bundle (canonical copy remains inarchive/; the active index already read_None._).Compatibility
validate_schema()is opt-in. With nonaming_convention, behavior is identical to 0.10.1. With ackconvention, validation that previously raised spuriously now passes when the DB constraint carries the convention-rendered name (created viacreate_allor convention-aware Alembic). No other behavior change.🤖 Generated with Claude Code