From f933d1e3c7d9f60b5df61e72c7c7c3e98aba8697 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 20:11:42 +0000 Subject: [PATCH 1/2] docs(cli): state the measured platform-id width at four citation sites All four sites cited driver-sql's `case 'lookup': case 'user':` arm BY NAME for "a platform id is 26 characters", two of them spelling out a ULID literal. #15522 corrected that origin sentence, so the citation chain pointed at text that no longer exists -- the arm now carries an explicit "do not restore the number this sentence used to carry" guard naming the same four copies. Measured on this branch by driving the real SqlDriver against SQLite rather than reading its constants: - the driver mints a 16-character nanoid when the caller supplies no id (12 samples, exactly one distinct width; the alphabet carries `-` and lowercase, so a Crockford-base32 ULID check over them returns false); - a SUPPLIED id is stored verbatim at whatever width the caller chose -- 10, 17, 18, 26, 40 and 200 all landed and read back unaltered, with a non-vacuity control: a query for an id never written returned 0 rows while the table held 6, so the filter really filters; - width is driver-owned, not a platform constant: driver-sql, mongodb and turso each spell DEFAULT_ID_LENGTH = 16, while driver-memory mints objectName-timestamp-counter, a variable-width shape. So the replacement does not swap 26 for 16. An id's width is not a fixed number at all, and each site now says which half it states -- what the driver MINTS versus what a supplied id is stored at -- because naming a new fixed number would only re-arm the same trap. Every site's conclusion is unchanged: a reference column takes `table.string(...)` / VARCHAR(255) rather than `table.uuid`, because Postgres refuses a platform id in a `uuid` column with 22P02 -- it refuses a 16-character nanoid exactly as it refused a ULID. Comment and failure-message text only: no behaviour, no asserted value and no minted width changes. The two CHANGELOG copies stay untouched as historical records. A fifth live-source site carrying the same sentence in its strongest "minted" form, in packages/platform-objects, is filed as #16410 rather than edited here -- a different package, a different verification surface. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N --- ...generate-field-type-vocabulary.pin.test.ts | 6 ++++-- .../generate-multiple-json-column.pin.test.ts | 4 +++- packages/cli/src/commands/generate.ts | 19 ++++++++++++------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/commands/generate-field-type-vocabulary.pin.test.ts b/packages/cli/src/commands/generate-field-type-vocabulary.pin.test.ts index 39a93d24f7..a37b2d8c97 100644 --- a/packages/cli/src/commands/generate-field-type-vocabulary.pin.test.ts +++ b/packages/cli/src/commands/generate-field-type-vocabulary.pin.test.ts @@ -512,8 +512,10 @@ describe('#14828 — the SQL answers are the platform’s, not this file’s inv expect( tsColumn(type), `os generate migration (typescript) gave a ${type} column something other than a string ` + - 'column. A platform id is 26 characters (driver-sql spells one out in its lookup arm), ' + - 'so a `uuid` column refuses it outright on Postgres with 22P02.', + 'column. A platform id is not a uuid, and its width is not a fixed number (driver-sql\'s ' + + 'lookup arm states both: it mints a 16-character nanoid, and stores a supplied id at ' + + 'whatever width the caller chose), so a `uuid` column refuses it outright on Postgres ' + + 'with 22P02.', ).toBe(`table.string('f_${type}')`); } // The width is knex's default for a bare `table.string(name)`, which is the diff --git a/packages/cli/src/commands/generate-multiple-json-column.pin.test.ts b/packages/cli/src/commands/generate-multiple-json-column.pin.test.ts index 37bdeada5e..bd78954a1d 100644 --- a/packages/cli/src/commands/generate-multiple-json-column.pin.test.ts +++ b/packages/cli/src/commands/generate-multiple-json-column.pin.test.ts @@ -273,7 +273,9 @@ describe('#14829 — `multiple: true` is one answer across all three surfaces', it('#14828 discharged — the five disputed SCALAR answers are the platform’s', () => { // A reference column holds the target's `id`: `table.string(name)`, knex's // varchar(255). `table.uuid` was the one HARD failure of the five — a - // platform id is 26 characters and Postgres refuses one in a `uuid` column. + // platform id is not a uuid, and its width is not a fixed number (driver-sql + // mints a 16-character nanoid, and stores a supplied id at whatever width + // the caller chose), so Postgres refuses one in a `uuid` column. expect(sqlColumn('single_lookup')).toBe('VARCHAR(255)'); expect(tsColumn('single_lookup')).toBe("table.string('single_lookup')"); diff --git a/packages/cli/src/commands/generate.ts b/packages/cli/src/commands/generate.ts index 14a7146778..3624e0cea6 100644 --- a/packages/cli/src/commands/generate.ts +++ b/packages/cli/src/commands/generate.ts @@ -992,9 +992,12 @@ async function runClientGeneration(configPath: string | undefined, flags: { outp * `lookup` / VARCHAR(36) → VARCHAR(255), with the migration switch's * `master_detail` `table.uuid` corrected in the same breath. The * `uuid` half is the only HARD failure of the five: a platform - * id is 26 characters (`createColumn`'s lookup arm says so and - * spells one out — `01JQ8XKZ9M4N7P2R5T6V8W0Y3B`), and Postgres - * refuses one in a `uuid` column with `22P02`. The width half + * id is NOT a uuid, and its width is not a fixed number at all + * (`createColumn`'s lookup arm states both): the driver mints a + * 16-character nanoid when the caller supplies none, and stores + * a SUPPLIED id verbatim at whatever width the caller chose. + * Postgres refuses either in a `uuid` column with `22P02`. The + * width half * is the same rule for the whole REFERENCE_VALUE_TYPES class: * `user` and `tree` moved with them, because a reference column * holds the TARGET's `id` — which the driver itself emits as @@ -1886,10 +1889,12 @@ export function generateMigrationTs(config: Record): string { // answer: `createColumn`'s `case 'lookup': case 'user':` is // `table.string(name)`, and `master_detail` reaches the same call // through its catch-all. `table.uuid` was the one HARD failure among - // this card's five rows — a platform id is 26 characters - // (`01JQ8XKZ9M4N7P2R5T6V8W0Y3B`, spelled out in that same driver arm), - // and Postgres refuses one in a `uuid` column with `22P02 invalid - // input syntax for type uuid` on the very first insert. + // this card's five rows — a platform id is NOT a uuid, and its width + // is not a fixed number at all: that same driver arm mints a + // 16-character nanoid when the caller supplies no id, and stores a + // SUPPLIED one verbatim at whatever width the caller chose. Postgres + // refuses either in a `uuid` column with `22P02 invalid input syntax + // for type uuid` on the very first insert. case 'lookup': case 'master_detail': case 'user': case 'tree': case 'image': case 'file': case 'avatar': case 'video': case 'audio': From e58829a25638f72ad1513ece36c53c48b8ef2d32 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 20:19:42 +0000 Subject: [PATCH 2/2] docs(cli): reflow an orphaned line left by the previous commit Commit f933d1e3c7d ("docs(cli): state the measured platform-id width at four citation sites") left the aligned doc-comment block in `generate.ts` reading: * Postgres refuses either in a `uuid` column with `22P02`. The * width half * is the same rule for the whole REFERENCE_VALUE_TYPES class: "width half" was stranded on a line of its own -- an artifact of where that commit's replacement text ended, not something the surrounding block ever said. Rewrapped to close the orphan; the sentence is unchanged word for word. Presentation only, and no line is being bought: nothing is added here, the same words occupy one line fewer, and the paragraph's content is identical. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N --- packages/cli/src/commands/generate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/generate.ts b/packages/cli/src/commands/generate.ts index 3624e0cea6..4186c4592c 100644 --- a/packages/cli/src/commands/generate.ts +++ b/packages/cli/src/commands/generate.ts @@ -997,8 +997,8 @@ async function runClientGeneration(configPath: string | undefined, flags: { outp * 16-character nanoid when the caller supplies none, and stores * a SUPPLIED id verbatim at whatever width the caller chose. * Postgres refuses either in a `uuid` column with `22P02`. The - * width half - * is the same rule for the whole REFERENCE_VALUE_TYPES class: + * width half is the same rule for the whole + * REFERENCE_VALUE_TYPES class: * `user` and `tree` moved with them, because a reference column * holds the TARGET's `id` — which the driver itself emits as * `table.string('id').primary()`, i.e. `varchar(255)` — and