Skip to content

Compare nullability as well as type when syncing columns - #19

Merged
alexstandiford merged 1 commit into
mainfrom
fix/nullability-drift
Aug 1, 2026
Merged

Compare nullability as well as type when syncing columns#19
alexstandiford merged 1 commit into
mainfrom
fix/nullability-drift

Conversation

@alexstandiford

Copy link
Copy Markdown
Contributor

The schema sync compared only column types, so nullability drift never reconciled — the root cause of the siren-team-os 1.11.0 production journal-write outage (Navigator charter 1500, journal 8826). IS_NULLABLE was already fetched; a mismatch now emits MODIFY. Declared nullability reads by containment since attributes are free strings ('NOT NULL DEFAULT ...') — equality matching would have dropped such constraints. Adds four tests including the undoing test and the compound-attribute regression case. Suite: 41 tests, exit code 0.

needsColumnModification compared only the normalized type, so a column
whose nullability changed in the declaration was never modified in any
existing database. That let journal_entries.fleetId stay NOT NULL after
its declaration went nullable, which broke journal creation in
production (siren-team-os 1.11.0). IS_NULLABLE was already fetched;
now a mismatch in either direction emits the MODIFY.

Declared nullability reads by containment, not equality, because
attributes are free strings and NOT NULL often travels with company,
as in "NOT NULL DEFAULT 'human'" — equality matching read that as
nullable and would have dropped the constraint.

Includes the undoing test: nullability-only drift must produce a
modification, which fails if the comparison is removed while the
fetch remains.
@alexstandiford
alexstandiford merged commit a164dd8 into main Aug 1, 2026
6 of 8 checks passed
@alexstandiford
alexstandiford deleted the fix/nullability-drift branch August 1, 2026 22:47

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f30d1ed719

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

$currentNullable = strtoupper(trim((string) $currentColumnData['IS_NULLABLE'])) === 'YES';
// Attributes are free strings and NOT NULL often travels with company
// ("NOT NULL DEFAULT 'human'"), so containment, not equality, decides.
$newNullable = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Treat primary-key declarations as non-nullable

When a schema represents non-nullability implicitly, such as new Column(..., 'PRIMARY KEY') without a separate NOT NULL, MySQL reports the primary-key column as IS_NULLABLE=NO, but this initializes the declaration as nullable and never considers PRIMARY KEY. Every synchronization therefore emits a MODIFY; because the existing key continues to force IS_NULLABLE=NO, subsequent runs repeat the table alteration. The replacement of PrimaryKeyFactory with a manually constructed column containing NOT NULL in the no-op test masks this regression.

Useful? React with 👍 / 👎.

// ("NOT NULL DEFAULT 'human'"), so containment, not equality, decides.
$newNullable = true;
foreach ($newColumn->getAttributes() as $attribute) {
if (str_contains(strtoupper((string) $attribute), 'NOT NULL')) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match the NOT NULL constraint outside attribute literals

When a nullable column has an attribute such as DEFAULT 'NOT NULL' or COMMENT 'NOT NULL', raw substring containment mistakes the literal text for a constraint. Against a currently non-nullable column this suppresses the required relaxation, while against a nullable column it triggers the same ineffective MODIFY on every run. The check needs to distinguish the NOT NULL clause from occurrences inside quoted attribute values.

Useful? React with 👍 / 👎.

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.

1 participant