Repository navigation
studio: machine names and raw ids shown where a label exists — Explain access principal, permission-set list, nav editor items, Changes panel #11862
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatarea:studioChanging a running app without code — authoring, publish, docs and the portalChanging a running app without code — authoring, publish, docs and the portal
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsPath: write metadata — the author sees labels, not machine names | 缺项 | P3
Triage: first grade,
bug·priority:p3·domain:ui·area:studio·pm:queue. Direction: labels first, machine names as secondary text, as the maintainer askedTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T03:56Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
AccessExplainPanel(the principal line), the Access pillar's permission-set list, the Interfaces nav editor items and the Changes panel ⇒domain:ui; rationale: a Studio or console surface in objectui. Read on objectuimain4e7dd56ed1.- Why p3: the values are right; the author reads ids where a label exists. Filed on the maintainer's word (「所有地方以标签为主,机器名只作为次要信息」).
- Direction:
- show the label (or a user's name and email) as the primary text, with the machine name or id as secondary text
- fall back to the name only when no label exists
- Related: studio(data): the Objects rail lists a draft-only object by its bare API name, not the label its draft declares #11843 (the Objects rail, the same rule for draft-only objects) is graded separately.
Clause-②: no. Patch changeset in objectui.
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 8
Session:session_01DrKzdPdyLLBW3qpZ4vtk7z
Account:huangyiirene
Branch:claude/issue-11862-labels-first
Worktree:objectui-issue-11862
Domain:domain:ui
Seat:domain:ui#1
File surface (line numbers ond4c39de), underpackages/app-shell/src/views/. Display only: the label is primary, the machine name or id is secondary text, and the name is the fallback only when no label exists.metadata-admin/AccessExplainPanel.tsx: the Principal line (decision.principal.userId/onBehalfOf.userId, about:471–:472). A user id resolves to a name and email through the lookup the panel's user picker already uses.studio-design/StudioDesignSurface.tsx, display spans only:- the Changes list (about
:1669); NavTree's item text (from:1856);StudioNavItemInspector's title;- the Access pillar's permission-set list (from
:6117).
- the Changes list (about
- At most one new module-private name-display helper or component in
studio-design/(labelplus optional secondaryname). - New
engine.studio.*rows ofmetadata-admin/i18n.ts(en and zh), only if a secondary-text label needs one. - The tests beside these, and
.changeset/11862-*.md.
⛔ Not on it:
- Seat 3's objectui#11823 step 2 (claim
6052347323):InterfacesPillar's New dashboard / New report entries and their create handler, andCreateItemDialog.tsx. - Seat 3's objectui#11786:
useDraftAutoSave, the pillars'doSaves,doPublishand their refusal strips. - How nav item ids are minted (
AppNavCanvas.tsxaddItem) and what is saved. A label is never written where the author typed none. - objectui#11843 (the Objects rail's draft-only label): its own card, serial behind this seat's objectui#11799.
packages/i18n/**andpackages/components/src/ui/**.
Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier)
Clause-②: no
Responsibility:objectui app-shell Studio: the Explain-access principal, the permission-set list, the nav editor's items and the Changes panel show machine names or raw ids where a label exists | the platform path is right: the labels and the user lookup are already loaded beside each list | every author reading Studio, on the maintainer's word (「所有地方以标签为主,机器名只作为次要信息」), measured by the filer
Thread-read: 6051871527
Serial constraints cleared:noneblocking.-
The nav inspector region objectui#11884 (objectui#11847) held has landed (
4373484). -
area:studioin flight:- seat 3's objectui#11823 step 2 (
InterfacesPillarcreate flows; it fencesNavTreeandStudioNavItemInspectoroff its own surface) and objectui#11786; - seat 2's objectui#11803;
- this seat's objectui#11871 (
ObjectFormDesigner.tsx) and objectui#11799 (PR objectui#11892: three load effects, inInterfacesPillarandAutomationsPillar).
Their claims were read 2026-10-08T05:06Z. None holds the display spans above.
- seat 3's objectui#11823 step 2 (
-
Open objectui PRs: objectui#11890 and fix(app-shell,data-objectstack): Studio stops probing expected misses as errors (objectui#11799) #11892 touch none of these spans. A
git merge-treeis owed at review. Read 2026-10-08T05:06Z. -
This seat: dispatch is parallel,
batch3 working devs, on the maintainer's word in this session's chat (「改为并行派发,batch 3」, 「继续派发」), paced by the shared hourly write budget.- objectui#11799's dev has finished (PR objectui#11892), which freed this slot.
Why
Clause-②: no: display text only. No export, prop,@object-ui/typesmember, accepted input or saved value changes.objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11862,
"status": "needs_decision",
"branch": "claude/issue-11862-labels-first",
"pr": "#11906",
"session": "session_01DrKzdPdyLLBW3qpZ4vtk7z (subagent mode: the parent's id, as the claim names it)",
"premise_still_valid": true,
"summary": "Draft PR objectui#11906 (first line Refs #11862, Clause-② line copied) lands the display change wherever a label is already in hand. Site 1: the Explain access Principal line shows the user's name and email, with the id beneath it as secondary text, for the principal and for onBehalfOf. The name comes from the picked row, or else from the picker's own lookup (one sys_user find through the data adapter per run, for ids not yet known). An unanswered id still reads as the id. Site 2: the permission-set rail shows the label primary and the machine name secondary, through one module-private StudioNameLabel in StudioDesignSurface.tsx. Site 3: NavTree does the same (label, then the target's machine name). An entry that names no target reads as the existing untitled wording 'Item N' by its place, never nav_item_N; the inspector's Label placeholder (it has no title) does the same. Not landed, needs a decision: (a) every draft-only row (the issue's own technician and repairs_repair_ticket examples). Its only label source is the _drafts header, which carries no label, and the dispatch rules out a fetch for a label. (b) Site 4, the Changes list. It is preview/DraftChangesPanel.tsx, outside the claim's file surface and not in StudioDesignSurface.tsx. (c) The nav editor's edit-mode cards. They are AppNavCanvas.tsx navLabel, outside the claim's surface, and that is where nav_item_N shows while an author edits. None of those files was edited. Recipes are in the PR body and in open_questions.",
"tests": "Gate union on local head 1ddad82 (git rev-parse --short HEAD after merging main 0855fc6; the remote tip is the same sha), run in one os-verify-lock hold. Turbo closure build of app-shell^...: exit 0, 28/28 tasks. pnpm --filter @object-ui/app-shell type-check: exit 0, echoing 'tsc --noEmit && tsc -p tsconfig.test.json'; --listFilesOnly counts the 3 new -11862 pin files in the test program. vitest run over studio-design/, metadata-admin/AccessExplainPanel*, viewCacheInvalidation.guard.test.tsx and apps/console/src/components/StudioRoute*: 'Test Files 128 passed (128)', 'Tests 810 passed (810)'. New pins: AccessExplainPanel.principalPerson-11862 (5), StudioDesignSurface.accessRailLabels-11862 (3), StudioDesignSurface.navRailLabels-11862 (6). Reverse checks ran with the fix committed (HEAD e8c50dd), one per site, through objectstack scripts/ablation-replace.mjs in wrap mode. Each anchor hit 1 to 0, the replacement 0 to 1, and the blob changed; red/green counts were written down before the run, and every observed count matched. A1, the principal person dropped: 2 red, 3 green. A2, the permission-set row back to the bare label span: 1 red, 2 green. A3, the nav row back to the bare label span: 3 red, 3 green. A4, the inspector placeholder back to the inherited text: 2 red, 12 green. Each restore was proven: blob after restore equals the HEAD blob, git diff HEAD empty. ablation-dist-preflight does not apply, because the pins import source by relative path. Lint, narrowed to the 8 touched ts/tsx files and run as app-shell's own lint script runs it (eslint, inline config on): population = the 8 files, all reported in --format json and none ignored; 0 errors, 28 warnings, the same per-file warning counts as the merge-base blobs. Invariance: eslint.config.js has no parserOptions.project or projectService, and no eslint-rules/ rule reads another file. CI on 1ddad82 at report time: 42 check runs, 21 success, 3 skipped, 18 in_progress, 0 failed (in_progress).",
"gates": [
"pnpm exec turbo run build --filter=@object-ui/app-shell^... --concurrency=2 → exit 0 → 'Tasks: 28 successful, 28 total' (os-verify-lock VERDICT command-exit 0)",
"pnpm --filter @object-ui/app-shell type-check → exit 0 → tsc --noEmit && tsc -p tsconfig.test.json",
"pnpm exec vitest run --maxWorkers=2 (studio-design/, AccessExplainPanel*, viewCacheInvalidation.guard, console StudioRoute*) → exit 0 → 'Test Files 128 passed (128)' / 'Tests 810 passed (810)'",
"pnpm check:control-bytes → exit 0 → 'check-control-bytes: OK'",
"pnpm check:new-line-citations → exit 0 → 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'",
"pnpm check:changeset-claims → exit 0 → 'No pending changeset names a file this change touches.'",
"pnpm check:pending-changeset-literals → exit 0 → 'No test source names a pending changeset.'",
"pnpm check:i18n-keys → exit 0 → 'Every in-scope call-site key resolves against the en pack'",
"pnpm check:vi-mock-specifiers → exit 0 → 'check-vi-mock-specifiers: OK'",
"pnpm check:vi-mock-inherit → exit 0 → 'check-vi-mock-inherit: OK'",
"pnpm check:vi-mock-override-shape → exit 0 → 'check-vi-mock-override-shape: OK'",
"pnpm check:test-path-roots → exit 0 → 'check-test-path-roots: OK'",
"node scripts/check-changeset-presence.mjs → exit 0 → '8 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11862-labels-first.md'",
"pnpm check:i18n-designer-parity → not run, not owed: no i18n row added",
"Re-derived after the last commit from the actual diff (app-shell src + tests + one changeset): the added vi-mock and test-path gates above are the ones the new test files touch; objectui has no dispatch-gates.mjs, so this was derived by hand from package.json and .github/workflows/lint.yml"
],
"hypotheses": [
"H1: true for published rows, false for draft-only rows. The rails render published rows that carry a label, and those now lead. A draft-only row is listed from the _drafts header (type, name, organizationId, packageId, updatedAt, updatedBy; no label: objectstack metadata-protocol listDrafts, and the client's MetadataDraftHeader), so no label is in hand anywhere on the surface. The issue's technician (a set just created as a draft) and repairs_repair_ticket (a draft-only object, objectui#11843's instance) are exactly such rows.",
"H2: true. navEntryLabelText with useNavTargetLabel gives the authored label, else the target's current label from the console metadata, else the target's machine name, else the entry id. NavTree did not bypass it. nav_item_N is the last rung, for an entry with no target. repairs_repair_tick… is the machine-name rung, because a draft-only object is not in the console metadata. Reused as is; only the no-target case is replaced by the untitled wording.",
"H3: true, but the list is elsewhere. The Changes list is preview/DraftChangesPanel.tsx (also mounted on Home through DraftPreviewBar), not StudioDesignSurface.tsx, where the cited spot is the 'Changes · N' count button. Its entries come from the _drafts header (no label). Labels already in hand inside the panel: the published list it reads per type for NEW/UPDATE (publishedNamesOf keeps only names), and the object draft bodies the security lint reads. A NEW non-object draft has none."
],
"deviations": [
"Site 4 not landed: the Changes list lives in preview/DraftChangesPanel.tsx, outside the claim's file surface, so it was reported and not edited. The PR's first line is therefore 'Refs #11862 (...)', as the order provides.",
"The edit-mode nav cards (metadata-admin/previews/AppNavCanvas.tsx navLabel, not its fenced addItem) still read nav_item_N for an unbound entry. The file is outside the claim's file surface, so it was reported and not edited.",
"Draft-only labels at sites 2 and 3 were not fetched: the order rules out a fetch for a label. These rows read as their name, the 'no label in hand' case, and are pinned as controls.",
"Site 1 adds one sys_user find per explain run, only for ids the picked row did not answer. That is the ruling's own 'lookup the panel's user picker already uses', not a label fetch.",
"'StudioNavItemInspector's title' measured: the inspector has no title. The one place it names the entry is the Label field's placeholder, which is what changed.",
"One existing pin changed on this ruling: StudioDesignSurface.navItemInspectorLabel-11196's unbound case expected the placeholder 'nav_item_3' (the #11196 last rung) and now expects 'Item 1'. Two existing guard suites (accessGuard, pillarNavGuard) asked the whole screen for 'set_a', which the rail now also shows as secondary text. They now scope those queries to the pillar's main panel.",
"The dependency-closure gate ran as turbo run build --filter=@object-ui/app-shell^... --concurrency=2, not pnpm --filter, per the resource rule on turbo concurrency.",
"The first full test run took os-verify-lock queue-timeout exit 99 (NOT MEASURED; another dev held the lock). It was retaken under the same slot name and ran.",
"The merge commit was first written without the trailer pair. It was amended locally, before any push, to carry it, so no force-push was involved.",
"The harness attribution reminder asks for a model-named Co-Authored-By trailer. The commits carry the model-free pair objectui AGENTS.md requires (Claude-Session plus Co-authored-by: Claude).",
"check:* gates and the 8-file eslint ran outside the verify lock, as the resource rules allow for check scripts. No browser or live-backend reading was taken."
],
"files_changed": [
"packages/app-shell/src/views/metadata-admin/AccessExplainPanel.tsx",
"packages/app-shell/src/views/metadata-admin/AccessExplainPanel.principalPerson-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.accessRailLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navRailLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspectorLabel-11196.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.accessGuard.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.pillarNavGuard.test.tsx",
".changeset/11862-labels-first.md"
],
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "2, both through the fleet-write relay. (1) pr_create: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft, #11906); read-back 8932 bytes sent and stored, identical. (2) This os-dev-report comment through post-stamped.mjs: POST /repos//issues/11862/comments. git push of the branch is not a REST write. No label or assignee write was made.",
"open_questions": [
{
"question": "Where should a draft-only row's label come from: sites 2 and 3 (technician, repairs_repair_ticket), the Changes list, and every other _drafts header consumer?",
"options": [
"A: objectstack's listDrafts adds label to each _drafts header (spec/protocol response, then the client's MetadataDraftHeader), taken from the row's own metadata body. The repository's listDrafts already reads whole sys_metadata rows and drops that body for the header (read in source, not measured live). Business need: real, measured; the issue's examples are all draft-only rows, and authors meet them right after creating. Long-term: contract-first, one producer change feeds every header consumer, the Changes list included, with no per-surface reads. AI-error: the header names what it lists, so each consumer stops growing its own name fallback. Startup: two small cards, one per repo, no staged window.",
"B: each list adds the draft-overlaid read withPreviewDrafts(true).list(type, { packageId }), the route objectui#11843 took for the Objects rail. Business need: covers the rails, but not the mixed-type Changes list without one read per type. Long-term: one extra request per list, and the header stays label-less. AI-error: each surface re-decides which label wins (published or draft), which is consumer-side tolerance that drifts. Startup: objectui only, quickest, precedent exists, but the dispatch ruled out a fetch for a label.",
"C: leave draft-only rows by name until published. Business need: misses the maintainer's word for exactly the rows an author is building now."
],
"recommendation": "A. It is the contract-first fix at the producer, it serves every consumer (Changes list, Home, both rails) at no extra query, and it keeps consumers from each inventing a label rule. That is why the dev did not fetch per surface. B only as the maintainer's explicit stopgap."
},
{
"question": "Two in-scope places sit outside this claim's file surface. How do they land: the Changes list (preview/DraftChangesPanel.tsx) and the edit-mode nav cards (metadata-admin/previews/AppNavCanvas.tsx navLabel, where an author sees nav_item_N while editing)?",
"options": [
"A: amend this card's claim surface and run a follow-up round. AppNavCanvas navLabel gets the same untitled wording (label absent and no target, then engine.appNav.item), mechanical and needing no label source. DraftChangesPanel's publishedNamesOf keeps name to label from the list it already reads, so UPDATE entries lead with the published label. NEW entries wait on question 1.",
"B: file them as their own cards."
],
"recommendation": "A. Same defect class, same seat, same pins shape. The AppNavCanvas part is the most visible nav_item_N and needs no decision. Doing it under this card avoids a second dispatch for a few lines, and keeps NavTree and the edit cards from disagreeing in the meantime."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · The nav-item inspector's object picker writes options as 'label (name)', so an object whose label equals its name reads 'repairs_repair_ticket (repairs_repair_ticket)'; optionsOf and the Explain access object dropdown skip the parenthesis when equal. Polish, noted in PR #11906 Acceptance notes, not filed."
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsSeat ruling on the dev's two open questions (report
6053465616) · claim amendmentdomain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· read onmain09821b1, 2026-10-08T06:05Z. The PR is draft objectui#11906 (Refs #11862). This is the seat's ruling, not a maintainer escalation: the maintainer's direction on this card already decides the product question (labels first), and what is left is where the label comes from and which surface carries which half.Question 1: a draft-only row's label. Ruled A, at the producer, filed as objectstack-ai/objectstack#22200
- Measured: the only list of draft-only items is
GET /meta/_drafts, andListDraftsResponseSchemadeclares nolabel.SysMetadataRepository.listDraftsalready reads the whole draft rows and drops the body down to the header, so the label is in hand at the producer and lost there. - Why A: one producer field serves every consumer: both rails, the Changes list and Home's preview bar, with no extra query. Each consumer stops deciding on its own which label wins. B would be a per-surface read for a label, which the dispatch ruled out, and a consumer-side workaround for a platform gap, which this seat does not take. C ignores the maintainer's word for exactly the rows an author is building.
- objectui waits. No per-surface read is added in the meantime. The draft-only rows stay pinned as the "no label in hand" controls in objectui#11906.
Question 2: the two sites outside the claim. Split by who holds the file
- The edit-mode nav cards,
AppNavCanvas.tsx'snavLabel: ruled A, folded into this claim now. It needs no label source (an entry with no label and no target reads the existing positionalengine.appNav.itemwording, the same asNavTreein objectui#11906). No other claim or open PR names the file. - The Changes list,
preview/DraftChangesPanel.tsx: not this round. That file is on seat 2's in-flight claim for objectui#11807. Its UPDATE entries could lead with the published label it already reads, and its NEW entries need metadata-protocol/spec: the_draftsheader carries no label, so a draft-only item can only be shown by its machine name (ListDraftsResponseSchema drops the label the repository already reads) objectstack#22200. It stays in this card's remainder.
Claim amendment
The file surface of claim
6052722965gains:packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx:navLabel(about:207) only. The text a card shows for an entry with no label and no target. ⛔ NotaddItem(about:329) and not any saved value: ids are minted as before, and no label is ever written.- The tests beside it.
The rest of the claim stands,
Clause-②: noincluded.What happens on merge
objectui#11906 stays
Refs #11862. When it lands, this card goes topm:blocked, with aBlocked-by: objectstack-ai/objectstack#22200line naming the remainder:- draft-only rows in the rails and the Changes list read the header's label after the pin bump that carries it;
- the Changes list also waits on objectui#11807 (seat 2) for its file.
Generated by Claude Code
- Measured: the only list of draft-only items is
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11862,
"status": "done",
"branch": "claude/issue-11862-labels-first",
"pr": "#11906",
"session": "session_01DrKzdPdyLLBW3qpZ4vtk7z (subagent mode: the parent's id, as the claim names it)",
"premise_still_valid": true,
"summary": "Follow-up round on the seat's rulings (comment 6053526025), on the same claim, branch and draft PR objectui#11906. Q2 part A landed: AppNavCanvas.tsx navLabel. An edit-mode card for an entry with no label that names no target (Add nav item not bound, or an unbind) now reads the existing positional engine.appNav.item wording, 'Item N' by its place (Chinese '导航项 N'), never its minted nav_item_N id. A card click titles the selection with the same text. The rule is the one NavTree uses in this PR, and 'names no target' is the module's own namesNoTarget. A bound entry, an authored label and a label-less group (the runtime names it by its id) read as before. addItem is untouched, ids are minted as before, and no label is written. The canvas also serves the app designer's navigation editor, so the card reads the same there; the changeset says so. Q1 ruled A at the producer (objectstack-ai/objectstack#22200): objectui added no read for a label, and the draft-only rows stay pinned as 'no label in hand' controls. DraftChangesPanel.tsx was not touched (objectui#11807's claim). The changeset and the PR body now name the edit-mode cards. The PR body keeps 'Refs #11862 (...)' as its first line, naming the remainder: draft-only labels (objectstack-ai/objectstack#22200) and the Changes list (objectui#11807's file). The body was edited once through fleet-write op issue_patch, and the read-back was identical, session footer kept. Round 1 (sites 1 to 3) stands as reported in 6053465616.",
"tests": "Gate union on local head 386bb41 (git rev-parse --short HEAD after merging main 09821b1 with a merge commit; the remote tip is the same sha), run in one os-verify-lock hold of 919s. Turbo closure build of app-shell^...: exit 0, 28/28 tasks (12 cached). pnpm --filter @object-ui/app-shell type-check: exit 0, echoing 'tsc --noEmit && tsc -p tsconfig.test.json'; --listFilesOnly counts the 4 new -11862 pin files in the test program. vitest run over studio-design/, metadata-admin/AccessExplainPanel*, metadata-admin/previews/ (all AppNavCanvas* included), viewCacheInvalidation.guard.test.tsx and apps/console/src/components/StudioRoute*: 'Test Files 240 passed (240)', 'Tests 2221 passed (2221)'. New pin this round: AppNavCanvas.untitledCard-11862.test.tsx, 7 tests. An unbound and an untyped entry read 'Item 2', the Chinese locale reads '导航项 2', and a click titles the selection 'Item 2'. Controls: a bound entry reads its object label, an authored label reads verbatim, a label-less group reads its id. Pins changed on the ruling, nav_item_N to the positional wording: AppNavCanvas.labelLessBirth-11196 (the card, and the new entry's selection title), AppNavCanvas.navPayload-11776 (finds the unbound card by its text), StudioDesignSurface.navPlaceholderSave-11776 and StudioDesignSurface.navItemTypes-11790 (the edit rail's text). Reverse check A5 ran with the fix committed (HEAD b79a392), through objectstack scripts/ablation-replace.mjs in wrap mode, deleting navLabel's no-target line. The anchor went 1 to 0 and the blob 2de1b77298d7 to ab62496e4494; predicted 8 red / 40 green, observed 'Tests 8 failed | 40 passed (48)'. Red: the 4 untitledCard pins, the 2 labelLessBirth pins, the 2 navPayload keyboard cases. Green: the 3 untitledCard controls and the rest. Restore proven: blob after restore 2de1b77298d7 equals the HEAD blob, git diff HEAD empty. Round 1's reverse checks A1 to A4 stand (6053465616). Lint, narrowed to the 14 touched ts/tsx files and run as app-shell's own lint script runs it: 14 files reported in --format json, none ignored; 0 errors, 30 warnings, the same per-file warning counts as the merge-base blobs (AppNavCanvas.tsx 2 and 2). Invariance as before: no type-aware linting, and no eslint-rules/ rule reads another file. CI on 386bb41 at report time: 42 check runs, 20 success, 3 skipped, 18 in_progress, 1 queued, 0 failed (in_progress).",
"gates": [
"pnpm exec turbo run build --filter=@object-ui/app-shell^... --concurrency=2 → exit 0 → 'Tasks: 28 successful, 28 total' (os-verify-lock VERDICT command-exit 0)",
"pnpm --filter @object-ui/app-shell type-check → exit 0 → tsc --noEmit && tsc -p tsconfig.test.json",
"pnpm exec vitest run --maxWorkers=2 (studio-design/, AccessExplainPanel*, metadata-admin/previews/, viewCacheInvalidation.guard, console StudioRoute*) → exit 0 → 'Test Files 240 passed (240)' / 'Tests 2221 passed (2221)'",
"pnpm check:control-bytes → exit 0 → 'check-control-bytes: OK'",
"pnpm check:new-line-citations → exit 0 → 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'",
"pnpm check:changeset-claims → exit 0 → 'No pending changeset names a file this change touches.'",
"pnpm check:pending-changeset-literals → exit 0 → 'No test source names a pending changeset.'",
"pnpm check:i18n-keys → exit 0 → 'Every in-scope call-site key resolves against the en pack'",
"pnpm check:vi-mock-specifiers → exit 0 → 'check-vi-mock-specifiers: OK'",
"pnpm check:vi-mock-inherit → exit 0 → 'check-vi-mock-inherit: OK'",
"pnpm check:vi-mock-override-shape → exit 0 → 'check-vi-mock-override-shape: OK'",
"pnpm check:test-path-roots → exit 0 → 'check-test-path-roots: OK'",
"node scripts/check-changeset-presence.mjs → exit 0 → '14 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11862-labels-first.md'",
"pnpm check:i18n-designer-parity → not run, not owed: no i18n row added (engine.appNav.item already exists in en and zh)",
"Re-derived after the last commit from the actual diff (app-shell src + tests + one changeset); objectui has no dispatch-gates.mjs, so this was derived by hand from package.json and .github/workflows/lint.yml. The new test file carries no vi.mock, and the vi-mock and test-path gates were rerun anyway"
],
"hypotheses": [
"Round 1's H1 to H3 readings stand (6053465616).",
"Round 2 measured: AppNavCanvas navLabel had four callers: the card render, the card click's selection title, the move handler's selection title, and addItem's selection title. All four now read the positional wording for a no-target entry. addItem's own code is unchanged; only the text it receives for the selection title follows navLabel."
],
"deviations": [
"addItem's emitted selection title changes from nav_item_N to 'Item N', because addItem calls navLabel. addItem's code, the id it mints and the entry it writes are unchanged, and the labelLessBirth pin on the written entry ({ id: 'nav_item_2', type: 'object' }, no label key) still holds.",
"The change also reaches the app designer's navigation canvas (AppPreview mounts the same AppNavCanvas). That is consistent with the maintainer's 'everywhere' wording; the changeset says so.",
"The union held the verify lock 919s (15m19s), longer than round 1, because the ordered set adds metadata-admin/previews/ (240 files in all). The lock printed its long-holder warning, recorded here as the holder-side cost.",
"The first merge attempt used 'git merge -F -', which git refused (exit 129, nothing merged). It was redone with -m, carrying the trailer pair.",
"PR body: edited once through fleet-write op issue_patch (issue 11906), as the seat's addendum directs, built from the body read back first. Everything was kept except the first line, a new What-changed bullet, the remainder section (replacing 'Reported, not landed') and the Tests section. The read-back was identical, 9565 bytes.",
"Commits carry the model-free trailer pair objectui AGENTS.md requires, not the harness's model-named Co-Authored-By."
],
"files_changed": [
".changeset/11862-labels-first.md",
"packages/app-shell/src/views/metadata-admin/AccessExplainPanel.tsx",
"packages/app-shell/src/views/metadata-admin/AccessExplainPanel.principalPerson-11862.test.tsx",
"packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx",
"packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.untitledCard-11862.test.tsx",
"packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.labelLessBirth-11196.test.tsx",
"packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.navPayload-11776.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.accessRailLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navRailLabels-11862.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemInspectorLabel-11196.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navItemTypes-11790.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navPlaceholderSave-11776.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.accessGuard.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.pillarNavGuard.test.tsx"
],
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "This round: 2, both through the fleet-write relay. (1) issue_patch on #11906: PATCH /repos//issues/11906 (the PR body), carried by POST /repos/objectstack-ai/objectstack/dispatches; read-back 9565 bytes, identical. (2) This os-dev-report comment through post-stamped.mjs: POST /repos//issues/11862/comments. git push is not a REST write. No label or assignee write. Round 1's 2 writes are in 6053465616.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · Round 1's polish note stands: the nav-item inspector's object picker writes 'label (name)' even when the two are equal. In PR #11906 Acceptance notes, not filed."
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsReview: ACCEPT as a partial landing — PR objectui#11906 (head
386bb41)domain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· reviewed against the PR's file list and diff hunks,git merge-tree,check-governed-merges.mjs, its check runs and the dev's reports6053465616(round 1) and6053848415(round 2), read 2026-10-08T06:29Z.- Shape: draft →
main. The first line isRefs #11862 (…), naming the remainder, andClause-②: nostarts the next line. - Scope: 15 files, +753/−41, inside claim
6052722965as amended by the ruling6053526025. Everything is underpackages/app-shell/src/views/.AccessExplainPanel.tsx: the Principal line (andonBehalfOf) shows the person's name and email, with the id as secondary text. The person comes from the picked row, or else from onesys_userfind through the data adapter for ids not yet known. An unanswered id still reads as the id.StudioDesignSurface.tsx: one module-privateStudioNameLabel, used by the permission-set rail andNavTree(label primary, name secondary). An entry with no target reads the existing untitled wording "Item N", nevernav_item_N, and so does the inspector's Label placeholder.AppNavCanvas.tsx(round 2):navLabelgives an entry with no label and no target the positionalengine.appNav.itemwording.addItem, the ids it mints and every saved value are unchanged.- Four new pin files. Five existing pins move from
nav_item_Nto the positional wording on this ruling, and two guard suites scope theirset_aqueries to the pillar's panel. Plus one changeset.
- Clause-② re-read: no
+exportline. No prop, type member, accepted input or i18n key changes (engine.appNav.itemalready exists in EN and ZH).noholds. - Governed surface: 0 paths governed, 794 changed lines. That is an ordinary queue landing.
- The rulings held:
- Display only. Nothing that is saved changes, and no label is written.
- Q1 (
6053526025): no read for a label was added. Draft-only rows (technician,repairs_repair_ticket) read as their name, pinned as "no label in hand" controls, until metadata-protocol/spec: the_draftsheader carries no label, so a draft-only item can only be shown by its machine name (ListDraftsResponseSchema drops the label the repository already reads) objectstack#22200. - Q2:
DraftChangesPanel.tsxwas not touched (seat 2's objectui#11807).
- Deviation, accepted: the principal line's one
sys_userfind is the ruling's "lookup the panel's user picker already uses", for ids the picked row does not answer. It is not a fetch for a metadata label. - Tests:
-
Local union on
386bb41(withmain09821b1merged in): 240 files and 2,221 tests green acrossstudio-design/,AccessExplainPanel*,metadata-admin/previews/, the view-cache guard and the console'sStudioRoute*. The type-check,eslinton the 14 touched files (no new warnings against their base versions) and the derivedcheck:*set are green. -
Reverse checks:
- A1–A4 (round 1, one per site) were red exactly as predicted.
- A5 (round 2,
navLabel's no-target line) gave 8 failed and 40 passed, as predicted.
Each restore was proven by blob hash.
-
- Overlap: an in-memory
git merge-treeagainstmain3683591is clean. - CI at
386bb41: converging at this read: 25 green, 3 expected skips, the rest running. The PR is queued when every check completes, and the seat sets its assignee in the same relay write. - On merge: the card goes to
pm:blocked, withBlocked-by: objectstack-ai/objectstack#22200, as the ruling6053526025set. The remainder is the draft-only labels in the rails and the Changes list, and the Changes list also waits on objectui#11807 for its file. - Noted, not filed: the nav-item inspector's object picker writes
label (name)even when the two are equal. That is polish, in the PR's Acceptance notes.
Generated by Claude Code
- Shape: draft →
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsLanded (partial): PR objectui#11906 →
main0feabe8· card blocked on the producerRelease:
session_01DrKzdPdyLLBW3qpZ4vtk7z(domain:uiseat 1, accounthuangyiirene) releases claim6052722965(amended by6053526025). Reason: a partial landing,Refs #11862, as accepted in6053877463. Next:pm:blockedwith the assignee cleared, until the producer change below lands. Verified 2026-10-08T07:08Z.Blocked-by: objectstack-ai/objectstack#22200
-
Merged through the merge queue at 2026-10-08T07:08:15Z, after it was queued at 2026-10-08T06:51:00Z.
- CI on head
386bb41before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones. check-governed-merges.mjs: not governed, +753/−41.
- CI on head
-
Content check:
0feabe8is one squash commit on parent72f5c60. It changes 15 files, +753/−41, the same as the PR.- 14 files are blob-identical to the reviewed head
386bb41. StudioDesignSurface.tsxdiffers only becausemainmoved under it. Its-U0patch-id matches (d0925e3e…), and so does the whole diff's (03ea7560…), against the PR's base09821b1.
-
What landed: labels first, with the machine name or id as secondary text, wherever the label is already in hand:
- the Explain access principal line (a person's name and email);
- the permission-set rail;
- the nav tree and the nav editor's edit-mode cards (an entry with no target reads "Item N", never
nav_item_N); - the nav inspector's Label placeholder.
It is display only: nothing saved changes.
-
The remainder, for the next claim:
- Draft-only items (a permission set or object that exists only as a draft) read as their machine name in the rails and the nav editor, because no label is in hand. This waits on metadata-protocol/spec: the
_draftsheader carries no label, so a draft-only item can only be shown by its machine name (ListDraftsResponseSchema drops the label the repository already reads) objectstack#22200 (the_draftsheader carrieslabel) and the objectui pin bump that carries it. ⛔ No per-surface read for a label meanwhile, per ruling6053526025. - The Changes list (
preview/DraftChangesPanel.tsx): its UPDATE entries can lead with the published label it already reads, and its NEW entries need the header label. The file is on seat 2's objectui#11807 (PR objectui#11916). Re-check that claim before taking it.
- Draft-only items (a permission set or object that exists only as a draft) read as their machine name in the rails and the nav editor, because no label is in hand. This waits on metadata-protocol/spec: the
-
Noted, not filed: the nav-item inspector's object picker writes
label (name)even when the two are equal.
Generated by Claude Code
-
- added a commit that references this issue
on Oct 9, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsBlocked audit: objectstack-ai/objectstack#22200 closed, so the card moves
pm:blocked→pm:on-hold. The remainder's hold is now only the install faceTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-09T12:04Z. ⛔ Not a claim, ⛔ not a dispatch.Thread-read: 6054565160
-
What closed: metadata-protocol/spec: the
_draftsheader carries no label, so a draft-only item can only be shown by its machine name (ListDraftsResponseSchema drops the label the repository already reads) objectstack#22200 closedcompletedat 2026-10-09T11:31Z. Each_draftsrow now carries the draft body's own label, or null:c512c255c5(PR feat(spec, metadata-protocol): each _drafts row carries the draft body's own label, or null objectstack#22323). -
Why on hold, not unblocked: the release
6054565160says the remainder waits on that change "and the objectui pin bump that carries it". The change is on the v18 line only:- npm
latestis 17.7.0, and no 18.x is published; app-shellpins@objectstack/spec^17.6.0.
So the console's
_draftsanswer still has no label. The precedents are objectui#11824 and objectui#11864. - npm
-
Restart-when: objectui's
@objectstack/*resolves a release that carriesc512c255c5. -
Then, as written in
6054565160:- draft-only items in the rails and the nav editor lead with the header label;
- the Changes list's NEW entries do the same. Re-check objectui#11807 / PR objectui#11916's claim on
DraftChangesPanel.tsxbefore taking it. - ⛔ No per-surface label read meanwhile (ruling
6053526025).
-
Filing gate ① — product defect with a named location and a reproduction. reach: Studio on the showcase boot: Access → Explain access names the principal
TCbwecFamZ9PuTlsv5X5z1RsFFP0v4qO; the Access list shows a new permission set astechnician; the Interfaces nav editor showsnav_item_2andrepairs_repair_tick….Who acts on it: objectui triage → the Studio owner. ⛔ Not a claim. Filed on the maintainer's word: 「以下「立卡」:每个"新建"入口先给 3–5 个常用预设或模板,再提供"高级"选项;所有地方以标签为主,机器名只作为次要信息。…」.
What happens
Where a label exists, Studio shows the machine name or the raw id instead:
decision.principal.userId(andonBehalfOf.userId) as the raw id, although the user picker right above it shows name and email (AccessExplainPanel).technician, not its label "Technician".nav_item_2; an existing object item shows its machine name truncated (repairs_repair_tick…) instead of the object's label while editing.repairs_repair_ticket"New").Expected
Label first; the machine name as secondary text (smaller, monospace) where an author needs it; user ids resolved to a person.
Related
#11697 (closed) fixed the same family for the audit-log actor and composite values on record pages.
Suggested direction (triage to rule)
One shared name display (
label+ optionalname) for these lists and chips; resolve user ids through the lookup the Explain access user picker already uses.Environment
Source read on objectui
mainat82500a7and objectstackmainat033e5c53. Live observations are from the 2026-10-07 browser QA pass:examples/app-showcasebooted withobjectstack dev --ui --seed-admin(objectstack879bd38c), console from objectui179f6fe9, Chromium 141 at 1440×900, signed in as the seeded platform adminadmin@objectos.ai.Duplicate check
Dedupe words: machine name shown instead of label studio · explain access principal raw user id · permission set list name not label
Filed by Claude Code (session
session_01D76mrPJrSSdaKRxR2rvrMG) from the 2026-10-07 QA pass and a follow-up source reading.Generated by Claude Code