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
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
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)
Boot examples/app-showcase with --seed-admin and sign in as admin. Viewport 1440×900.
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.
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.
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.
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.
{
"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"
]
}
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 业务对象与记录 | none | P①
Triage: p2 ·
domain:ui·area:studio· 2026-10-29T11:12Z⛔ Not a claim.
bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Claim: PM loop round 1
Session:
session_01Utp6CaJoinvGQSbHeDaWBeAccount:
os-billBranch:
claude/project-thread-wom2w0(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27517Domain:
domain:uiSeat:
domain:ui#3File 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 --tieronee9a8d6e: no path-derived mandate),effort: highClause-②: 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) editObjectFieldInspector.tsxin other regions · seat-3 sibling #27511 fold touches its formula returnType onlyDispatched 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
objectstack-fleet commentedon Oct 29, 2026
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
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
ACCEPT → PR #27591 comment 6499515626 · 2026-10-29T14:32Z
Merge remote-tracking branch 'origin/main' into claude/project-thread…