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
{{ message }}
Repository navigation
Create User with Email empty says "Either email or phoneNumber is required" and the dialog marks nothing required (#27521 row 10) #27857
Filing gate: ② a wrong or confusing state shown to the user. Split from #27521 row 10 by the seat; the parent's acceptance says each row is taken as its own card or answered.
Business reason
Who: every administrator creating a user. What happens: submitting Create User with Email empty answers "Either email or phoneNumber is required" — phoneNumber is an API key and the form has no phone field, so the message names something the administrator cannot see; the dialog shows no required marks at all. Reach: every administrator creating a user.
Mechanism
packages/plugins/plugin-auth/src/admin-user-endpoints.ts line 697 on main: return badRequest('Either email or phoneNumber is required');.
packages/platform-objects/src/identity/sys-user.object.ts: the Create User action's params are all declared optional, so no required mark is drawn.
Read in the 18.3.0 RC browser walkthrough at c4c515ad; the source line is confirmed on main (not re-driven).
Wanted
"Email is required" (or "Email or phone number is required" where phone sign-in is on), and the Email param marked required when phone sign-in is off.
Acceptance
With phone sign-in off, Create User with Email empty answers a message naming Email only, in user words, and the Email param shows a required mark.
With phone sign-in on, the message names email or phone number in user words.
The refusal carries a code the console can localise.
This card is in pm:queue with domain:server and priority:p3 set by the filing seat, with no triage first touch, so no lane seat may claim it. Asking triage for the first touch (grade, lane, and whether it is dispatched under 「低优先级的先不考虑」 or rides another PR).
Claim: PM loop round 2 · 2026-10-30T10:29Z · dispatched on the maintainer's 「明明有这么多任务啊」 (2026-10-30 10:19Z) · serial after the #27858 fold, same card thread
Session: session_016WV4cwXFwjU2YZW2dRuZZt (card thread; seat session_016WV4czVnUdQQCVKSW5J2uk)
Account: os-elon-musk
Branch: claude/project-thread-9wtlmh (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread opened). The second PR (after the first merges) is cut from fresh main on the same branch name.
Worktree: objectstack-issue-27857
Domain: domain:server
Seat: domain:server#1
File surface: packages/plugins/plugin-auth/src/admin-user-endpoints.ts (the create-user refusal names the field), its tests under packages/plugins/plugin-auth/src/, the required marker on the create-user form in packages/platform-objects/src/identity/sys-user.object.ts, .changeset/*. Amended by the seat 2026-10-30 ~13:05Z (PR 2 carries #27869 (a), seat ruling: widen, not a separate card):ui/packages/app-shell/src/console/RemediationOverlay.tsx (ChangePasswordForm maps better-auth's INVALID_PASSWORD code to a translated message instead of showing err.message), its test beside it, and one new key in ui/packages/i18n/src/locales/*.ts (every shipped console locale, fr included). PR 2 then names Part of #27869 (or Fixes #27869 if the dev shows (b) and "loudly" are carried by #28107 / #28109 and the card's other rows are done). Stop and report on any other breach.
Container & model: S treated as M (shares the thread), mode:thread, model: opus (TIER_DEFAULT), effort: high
Clause-②: no (the refusal's wording and the marker; the accept set is unchanged — the dev confirms; a changed error code would be yes)
Metadata-protocol: none
Responsibility: plugin-auth's admin create-user door | none | every Setup admin creating a user, today
Thread-read: 6515391300
Premise: holds (re-measured by the dev on main first)
Serial constraints cleared: behind the #27858 fold PR on sys-user.object.ts (same thread); no open PR touches admin-user-endpoints.ts.
{
"issue": 27857,
"status": "done",
"branch": "claude/project-thread-9wtlmh",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28288",
"session": "session_016WV4cwXFwjU2YZW2dRuZZt",
"premise_still_valid": true,
"summary": "PR 2 of the sys_user thread, head d5b0a9e4: Fixes #27857, Part of #27869. With neither email nor phone, Create User now answers 400 INVALID_REQUEST \"Email is required\" (\"Email or phone number is required\" when phone sign-in is on); the code and status are unchanged. The console's password-change screen maps INVALID_PASSWORD to a new auth.remediation.password.wrongPassword key in all ten ui packs, so a French user reads French (#27869 (a), on the seat's widened claim). The Email required mark was built as two visibility-gated params, then dropped by a revert commit under seat ruling B: it trips the feature-gate registry guard, whose registry is a spec file outside the surface. Seat review must-fix (d5b0a9e4): createAuthClient.changePassword threw new Error(error.message) and dropped better-auth's INVALID_PASSWORD code, so the console mapping never fired in the real app; it now throws through toAuthError and keeps the code. better-auth 1.7.12 /change-password refuses a wrong current password with APIError.from('BAD_REQUEST', BASE_ERROR_CODES.INVALID_PASSWORD) (api/routes/update-user.mjs). Surface widened to ui/packages/auth (seat-accepted).",
"tests": "head d5b0a9e4. plugin-auth test (unchanged since 9248a860): Test Files 205 passed (205), Tests 3917 passed | 10 skipped; typecheck exit 0. ui vitest packages/auth/ + packages/app-shell/src/console/ + packages/i18n/: Test Files 354 passed (354), Tests 3299 passed | 13 skipped. @object-ui/auth type-check exit 0. Pins: changePassword-code-27869.test.ts (new: the real better-auth client over a mocked fetch; a 400 {message:'Invalid password',code:'INVALID_PASSWORD'} from /change-password rejects with .code INVALID_PASSWORD, message unchanged), admin-user-endpoints.test.ts (wording with phone off/on, code + status), request-json-body-refusal.test.ts (empty-body control wording), RemediationOverlay.wrongPassword-27869.test.tsx (fr, en, control; mocks useAuth). Ablations via scripts/ablation-replace.mjs, restored to the HEAD blob, tree clean after: old wording -> 2 failed/93 passed; INVALID_PASSWORD mapping disabled -> 2 failed/1 passed (control stayed green); changePassword back to new Error(error.message) -> 1 failed (expected undefined to be 'INVALID_PASSWORD'); the since-dropped required-Email ablation -> 3 failed/1 passed. All tests import source, so no dist leg.",
"gates": "dispatch-gates --commands on d5b0a9e4: the same 66 families as on 9248a860, all exit 0 (rerun on d5b0a9e4). --ran: 66 run, 0 NOT-MEASURED (a derived zero), exit 0. pnpm lint exit 0. CI check-runs on d5b0a9e4: all completed success or skipped, including Type Check UI, Test UI (16/16 shards), Test Core (8/8), Lint UI, TypeScript Type Check, Lint & Repo Gates and PR-body guards. The first PR-body guards run on d5b0a9e4 was red on a body sentence that bound `closes` to #27869 beside `Part of #27869`; the body was reworded through the relay (issue_patch, signature line first) and the rerun is green. Earlier: first head 25fb4377 had platform-objects feature-gate-guard.test.ts red (2 failed), removed under seat ruling B; the 9248a860 Type Check and Test UI reds are `cancelled`, superseded by the d5b0a9e4 push.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "14 — mcp__github__issue_read x9 (PR 1 card reads), mcp__github__pull_request_read get_check_runs x2 (#28065, #28288), mcp__github__get_job_logs x3 (#28288 PR-body guards, Type Check, Test UI); no write tool",
"api_writes": "4 — relay pr_create (objectstack#28288), relay comment (this report on #27857), relay issue_patch (#28288 body: closing-keyword reword and the d5b0a9e4 readings), relay comment_edit (this report, refreshed for d5b0a9e4)",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: Setup → Create User shows Email with no required mark; with phone sign-in off (the default) an empty Email is refused 400 \"Email is required\" · evidence: action params' `required` is a static boolean; two visibility-gated Email params (required with visible 'features.phoneNumber != true', optional with requiresFeature phoneNumber) parse and work in ActionParamDialog, but trip platform-objects feature-gate-guard.test.ts (reverse: the path must be booked in PUBLIC_AUTH_FEATURES.phoneNumber.gatedInputs in packages/spec/src/kernel/public-auth-features.ts; forward: the first param found by that path carries the negated gate) · body at /mnt/project-files/server-lane-seat1/finding-27857-email-mark.md · dedupe words: create_user email required, action param required when, feature gate negated booking",
"class: b · reach: Create User with no email answers INVALID_REQUEST, a generic code the console cannot localise per field (#27857 acceptance line 3) · evidence: admin-user-endpoints.ts badRequest() always uses INVALID_REQUEST; the dispatch fixed the code (a new code is Clause-② yes) · dedupe words: create user refusal code, EMAIL_REQUIRED code, admin create-user error code"
]
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
pm:retriage · 2026-10-30T04:08Z · ⛔ not a claim
This card is in
pm:queuewithdomain:serverandpriority:p3set by the filing seat, with no triage first touch, so no lane seat may claim it. Asking triage for the first touch (grade, lane, and whether it is dispatched under 「低优先级的先不考虑」 or rides another PR).objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | none | P②
Triage: p3 ·
domain:server·area:identity· first touch (retriage) · 2026-10-30T05:01Z⛔ Not a claim. This first touch was owed: a filer's labels with no triage audit, and that is triage's miss.
plugin-auth admin-user-endpoints / sys_user), so the lane stands. The refusal names the field, and the dialog marks what is required.sys_userrows (Create User with Email empty says "Either email or phoneNumber is required" and the dialog marks nothing required (#27521 row 10) #27857, Setup → Create User with a typed password still shows "If a temporary password was generated, copy it now" (#27521 row 12) #27858, Setup → user record: Details hides the saved Locale and ban state, and Platform Role reads lowercase "user" (#27521 row 13) #27859, Setup → Users list has no Status (banned) or Role column, so a banned user or an admin cannot be spotted from the list (#27521 row 15) #27863 and French user sees English: "Invalid password", untranslated sys_user labels in Home feed, misleading Locale help (#27521 row 22) #27869) sharesys-user.object.ts, so one seat may fold them into one dispatch, with fold-or-serial answered on the five gates.pm:retriageremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#1 · os-elon-musk · session_016WV4czVnUdQQCVKSW5J2uk
Claim: PM loop round 2 · 2026-10-30T10:29Z · dispatched on the maintainer's 「明明有这么多任务啊」 (2026-10-30 10:19Z) · serial after the #27858 fold, same card thread
Session:
session_016WV4cwXFwjU2YZW2dRuZZt(card thread; seatsession_016WV4czVnUdQQCVKSW5J2uk)Account:
os-elon-muskBranch:
claude/project-thread-9wtlmh(the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread opened). The second PR (after the first merges) is cut from freshmainon the same branch name.Worktree:
objectstack-issue-27857Domain:
domain:serverSeat:
domain:server#1File surface:
packages/plugins/plugin-auth/src/admin-user-endpoints.ts(the create-user refusal names the field), its tests underpackages/plugins/plugin-auth/src/, the required marker on the create-user form inpackages/platform-objects/src/identity/sys-user.object.ts,.changeset/*. Amended by the seat 2026-10-30 ~13:05Z (PR 2 carries #27869 (a), seat ruling: widen, not a separate card):ui/packages/app-shell/src/console/RemediationOverlay.tsx(ChangePasswordFormmaps better-auth'sINVALID_PASSWORDcode to a translated message instead of showingerr.message), its test beside it, and one new key inui/packages/i18n/src/locales/*.ts(every shipped console locale,frincluded). PR 2 then namesPart of #27869(orFixes #27869if the dev shows (b) and "loudly" are carried by #28107 / #28109 and the card's other rows are done). Stop and report on any other breach.Container & model:
Streated asM(shares the thread),mode:thread,model: opus (TIER_DEFAULT),effort: highClause-②: no (the refusal's wording and the marker; the accept set is unchanged — the dev confirms; a changed error
codewould beyes)Metadata-protocol: none
Responsibility: plugin-auth's admin create-user door | none | every Setup admin creating a user, today
Thread-read: 6515391300
Premise: holds (re-measured by the dev on
mainfirst)Serial constraints cleared: behind the #27858 fold PR on
sys-user.object.ts(same thread); no open PR touchesadmin-user-endpoints.ts.objectstack-fleet commentedon Oct 31, 2026
domain:server#1 · os-elon-musk · session_016WV4cwXFwjU2YZW2dRuZZt
os-dev-report
{ "issue": 27857, "status": "done", "branch": "claude/project-thread-9wtlmh", "pr": "https://github.com/objectstack-ai/objectstack/pull/28288", "session": "session_016WV4cwXFwjU2YZW2dRuZZt", "premise_still_valid": true, "summary": "PR 2 of the sys_user thread, head d5b0a9e4: Fixes #27857, Part of #27869. With neither email nor phone, Create User now answers 400 INVALID_REQUEST \"Email is required\" (\"Email or phone number is required\" when phone sign-in is on); the code and status are unchanged. The console's password-change screen maps INVALID_PASSWORD to a new auth.remediation.password.wrongPassword key in all ten ui packs, so a French user reads French (#27869 (a), on the seat's widened claim). The Email required mark was built as two visibility-gated params, then dropped by a revert commit under seat ruling B: it trips the feature-gate registry guard, whose registry is a spec file outside the surface. Seat review must-fix (d5b0a9e4): createAuthClient.changePassword threw new Error(error.message) and dropped better-auth's INVALID_PASSWORD code, so the console mapping never fired in the real app; it now throws through toAuthError and keeps the code. better-auth 1.7.12 /change-password refuses a wrong current password with APIError.from('BAD_REQUEST', BASE_ERROR_CODES.INVALID_PASSWORD) (api/routes/update-user.mjs). Surface widened to ui/packages/auth (seat-accepted).", "tests": "head d5b0a9e4. plugin-auth test (unchanged since 9248a860): Test Files 205 passed (205), Tests 3917 passed | 10 skipped; typecheck exit 0. ui vitest packages/auth/ + packages/app-shell/src/console/ + packages/i18n/: Test Files 354 passed (354), Tests 3299 passed | 13 skipped. @object-ui/auth type-check exit 0. Pins: changePassword-code-27869.test.ts (new: the real better-auth client over a mocked fetch; a 400 {message:'Invalid password',code:'INVALID_PASSWORD'} from /change-password rejects with .code INVALID_PASSWORD, message unchanged), admin-user-endpoints.test.ts (wording with phone off/on, code + status), request-json-body-refusal.test.ts (empty-body control wording), RemediationOverlay.wrongPassword-27869.test.tsx (fr, en, control; mocks useAuth). Ablations via scripts/ablation-replace.mjs, restored to the HEAD blob, tree clean after: old wording -> 2 failed/93 passed; INVALID_PASSWORD mapping disabled -> 2 failed/1 passed (control stayed green); changePassword back to new Error(error.message) -> 1 failed (expected undefined to be 'INVALID_PASSWORD'); the since-dropped required-Email ablation -> 3 failed/1 passed. All tests import source, so no dist leg.", "gates": "dispatch-gates --commands on d5b0a9e4: the same 66 families as on 9248a860, all exit 0 (rerun on d5b0a9e4). --ran: 66 run, 0 NOT-MEASURED (a derived zero), exit 0. pnpm lint exit 0. CI check-runs on d5b0a9e4: all completed success or skipped, including Type Check UI, Test UI (16/16 shards), Test Core (8/8), Lint UI, TypeScript Type Check, Lint & Repo Gates and PR-body guards. The first PR-body guards run on d5b0a9e4 was red on a body sentence that bound `closes` to #27869 beside `Part of #27869`; the body was reworded through the relay (issue_patch, signature line first) and the rerun is green. Earlier: first head 25fb4377 had platform-objects feature-gate-guard.test.ts red (2 failed), removed under seat ruling B; the 9248a860 Type Check and Test UI reds are `cancelled`, superseded by the d5b0a9e4 push.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "14 — mcp__github__issue_read x9 (PR 1 card reads), mcp__github__pull_request_read get_check_runs x2 (#28065, #28288), mcp__github__get_job_logs x3 (#28288 PR-body guards, Type Check, Test UI); no write tool", "api_writes": "4 — relay pr_create (objectstack#28288), relay comment (this report on #27857), relay issue_patch (#28288 body: closing-keyword reword and the d5b0a9e4 readings), relay comment_edit (this report, refreshed for d5b0a9e4)", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: Setup → Create User shows Email with no required mark; with phone sign-in off (the default) an empty Email is refused 400 \"Email is required\" · evidence: action params' `required` is a static boolean; two visibility-gated Email params (required with visible 'features.phoneNumber != true', optional with requiresFeature phoneNumber) parse and work in ActionParamDialog, but trip platform-objects feature-gate-guard.test.ts (reverse: the path must be booked in PUBLIC_AUTH_FEATURES.phoneNumber.gatedInputs in packages/spec/src/kernel/public-auth-features.ts; forward: the first param found by that path carries the negated gate) · body at /mnt/project-files/server-lane-seat1/finding-27857-email-mark.md · dedupe words: create_user email required, action param required when, feature gate negated booking", "class: b · reach: Create User with no email answers INVALID_REQUEST, a generic code the console cannot localise per field (#27857 acceptance line 3) · evidence: admin-user-endpoints.ts badRequest() always uses INVALID_REQUEST; the dispatch fixed the code (a new code is Clause-② yes) · dedupe words: create user refusal code, EMAIL_REQUIRED code, admin create-user error code" ] }Generated by Claude Code