Skip to content

Studio field inspector: typing an existing field's API name drops the last keystroke without a message and saves the half-typed name (status → statu); a trailing "!" saves estimated_hours_ #27517

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcUoS2G4jgqRskpExS7

Found in the 18.3.0 release-candidate browser walkthrough (wave anchor #27377, card W3-UX), at framework main @ c4c515ad, Console built in-repo from the same commit.

Repro (fresh boot)

  1. Boot examples/app-showcase with --seed-admin and sign in as admin. Viewport 1440×900.
  2. From Home choose New in Studio, create a package (e.g. "Field Service"), and create an object Work Order with an optional Number field Estimated Hours and a Picklist Status (option value new, label New Request). Create a second object, Site.
  3. On Work Order's Form tab, select Estimated Hours. In the inspector's API name, select all and type status, the API name of an existing field.

Expected

An inline refusal, "Another field is already named status", with the previous name kept. The Add field popover already says exactly that for the same case.

Actual

  • The box shows statu, with no message. After the debounce, statu is saved as the field's draft API name and survives a reload.
  • Typing Estimated Hours! saves estimated_hours_ with a trailing underscore. The new-object dialog trims that; the field inspector does not.

QA-source: #27377 · ux-walkthrough · track 3


Generated by Claude Code

Activity

  1. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    on Oct 29, 2026
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 业务对象与记录 | none | P①

    Triage: p2 · domain:ui · area:studio · 2026-10-29T11:12Z

    ⛔ Not a claim.

    • Read fresh. Typing an existing field's API name in the inspector drops the last keystroke with no message and saves the half-typed name, and a trailing punctuation mark saves a trailing underscore. A wrong value is silently stored in the draft: p2.
    • Reuse the Add field popover's duplicate-name refusal and the new-object dialog's name normaliser. No second validator.
    • bug, pm:queue.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    Claim: PM loop round 1
    Session: session_01Utp6CaJoinvGQSbHeDaWBe
    Account: os-bill
    Branch: claude/project-thread-wom2w0 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27517
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx (API-name input region), the Add field popover's duplicate-name refusal and the new-object dialog's normaliser if they must be exported, tests beside, root .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on ee9a8d6e: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
    Thread-read: 6495115704
    Premise: holds
    Serial constraints cleared: PR #27533 (#27462) and PR #27340 (#27188, pm:epic #8345) edit ObjectFieldInspector.tsx in other regions · seat-3 sibling #27511 fold touches its formula returnType only

    Dispatched 2026-10-29T13:17Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CYtNGSzW4fU2cRSbut

    os-dev-report

    {
      "issue": 27517,
      "status": "done",
      "branch": "claude/project-thread-wom2w0",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27591",
      "session": "session_01Utp6CYtNGSzW4fU2cRSbut",
      "premise_still_valid": true,
      "summary": "Premise measured on origin/main 72b08eec: the inspector's API name box was an InspectorTextField controlled by entry.name and setKey refused a colliding keystroke, so the box snapped back to the last accepted prefix (statu) and that prefix stayed written; toFieldNameLoose kept a trailing underscore. Fix: the box is FieldApiNameInput, which keeps the typed text as its own state, writes per keystroke as before, writes toFieldNameOrEmpty (the CreateItemDialog toFieldName rule without its placeholder) so no trailing underscore is saved, refuses a taken name with the Add field popover's sentence via the newly exported fieldNameTakenRefusal (popover now reads the same function, branches unchanged), and leaves the field on the name it had when the edit began; blur shows the stored name. No new i18n key, no second validator. Card assignee untouched; PR opened draft with no assignee and no review request (maintainer rule), so the harness after-PR assign/review step was skipped on purpose.",
      "tests": "head d16e14ba (after merging origin/main): new ObjectFieldInspector.apiNameRefusal-27517.test.tsx 6/6; pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/ packages/app-shell/src/views/studio-design/: Test Files 910 passed, Tests 8913 passed / 1 skipped, lock VERDICT command-exit 0. Ablation on e305b3c4+2373d784 (source-imported suite, no dist in path), each leg via scripts/ablation-replace.mjs with anchor 1 -> 0 and blob change proven, restore automatic, git diff HEAD empty after: rollback leg (refused name written instead of edit-start name) 2/6 red; normaliser leg (loose text written) 1/6 red; display leg (box shows stored name) 3/6 red.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on d16e14ba: 34 derived, all exit 0; --ran reconciliation: 34 run, 0 NOT-MEASURED, 0 UNRUN. Outside derivation, also exit 0: pnpm --filter @object-ui/app-shell type-check; eslint on the 3 changed source/test files; the directory vitest run above; pnpm --dir ui run check:new-line-citations (VERDICT 0 new citations). check-sdui-manifest.mjs and --self-test exit 0. CI on d16e14ba at report time: Test Core success, Live E2E UI success, Lint ESLint/repo/docs/PM/CI gates success, Type Check source/debt success; Test UI 1-16/16, Type Check UI, Lint UI, Type Check workspace/consumer in_progress.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no MCP GitHub tool used",
      "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, run 40889887123, PR 27591); this report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/27517/comments). git push x3 not counted (not REST).",
      "line_budget": "4 files, +293 / -21 (dispatch-gates count), under the 3000 human-merge threshold",
      "files_changed": [
        ".changeset/27517-field-inspector-api-name-refusal.md",
        "ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx",
        "ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.apiNameRefusal-27517.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/AddFieldPopover.tsx"
      ],
      "deviations": [
        "PR body attribution line links this card thread (session-context block) rather than the seat thread link in the dispatch order; the session-context text binds the attribution block byte-exact.",
        "The first unpushed WIP commit carried a wrong Claude-Session id and was amended before its first push; pushed history carries the correct trailer pair.",
        "The derived-list extra pnpm check:new-line-citations was first spelled at the repo root (exit 254, script not found, not a gate verdict); re-run as pnpm --dir ui run check:new-line-citations, exit 0."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — by code reading only (not reproduced): the Label to API name derivation (deriveNameFor) skips a colliding derived name, so a label typed letter by letter toward an existing field's name leaves the last free prefix (e.g. statu) as the field name; recorded in the PR acceptance notes"
      ]
    }

    Posted 2026-10-29T14:23Z.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    ACCEPT → PR #27591 comment 6499515626 · 2026-10-29T14:32Z

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

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uipm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions