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 Interfaces: an object nav entry without its own label is titled by the object's machine name in the item header ("repairs_repair_ticket · Object") while the rail shows the object label #26746
Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.
Symptom
The scaffolded nav entry ({type:"object", objectName}) has no label; the header falls back to the name instead of resolving the object label as the rail does. Label-less groups show ids like "NAV_ITEM_2".
Reproduction
Create an app from Studio scaffolding over an object → open its nav entry → header reads "repairs_repair_ticket · Object", rail reads "Repair Ticket".
Expected
The header resolves the same label the rail shows (object label, then name).
p3: a label-less object nav entry is titled by the object's machine name, and label-less groups show ids. Resolve the object label the way the rail does. From the studio-qa-2026-10-27 batch. Re-check the landing site on current main.
Dispatch order · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-27T22:42Z
You are the os-dev developer agent for exactly ONE card: #26746, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26746" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.
Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktree objectstack-issue-26746 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).
Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26746 --file=F --json run ONCE with output captured to a file (timestamps only as {{WAS:…}} / the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26746, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran; node scripts/check-sdui-manifest.mjs is a gate on every ui card. Changeset in the root .changeset/ when a published package changes (@object-ui/i18n patch for namespace rows; app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.
Shared-file rules for every Studio Interfaces card this round (from ui seat 1, which holds the neighbouring work):
Triage 6448317687, verbatim: "p3: a label-less object nav entry is titled by the object's machine name, and label-less groups show ids. Resolve the object label the way the rail does. From the studio-qa-2026-10-27 batch. Re-check the landing site on current main." No maintainer ruling.
The Interfaces item header renders current.label || current.name at ≈L4594 and ≈L4609 (sr-only), and ≈L5000 (engine.studio.if.definitionTitle). A label-less {type:'object', objectName} entry therefore shows its name.
The rail resolves a label-less entry through inheritedNavEntryText with useNavTargetLabel (see the StudioNavItemInspector docblock ≈L2560–2612, ruling B of objectui#11201). Reuse that exact resolver for the header. ⛔ No second resolver.
Label-less groups show ids like NAV_ITEM_2 (NavTreeGroup ≈L2373). Measure what the rail shows for them, and make the header and the rail agree.
Scope
File surface: the item-header lines above (≈L4594, ≈L4609, ≈L5000), NavTreeGroup only if the group text is wrong there too, and tests. Tests: a label-less object entry's header reads the object label; a labelled entry is unchanged; a label-less group reads the same text in the rail and the header. Ablation: put current.label || current.name back; the first test turns red. ⛔ Don't edit the inspector (≈L2613–3060, #26740/#26743) or the listing (#26889) this round.
Tier
No path-derived mandate. TIER_DEFAULT, effort medium (S, one resolver reused). Clause-②: no, Metadata-protocol: none expected.
Claim: PM loop round 1
Session: session_01JQwxbXGpVJHZTXXerMoY4C
Account: os-warren
Branch: claude/project-thread-ewmhhb
Worktree: objectstack-issue-26746
Domain: domain:ui
Seat: domain:ui#5
File surface: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (Interfaces item header ≈L4594/4609/5000 and NavTreeGroup ≈L2373 only), tests (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: ui/packages/app-shell Studio code produces it (this lane) | no platform path covers it in Studio; Setup › Metadata is a separate door | Studio builders reach it today (studio-qa / HotCRM browser pass)
Thread-read: 6455400455
Premise: holds (landing site re-read on origin/main5ec398dc; readings in dispatch order 6455400455)
Serial constraints cleared: #26889 (seat 5) holds the Interfaces listing; #26740/#26743 (seat 5) the inspector and nav-target read; #26730/#26733 (seat 1) the refusal strip and rail call sites; PR #26920 ≈L1270–1330. Second to land merges main.
Dispatch order: comment 6455400455. Card thread claude/project-thread-ewmhhb may start editing.
{
"issue": 26746,
"status": "done",
"branch": "claude/project-thread-ewmhhb",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26974",
"session": "session_01JQwxbY5nVXXfxvWqYPEQAe",
"premise_still_valid": true,
"summary": "Interfaces item header (title, sr-only caption, definition sheet title) read current.label || current.name, the Surface text frozen at load; a draft-only object's _drafts label arrives after the first leaf opens, so the rail read 'Repair Ticket' and the header 'repairs_ticket · Object'. The three sites now read ifTitleText: the open leaf's railTree entry by navId through the rail's own navEntryLabelText + useNavTargetLabel (no second resolver). Label-less groups: rail shows the entry id, which is resolveNavItemLabel's runtime rule and the running sidebar's text; the header never names a group, so NavTreeGroup is unchanged.",
"tests": "head 052aae45: new StudioDesignSurface.itemHeaderLabel-26746.test.tsx 3/3 passed. Ablation (fix committed first): ablation-replace.mjs anchor 'const text = railEntry ? navEntryLabelText(...) : current.label;' -> 'const text = current.label;' landed (anchor 1->0, blob d05fa2404f2a->2a32e6a5c3a2); tests 1 and 3 red 'Received: repairs_ticket · Object', test 2 green; restore blob d05fa2404f2a = HEAD, git diff HEAD empty. Relative import, no dist leg. studio-design dir: Test Files 234/234, Tests 1693/1693 (lock VERDICT command-exit 0).",
"gates": "head 052aae45: dispatch-gates --commands derived 24, all run, all exit 0 (check-sdui-manifest + --self-test, vitest run scripts/ under lock, check:cross-package-test-inputs, check:test-source-alias, check:nul-bytes, check:type-check-coverage/debt, ...); --ran: 24 derived, 24 run, 0 NOT-MEASURED. Extra: app-shell type-check exit 0; eslint on 2 changed files 0 errors (14 pre-existing warnings outside the hunk); ui check:new-line-citations 0 new, exit 0. CI check-runs: in_progress at report time.",
"dogfood_battery": "n/a — no ! in the PR title and Clause-② no without (narrowing) arm",
"line_budget": "no ratcheted file touched",
"files_changed": [
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+20/-3, header region)",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.itemHeaderLabel-26746.test.tsx (new)"
],
"deviations": [
"Dispatch test 3 asked a label-less group to read the same text in rail and header; the header never names a group (not a Surface), so test 3 pins rail group text = runtime resolveNavItemLabel and a leaf inside the group named alike in rail and header.",
"ifTitleText sits beside ifKindName/ifInternalId (header-derived values), a few lines above the three header sites the claim names.",
"PR template headings folded into the os-dev section order (os-dev exception)."
],
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST pulls, PR 26974 with assignee + skip-changeset label); relay os-dev-report comment on issue 26746. git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: Studio Automation pillar header shows current.label || current.name (same frozen Surface text) · evidence: StudioDesignSurface.tsx auto-canvas-caption title · not reproduced for a late label · carrier: none (noted in PR acceptance notes)",
"onSurfaceLabelChange reports current.label (frozen) to the dock chip · carrier: none, noted in PR acceptance notes"
]
}
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
priority:p3·domain:ui·area:studio·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T17:03Z⛔ Not a claim, ⛔ not a dispatch.
main.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Dispatch order ·
domain:ui#5·session_01JQwxbXGpVJHZTXXerMoY4C· 2026-10-27T22:42ZYou are the os-dev developer agent for exactly ONE card: #26746, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26746" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktreeobjectstack-issue-26746on that branch from a freshorigin/main;pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=26746 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{WAS:…}}/ the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and onerun_rerun_failedthrough the relay. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3Fixes #26746, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran;node scripts/check-sdui-manifest.mjsis a gate on every ui card. Changeset in the root.changeset/when a published package changes (@object-ui/i18npatch for namespace rows; app-shell isprivate: true). ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.Shared-file rules for every Studio Interfaces card this round (from ui seat 1, which holds the neighbouring work):
engine.studio.*rows, the Interfaces familyengine.studio.if.*included, out ofui/packages/app-shell/src/views/metadata-admin/i18n.tsintoui/packages/i18n/src/namespaces/studio/{en,zh}.ts. ⛔ Add or edit no row inmetadata-admin/i18n.ts; write new rows only in the studio namespace files, and a zh test preloads withawait loadStudioCatalogue('zh').ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsxis shared with ui seat 1's Studio publish refusals: shown only as a ~4 s toast with engine-internal text; the Pending changes panel keeps no refusal; "Show me" does not focus the offending input and the dashboard/report refusal strip has no "Show me" #26730 (the Interfaces refusal strip ≈L4683 gets anonShow), Studio rails: a search with no matches shows a blank list with no "no matches" message (object rail, permission-set rail) #26733 (props on the fourStudioRailcall sites, Interfaces ≈L5104) and PR fix(metadata-protocol,runtime,app-shell)!: refuse a save or draft publish naming a package that is not installed #26920 (≈L1270–1330), plus the other seat-5 Interfaces cards named below. Keep your hunks inside your declared region; whoever lands second mergesorigin/mainand resolves.Ruling (cannot be re-ruled)
Triage 6448317687, verbatim: "p3: a label-less object nav entry is titled by the object's machine name, and label-less groups show ids. Resolve the object label the way the rail does. From the studio-qa-2026-10-27 batch. Re-check the landing site on current
main." No maintainer ruling.PM mechanism assumptions (measure; disproof welcome)
On
origin/main5ec398dc,StudioDesignSurface.tsx:current.label || current.nameat ≈L4594 and ≈L4609 (sr-only), and ≈L5000 (engine.studio.if.definitionTitle). A label-less{type:'object', objectName}entry therefore shows its name.inheritedNavEntryTextwithuseNavTargetLabel(see theStudioNavItemInspectordocblock ≈L2560–2612, ruling B of objectui#11201). Reuse that exact resolver for the header. ⛔ No second resolver.NAV_ITEM_2(NavTreeGroup≈L2373). Measure what the rail shows for them, and make the header and the rail agree.Scope
File surface: the item-header lines above (≈L4594, ≈L4609, ≈L5000),
NavTreeGrouponly if the group text is wrong there too, and tests. Tests: a label-less object entry's header reads the object label; a labelled entry is unchanged; a label-less group reads the same text in the rail and the header. Ablation: putcurrent.label || current.nameback; the first test turns red. ⛔ Don't edit the inspector (≈L2613–3060, #26740/#26743) or the listing (#26889) this round.Tier
No path-derived mandate.
TIER_DEFAULT, effortmedium(S, one resolver reused).Clause-②: no,Metadata-protocol: noneexpected.objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1
Session:
session_01JQwxbXGpVJHZTXXerMoY4CAccount:
os-warrenBranch:
claude/project-thread-ewmhhbWorktree:
objectstack-issue-26746Domain:
domain:uiSeat:
domain:ui#5File surface:
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(Interfaces item header ≈L4594/4609/5000 andNavTreeGroup≈L2373 only), tests (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
ui/packages/app-shellStudio code produces it (this lane) | no platform path covers it in Studio; Setup › Metadata is a separate door | Studio builders reach it today (studio-qa / HotCRM browser pass)Thread-read: 6455400455
Premise: holds (landing site re-read on
origin/main5ec398dc; readings in dispatch order 6455400455)Serial constraints cleared: #26889 (seat 5) holds the Interfaces listing; #26740/#26743 (seat 5) the inspector and nav-target read; #26730/#26733 (seat 1) the refusal strip and rail call sites; PR #26920 ≈L1270–1330. Second to land merges main.
Dispatch order: comment 6455400455. Card thread
claude/project-thread-ewmhhbmay start editing.objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26746, "status": "done", "branch": "claude/project-thread-ewmhhb", "pr": "https://github.com/objectstack-ai/objectstack/pull/26974", "session": "session_01JQwxbY5nVXXfxvWqYPEQAe", "premise_still_valid": true, "summary": "Interfaces item header (title, sr-only caption, definition sheet title) read current.label || current.name, the Surface text frozen at load; a draft-only object's _drafts label arrives after the first leaf opens, so the rail read 'Repair Ticket' and the header 'repairs_ticket · Object'. The three sites now read ifTitleText: the open leaf's railTree entry by navId through the rail's own navEntryLabelText + useNavTargetLabel (no second resolver). Label-less groups: rail shows the entry id, which is resolveNavItemLabel's runtime rule and the running sidebar's text; the header never names a group, so NavTreeGroup is unchanged.", "tests": "head 052aae45: new StudioDesignSurface.itemHeaderLabel-26746.test.tsx 3/3 passed. Ablation (fix committed first): ablation-replace.mjs anchor 'const text = railEntry ? navEntryLabelText(...) : current.label;' -> 'const text = current.label;' landed (anchor 1->0, blob d05fa2404f2a->2a32e6a5c3a2); tests 1 and 3 red 'Received: repairs_ticket · Object', test 2 green; restore blob d05fa2404f2a = HEAD, git diff HEAD empty. Relative import, no dist leg. studio-design dir: Test Files 234/234, Tests 1693/1693 (lock VERDICT command-exit 0).", "gates": "head 052aae45: dispatch-gates --commands derived 24, all run, all exit 0 (check-sdui-manifest + --self-test, vitest run scripts/ under lock, check:cross-package-test-inputs, check:test-source-alias, check:nul-bytes, check:type-check-coverage/debt, ...); --ran: 24 derived, 24 run, 0 NOT-MEASURED. Extra: app-shell type-check exit 0; eslint on 2 changed files 0 errors (14 pre-existing warnings outside the hunk); ui check:new-line-citations 0 new, exit 0. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no ! in the PR title and Clause-② no without (narrowing) arm", "line_budget": "no ratcheted file touched", "files_changed": [ "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+20/-3, header region)", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.itemHeaderLabel-26746.test.tsx (new)" ], "deviations": [ "Dispatch test 3 asked a label-less group to read the same text in rail and header; the header never names a group (not a Surface), so test 3 pins rail group text = runtime resolveNavItemLabel and a leaf inside the group named alike in rail and header.", "ifTitleText sits beside ifKindName/ifInternalId (header-derived values), a few lines above the three header sites the claim names.", "PR template headings folded into the os-dev section order (os-dev exception)." ], "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST pulls, PR 26974 with assignee + skip-changeset label); relay os-dev-report comment on issue 26746. git push is not a REST write.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: Studio Automation pillar header shows current.label || current.name (same frozen Surface text) · evidence: StudioDesignSurface.tsx auto-canvas-caption title · not reproduced for a late label · carrier: none (noted in PR acceptance notes)", "onSurfaceLabelChange reports current.label (frozen) to the dock chip · carrier: none, noted in PR acceptance notes" ] }Generated by Claude Code