Repository navigation
setup(app editor): the nav inspector offers Label and Icon on a separator entry, and a label typed there is refused at save (unrecognized_keys [label]) #11847
Description
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsPath: write metadata — Studio's navigation editor saves what the author sees | 缺项 | P3
Triage: first grade,
bug·priority:p3·domain:ui·area:studio·pm:queue. Direction: Setup's app editor offers a separator only the keys the separator member declaresTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T01:57Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsx⇒domain:ui; rationale: Setup's app editor in objectui. Read on objectuimain5aa7f55dfa.- Why p3: a label typed on a separator is refused at save (
unrecognized_keys [label], measured through the real component). The refusal is loud, and removing the label recovers. - Direction:
- a separator entry shows no Label or Icon field;
- an edit never writes a key
NavigationItemSchema's separator member refuses; - mirror what PR feat(app-shell): Studio's nav editor offers every nav item type the spec declares (objectui#11790) #11846 (studio(interfaces): a writable package cannot create dashboards, reports, pages or list views, and nav items can only link objects #11790) does for Studio's nav inspector, ideally through one shared "fields for this nav item type" helper, so the two inspectors cannot drift. The claimant names the choice.
- Pins (as the body states):
- a separator entry shows no Label or Icon field;
- editing it never writes a refused key;
- control: a page or object entry keeps both fields.
Clause-②: no. Patch changeset in objectui.
- Why p3: a label typed on a separator is refused at save (
- addedarea:studioChanging a running app without code — authoring, publish, docs and the portalChanging a running app without code — authoring, publish, docs and the portalbugSomething 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 seatand removed
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 8
Session:session_01DrKzdPdyLLBW3qpZ4vtk7z
Account:huangyiirene
Branch:claude/issue-11847-setup-nav-separator-fields
Worktree:objectui-issue-11847
Domain:domain:ui
Seat:domain:ui#1
File surface (line numbers oncef0eee):packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsx(Setup's app editor nav inspector): aseparatorentry shows no field its spec member does not declare (no Label, no Icon), and editing one never writes a keyNavigationItemSchema's separator member refuses.- The tests beside it, and
.changeset/11847-*.md.
⛔ Not on it:
- Studio's
StudioNavItemInspectorandNavTreeinStudioDesignSurface.tsx. objectui#11790 handled Studio's side, and the rail's separator rendering is seat 2's objectui#11791. previews/AppNavCanvas.tsx,inspectors/nav-target.tsandpreviews/navItemLabel.ts: import only.- Setup's editor offering six of the spec's ten types: noted on objectui#11790, not this card.
packages/components/src/ui/**andpackages/i18n/**.
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 Setup app editor: AppNavInspector renders Label and Icon for every nav entry, so a label typed on a separator writes {type: 'separator', label}, which NavigationItemSchema refuses with unrecognized_keys [label] at save | the platform path is right: the spec's separator member declares type, id and order only | every administrator editing an app's navigation in Setup; measured by the objectui#11790 dev through the real component (filed by this seat as this card)
Thread-read: 6050602827
Serial constraints cleared:noneblocking.-
area:studioin flight:- seat 2's objectui#11781, studio(interfaces): the nav rail draws a separator item as an unlabeled disabled row and ignores badge #11791, studio: duplicate API reads on entry (packages ×3, _drafts ×4, sys_user_preference ×3) — no shared query cache #11797 and studio(api panel): the example request body types every field as "string" and lists 8 of 23 fields #11803;
- seat 3's objectui#11786;
- this seat's objectui#11804 and studio(interfaces): create flows for list views, dashboards, reports and pages in a writable package (ADR-0084), after #11790's nav item types #11823 (PR objectui#11868, CI converging).
Their claims were read 2026-10-08T03:39Z. None holds
AppNavInspector.tsx. -
Open objectui PRs: none touches
AppNavInspector.tsx,AppNavCanvas.tsxornav-target.ts. Read 2026-10-08T03:39Z. -
Not taken this round, for serial reasons:
- objectui#11842 shares
flow-node-config.ts'screate_record/update_recordblocks with seat 2's in-flight objectui#11788. - objectui#11843 changes the Data pillar's draft read, which seat 2's in-flight objectui#11797 is consolidating (
_draftsreads).
- objectui#11842 shares
-
This seat: dispatch is parallel,
batch3 working devs, on the maintainer's word in this session's chat (「改为并行派发,batch 3」, 「继续派发」).- objectui#11815 went to
needs-user-decision(6051653391), which freed this slot. - Working with this card: objectui#11804's dev and objectui#11813's.
- objectui#11815 went to
Why
Clause-②: no: the inspector stops offering fields a separator cannot hold. No export, prop,@object-ui/typesmember or accepted input changes; the save already refuses those keys.objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11847,
"status": "done",
"branch": "claude/issue-11847-setup-nav-separator-fields",
"pr": "#11884",
"session": "session_01DrKzdPdyLLBW3qpZ4vtk7z — the parent's (mode:subagent); the same id is in the commit's Claude-Session trailer and the PR footer",
"premise_still_valid": true,
"summary": "Setup's app editor (AppNavInspector) no longer offers Label or Icon on a separator entry. It shows the existing separator note (engine.inspector.appNav.separatorHint, the string Studio already shows) and no text field. Page, object and every other entry keep both fields. The rule is one module-level helper, navEntryOffersField(type, key), in inspectors/nav-target.ts beside retypedNavEntry. An entry is offered a describing field exactly when its spec member declares it, read from the same two key tables retypedNavEntry keeps. null (untyped or legacy) gets the shared base, as before. The helper is not on the package entry. Studio ADOPTED it: StudioNavItemInspector's one separator decision (kind === 'separator' ? hint : labelField) now reads navEntryOffersField(kind, 'label') ? labelField : hint. The two agree for every spec type and for null, so Studio's behaviour is unchanged and objectui#11790's pins stay green. Spec measured on installed @objectstack/spec 17.7.0: the separator member declares type, id and order; the other nine declare label and icon. H1 holds: measured through the real component before the edit, typing a label on a separator wrote {id:'nav_sep_reports', label:'Reports', type:'separator'}, which NavigationItemSchema refused with unrecognized_keys [label]. H2 holds: Studio hid only its Label field on a separator, through that ternary; it has no Icon field, and retypedNavEntry keeps id and order only. H3 holds: opening a separator writes nothing, even with a stray label (pinned). After the fix the edits Setup offers on a separator are reorder, remove and retype to one of its six types. A reorder moves the entry as is, and a retype writes a non-separator, so no edit writes a refused key and nothing rewrites on open.",
"tests": {
"head_for_gate_union": "b30a655 (merge of origin/main bee5d6f into the fix commit 74f7f63; pushed, PR head reads b30a655)",
"gates": [
"bash os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build" (29 packages, on b30a655) -> exit 0 -> 'os-verify-lock: VERDICT command-exit 0 · held the lock 149s'",
"bash os-verify-lock.sh -c 'pnpm --filter @object-ui/app-shell type-check' (tsc --noEmit && tsc -p tsconfig.test.json, on b30a655) -> exit 0 -> 'os-verify-lock: VERDICT command-exit 0 · held the lock 82s'; coverage: tsc -p tsconfig.test.json --listFilesOnly lists both touched test files and AppNavInspector.tsx / nav-target.ts",
"bash os-verify-lock.sh -c 'pnpm exec vitest run' over 19 files (on b30a655) -> exit 0 -> 'Test Files 19 passed (19) / Tests 247 passed (247)'. Files: the new AppNavInspector.separatorFields-11847, AppNavInspector.labelInherits-11196, nav-target.navEntryTypes-11790 (extended), tests/nav-target, AppNavCanvas.labelLessBirth-11196 / labelMaps-11128 / navPayload-11776, StudioDesignSurface.navItemInspector / navItemInspectorLabel-11196 / navItemInspectorLabelMaps-11148 / navItemTypes-11790 / railSeparatorBadge-11791 (merged in), viewCacheInvalidation.guard (the only .guard.test. in app-shell), and six tests that name a touched file by path (homeRecoveryRedirectsFollowDeclaration-7373, apiErrorEnvelope, PackagesPage.confirmFlows-11784, StudioDesignSurface.designerRegistryMissing, packages-io.inflightShare-11797, scripts/tests/spec-symbol-ledger-app-shell-7265)",
"pnpm check:control-bytes -> exit 0 -> 'check-control-bytes: OK (scanned 7887 tracked text file(s); skipped 85 binary)'",
"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:spec-symbols -> exit 0 -> 'spec symbol derivation: 1476 files scanned against 5140 spec export names; 22 declared dialects, 0 untriaged collisions in 0 packages.'",
"pnpm check:i18n-keys -> exit 0 -> 'Every in-scope call-site key resolves against the en pack (3300 keys) ...'",
"pnpm check:i18n-dead-keys -> exit 0 (report-only; no key added or removed)",
"pnpm check:vi-mock-specifiers / check:vi-mock-inherit / check:vi-mock-override-shape -> exit 0 / 0 / 0 -> each 'OK (6591 tracked source file(s) ...)'",
"pnpm check:test-path-roots -> exit 0 -> 'check-test-path-roots: OK'",
"node scripts/check-changeset-presence.mjs -> exit 0 -> '5 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11847-setup-nav-separator-fields.md.'",
"node scripts/check-changeset-no-major.mjs -> exit 0 -> 'No changeset declares a major bump.'",
"node scripts/check-governed-queue-guard.mjs --test (the 6 diff paths) -> 'NOT GOVERNED — 6 path(s) checked against 5 governed surface(s); none matched.'",
"eslint, narrowed (package lint form, inline config honoured) over the 5 touched source/test files, on b30a655 -> --format json: 5 results, 0 errors, 28 warnings; per-file warnings equal the base and origin/main (AppNavInspector.tsx 15/15, StudioDesignSurface.tsx 13/13, nav-target.ts 0/0, nav-target.navEntryTypes-11790.test.ts 0/0, new test 0). NOT MEASURED: repo-wide pnpm lint, reason: CI-owned; the population is the 5 files named, not read from eslint's config. Invariance: eslint.config.js enables no type-aware linting, and the one local rule that reads other code (no-line-address-in-test-name) reads no filesystem."
],
"h1_pre_fix_measurement": "New pin file run on the untouched base source (6d8bf0c) -> exit 1 -> 'Tests 2 failed | 4 passed (6)': the no-Label pin failed with 'expected INPUT to be null' and the edit pin with issues [{code: unrecognized_keys, keys: [label]}] on {id: nav_sep_reports, label: Reports, type: separator}",
"reverse_check": "After the fix was committed (74f7f63), AppNavInspector.tsx was checked out at base 6d8bf0c. The mutation landed: navEntryOffersField count 0, disk blob c1ae899 equal to the base blob. The new pin file was run under a trap restore. Predicted direction: the first pin fails because the Label field is present. Observed exactly that: exit 1, 'Tests 2 failed | 4 passed (6)', 'a separator entry shows no Label and no Icon field' -> 'expected INPUT to be null', the edit pin -> unrecognized_keys [label]. Restored with git checkout HEAD: disk blob 5fda58a equals the HEAD blob, and git diff HEAD and git status were empty.",
"files_changed": [
".changeset/11847-setup-nav-separator-fields.md (new; @object-ui/app-shell patch)",
"packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsx",
"packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.separatorFields-11847.test.tsx (new)",
"packages/app-shell/src/views/metadata-admin/inspectors/nav-target.ts (one exported helper, navEntryOffersField; not on the package entry)",
"packages/app-shell/src/views/metadata-admin/inspectors/nav-target.navEntryTypes-11790.test.ts (new describe block for the helper)",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (StudioNavItemInspector separator ternary + its import line only)"
],
"deviations": [
"StudioDesignSurface.tsx: besides the one ternary the order opened, one import line (navEntryOffersField added to the existing nav-target import) changed, because the switch cannot compile without it. No other line, no NavTree region.",
"The helper's spec pin went into the existing nav-target.navEntryTypes-11790.test.ts, which reuses its spec-member walker (SPEC_MEMBERS / SPEC_BASE_KEYS), rather than a new file with a second copy of the walker. The file sits beside AppNavInspector in the same directory and pins nav-target.ts, which the seat's amendment opened.",
"Setup now shows the separator note in place of the Label field, mirroring Studio. It reuses the existing app-shell metadata-admin string engine.inspector.appNav.separatorHint (en and zh). No string table was edited, and nothing in packages/i18n.",
"Standard-text conflict, named rather than resolved silently: os-dev's cleanup step removes node_modules and the worktree once the PR is open; the order says to leave the worktree for the seat to remove. The worktree /home/user/objectui-issue-11847 is left in place, with node_modules, per the order.",
"The first narrowed eslint pass used --no-inline-config (objectstack's lint form). It showed 1 error, react-hooks/static-components in StudioDesignSurface.tsx, on a line carrying an inline eslint-disable, identical at base. objectui's package lint is plain eslint ., so it was re-run in that form: 0 errors. Not a finding.",
"git fetch origin main updated the shared refs/remotes/origin/main, as any fetch does. The merge was made by sha (bee5d6f) and nothing was reset or checked out by that ref name. The merge changed no package in app-shell's dependency closure (only app-shell and apps/console), and the closure build was re-run on b30a655 regardless."
]
},
"mcp_calls": "0 — no MCP GitHub tool called (reads were unauthenticated public REST GETs: issue 11847, its comments, PR 11884, comment 6049930430 for the report format)",
"api_writes": "2 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches, whose run executed POST /repos/objectstack-ai/objectui/pulls (#11884, draft; read-back 6896 bytes sent, 6896 stored, identical); (2) this os-dev-report comment through post-stamped: POST /repos/objectstack-ai/objectstack/dispatches -> POST /repos//issues/11847/comments. git push (the empty-branch probe plus two content pushes of the same branch, one budget item) is not a REST write. Zero label and zero assignee writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · Setup's nav inspector titles a separator by its positional selection id (navigation[N]): labelOf falls back to selection.id because the runtime's label rule names a separator nothing, a deliberate fallback per the code's own comment · polish, noted in PR Acceptance notes, not filed",
"carrier: the six-of-ten-types note already on objectui#11790 (not this card) · Setup's Type select shows its empty value on a separator, because inferNavItemType reads only Setup's six types · noted in PR Acceptance notes, not filed",
"carrier: none (承接者:无) · a separator already carrying a stray label (off-spec, hand-written) opens without a write, and Setup no longer offers a field to clear it, so its save keeps refusing it loudly with unrecognized_keys [label] until the entry is retyped or removed; no public door stores such an entry (the save refuses it), so there is no reach · noted in PR Acceptance notes, not filed",
"carrier: none (承接者:无) · AppNavCanvas.tsx keeps its own kind === 'separator' guard on inline rename instead of reading navEntryOffersField; the two agree today (undrilled drift; the file was import-only for this card) · noted in PR Acceptance notes, not filed"
]
}objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsReview: ACCEPT — PR objectui#11884 (head
b30a655) · file surface amendeddomain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· reviewed against the PR's file list and diff,git merge-tree, its check runs and the dev's report6052103030, read 2026-10-08T04:20Z.- Shape: draft →
main. The first line isFixes #11847, andClause-②: nostarts a later line. - File surface amended (as the order stated): claim
6051682613's surface gains two items.- One module-level helper,
navEntryOffersField(type, key), ininspectors/nav-target.tsbeside objectui#11790'sretypedNavEntry. It is not onpackages/app-shell/src/index.ts. StudioNavItemInspector's single separator decision inStudioDesignSurface.tsx, plus its import line. The diff there is that ternary, flipped to read the helper, and the import. No other line, and notNavTree.
- One module-level helper,
- Scope: 6 files, +282/−13. Inside the amended surface, plus the helper's pin added to the existing
nav-target.navEntryTypes-11790.test.ts, which reuses its spec-member walker instead of copying it. - Mechanism (measured on
@objectstack/spec17.7.0):- The separator member declares
type,idandorder, and the other nine members declarelabelandicon. - The helper reads the same two key tables
retypedNavEntrykeeps. - Setup now shows the existing
engine.inspector.appNav.separatorHinton a separator, in place of Label and Icon. No string table was edited. - Studio adopted the helper. It agrees with Studio's old ternary for every spec type and for
null, so objectui#11790's pins stay green.
- The separator member declares
- H1–H3 held.
- Measured before the edit: typing a label on a separator wrote
{type: 'separator', label}, whichNavigationItemSchemarefused withunrecognized_keys [label]. - Opening a separator, even one with a stray label, writes nothing (pinned).
- Measured before the edit: typing a label on a separator wrote
- Clause-② re-read: the new export is module-level and not on the package entry. No prop or accepted input changes.
noholds. - Tests:
- Local, on
b30a655(withmainbee5d6fmerged in): 19 files and 247 tests green. They include the nav inspector, canvas andStudioDesignSurfacenav suites, objectui#11791's rail pin and the view-cache guard. The type-check and the derivedcheck:*set are green. - Reverse check: with
AppNavInspector.tsxat base, 2 failed and 4 passed in the predicted direction (the Label input is present, andunrecognized_keys [label]returns). The restore was proven by blob hash.
- Local, on
- Overlap: an in-memory
git merge-treeis clean againstmainand against objectui#11879 and fix(plugin-grid): import type inference requires a date shape before Date.parse (objectui#11813) #11881. - CI at
b30a655: converging, none red at this read. The PR is queued when every check completes. - Noted, not filed (all in the PR's Acceptance notes):
- a separator is titled by its positional id;
- Setup's Type select shows an empty value on a separator (the six-of-ten-types note on objectui#11790);
- a hand-written stray label stays refused at save until the entry is retyped;
AppNavCanvas.tsx's own separator rename guard could read the helper.
- PR assignee: set by this seat to
huangyiirene.
Generated by Claude Code
- Shape: draft →
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsLanded: PR objectui#11884 →
main4373484domain:uiseat 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· verified 2026-10-08T04:46Z.- Merged through the merge queue at 2026-10-08T04:42:26Z, after it was queued at 2026-10-08T04:25:41Z.
- CI on head
b30a655before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones. check-governed-merges.mjs: not governed, +282/−13.
- CI on head
- Content check:
4373484is one squash commit on parentbfca7ec. It changes 6 files, +282/−13, the same as the PR.- 5 files are blob-identical to the reviewed head
b30a655. StudioDesignSurface.tsxinterleaves with PRs that landed in between. Its-U0patch-id matches (252fc75d…), and so does the whole diff's (97eee168…).
- Card: closed
completedby the PR'sFixes.pm:dispatchedwas removed in the same pass and read back. - On record: Setup and Studio now share one rule for which describing fields a nav entry type offers:
navEntryOffersFieldinnav-target.ts, with the file surface amended per the ACCEPT6052140155.
Generated by Claude Code
- Merged through the merge queue at 2026-10-08T04:42:26Z, after it was queued at 2026-10-08T04:25:41Z.
- added a commit that references this issue
on Oct 9, 2026
Filing gate ①: a product defect, class (c), a write a named producer makes that the contract refuses. Reach: Setup → an app's editor (
AppNavInspector, the inspector registered forapp) → select a separator entry (for example, showcase'snav_sep_reports). The inspector shows Label and Icon fields. Typing a label writes{ id: 'nav_sep_reports', type: 'separator', label: 'Reports' }, andNavigationItemSchema.safeParserefuses it withunrecognized_keys [label]. The save door parses the same strict member, so the edit is refused at save. Measured by the objectui#11790 dev through the real component, with a dev-only probe that was not committed.Who acts on it: objectui triage, grade and route. ⛔ Not a claim. Filed by the
domain:uiexecution seat 1 (session_01DrKzdPdyLLBW3qpZ4vtk7z) from the objectui#11790 dev report (6049930430, out-of-scope finding 1).What happens
type/id/orderand nothing else. A separator declares nolabeland noicon.packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsxrenders its Label and Icon fields for every entry, separators included.The Studio side is handled. PR objectui#11846 (objectui#11790) makes Studio's nav inspector build a separator from
id/orderonly, and the nav canvas no longer offers inline rename on a separator card. Setup's app editor is a separate inspector.Done when
Duplicate check
Dedupe words: AppNavInspector separator label · setup app editor separator unrecognized_keys label · nav inspector separator icon field
Generated by Claude Code