Found by the driver-materialisation consumer census on #13973 (class (c) — genuinely wrong on one side). That sweep is not addressed by this card and does not close it.
The site
packages/rest/src/rest-server.ts:515-538, importJobToProgress(row) — the mapper behind the import-job progress and summary REST responses:
...(row?.reverted_at ? { revertedAt: String(row.reverted_at) } : {}), // :520
...(row?.started_at ? { startedAt: String(row.started_at) } : {}), // :533
...(row?.completed_at ? { completedAt: String(row.completed_at) } : {}), // :534
createdAt: String(row?.created_at ?? ''), // :536
row is a sys_import_job record read through the engine's record read door.
Why it is wrong on the production default driver
This site is unusual in the census in that it covers both halves of #13973's value enumeration at once:
created_at is a builtin audit column — not in datetimeFields, repaired by formatOutput only inside if (this.isSqlite).
started_at, completed_at and reverted_at are declared Field.datetime (packages/platform-objects/src/audit/sys-import-job.object.ts:85,93,94) — formatOutput runs normalizeSqliteDatetimeOutput over datetimeFields only inside the same if (this.isSqlite) arm.
So on Postgres and MySQL all four arrive as JS Dates and String() renders the Date.prototype.toString form — whole seconds, process timezone baked in, no Z:
Sun Aug 30 2026 18:19:25 GMT+0800 (China Standard Time) <- what the API serves on PG/MySQL
2026-08-30T10:19:25.947Z <- what it serves on SQLite
Milliseconds are dropped and the value is not Date.parse-safe for any client doing strict ISO parsing. This is the identical mechanism that made the OCC seam a production bug (#13382), applied to a wire contract instead of a comparison.
Note JSON.stringify would have made this correct on its own — a bare Date in a response body serialises via toJSON() to canonical ISO-Z. The explicit String() is what breaks it.
Why this is not a ?? fallback
Per #13973's standing prohibition: which side owes the canonical spelling is the question. Two shapes:
- A — spell the repair at the mapper, the shape this repo already uses one file over in
packages/metadata-protocol/src/protocol.ts:7710-7715, which is class (a) precisely because it handles both:
typeof r.occurred_at === 'string' ? r.occurred_at
: r.occurred_at instanceof Date ? r.occurred_at.toISOString()
: String(r.occurred_at ?? '')
- B — normalise at the producer (one presented shape per dialect at the read door). Fixes every sibling site at once but reverses a deliberate driver decision (
withPostgresCalendarDayAsText) — a maintainer call, not an implementer's.
Re-run
rg -n 'String\(row\??\.?(created_at|started_at|completed_at|reverted_at)' packages/rest/src/
Backlink: #13973 (census), #13382 (the OCC seam, the same shape). Neither is addressed here.
Found by the driver-materialisation consumer census on #13973 (class (c) — genuinely wrong on one side). That sweep is not addressed by this card and does not close it.
The site
packages/rest/src/rest-server.ts:515-538,importJobToProgress(row)— the mapper behind the import-job progress and summary REST responses:rowis asys_import_jobrecord read through the engine's record read door.Why it is wrong on the production default driver
This site is unusual in the census in that it covers both halves of #13973's value enumeration at once:
created_atis a builtin audit column — not indatetimeFields, repaired byformatOutputonly insideif (this.isSqlite).started_at,completed_atandreverted_atare declaredField.datetime(packages/platform-objects/src/audit/sys-import-job.object.ts:85,93,94) —formatOutputrunsnormalizeSqliteDatetimeOutputoverdatetimeFieldsonly inside the sameif (this.isSqlite)arm.So on Postgres and MySQL all four arrive as JS
Dates andString()renders theDate.prototype.toStringform — whole seconds, process timezone baked in, noZ:Milliseconds are dropped and the value is not
Date.parse-safe for any client doing strict ISO parsing. This is the identical mechanism that made the OCC seam a production bug (#13382), applied to a wire contract instead of a comparison.Note
JSON.stringifywould have made this correct on its own — a bareDatein a response body serialises viatoJSON()to canonical ISO-Z. The explicitString()is what breaks it.Why this is not a
??fallbackPer #13973's standing prohibition: which side owes the canonical spelling is the question. Two shapes:
packages/metadata-protocol/src/protocol.ts:7710-7715, which is class (a) precisely because it handles both:withPostgresCalendarDayAsText) — a maintainer call, not an implementer's.Re-run
Backlink: #13973 (census), #13382 (the OCC seam, the same shape). Neither is addressed here.