fix(objects): stop declaring maxLength on the platform's own id column - #16936
Conversation
`sys_metadata_commit` and `sys_http_delivery` were the last two shipped declarations that made a clean boot warn about the platform's own tables. `initObjects` emits `id`, `created_at` and `updated_at` itself and skips any declared field colliding with one, so the storage half of such a declaration is discarded before it reaches DDL. #12015 made that discard loud instead of silent; #12131 then cleared 45 system objects declaring `id` as `text`. These two survived that sweep because their residue was an attribute (`maxLength: 64`) rather than a type — nothing can honour a bound on a column the platform emits as varchar(255). Measured on origin/main at 70f7d6d over all 112 `*.object.ts` files (117 object declarations, 215 fields declared on a platform-emitted builtin column): exactly 2 declarations still tripped the diagnostic, and both are these. Fed through the real SqlDriver DDL path — one create pass, then one alter pass over the now-existing tables — they produced 4 `[sql-driver]` collision warning blocks; after this change the same two runs produce 0, with the 215-field sweep unchanged so the empty result is a measurement rather than an empty loop. The diagnostic itself is untouched, on purpose: it is working as designed and is what #12015 was filed for. Each package gains an in-package pin holding every object schema it ships to that shape, with a positive control in the same run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ADLdAs2pVcH17h9tZKWMBg
📓 Docs Drift Check2 anchor(s) derived from 2 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 7 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b4ae0f52b325489d65f5c3c8fcc7f0f69ca2517e && git checkout b4ae0f52b325489d65f5c3c8fcc7f0f69ca2517e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9a89a0040de98fc77046c5b405db1a3935fd7b18 54828f4759c54044b67a5b5366ef1fae6874241a && git checkout -B drift-repro 9a89a0040de98fc77046c5b405db1a3935fd7b18 && git merge --no-ff 54828f4759c54044b67a5b5366ef1fae6874241a
node scripts/docs-audit/affected-docs.mjs --json 9a89a0040de98fc77046c5b405db1a3935fd7b18 |
Fixes #15335
Clause-②: no
sys_metadata_commitandsys_http_deliverystop declaringmaxLength: 64onid. Two deletions, one judgement — the shape the clean siblings already carry.What was wrong
initObjectsemitsid,created_atandupdated_atitself and skips any declared field colliding with one, so the storage half of such a declaration is discarded before it reaches DDL. #12015 made that discard loud instead of silent, and #12131 then cleared 45 system objects that were declaringidastext. These two survived that sweep because their residue was an attribute rather than a type: nothing can honour amaxLength: 64on a column the platform emits asvarchar(255).⛔ The diagnostic is untouched, on purpose. It is working as designed — it is what #12015 was filed for, because a declared
idused to be discarded in silence. Quieting, suppressing or narrowing it was never the remedy; the platform's own declarations getting clean is.Measured, not inherited
The card's boot numbers are the filer's, taken on a pty from a pristine home. This branch did not inherit them; every number below was taken here. Tree:
origin/mainat70f7d6d735, in a dedicated worktree.Baseline — the whole tree, not just the two named sites. A throwaway harness enumerated every
*.object.tsdeclaration in the repo with the TypeScript parser and ran the driver's own predicate,undeliveredStorageAttributesfrompackages/drivers/driver-sql/src/builtin-column-collision.ts, over every field declared on a platform-emitted builtin column:*.object.tsfiles scannedid/created_at/updated_atBoth hits were the two the card names, both
maxLength: declared 64, column provides 255. The 215 stays put across the two runs, so the zero is a measurement rather than an empty loop.Boot path. The two shipped declarations, read from each package's built
dist/, fed through a realSqlDriveronbetter-sqlite3— one create pass, then one alter pass over the now-existing tables:[sql-driver]collision warning blocksos starton a pty; the block count is a function of how many sync passes a real boot makes over each table, and the declaration set is what this PR changes. The count of declarations — 2 to 0 — is the invariant, and it is the whole population.⭐ The 17.2.0 comparison table, carried forward
Triage asked that this not disappear along with the card, because it is what shows the warnings are residue rather than a steady state. The filer's measurement, on a pty from a pristine home with an exact-pinned 17.2.0 scaffold as the control:
[sql-driver]warning linesos startpnpm dev338 to 5 inside one minor. This PR is about the remainder, and the card was filed precisely because a count that small is the one most likely to be left as permanent background noise.⚠️ Those two rows are the filer's numbers and are reproduced here as such — neither triage nor this branch re-ran them.
Reverse verification
Run from the committed fix, both legs symmetric, each proved on disk before its verdict was read.
maxLength: 64and itsablation-dist-preflightsaid "marker present" — butmaxLength: 64occurs 3 times inmetadata-core'sdist/index.jsand 8 times inservice-messaging's with no ablation at all (other fields legitimately carry that bound). That pre-flight could not have failed, so it certified nothing.Attempt 2 mutates to
maxLength: 61, a value that occurs nowhere in either source or eitherdist(verified: 0 hits in all six files first). It trips the diagnostic exactly as 64 did — the trigger is "declared bound is not the column's 255", not the number.HEADblob, both files differing; rebuild green;ablation-dist-preflightexit 0 for both packages, marker present in 2 built files each. Then: sweep 0 to 2, boot 0 to 4, and both pins RED by name —sys_metadata_commit.id declares maxLength: 61andsys_http_delivery.id declares maxLength: 61.git checkout HEAD -- path(never baregit checkout --), proved by state and not by exit code: whole-treegit status --porcelainis 0 lines,git diff HEADempty, and both blob hashes byte-equal to theirHEADblobs. Rebuild, thenablation-dist-preflight --absentexit 0 for both — marker absent from all 12 and all 6 built files, "working tree clean against HEAD". Sweep back to 0, boot back to 0, both pins green.Every mutating script carried
traprestore onEXIT INT TERMwith absolute paths seeded fromgit rev-parse --show-toplevel.Tests
Each package gains an in-package pin,
src/objects/builtin-column-storage-attributes.test.ts, holding every object schema it ships to the clean shape — 6 inmetadata-core, 7 inservice-messaging— with a positive control in the same run so a green is a measurement. Neither pin imports the driver: the authoritative storage/presentation classification lives in one table,FIELD_KEY_STORAGE_CLASS, pinned there againstFieldSchema.shape, and a hand-copied second list is how the two halves drift.Changeset
patchfor both packages, measured rather than assumed:@objectstack/metadata-coreand@objectstack/service-messagingare bothprivate: falseat 17.3.0, and the removal reaches their builtdist/(verified — the key is gone from the emitted declaration, with no default put back in its place). A diff that publishes from a released package takes apatchchangeset and ⛔ neverskip-changeset—AGENTS.md:1036onorigin/mainat70f7d6d735, and still:1036on this branch, which changes no line of that file — but:1019in the shared checkout at9407e18651. Measured on each tree rather than carried over; the dispatch's:1029belongs to a branch that editsAGENTS.md, and this one does not.Not breaking: nothing an author can write changes, no export moves, and the attribute was already being discarded before it reached DDL — the physical columns, the accept set and every write path are what they were.
验收备注
sys_metadata_commitis engine lane andsys_http_deliveryis services lane; triage assigned both to engine because it is one judgement and two deletions. That concession stands: if the services seat wants its own half, it says so on the card and a sibling card is opened.sys_metadata_commit.commit_id-class fields elsewhere in these packages keepmaxLength: 64and are correct to — they are ordinary columns the driver actually emits from the declaration, not platform-emitted builtins. The pins above cover only the three builtin names.Generated by Claude Code