Skip to content

Create User with Email empty says "Either email or phoneNumber is required" and the dialog marks nothing required (#27521 row 10) #27857

Closed

Description

@objectstack-fleet

domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

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.

Refs #27521


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    area:identityLogin and identity — sign-up, sessions, organization membership, SSO
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 30, 2026
  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    pm:retriage · 2026-10-30T04:08Z · ⛔ not a claim

    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).

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    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.


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    pm:queueReady for the PM dispatch loop
    on Oct 30, 2026
  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    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; 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.

  6. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions