You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
spec/identity: UserSchema.image and OrganizationSchema.logo are the same better-auth nullable-column shape #17235 just fixed — measure whether either is served present-and-null #18509
Filed by the domain:spec execution seat, session session_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T17:16Z, out of the at-tier contract review of PR #18501 (card #17235), record 5701552216, flag 「Same-class candidates, NOT MEASURED here」. ⛔ Unlabelled beyond finding and unassigned; grading and routing are triage's.
⭐ This card exists because the review refused to guess. It measured the one declaration the ruling reached and then named two siblings it did not measure, rather than folding them in or waving them off.
The shape that was just fixed
SessionUserSchema.image was declared z.string().optional() — a string or the key absent, ⛔ notnull. better-auth stores the avatar column nullable and serialises it present-and-null for a user who never set one, so every /auth/* session body failed its own declared type. PR #18501 widens it to z.string().nullish() per ruling batch #138 item 1.
Both columns are better-auth-owned and nullable by the same data model that produced the #17235 defect.
⚠️What is NOT measured, and it is the whole card: whether any route actually serves either one present-and-null. ⛔ 「Same owner, same model」 is a reason to look, ⛔ not a finding. Runtime parsers of either schema in plugin-auth / plugin-hono-server / client: 0 — so unlike #17235, there is no measured victim path yet, and that is exactly why this is a measurement request rather than a widening request.
If no for either: say so with the probe and the control, and close it. ⛔ A measured 「does not reproduce」 is the good outcome here.
⛔ Do not widen either declaration on the strength of the #17235 ruling. That ruling names SessionUserSchema.image and nothing else; batch #138's own execution note says 「the one declaration」.
Two boundary notes carried here rather than filed separately
SessionUser.image accepts "" on both the base and the head — z.string() carries no .min(1) and no .url(). Pre-existing, ⛔ not moved by PR fix(spec): SessionUser.image accepts null, the shape every /auth/* route serves #18501, and ⛔ recorded rather than filed: an empty avatar URL is not measurably reaching anyone. ⚠️ It becomes live if step 2 above adds .url() reasoning to this family. Dedupe: SessionUser.image, empty string, .url().
Population method: the review reached these two by grep -rn '^\s*\(image\|avatar\|avatarUrl\|logo\)\s*:\s*z\.' --include=*.zod.ts packages/spec/src = 8 declarations, of which these two are the better-auth-owned ones. ⇒ the population is small and enumerable; ⛔ whoever takes this should re-derive it rather than trust the 8.
Filed by the
domain:specexecution seat, sessionsession_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T17:16Z, out of the at-tier contract review of PR #18501 (card #17235), record5701552216, flag 「Same-class candidates, NOT MEASURED here」. ⛔ Unlabelled beyondfindingand unassigned; grading and routing are triage's.⭐ This card exists because the review refused to guess. It measured the one declaration the ruling reached and then named two siblings it did not measure, rather than folding them in or waving them off.
The shape that was just fixed
SessionUserSchema.imagewas declaredz.string().optional()— a string or the key absent, ⛔ notnull. better-auth stores the avatar column nullable and serialises it present-and-null for a user who never set one, so every/auth/*session body failed its own declared type. PR #18501 widens it toz.string().nullish()per ruling batch #138 item 1.The two siblings, same owner, same nullable model
Both columns are better-auth-owned and nullable by the same data model that produced the #17235 defect.
plugin-auth/plugin-hono-server/client: 0 — so unlike #17235, there is no measured victim path yet, and that is exactly why this is a measurement request rather than a widening request.What the round owes
AuthManagerover a real store the waySessionUser.imageis declaredz.string().optional(), but every/auth/*session route serves"image": null— no real session body parses asSessionResponse#17235's evidence was taken, whetherUserSchema.imageandOrganizationSchema.logoare ever served present-and-null.SessionUser.imageis declaredz.string().optional(), but every/auth/*session route serves"image": null— no real session body parses asSessionResponse#17235 shape and the remedy is the ruled one —.nullish(), ⛔ not.nullable(), which would retire the legal 「key absent」 shape..url(), whichSessionUser.imageis declaredz.string().optional(), but every/auth/*session route serves"image": null— no real session body parses asSessionResponse#17235's declaration did not — so a widening here has to say what.url()means besidenull, and that is a real question, not a copy ofSessionUser.imageis declaredz.string().optional(), but every/auth/*session route serves"image": null— no real session body parses asSessionResponse#17235.⛔ Do not widen either declaration on the strength of the #17235 ruling. That ruling names
SessionUserSchema.imageand nothing else; batch #138's own execution note says 「the one declaration」.Two boundary notes carried here rather than filed separately
SessionUser.imageaccepts""on both the base and the head —z.string()carries no.min(1)and no.url(). Pre-existing, ⛔ not moved by PR fix(spec): SessionUser.image accepts null, the shape every /auth/* route serves #18501, and ⛔ recorded rather than filed: an empty avatar URL is not measurably reaching anyone..url()reasoning to this family. Dedupe:SessionUser.image,empty string,.url().grep -rn '^\s*\(image\|avatar\|avatarUrl\|logo\)\s*:\s*z\.' --include=*.zod.ts packages/spec/src= 8 declarations, of which these two are the better-auth-owned ones. ⇒ the population is small and enumerable; ⛔ whoever takes this should re-derive it rather than trust the 8.Dedupe words
UserSchema.image·OrganizationSchema.logo·present-and-null·better-auth nullable column·identity.zod.ts nullishRefs
#17235 / PR #18501 (the measured instance and its ruling) · batch #138 item 1
Generated by Claude Code