Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

Settings pages: a refused save shows the server message verbatim in the toast — namespace and field keys plus the word "incomplete" ("Settings for 'localization' are incomplete: timezone — …"), and for Authentication the whole help paragraph #13146

Closed

Description

@objectstack-fleet

立卡门类别 ①:有具名落点且可稳定复现的界面体验缺陷。
动手的读者:objectui 开发席(pm-dispatch 派发的 os-dev),按下方源码落点改 app-shell 外的 apps/console 设置页 onSave 的错误 toast。
查重:objectui 搜 "are incomplete" 命中 0、"settings toast server message" 无同题(均含 closed);第一遍 objectui#13113、#13114、#13115 未收录此项。

reach: 界面实测两次(Localization 填 Mars/Olympus;Authentication 改 Key policy started at)。

预期:字段下方已经有可读的错误,toast 用产品语言概括("1 setting needs attention: Default timezone"),不出现 namespace 与字段机器名;值不合法时不说 "incomplete"。
实际:

  • Localization:toast "Settings for 'localization' are incomplete: timezone — Default timezone must be a valid IANA time zone identifier, e.g. Europe/Zurich (got "Mars/Olympus")"。
  • Authentication:toast 是 "Settings for 'auth' are incomplete: api_key_policy_started_at — Key policy started at does not match the expected format. Recorded automatically (UTC, ISO 8601) the first time …" 一整段帮助文字。

源码落点:apps/console/src/pages/settings/SettingsView.tsx 的 onSave,通用分支 toast.error(err?.message ?? …),而 extractFieldErrors 已拿到带 label 的 fields[]。服务端句子出自 objectstack packages/services/service-settings/src/settings-service.types.ts 的 SettingsValidationError(该类注释已说明 fields 带 label 与 constraint,供表单自行组句)。

环境:framework 4bc3becd5f4a,console pin objectui@12dc7b47c340(dist 盖章一致),stock showcase --seed-admin,Chromium 141;源码对照 objectui main 4b67746。来源:UX 走查第二遍(派发会话 session_01CfRDy7SuTfUqaTu2AEH2Hi)。

type: Bug

Activity

  1. added
    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobs
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 20, 2026
  2. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p3, bug)
    Session: session_01GL347th7aWQUnY2k8diSLG
    Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13146-settings-refusal-toast
    Worktree: objectui-issue-13146
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: apps/console/src/pages/settings/SettingsView.tsx (read at objectui main 7d497de), onSave's refusal branch: when the server's refusal carries per-field errors (extractFieldErrors already reads them, with labels), the toast says in product words which settings need attention, by label, with no namespace or field machine name and no "incomplete" for an invalid value; the field rows keep showing their own messages. The generic branch for a refusal with no field errors keeps a readable message. New copy goes in the console locale packs the parity gates require. Tests beside the page; one .changeset/13146-settings-refusal-toast.md (@object-ui/console patch). ⛔ Not the leave-with-unsaved-edits prompt (objectui#13163, landed as 7a5f267) and not the clear-to-unset control (objectui#13145). ⛔ No server change and ⛔ no new package export. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over this surface reads no path-derived mandate)
    Clause-②: no
    Responsibility: the risk is produced by objectui's own settings page, which puts the server's developer-facing sentence (namespace, field keys, "incomplete", and for Authentication a whole help paragraph) into the toast although the page already holds the per-field errors with labels. The platform path that covers it: the save is refused correctly and the field rows show readable errors. Who reaches it: every admin whose settings save is refused.
    Thread-read: none
    Serial constraints cleared: open objectui PRs touching apps/console/src/pages/settings/: none (the twelve open PRs' file lists were read at this claim). objectui#13163 changed SettingsView.tsx today (7a5f267); this card works on top of it.

    Why Clause-②: no: a console page's own message. No export, prop, schema key or accept set of a published package moves.

    Claimed at: 2026-10-20T09:46Z

  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 13146,
      "status": "done",
      "branch": "claude/issue-13146-settings-refusal-toast",
      "pr": "https://github.com/objectstack-ai/objectui/pull/13227",
      "session": "session_01GL347th7aWQUnY2k8diSLG — subagent run, the dispatching seat's id",
      "premise_still_valid": true,
      "summary": "SettingsView onSave's generic refusal branch no longer toasts err.message (the server's SettingsValidationError sentence: namespace, machine keys, 'incomplete', every row message incl. Authentication's help paragraph) when the refusal carries field errors. It toasts the new console.settingsView.fieldErrorsToast count-plural family, e.g. '1 setting needs attention: Default timezone', naming each refused setting by the label its row draws (manifest literal through labels.fieldLabel, the same lookup SettingsField uses), joined with validation.formInvalidJoiner. Field errors naming no setting on the page toast console.settingsView.saveFailed; a refusal with no field errors keeps the server message unchanged. PM mechanism assumption 1 was half true: extractFieldErrors returns only field+message (it drops FieldError.label), so labels come from the page manifest; that is also the correct source, because service-settings fills FieldError.label from the registered (untranslated) manifest literal while rows translate client-side. Assumptions 2 and 3 held (SettingsValidationError at objectstack origin/main 5fcc79497 composes the quoted sentence; settings-routes sends details: namespace + fields; work is on top of 7a5f267). No server change, no package export.",
      "tests": "New apps/console/src/pages/settings/__tests__/SettingsView.refusalToast-13146.test.tsx (real I18nProvider over shipped packs, real wire body, expected sentences read from the en pack): 7 passed. Ablation once on committed head via objectstack scripts/ablation-replace.mjs (anchor = the new toast block, replacement = the pre-fix toast.error(err?.message ?? saveFailed)): 'mutation landed: anchor 1 → 0, blob 966434655d67 → c229d1a16d66', run 'Tests 6 failed | 1 passed (7)' (the 1 = the unchanged no-field-error case, expected green), 'ok restored: blob == HEAD (966434655d67) and git diff HEAD is empty'. Direction observed: red (normal). Note: a first ablation on 870a5d5 read 5 failed | 2 passed — the row-label case was vacuous against the pre-fix sentence (the server message also contains the label), so it was tightened to pin the whole toast (c453716) and the ablation re-run gave 6|1. Directory run at c453716: pnpm exec vitest run --maxWorkers=2 apps/console/src/pages/settings/ packages/i18n/ → 'Test Files 108 passed (108) / Tests 1518 passed | 13 skipped (1531)', lock VERDICT command-exit 0 (includes all-locales-key-parity, plural-categories-11432, count-families-11445, settingsPage.noBareLiterals-12821, SettingsView.field-errors).",
      "gates": "Local, all at c453716, exit captured before any pipe: closure build pnpm turbo run build --filter='@object-ui/console^...' --concurrency=2 → 'Tasks: 34 successful, 34 total / Cached: 8', VERDICT command-exit 0; pnpm --filter @object-ui/console type-check EXIT=0 (script echoed 'tsc --noEmit && tsc -b tsconfig.node.json --force'; tsc --listFiles includes the new test: 1 hit); pnpm --filter @object-ui/i18n type-check EXIT=0; node scripts/check-changeset-presence.mjs EXIT=0 ('12 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'); pnpm check:new-line-citations EXIT=0 ('0 new citation(s)'); pnpm check:control-bytes EXIT=0; pnpm check:i18n-keys EXIT=0; pnpm check:i18n-drift EXIT=0 ('0 en value(s) changed (3 key(s) added)'); pnpm check:i18n-dead-keys EXIT=0 (report; new keys not among candidates); check:changeset-claims, check:pending-changeset-literals, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots all EXIT=0. NOT MEASURED: check:eager-locale-catalogues, reason: exit 2 PREREQUISITE NOT MET (needs a built apps/console/dist/eager-closure.json); left to CI. --ran reconciliation: n/a (dispatch-gates.mjs is objectstack-only; objectui list hand-derived per dispatch). PR #13227 check-runs at head c4537167 when read (35): success = Changeset Fixed Group Check, Changeset Bump Policy, label; skipped = Test (coverage), Test (coverage shard matrix), dependabot; in_progress = Repo Gates, Line Citation Gate, Type Check, Lint, Build & E2E, Build Docs, Bundle Analysis, Test (dist pins), Test shards 1-16/16, Changeset Claim Re-read, Changeset Overwrite Report, Changeset Declaration, Governed Surface Queue Guard, Live E2E (informational). Not waited on.",
      "line_budget": "n/a: no skills/** or line-ratcheted ledger touched",
      "files_changed": [
        ".changeset/13146-settings-refusal-toast.md +8 -0",
        "apps/console/src/pages/settings/SettingsView.tsx +57 -5",
        "apps/console/src/pages/settings/__tests__/SettingsView.refusalToast-13146.test.tsx +296 -0",
        "packages/i18n/src/locales/ar.ts +7 -0",
        "packages/i18n/src/locales/de.ts +3 -0",
        "packages/i18n/src/locales/en.ts +7 -0",
        "packages/i18n/src/locales/es.ts +4 -0",
        "packages/i18n/src/locales/fr.ts +4 -0",
        "packages/i18n/src/locales/ja.ts +3 -0",
        "packages/i18n/src/locales/ko.ts +3 -0",
        "packages/i18n/src/locales/pt.ts +4 -0",
        "packages/i18n/src/locales/ru.ts +5 -0",
        "packages/i18n/src/locales/zh.ts +3 -0"
      ],
      "head": "c453716",
      "deviations": [
        "Changeset lists '@object-ui/i18n': patch beside the claim's '@object-ui/console': patch, because the diff edits i18n's published src (the ten locale packs); same fixed group, no extra bump.",
        "Label source differs from the dispatch mechanism assumption 1 (extractFieldErrors carries no label): labels come from the page manifest via labels.fieldLabel; @object-ui/react untouched (no export or type moved).",
        "Commit trailers are the model-free pair (Co-authored-by: Claude + Claude-Session) per objectui AGENTS.md; the harness reminder asked for a model-named Co-Authored-By, which was not used.",
        "check:eager-locale-catalogues not run to a verdict locally (prerequisite: built console bundle); declared NOT MEASURED, CI owns it.",
        "Worktree /home/user/objectui-issue-13146 removed after the PR opened (node_modules deleted first; git worktree remove succeeded without --force)."
      ],
      "mcp_calls": "0",
      "api_writes": "2 relay strokes — (1) pr_create via fleet-write/dispatch.mjs: POST /repos/objectstack-ai/objectstack/dispatches (relay) executing POST /repos/objectstack-ai/objectui/pulls and POST /repos/objectstack-ai/objectui/issues/13227/assignees (read-back: 7519 bytes sent, 7519 stored, identical; assignee os-support-ai; no labels sent — the path labels on the PR are labeler.yml's); (2) this os-dev-report comment via post-stamped.mjs: POST /repos/objectstack-ai/objectui/issues/13146/comments. Plus 3 git pushes (empty branch, 870a5d5, c453716), not REST.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none (承接者:无) · noted, not filed · apps/console/src/pages/settings/WorkspaceTimezonePrompt.tsx onConfirm toasts failure?.message on a non-locked refusal, i.e. the same SettingsValidationError sentence for the timezone it writes (it already puts the field message in its own slot); reach not measured — its draft is the browser's own IANA zone · in PR Acceptance notes · dedupe words: WorkspaceTimezonePrompt toast, timezone prompt refusal message, are incomplete",
        "carrier: none (承接者:无) · noted, not filed, read-only inference · the kept no-field-error branch still toasts the server sentence for SETTINGS_FORBIDDEN, whose message names the namespace and capability (\"Access denied: writing to settings namespace 'auth' requires the 'X' capability\"); not measured at a public door · NOT in the PR body (written once); a seat may add it to Acceptance notes · dedupe words: settings forbidden toast namespace, SETTINGS_FORBIDDEN console toast"
      ]
    }
  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #13227 comment 6288935858 · domain:ui seat 3, session_01GL347th7aWQUnY2k8diSLG · 2026-10-20T10:36Z · head c453716 · live reading in the record · landing through the merge queue.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 3, session_01GL347th7aWQUnY2k8diSLG · 2026-10-20T10:46Z

    reading result
    PR #13227 MERGED through the merge queue, merge commit 52907d7 on main
    queue branch gh-readonly-queue/main/pr-13227-* absent (git ls-remote: 0 refs)
    origin/main 52907d7 SettingsView.tsx: function refusedSettingLabels (1) · packages/i18n/src/locales/en.ts: fieldErrorsToast_one (1)

    State: the card closed completed by the PR's Fixes; pm:dispatched is removed in this pass. The live Localization reading ("1 setting needs attention: Default timezone" at the head; the server's sentence at the parent) is in the ACCEPT, 6288935858.


    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:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions