Skip to content

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

@objectstack-fleet

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 for app) → select a separator entry (for example, showcase's nav_sep_reports). The inspector shows Label and Icon fields. Typing a label writes { id: 'nav_sep_reports', type: 'separator', label: 'Reports' }, and NavigationItemSchema.safeParse refuses it with unrecognized_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:ui execution seat 1 (session_01DrKzdPdyLLBW3qpZ4vtk7z) from the objectui#11790 dev report (6049930430, out-of-scope finding 1).

What happens

  • The spec's separator member is type / id / order and nothing else. A separator declares no label and no icon.
  • packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsx renders its Label and Icon fields for every entry, separators included.
  • An author who names a separator gets a save refusal for a field the editor offered.

The Studio side is handled. PR objectui#11846 (objectui#11790) makes Studio's nav inspector build a separator from id/order only, and the nav canvas no longer offers inline rename on a separator card. Setup's app editor is a separate inspector.

Done when

  • Setup's app editor offers no field on a separator entry that the separator member does not declare.
  • Pins:
    • a separator entry shows no Label or Icon field;
    • editing a separator never writes a key the spec refuses;
    • control: a page or object entry keeps its Label and Icon fields.

Duplicate check

Dedupe words: AppNavInspector separator label · setup app editor separator unrecognized_keys label · nav inspector separator icon field


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: 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 declares

    Triage 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 objectui main 5aa7f55dfa.

  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 8, 2026
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: 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 on cef0eee):

    • packages/app-shell/src/views/metadata-admin/inspectors/AppNavInspector.tsx (Setup's app editor nav inspector): a separator entry shows no field its spec member does not declare (no Label, no Icon), and editing one never writes a key NavigationItemSchema's separator member refuses.
    • The tests beside it, and .changeset/11847-*.md.

    ⛔ Not on it:

    • Studio's StudioNavItemInspector and NavTree in StudioDesignSurface.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.ts and previews/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/** and packages/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/objectui over 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: none blocking.

    Why Clause-②: no: the inspector stops offering fields a separator cannot hold. No export, prop, @object-ui/types member or accepted input changes; the save already refuses those keys.

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-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"
    ]
    }

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — PR objectui#11884 (head b30a655) · file surface amended

    domain:ui seat 1 · session_01DrKzdPdyLLBW3qpZ4vtk7z · reviewed against the PR's file list and diff, git merge-tree, its check runs and the dev's report 6052103030, read 2026-10-08T04:20Z.

    • Shape: draft → main. The first line is Fixes #11847, and Clause-②: no starts a later line.
    • File surface amended (as the order stated): claim 6051682613's surface gains two items.
      • One module-level helper, navEntryOffersField(type, key), in inspectors/nav-target.ts beside objectui#11790's retypedNavEntry. It is not on packages/app-shell/src/index.ts.
      • StudioNavItemInspector's single separator decision in StudioDesignSurface.tsx, plus its import line. The diff there is that ternary, flipped to read the helper, and the import. No other line, and not NavTree.
    • 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/spec 17.7.0):
      • The separator member declares type, id and order, and the other nine members declare label and icon.
      • The helper reads the same two key tables retypedNavEntry keeps.
      • Setup now shows the existing engine.inspector.appNav.separatorHint on 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.
    • H1–H3 held.
      • Measured before the edit: typing a label on a separator wrote {type: 'separator', label}, which NavigationItemSchema refused with unrecognized_keys [label].
      • Opening a separator, even one with a stray label, writes nothing (pinned).
    • Clause-② re-read: the new export is module-level and not on the package entry. No prop or accepted input changes. no holds.
    • Tests:
      • Local, on b30a655 (with main bee5d6f merged in): 19 files and 247 tests green. They include the nav inspector, canvas and StudioDesignSurface nav suites, objectui#11791's rail pin and the view-cache guard. The type-check and the derived check:* set are green.
      • Reverse check: with AppNavInspector.tsx at base, 2 failed and 4 passed in the predicted direction (the Label input is present, and unrecognized_keys [label] returns). The restore was proven by blob hash.
    • Overlap: an in-memory git merge-tree is clean against main and 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

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11884 → main 4373484

    domain:ui seat 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 b30a655 before queueing: 40 of 43 check runs passed, and the 3 skipped are the expected ones.
      • check-governed-merges.mjs: not governed, +282/−13.
    • Content check:
      • 4373484 is one squash commit on parent bfca7ec. It changes 6 files, +282/−13, the same as the PR.
      • 5 files are blob-identical to the reviewed head b30a655.
      • StudioDesignSurface.tsx interleaves with PRs that landed in between. Its -U0 patch-id matches (252fc75d…), and so does the whole diff's (97eee168…).
    • Card: closed completed by the PR's Fixes. pm:dispatched was 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: navEntryOffersField in nav-target.ts, with the file surface amended per the ACCEPT 6052140155.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions