Found by the driver-materialisation consumer census on #13973 (class (c) — genuinely wrong on one side, lowest severity of the seven the census found). That sweep is not addressed by this card and does not close it.
The site
packages/cli/src/commands/migrate/duplicates.ts:684, building a DuplicateHolder:
constholder: DuplicateHolder={id: row.holder_id==null ? null : String(row.holder_id),
organization,partition: organization??globalTenant,createdAt: row.created_at==null ? null : String(row.created_at),// <-- here};row comes from the CLI's own holder query, which selects the column explicitly at line 346:
constcreated=withCreatedAt ? `, ${quoteIdent('created_at',client)} AS created_at` : '';DuplicateHolder.createdAt is declared string | null (line 133).
Why it is wrong on the production default driver
created_at is a builtin audit column: not in datetimeFields, and SqlDriver#formatOutput repairs it only inside if (this.isSqlite) — and this path reads through knex directly anyway, so no presentation runs at all. Pinned in packages/drivers/driver-sql/src/sql-driver-13567-audit-stamp-materialisation.test.ts: the live dialects materialise it as a JS Date, SQLite as canonical ISO-Z text.
So the operator running os migrate duplicates against Postgres or MySQL sees
Sun Aug 30 2026 18:19:25 GMT+0800 (China Standard Time)
where the same command against SQLite prints 2026-08-30T10:19:25.947Z — whole seconds, the operator's local zone baked in, no Z, and not Date.parse-safe for anything consuming the CLI's JSON output.
Why it is ranked lowest, and why it is still class (c)
createdAt here is reported, never compared — measured: the identifier appears at exactly three places in the file (:133 the declaration, :325 a doc comment, :684 this assignment) and at no comparison or sort. So no wrong record is chosen and nothing is written; the defect is confined to a spelling in an operator-facing report and in the command's JSON.
It is still class (c) rather than (b) because the value is wrong on one side, not merely untested there: string | null is declared, a Date-derived non-ISO string is delivered, and which one you get depends on the dialect.
Why this is not a ?? fallback
Per #13973's standing prohibition, the question is which side owes the canonical spelling. Here the CLI is a leaf consumer with a declared string | null, so the cheapest correct shape is canonicalise at the mapper — the repo's existing correct form is packages/metadata-protocol/src/protocol.ts:7710-7715. If the producer-side option (one presented shape per dialect at the read door) is taken for the census as a whole, this site is repaired by it for free — but that reverses a deliberate driver decision (withPostgresCalendarDayAsText) and is a maintainer call.
Re-run
rg -n 'String\(row\.created_at\)' packages/cli/src/
Backlink: #13973 (census), #13382 (the OCC seam, the same class). Neither is addressed here.
Found by the driver-materialisation consumer census on #13973 (class (c) — genuinely wrong on one side, lowest severity of the seven the census found). That sweep is not addressed by this card and does not close it.
The site
packages/cli/src/commands/migrate/duplicates.ts:684, building aDuplicateHolder:rowcomes from the CLI's own holder query, which selects the column explicitly at line 346:DuplicateHolder.createdAtis declaredstring | null(line 133).Why it is wrong on the production default driver
created_atis a builtin audit column: not indatetimeFields, andSqlDriver#formatOutputrepairs it only insideif (this.isSqlite)— and this path reads through knex directly anyway, so no presentation runs at all. Pinned inpackages/drivers/driver-sql/src/sql-driver-13567-audit-stamp-materialisation.test.ts: the live dialects materialise it as a JSDate, SQLite as canonical ISO-Z text.So the operator running
os migrate duplicatesagainst Postgres or MySQL seeswhere the same command against SQLite prints
2026-08-30T10:19:25.947Z— whole seconds, the operator's local zone baked in, noZ, and notDate.parse-safe for anything consuming the CLI's JSON output.Why it is ranked lowest, and why it is still class (c)
createdAthere is reported, never compared — measured: the identifier appears at exactly three places in the file (:133the declaration,:325a doc comment,:684this assignment) and at no comparison or sort. So no wrong record is chosen and nothing is written; the defect is confined to a spelling in an operator-facing report and in the command's JSON.It is still class (c) rather than (b) because the value is wrong on one side, not merely untested there:
string | nullis declared, aDate-derived non-ISO string is delivered, and which one you get depends on the dialect.Why this is not a
??fallbackPer #13973's standing prohibition, the question is which side owes the canonical spelling. Here the CLI is a leaf consumer with a declared
string | null, so the cheapest correct shape is canonicalise at the mapper — the repo's existing correct form ispackages/metadata-protocol/src/protocol.ts:7710-7715. If the producer-side option (one presented shape per dialect at the read door) is taken for the census as a whole, this site is repaired by it for free — but that reverses a deliberate driver decision (withPostgresCalendarDayAsText) and is a maintainer call.Re-run
Backlink: #13973 (census), #13382 (the OCC seam, the same class). Neither is addressed here.