Repository navigation
fix(spec): a user field over a text column passes the type-compat check; ADR-0015 names the odata vocabulary - #28011
Conversation
…ck; ADR-0015 names the odata vocabulary A `user` field's target is fixed to sys_user, so its column holds a platform user id. Measured: better-auth mints a 32-character alphanumeric string for every user it creates, and the SQL driver mints a 16-character nanoid for a row the engine writes without one, so the id is always a string and never an integer. `user` joins the text row's exact set; the integer and bigint rows keep refusing it, though lookup and master_detail are exact there. ADR-0015 §4.6 lists `odata` among the dialects the matrix knows. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2dhraZ7BwSanQPGEAb
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV The seat's at-tier review call is refused by the model quota (probe just now: HTTP 429 rate_limit), and per contract-review.md the tier is not lowered. One same-shape
|
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV The epic PM weighed whether admitting Please judge one point explicitly in ④. An external table's text column holds the external system's user keys, not platform |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract-review-claim: Generated by Claude Code |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract reviewServed-tier: Inputs: card #27917 (body, claim 6516916650, os-dev-report 6517630083), PR #28011 (body, file list, net diff of four files against ① Derived judgmentsAccept-set changes the diff implies, each judged against the live tree:
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning: one must-fix on a Implemented-by: VERDICT: FAIL Generated by Claude Code |
…ries Contract review on ecf8b5c: §4.6 called `odata` the one vocabulary that is not SQL, but `mongo` maps BSON type names too, as the SqlDialect doc comment says. The sentence now names both, and says which EDM types the odata arm leaves unmapped for review. The text row's comment no longer says a user id is never a UUID: only a minted one is never; a caller-supplied id is stored verbatim, which is why the uuid row keeps `user`. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2dhraZ7BwSanQPGEAb
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract-review-claim: Generated by Claude Code |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract reviewServed-tier: Inputs: card #27917 (body, claim 6516916650, os-dev-report 6517630083), PR #28011 (body, file list, net diff of four files against Delta shape. This is the delta review of record 6518256754 by the same reviewer. ① Derived judgments
② Semver levelUntouched by the move; stands as judged in record 6518256754 §②. Re-checked on this head: ③ Boundary flags
④ Design judgment
Verdict reasoning: the move lands the three findings of record 6518256754, each now judged to hold against the code it cites, and nothing else moved; the judgments of that record the move does not touch stand by its name. No must-fix on either Implemented-by: VERDICT: PASS Generated by Claude Code |
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV 维护者速读
席位意见:ACCEPT。契约复核 PASS 在案:先是 6518256754,在 席位核对
|
epic:#27261#1 · marchtian · session_017ihL2dhraZ7BwSanQPGEAb
Requested by 田騏 · project thread
Fixes #27917
Clause-②: yes (widening)
Metadata-protocol: none
Fable review owed. The review quota was out when this PR was opened. It stays draft until the independent full review, the contract review PASS on head and an authorized approval (Tier H:
docs/adr/**).维护者速读
odata,并指向DIALECT_ALIASES.odata(代码在 feat(datasource): import objects from an OData datasource's $metadata, and import several entity sets from Studio and MCP #27880 已加)。二是user字段加入类型矩阵text行的 exact 集合:外部表里用文本列存平台用户 id 的user字段,启动校验不再报type_mismatch错误。整数行(integer/bigint)不加。sys_user.id)永远是字符串:better-auth 为每个用户生成 32 位字母数字串,引擎直写时 SQL 驱动生成 16 位 nanoid,既不是 UUID 也不是整数。文本列装得下,整数列装不下,所以只放宽text行。What changes
packages/spec/src/data/type-compat.ts.userjoins thetextrow's exact set (it was already exact underuuid). A comment on the row records the measurement and why the integer rows stay closed whilelookup/master_detailare open there: auserfield's target is fixed tosys_user, so the column holds a platform user id, whose shape is the platform's and not the remote system's.docs/adr/0015-external-datasource-federation.md. §4.6 listsodataamong the dialects, with one sentence naming the two non-SQL vocabularies:DIALECT_ALIASES.mongo(BSON type names) andDIALECT_ALIASES.odata(EDM primitive types, exceptEdm.Durationand the geography / geometry families, left unmapped for review). TheAmended byline records it as a dialect-list-only amendment.packages/spec/src/data/type-compat.test.ts. One case pins the decision both ways:useris exact overvarchar(255),text, postgrescitext, bigquerySTRING, odataEdm.String(and still overuuid/Edm.Guid); it is refused overinteger,bigint, postgresint8,Edm.Int32,Edm.Int64,booleanandjsonb, whilelookupstays exact over the same integer columns. A second case pins that the draft still suggeststextfor a text column (the suggestion is read from the column alone)..changeset/27917-type-compat-user-text.md.@objectstack/specpatch, with both declaration lines.Why
The measurement (
sys_user.id)@objectstack/plugin-authpins. Fiveauth.api.signUpEmailcalls through acreateAdapterFactoryadapter configured asobjectql-adapter.tsconfigures it (noadvanced.database.generateId) wrote fiveuserrows. Every id was 32 characters, all alphanumeric, not all-digit, not UUID-shaped (for examplejaS4bSf4BGL50JWp7UaSlvZFEEAKHKiE). Admin create and the user import go throughauth.api.createUser, the same id path.nanoid(DEFAULT_ID_LENGTH)withDEFAULT_ID_LENGTH = 16(packages/drivers/driver-sql/src/sql-driver.ts), a string; a caller-supplied id is stored verbatim.useris exact undertext. No path produces an integer user id, souserstays refused underinteger/bigint. This follows the card's own condition ("the integer rows only if a platform user id can be an integer").What an author can declare
The
userfield's own schema is unchanged. The only reader of the matrix that refuses is Gate 2 (validateObjectinservice-datasource): a federated object with auserfield over a text column used to get atype_mismatcherror (boot fails underonMismatch: 'fail') and now passes. Nothing that passed before fails now. The draft generator never suggestsuser(suggestion is per column and staystext), so imports are unchanged.Verification
pnpm --filter @objectstack/spec exec vitest run src/data/type-compat.test.ts: 29 passed.'user'from thetextrow alone fails the new case at thevarchar(255)assertion (expected false to be true, line 190); restored withgit checkout HEAD --.dispatch-gates --commandsderived 85 families onecf8b5c4; all 85 run with exit codes recorded before any pipe. Four exited 3 on the first pass (not measured: plugin-teardown self-test fixture, doc-formula-expressions, dual-build-cjs-loads, lean-entry-closure) and exit 0 after fetching the fixture commit and building./packages/**.--ran: 85 derived, 85 run, 0 NOT-MEASURED (a derived zero).pnpm --filter @objectstack/spec typecheck: exit 0 (test-typecheck ledger held).vitest run src/data/in spec: 149 files, 4588 passed.Contract review 6518256754 (FAIL on
ecf8b5c4), fixed in10deba35; delta 6518728501 PASSodatathe one vocabulary that is not SQL;mongomaps BSON type names too, as theSqlDialectdoc comment says. The sentence now names both, pointing atDIALECT_ALIASES.mongoandDIALECT_ALIASES.odata.Edm.Durationand theEdm.Geography*/Edm.Geometry*families unmapped so a draft flags them for review.type-compat.tsrow comment. "Never a UUID" held for minted ids only. The comment now says a minted id is never a UUID or an integer, and a caller-supplied id is stored verbatim as a string, which is why theuuidrow keepsuser.driver-memorymints anobjectName-timestamp-counterstring anddriver-mongodba 16-character nanoid.Delta review 6518728501 by the same reviewer: PASS on
10deba35, every finding closed.Re-run in full on
10deba35:dispatch-gates --commandsderived the same 85 families; all 85 run with exit codes recorded. Five spec gates (api-surface, browser-reachable-entries, dual-source-exports, entry-nameability, exported-any) exited 3 on the stale specdist/and exit 0 afterpnpm --filter @objectstack/spec build.--ran: 85 derived, 85 run, 0 NOT-MEASURED (a derived zero).Acceptance notes
Human Minimum
packages/specholds no runtime logic. (A matrix entry and its test only.)pnpm lintis CI's).main, one pull request.packages/spectouched: the type-compat matrix and its test, no schema.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_017ihL2dhraZ7BwSanQPGEAb