Skip to content

Commit 722880a

Browse files
committed
test(cli): make the oracle enter initObjects, not re-compose its leaves
CORRECTING THE RECORD, first. Commit 11d0e8d's message states "a swept corpus of 1,224 objects" and "37 declarations". Both counts are wrong, and this queue composes the squash body from the branch's commit messages, so they would land in `main` as written. Counted mechanically by parsing the array literals and confirmed by generating the corpus: keyProbeCorpus() 6 uniques x 16 indexSets x 6 tenancies x 2 shapes = 1,152 WIDTH_DECLARATIONS 38 Four of those sixteen index shapes are the already-normalized ones, not three. Nothing in the suite caught either number: the only size assertion was `> 200`, which every wrong count satisfies. Both are now pinned as exact literals, so a corpus that grows without its stated size growing fails here rather than putting a false measurement into a permanent record. ASKING THE DRIVER'S LEAVES IS NOT ASKING THE DRIVER Round 2 transcribed the driver's answers, and mutating the driver left every pin green. Round 3 asked the driver's exported LEAVES -- `uniqueIndexesFromFields`, `normalizeDeclaredIndex`, `computeTenantField` -- and then RE-COMPOSED them in the test file, which left every layer between those leaves and the emitted column a second copy of the pin's own belief. It never called the driver's own `indexedKeyColumns`, nor `initObjects`' wiring of `tenantField` into it, nor `createColumn`'s dispatch on `keyed`. Measured driver-side at f3661ac, each mutation rebuilt into `dist`: indexedKeyColumns stops recording declared indexes 78 passed (78) initObjects passes tenantField: null into it 78 passed (78) against 764 and 276 of 1,152 objects respectively diverging between the real `initObjects` and the generators. Both of those are this card's own subject -- the driver changes what it keys and the generated column stays bounded where the platform's is unbounded -- and the instrument reported everything fine. The reddening of the pin as it now stands, under both mutations, is recorded in the PR body with its counts. WHAT MOVES The authority in the pin is now `SqlDriver.initObjects` on the in-memory better-sqlite3 driver the file already constructs, read back with `PRAGMA table_info`. That is computeAndRecordTenantField -> indexedKeyColumns -> createColumn -> knex -> an actual column, with nothing re-derived in the test. Two differentials run over it: * the whole 1,152-object corpus, comparing all 4,032 declared columns against both generators' emitted width; * every character TYPE the driver cases or catches -- membership read off `createColumn`'s own case labels and its catch-all derivation, 18 today -- at all 38 declarations, keyed and unkeyed, 1,368 probes. The leaf differential is KEPT underneath, because it localises a failure to one builder, and is now documented as NOT the authority. The width differentials against `keyableTextLength` / `declaredVarcharLength` are kept for the same reason: they say which method body moved, while the real chain also covers `createColumn`'s dispatch onto them. Each probe mints its own table name. `initObjects` takes the ALTER path on a name it has already seen and an ALTER cannot retype a column, so a shared name would report the first probe's answer for all 1,152. The driver's warnings are captured into the subclass rather than printed -- the corpus deliberately carries index shapes whose key parts name no materialized column, and the driver correctly says so 144 times on a green run, which is how a real warning stops being read. `logger` is the driver's own documented injection point; nothing about its behaviour changes and the messages stay available to a failure report. TWO SENTENCES THAT WERE STILL WRONG * The pin still said "`packages/cli` does not depend on the driver at runtime, so the ceiling is transcribed in generate.ts" -- verbatim the reason this branch already established as false, that `generate.ts` carries with a ban, and that the same test file contradicts 500 lines earlier. Replaced with the real reasons: `MAX_VARCHAR_CHARS` is `protected static` and reaches no exported surface, and #5726 leaves a CLI production module only `await import()`, which these synchronous generators cannot use. * `generate.ts`'s `isUniqueScopeDeclared` docblock restated a stale driver comment as present fact. Measured against the built spec, `isUniqueDeclared('organization')` is already `true`, so the disjunct is redundant today and both halves are spec's. The disjunct stays -- it is the driver's spelling and the mirror matches it character for character -- but it is no longer described as a scope spec does not accept. The changeset said the generators invented `2048 / 50 / 7`. Only the SQL format did; the TypeScript format emitted a bare `table.string(name)` for all three. Release-notes input, so it is corrected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
1 parent f3661ac commit 722880a

3 files changed

Lines changed: 406 additions & 42 deletions

File tree

‎.changeset/generated-migration-character-column-widths.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
`os generate migration` now emits the character column `driver-sql` actually creates, in both the TypeScript and the SQL format.
66

7-
A `text` field took `VARCHAR(255)` from both generators while the platform creates an unbounded `text` column for it, so a 300-character value the platform stores was refused by every generated table with `value too long for type character varying(255)`. Enumerating the whole character-column family found the same disagreement in eight more places: `url` and `phone` and `color` carried widths the generators invented (2048, 50 and 7 against the platform's 255), and neither generator read a field's declared `maxLength` at all, so a `maxLength: 400` email was `varchar(400)` on the platform and `varchar(255)` in the migration generated for it.
7+
A `text` field took `VARCHAR(255)` from both generators while the platform creates an unbounded `text` column for it, so a 300-character value the platform stores was refused by every generated table with `value too long for type character varying(255)`. Enumerating the whole character-column family found the same disagreement in eight more places: the SQL format gave `url` and `phone` and `color` widths nothing on the platform has (2048, 50 and 7 against the platform's 255), and neither format read a field's declared `maxLength` at all, so a `maxLength: 400` email was `varchar(400)` on the platform and `varchar(255)` in the migration generated for it.
88

99
All of them now follow the platform's own three answers: the text family is unbounded unless the object KEYS the column — a field declared `unique`, or one an object-level `indexes[]` entry lists, takes `varchar(maxLength)` up to the 768-character key-part ceiling, exactly as the platform builds it, and stays unbounded above that ceiling or with no declared bound, where the declared bound is enforced at the write seam instead — the string family takes its declared `maxLength` verbatim in both directions, and TEXT rather than a clamp when it exceeds what a `varchar` can express, and the remaining string-valued types keep the default width and ignore a declaration, because their stored value is an option code or another row's id rather than the declared string.
1010

0 commit comments

Comments
 (0)