You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(driver-sql): schema drift reports a single-value JSON-class field on a stale text column (#16073)
* fix(driver-sql): schema drift reports a single-value JSON-class field on a stale text column
`createColumn` gives a json column to every JSON-class TYPE and `isJsonField`
is `JSON_COLUMN_TYPES.has(type) || !!field.multiple`, but `diffManagedTable`'s
base-type branch asked only `field.multiple === true`. A single-value `file` /
`location` / `record` / `vector` / `json` field on a `varchar`/`text` column was
therefore written as JSON by the writer and invisible to the differ — and the
additive sync never revisits a column, so the divergence was permanent and
silent. Measured on the previous tree: all fifteen JSON-class types the spec
declares produced zero findings on that column under `postgres` and `mysql`.
The detector now reads the writer's predicate. The remedy splits by VALUE
SHAPE: `os migrate multi-value-columns` wraps each value in a one-element JSON
array, so it stays offered to array-valued fields — whose message is unchanged
character for character, which is what lets `planStaleColumnTargets` keep
recovering the dialect from it — and is withheld from single-value ones, whose
message carries neither the command nor its statement and is therefore refused
with `remedy_not_recognized` rather than running array SQL over scalar rows.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
* fix(driver-sql): keep the tracker id out of the drift message's runtime prose
`check:doc-authoring` refuses a `#NNNN` in a string an operator reads — it
resolves to nothing without the tracker (maintainer ruling 2026-08-12). The
anchor stays in the `//` comment beside the emission and in git history; the
message now carries the CAUSE in words instead, which is what the reader
actually needs. The pin asserts that wording rather than the id.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
---------
Co-authored-by: Claude <noreply@anthropic.com>
Schema drift now reports a SINGLE-VALUE JSON-class column that a stale `varchar`/`text` column is holding — the population the detector could never see.
6
+
7
+
The driver decides a field's column type with `JSON_COLUMN_TYPES.has(type) || !!field.multiple`: `createColumn` gives a json column to every JSON-class TYPE, and `isJsonField` — the read-side deserializer — asks the same question. The drift detector asked only `field.multiple === true`. So a single-value `file` / `image` / `location` / `address` / `record` / `vector` / `json` field (and the option families) sitting on a `varchar` or `text` column was written as JSON by the writer and did not exist to the differ. Because the additive sync never migrates a column's type, that column stayed wrong permanently and nothing reported it. Measured on the previous tree, one call per type: all fifteen JSON-class types the spec declares returned zero findings over a `character varying(2048)` column on `postgres` and `mysql`, while the same column under a `multiple: true` field returned one in the same run.
8
+
9
+
The detector now reads the writer's own predicate, so the two halves can no longer disagree about which declarations get a json column. `SQLite is unchanged and still reports nothing`: its read path parses a textual column regardless of what the column calls itself, re-measured on an in-memory cell as a byte-identical round-trip between the stale column and the driver's own.
10
+
11
+
**The remedy is offered to the array-valued half only.**`os migrate multi-value-columns` repairs a stale column by wrapping each stored value in a one-element JSON array, which is the right repair for a field whose value is a list and the wrong one for a field whose value is a scalar or an object. Findings for array-valued fields (`multiple: true`, and the inherently-multi option types) keep their message character for character, so that command keeps recovering the dialect from it and keeps working exactly as before. Findings for single-value JSON-class fields carry a message of their own that names neither the command nor its statement, explains why the automated route is withheld, and describes the by-hand conversion; the command refuses such an entry (`remedy_not_recognized`) instead of running array SQL over scalar rows.
12
+
13
+
Also fixed by the same predicate: a single-value JSON-class field declaring a `maxLength` over a wider `varchar` column used to be reported as `narrow_varchar` at category `destructive` — inviting `os migrate apply --allow-destructive` to rewrite the column to a narrower varchar, the opposite of the repair it needs. It is now reported once, as the base-type divergence.
0 commit comments