Skip to content

fix(compat): whitespace-insensitive schema lineage (#52) - #55

Merged
pablontiv merged 5 commits into
mainfrom
fix/issue-52-schema-lineage
Aug 22, 2026
Merged

fix(compat): whitespace-insensitive schema lineage (#52)#55
pablontiv merged 5 commits into
mainfrom
fix/issue-52-schema-lineage

Conversation

@pablontiv

@pablontiv pablontiv commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Root Cause (First Issue — Corrected by d46cdf6)

Issue #52 reported that healthy databases migrated V1→V13 by published releases were rejected as unsupported_lineage. The root cause: normalizeSQL() was naively TrimSpace(), making whitespace layout in stored DDL part of the schema signature. Altered tables with inline columns (as ALTER TABLE ADD COLUMN leaves them) differed in signature from hand-formatted fixtures.

Root Cause (Second Issue — This PR, Fix #52)

Even AFTER the normalizeSQL fix, CI tests still failed: runtime computed the NEW correct signature, but internal/storage/recovery_records.go contained a hardcoded switch with 19 OLD signature literals. The file was a second, stale lineage catalog that silently rejected all signatures with unsupported_lineage before semantic diagnostics could run.

The Actual Problem

Two independent catalogs:

  • internal/compat/manifest.json (data, regenerable) — the single source of truth
  • internal/storage/recovery_records.go:36-64 (hardcoded Go source literals) — stale copy

Nothing forced them to agree. When normalizeSQL() changed, compat's catalog was regenerated, but the hardcoded switch was NOT. The switch rejected every known signature, masking the real diagnostics (recovery_conflict, uninterpretable_row).

Solution

Replace the hardcoded switch with a call to the canonical source:

  1. compat.Catalog.IsKnownSignature(signature) checks if the schema is recognized
  2. No duplication, no stale copy problem
  3. internal/storage/recovery_records.go queries compat instead of owning a second catalog

Collision Safety: When whitespace normalization collapsed 76 fixtures into 17 distinct signatures, a new test verifies all entries with the same signature agree on AppliedVersion and HasSourceMetadata. Any mismatch would be a real bug (recovery could plan wrong steps). The test passes, confirming the manifest is safe.

Verification

Local CI gate (build, scrubbed-HOME tests, aggregate coverage ≥85%):

$ just ci
Coverage: 85.6%

Tests passing:

  • TestReadRecoveryInputSupportsCatalogReadableSignatures — all 20 catalog fixtures readable
  • TestCollisionConsistencyGuardsAgainstSignatureAmbiguity — collision groups consistent
  • TestValidateTextReportsSemanticRecoveryDiagnosticsReadOnly — correct semantic codes
  • TestBlockingDiagnosticsHaveExecutableContinuations — all diagnostic paths unblocked

Commits

  1. 516be28 — Collapse the duplicated catalog (the fix for this PR)
  2. c78c089 — Document the design decision in CLAUDE.md

… normalization

Issue #52: databases migrated V1→V13 by published releases were rejected as
unsupported_lineage because normalizeSQL()'s sensitivity to whitespace layout
made ALTER TABLE ADD COLUMN output (inline columns) incompatible with
hand-formatted fixtures.

Changes:
1. Replace normalizeSQL's naive TrimSpace with full whitespace collapse outside
   SQL string literals. Preserves whitespace inside single-quoted literals and
   handles '' escape sequences correctly. This eliminates cosmetic layout
   differences as a source of signature mismatch.

2. Regenerate all 76 manifest signatures under the new normalization via
   RegenerateManifestJSON(). The regeneration is reproducible: load fixtures,
   compute signatures under current normalizeSQL, and write back manifest.json.
   See TestRegenerateManifestOnNormalizationChange with REGEN_MANIFEST=1.

3. Correct v13-legacy-alter-built.sql: replace hand-wrapped multi-line DDL
   with inline columns as ALTER TABLE ADD COLUMN actually produces. Fixtures
   for migrated lineages must be dumped from real migration runs, never edited.

4. Add regression test framework: TDD tests for normalizeSQL() behavior, plus
   TestInspectIndexRecognizesObservedDevelopmentV13Shape updated to reflect
   new post-normalization signature.

This fix prevents false rejections when published-release-migrated databases
encounter the catalog. The root cause (whitespace-sensitive identity) is
eliminated; cosmetic DDL formatting will no longer silently fall a schema out
of the catalog.

Closes #52

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
…truth

The hardcoded switch in internal/storage/recovery_records.go(36-64) contained
19 signature literals that were NOT regenerated after normalizeSQL became
whitespace-insensitive, causing it to reject all known signatures with
unsupported_lineage instead of proceeding to semantic diagnostics.

Replace the hardcoded switch with a call to the canonical source: ask
compat.Catalog.IsKnownSignature() instead of carrying a second, stale catalog
in Go source. This is both a fix and a simplification: recovery_records.go no
longer owns or maintains a separate lineage enumeration.

Add IsKnownSignature() method to Catalog as the narrow interface recovery needs.
Verify collision consistency in a new test: all fixtures that collapse to the
same whitespace-normalized signature must agree on AppliedVersion and
HasSourceMetadata, or recovery could plan wrong migration steps. The test passes,
confirming the manifest is safe.

Fix issue #52 where recovery diagnostics were masked by false positives.

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
Record the design decision to centralize all lineage catalog logic in
internal/compat and eliminate the hardcoded switch in recovery_records.go.
Note the collision consistency guarantee and whitespace normalization drift
prevention.

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
Record the design decision for normalizeSQL() to collapse whitespace outside
string literals, eliminating cosmetic DDL formatting as a source of signature
mismatch. Note the regeneration of all 76 signatures and the false-rejection
prevention for published-release-migrated databases.

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
@pablontiv
pablontiv force-pushed the fix/issue-52-schema-lineage branch from c78c089 to 123977e Compare August 22, 2026 17:40
…atalog

Issue #52: databases migrated V1→V13 by published releases were rejected
because normalizeSQL() was whitespace-sensitive, making ALTER TABLE ADD
COLUMN output (inline) incompatible with hand-formatted fixtures.

This regression test migrates a V1 fixture forward through SetupSchema()
and asserts the resulting signature is recognized by the catalog. It would
have caught the false rejection during development and prevents future
cosmetic DDL changes from silently breaking lineage recognition.

Relates to #52 fix.

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
@pablontiv
pablontiv merged commit 5d5f479 into main Aug 22, 2026
6 checks passed
@pablontiv
pablontiv deleted the fix/issue-52-schema-lineage branch August 22, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: index migrated V1→V13 by official releases is rejected as unsupported_lineage

1 participant