Repository navigation
fix(app-shell): Studio names a draft-only item by its _drafts label, machine name second (objectui#11862 remainder) - #12419
Merged
objectstack-fleet[bot] merged 1 commit intoOct 15, 2026
Conversation
…machine name second (objectui#11862 remainder) Each `GET /meta/_drafts` row carries the draft body's own label since objectstack#22200 (installed as 18.0.0-next.1). Read it off the row, never by reading the item: - Access: a draft-only permission set leads with its label in the rail. - Automations: a draft-only flow reads as its label (packageSurfaces). - Interfaces: a label-less nav entry that opens a draft-only object or dashboard inherits the draft's label (rail, edit-mode cards, inspector placeholder) through a last rung on useNavTargetLabel fed with the surface's pending drafts; the target pickers offer draft rows by label. - Changes list: every row leads with the row's label, name beneath it. A row with no label keeps its name alone. Display only. Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Oct 15, 2026
Contributor
Author
Seat ACCEPT: objectui PR #12419 at
|
objectstack-fleet
Bot
deleted the
claude/issue-11862-labels-first-remainder
branch
October 15, 2026 04:35
This was referenced Oct 15, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11862 (the remainder after PR #11906, which landed as
Refs #11862)Clause-②: no
Dispatched by the
domain:uiseat 1 (claim comment6183259744). Implementing session:https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB.What changed
Since objectstack
c512c255c5(objectstack#22200, installed here as@objectstack/*18.0.0-next.1), eachGET /meta/_draftsrow carries the draft body's own label, ornull. Studio now reads that label off the row, as the seat ruling6053526025(question 1, A at the producer) asked. No item is read to find its label. The label leads, and the machine name follows as smaller monospace text. A row with no label shows its name alone, as before.AccessPillarinStudioDesignSurface.tsx): a draft-only set tooklabel: name. It now takes the_draftsrow's label, resolved in the designer locale.packageSurfaces.ts, the draft merge behindloadPackageSurfaces/loadPackageLessSurfaces): a draft-only row took the machine name as its label. It now takes the row's label. Both loaders take the designerlocalefor a locale-map label.hooks/useNavTargetLabel.ts): a label-less nav entry inherits its target's current label from the console's metadata. A draft-only object or dashboard is in no published list, so the entry read as its machine name in the rail, on the edit-mode cards and in the inspector's Label placeholder. The resolver gains a last rung,DraftTargetLabels. The surface provides the_draftsrows it already reads for its Changes count, so no request is added. The rung is asked only when the metadata has no label, so a published label still wins. A stored plural type spelling is folded withcanonicalMetaUrlType. With no provider the list is empty and the hook answers as before, which is the console's case.usePackageNavTargets): the page, dashboard and report pickers now keep a draft row's label, so they offer a draft-only item asLabel (name), the same as a published one.preview/DraftChangesPanel.tsx, on top of PR fix(app-shell): Studio's draft panel and build history address a bundle member (?member=) #12400's?member=and PR fix(app-shell): the Changes panel splits added/changed/removed keys and drops Update on a no-op draft; Studio's publish names its count (objectui#11807) #11916's added/changed/removed split): each row leads with the row's label, in the console language, and shows the name beneath it in monospace. A row with no label keeps the name alone, in monospace. The label reaches the panel throughfetchPendingDrafts(preview/usePendingDrafts.ts), which now keepslabelwhen it is served. It used to drop it.Display only: nothing saved changes, and no label is written.
The remainder rows, re-measured on
main2fc31ea94abefore any changeEach row has a pin. Every pin was run against unmodified
mainfirst. Reading: 16 failed, 18 passed (34), and every control passed.qa_readers: still failing.AccessPillarset a draft row's label to its name.label: name.entry.namein monospace, andfetchPendingDraftsdroppedlabel.main, after the re-measure. PR fix(app-shell,plugin-grid,i18n): inline-edit saves and draft discard say what they did, read-only reasons reach keyboard and assistive tech, and the lookup rail reads label first (objectui#12303) #12324 (b64fda3f60, objectui#12303, row 6) madeInspectorComboFieldandObjectPickerread the label first. Its pinlookupLabelFirst-12303.test.tsxgives 7 passed on this branch. Reported, not rebuilt.Mechanism assumptions, measured
_draftsrow shape: read from the installed@objectstack/spec18.0.0-next.1type,ListDraftsResponseSchema:drafts[].labelisstring | I18nLabel map | null, and its doc says a locale map is resolved by the reader. Every consumer here resolves it with the spec'sresolveI18nLabel.@object-ui/data-objectstack'sMetadataDraftHeaderdoes not declarelabel(ormember), so the two Studio reads that go throughclient.listDraftstype the row locally (see the Acceptance notes).DraftChangesPanel.tsx. The lookup inspector isObjectFieldInspector.tsx, through the sharedObjectPickerandInspectorComboField(row d). The nav editor isNavTree,AppNavCanvasandStudioNavItemInspector, which all askuseNavTargetLabel.memberhandling is untouched.File surface
Expected and touched:
StudioDesignSurface.tsx,DraftChangesPanel.tsx, their tests and one changeset. Three more files are the seams the named rows read through, inside@object-ui/app-shell:preview/usePendingDrafts.ts: the one_draftsrow parser. It droppedlabel, so the Changes list could not read the row's label without it.views/studio-design/packageSurfaces.ts: the flow rail's draft merge, which the release6054565160counts among "the rails".hooks/useNavTargetLabel.ts: the label resolver every nav-editor view asks. The new context is a module export, not exported from the package entry.AppNavCanvas.tsxneeded no edit: it asks the same resolver, inside the provider.Clause-② re-read: nothing is added to the package entry. There is no new package-root export, published prop, type member on a published type, accepted input or language-pack key. The new names are module-internal:
DraftTargetLabels/DraftTargetLabelinhooks/useNavTargetLabel.ts, an optionallocaleparameter on the twopackageSurfacesloaders, andlabelon the module-internalPendingDraftEntryandDraftChangeEntry.noholds.One deviation from the suggested route: the Changes list's UPDATE row leads with the
_draftsrow's label, as the NEW row does, not with the published label. The ruling's reason for A was that "each consumer stops deciding on its own which label wins". The_draftslabel is the one publishing makes live, and it needs no change to the published-list read. When a draft renames an item, the drill-in already listslabelamong the changed keys.Tests
The final head is the commit this PR opens on. Every run went through the shared verify lock, and its
VERDICTline is quoted.New and updated pins (35 tests across 4 files, all passing,
VERDICT command-exit 0):StudioDesignSurface.accessRailLabels-11862.test.tsx: a draft-only set with a label, a locale-map label, and anull-label control. It also checks that the draft-only set is never read for its label.packageSurfaces.test.ts: the flow rail's draft label, a locale map inzh-CNanden-US, anullor blank control, published wins, and the package-less loader.StudioDesignSurface.navDraftLabels-11862.test.tsx, through the whole surface: the rail for an object and a dashboard, anullcontrol, and the edit-mode cards. Through the resolver: published wins, a plural type folds, another type does not match, and with no provider nothing changes. Also the inspector's placeholder and the dashboard picker, with anullcontrol.DraftChangesPanel.labelFirst-11862.test.tsx: a NEW row, an UPDATE row, a locale map, anullcontrol, and no read by name of the permission or page rows.Wider suites (all passing):
studio-design/StudioDesignSurface.*: 76 files, 511 tests.StudioRoute*: 98 files, 803 tests.studio-design/__tests__/: 5 files, 20 tests.preview/,hooks/,metadata-admin/previews/,console/ai/,console/home/and the twoviews/__tests__nav-label files: 267 files, 2546 tests.Ablations were run with the fix committed, through objectstack's
scripts/ablation-replace.mjsin wrap mode. The predicted counts were written down before each run, and every observed count matched. Each anchor went from 1 hit to 0, and each restore was proven: the blob equals HEAD andgit diff HEADis empty.labelTextset to''DraftChangesPanel.labelFirst-11862label: nameaccessRailLabels-11862navDraftLabels-11862navDraftLabels-11862label: namepackageSurfacesablation-dist-preflightdoes not apply: every pin imports its subject by relative source path.Gates (local subset; CI runs the full farm)
pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2: exit 0, 28 of 28 tasks.pnpm --filter @object-ui/app-shell type-check: exit 0. The script echoedtsc --noEmit && tsc -p tsconfig.test.json, and--listFilesOnlyshows the 4 pin files in the test program.eslinton the 9 touched.ts/.tsxfiles: exit 0, with 0 errors. Warnings per file equal the base blobs':StudioDesignSurface.tsx13 and 13,DraftChangesPanel.tsx2 and 2,usePendingDrafts.ts1 and 1, and 0 in the rest.check:control-bytes,check:new-line-citations(0 new) andcheck:spec-symbols;check:changeset-claims,check:pending-changeset-literals,check-changeset-presence.mjs,check-changeset-no-major.mjsandcheck-changeset-fixed.mjs;check:i18n-keys;check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shapeandcheck:test-path-roots;check:phantom-depsandcheck:unreferenced-sources.check-governed-queue-guard.mjs --testover the 10 paths: NOT GOVERNED.check:eager-closureneeds a console build, which CI does.Acceptance notes (noted, not filed)
@object-ui/data-objectstack'sMetadataDraftHeaderlagsListDraftsResponseSchema: it has nolabeland nomember. The Studio reads that go throughclient.listDraftstherefore type the served row locally. Deriving the header from the spec type would end that. This is type drift with no failing reader. No owner._draftslabel. It was left in place because the row already works. No owner.permission · 1). The panel stays off the metadata-admin string table on purpose, because it sits on the console's eager graph. Observation only.Generated by Claude Code