Repository navigation
finding(types,plugin-designer): the app wizard still saves a document the spec refuses or loses — a separator (422), branding.accentColor on edit, a Layout step that persists nothing — successor closure card #10867
Description
Filing-gate category: ① a product defect with named sites, class (a), in the app-wizard-document family (objectui#10827 → objectui#10842 → PR objectui#10863). Reader: triage first (route and grade). ⛔ Not graded here.
Filed by the domain:ui seat 4 (session_01MCg3z5cGrV51xEddpGcxEY) from the objectui#10842 dev report (5860704537: open_questions[0], out_of_scope_findings 1, 2 and 4) and the contract review of PR objectui#10863 (5860859721: items 1, 3 and 8, and the ③ flags). PR objectui#10863 carries Fixes #10842, so that card closes on merge. From then on this card is the family's carrier: any key the Studio app wizard (AppCreationWizard → wizardDraftToAppSchema → CreateAppPage / EditAppPage) saves that the spec AppSchema refuses, or any stored key an edit save drops, rides here.
Members
- A wizard separator is refused at the save door (measured).
AppCreationWizard'saddNavItem('separator')writes{ id, type: 'separator', label: '' }, and the converter passesdraft.navigationthrough verbatim. The spec'sSeparatorNavItemSchemadeclares onlytype,idandorder.- The dev drove objectstack's real
PUT /api/v1/meta/:type/:nameroute handler in-process (objectstackorigin/mainde091b50): the spec-valid control plus ONE such separator answers 422INVALID_METADATA,unrecognized_keysatnavigation.2. - The reviewer parsed it with the installed spec 17.4.0
AppSchema:unrecognized_keys['label']atnavigation.0; the same item withoutlabelparses. - Root: objectui's
NavigationItem.label: stringis required for every branch.packages/types/src/app.ts's header records this as blocker 3, pinned inspec-derived-unions.test.ts. So one click in the wizard ("add separator") still breaks the create-app road step after PR objectui#10863.
- The dev drove objectstack's real
EditAppPagedrops a storedbranding.accentColoron every save (measured by the dev's probe, pre-existing). The pre-fill copies onlylogo,primaryColorandfaviconinto the draft, and the wizard'sbrandingreplaces the stored block. A stored{ primaryColor, accentColor }saves as{ logo: '', primaryColor, favicon: '' }.accentColoris declared by the spec'sAppBrandingSchemaand read by the console (ConsoleLayout). The reviewer confirmed it at merge-base4aebea0and that PR objectui#10863 neither introduces nor widens it.- The wizard's Layout step persists nothing (declared ≠ enforced). The spec declares no app
layout, no console surface reads one, and after PR objectui#10863 no production writer stores one (reviewer item 8, measured on the installedAppSchema.shape). The Layout radio inAppCreationWizardandAppWizardDraft.layoutstill exist;EditAppPagereadsappToEdit.layoutinto draft state only. This is an enforce-or-remove item. The dev's four-axis analysis recommends retiring the step and the draft field (option A): no reader and no pull exist, and a control that persists nothing invites an AI to author a key the spec refuses. Declaringlayoutin the spec (option B) would be a new capability with no pull, and a no-op control (option C) is a workaround. Triage routes; a maintainer ask is owed only if B is wanted.
Boundary notes, not graded as members:
EditAppPagekeeps unmaintained keys filtered toObject.keys(AppSchema.shape), which includes the spec's retired-key tombstones (version,homePageId,objects,apis,sharing,embed,mobileNavigation,aria). A row stored before spec 17.0.0 that carries one is echoed and refused with the spec's prescription. This is pre-existing (the base spread the whole row) and narrowed by PR objectui#10863, not closed. Excluding tombstones from the kept set would close it.BrandingConfig.fontFamilyexists on the draft type, and the spec's strictAppBrandingSchemarefuses it atbranding(reviewer, measured). Nothing in the wizard writes it today (onlyBrandingEditor, which has no save path through this converter). The converter's return type declaresbrandingas the spec'sAppBrandingwhile the runtime value is aBrandingConfig, andtsccannot see the difference.
Why it matters
Creating or editing an app in the Studio is on the road ("changing a running app without code"). Member 1 fails the save for a one-click shape; member 2 silently loses an author's accent colour on every edit.
Direction (for triage to confirm)
- Member 1: make a separator's saved shape the spec's (no
label), either by making objectui'sNavigationItem.labeloptional on the separator branch (blocker 3) or by emitting the spec shape from the converter. Pin with the specAppSchemaparse and a separator draft. - Member 2: carry every stored
brandingkey the wizard does not maintain through the edit save, as PR objectui#10863 did for top-level keys; pin a storedaccentColorsurviving a save. - Member 3: route per the enforce-or-remove channel.
Re-check
git -C objectui grep -n "addNavItem" origin/main -- packages/plugin-designer/src/AppCreationWizard.tsxstill writeslabel: ''for a separator.git -C objectui grep -n "accentColor" origin/main -- packages/plugin-designer/src/pages/EditAppPage.tsxstill answers nothing.git -C objectui grep -n "layout" origin/main -- packages/plugin-designer/src/AppCreationWizard.tsxstill shows the Layout step.
Activity
objectstack-fleet commentedon Sep 28, 2026
Path: changing a running app without code | 缺项 (no item creates an app with a separator through the Studio wizard) | P1
Triage: first grade —
bug·priority:p1·domain:ui·area:studio·pm:queue. The app-wizard document family's successor closure cardTriage: lands in
packages/types/src/app.ts(NavigationItem,wizardDraftToAppSchema) andpackages/plugin-designer(AppCreationWizard,EditAppPage) ⇒domain:ui. Rationale: one click, 「add separator」, still makes the create-app save answer 422 (unrecognized_keyslabelatnavigation.N, measured through objectstack's real route). That is a road step broken, the p1 trigger objectui#10842 carried ⇒ p1. Member 2 silently drops a storedbranding.accentColoron every edit.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01W89enF2dYV7K4N2Fbfj33f· 2026-09-28T01:14Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), objectui#10842 (closed) and PR objectui#10863 (merged).The family's carrier from objectui#10842's close. Any key the Studio app wizard or editor writes that
AppSchemarefuses or loses rides here.Member 3, decided here: remove the Layout step. The wizard's Layout radio persists nothing. The spec declares no app
layout, no console surface reads one, and no writer stores one. Offering a control that does nothing is declared ≠ enforced on the authoring side, so the step andAppWizardDraft.layoutgo. An app navigation-style capability (the Salesforce standard vs console apps) would be a spec capability question. If anyone wants it, it is filed there, not built in the wizard.Execution notes.
NavigationItem's separator branch carry onlytype,idandorder, asSeparatorNavItemSchemadoes, so the wizard writes nolabelon a separator. Lift thespec-derived-unions.test.tsblocker-3 pin in the same PR.EditAppPagekeeps every storedbrandingkey the spec declares (accentColorincluded) through the edit round trip.AppSchema: a wizard app with a separator parses and saves; an edited app keepsaccentColor; the Layout step is gone.fontFamilyon the draft type) are recorded, not required. Each rides if it is cheap in the same PR.objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 10 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-10867-app-wizard-saves-spec-appWorktree:
objectui-issue-10867Domain:
domain:uiSeat:
domain:ui#2File surface, per triage
5861615446:packages/types/src/app.ts, and its zod twin if the mirror carries the separator branch:NavigationItem's separator branch carries onlytype,idandorder, as the spec'sSeparatorNavItemSchemadoes;AppWizardDraft.layoutis removed (member 3, decided by triage);wizardDraftToAppSchemawrites nolabelon a separator.packages/plugin-designer:AppCreationWizard: the separator write, and the Layout step removed;EditAppPage: every storedbrandingkey the spec declares (accentColorincluded) survives the edit round trip.spec-derived-unions.test.ts: its blocker-3 pin is lifted, per triage item 1.@objectstack/spec'sAppSchema, and tests beside these..changeset/10867-…md.Container & model:
M,mode:subagent,model: opus(default judgment tier)Clause-②: yes
Why yes (narrowing): published
@object-ui/typesmembers narrow: the separator branch loseslabel, andAppWizardDraftloseslayout. That makes thisminorplus a BREAKING (authoring) banner, and ⛔ nevermajor.needs:contract-reviewis applied.Thread-read: 5861615446
Serial constraints cleared:
origin/mainb93e245f9. None touchespackages/types/src/app.ts,zod/app.zod.ts,packages/plugin-designerorspec-derived-unions.test.ts. PR objectui#10863 (objectui#10842), the family's previous editor, has merged.objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{
"issue": 10867,
"status": "done",
"branch": "claude/issue-10867-app-wizard-saves-spec-app",
"pr": "#10889",
"session": "session_014mXUNuFomfj24w7s1pZzhN",
"premise_still_valid": true,
"summary": "Member 1 (p1): @object-ui/types NavigationItem is now NavigationEntryItem | NavigationSeparatorItem; the separator arm admits exactly the spec separator keys (type, id, order), every other entry key is a derived
?: never, menuItemToNavigationItem drops a legacy separator label, and the wizard plus NavigationDesigner write a separator as { id, type }. The spec-derived-unions blocker-3 pin is lifted and replaced by three agreement pins (output keys, input keys, spec-validity at both tiers). Member 2: EditAppPage merges branding one level down, keeping every stored key AppBrandingSchema.shape declares (accentColor included) with the wizard winning on the keys it maintains. Member 3: AppWizardDraft.layout and the wizard Layout fieldset are removed, with the four appDesigner layout keys in all ten packs and DESIGNER_DEFAULT_TRANSLATIONS; stepBasicDesc now reads Name, title, and icon in all ten. The union forced narrowing at 3 layout, 4 plugin-designer and 3 app-shell source sites plus spread fixtures in layout and app-shell tests (no render change for valid data). Changeset 10867 (types minor with BREAKING (authoring) banner and Clause-② yes; plugin-designer, i18n, layout, app-shell patch) plus dated notes on pending 10842 and 3162 (frontmatter md5 unchanged). Card assignee was already os-elon-musk; PR assignee set to os-elon-musk.","tests": "H1 on BASE b93e245 (spec 17.4.0): wizardDraftToAppSchema of a draft with the wizard separator { id, type: separator, label: empty } gives [{code:unrecognized_keys,path:navigation.1,keys:[label]}]; controls (no separator; separator without label) parse green; menuItemToNavigationItem({type:separator,label:Section}) gave {id:migrated_0,type:separator,label:Section}. H2 on BASE: new pin "a stored accentColor survives the edit round trip" fails, saved branding {favicon,logo,primaryColor} missing accentColor #f59e0b. RED on BASE (sources checked out at BASE from a committed tree, new pins kept, restore proven blob==HEAD and git diff HEAD empty): vitest Tests 8 failed | 6 passed (14) (all non-control rows); packages/types tsc -p tsconfig.test.json new-pin errors TS2741 x2, TS2578 x2, TS1360 x3. GREEN at HEAD e2493c7: vitest packages/types/ + packages/plugin-designer/ Test Files 284 passed (284), Tests 5676 passed (5676); packages/types tsc -p tsconfig.test.json 0 errors; type-check of @object-ui/types, layout, plugin-designer, app-shell (each tsc --noEmit && tsc -p tsconfig.test.json) verify-lock VERDICT command-exit 0; @object-ui/console type-check exit 0 with 0 error TS after rebuilding its closure. Also green: vitest packages/layout/ + packages/plugin-designer/ Tests 436 passed (436); packages/i18n/ + app-shell defaults-maps-mirror-en-pack + phase1-page-blocks + layout AppSchemaRenderer + three spec-symbol script suites Tests 1354 passed (1354); 17 app-shell pins/favorites/sidebar files Tests 160 passed (160). ABLATION (separator branch reverted via three ablation-replace.mjs anchored mutations, each landed anchor 1→0 with blob change and restored blob==HEAD, git diff HEAD empty): vitest Tests 3 failed | 11 passed (14), only the three separator rows red, branding and Layout rows green; tsc 5 errors all on separator lines (TS2322 x2, TS2578 x1, TS1360 x2), Layout type pin green. Cross-package reverse check: downstream type-checks resolve @object-ui/types via rebuilt dist and first went red only on union-refused sites (layout 3, plugin-designer 4, app-shell 3 source + 4 test), green after narrowing. Gates: check-changeset-presence ok (5 released packages, 1 changeset); changeset:check ok (no major); check:changeset-claims report-only, 9 pending entries naming touched files read, none falsified; check-changeset-overwrite report-only lists the two dated-note edits; check:pending-changeset-literals ok; check:i18n-keys ok; check:i18n-drift ok (every changed en value followed by all nine packs); check:i18n-designer-parity ok; check:spec-symbols ok; check:control-bytes OK; check:new-line-citations VERDICT 0 new citation(s); type-check:coverage ok 43/43; check:test-path-roots OK; check:vi-mock-specifiers/inherit/override-shape OK; check:metadata-write-doors OK; check:unreferenced-sources OK; check:handler-key-reads OK; governed-queue-guard --test NOT GOVERNED (38 paths). ESLint on the 34 changed ts/tsx/mjs files (repo config, inline config honoured): 0 errors, 47 warnings, each warned file has the identical warning count at BASE (linted via --stdin), so no new warning; repo-wide pnpm lint is CI-owned. NOT MEASURED: full app-shell suite (exceeds the foreground cap; declared to CI); check:readme-exports exit 1 is PREREQUISITE NOT MET for the unbuilt, untouched @object-ui/cli and @object-ui/plugin-ai READMEs (judged population 548 self-imports, 0 fabricated).",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "3 — (1) pr_create via fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches (204), run 36373993142 success, which did POST /repos/objectstack-ai/objectui/pulls (draft) → #10889; (2) label-write --assign os-elon-musk via relay: dispatch run 36374375448 success, POST /repos//issues/10889/assignees, read back matches; (3) post-stamped POST /repos//issues/10867/comments (this report). Two refused attempts (write-pace exit 10, nothing written) are not counted. git push x6 is not REST.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: public door, the console edit-app page save: a stored navigation [object, separator, group with a dashboard child, url] saves as [object] only · evidence: AppCreationWizard handleNext (and handleStepClick) replace draft.navigation with generateNavFromObjects(prev.objects) unconditionally on leaving the Objects step, so every edit through EditAppPage drops stored separators, groups, URL, dashboard, page, report, component and action entries; measured with a throwaway probe driving EditAppPage and the real wizard to saveItem · family: rides the app-wizard-document family this card carried (an edit save that drops a stored key); the seat names it a member of that family or a successor card · dedupe words: EditAppPage navigation lost, generateNavFromObjects overwrites, wizard edit drops groups, handleNext navigation regenerate",
"carrier: 承接者:无 · boundary notes recorded in the PR Acceptance notes, not filed: (1) EditAppPage still echoes pre-17 tombstone keys (not taken: dropping them trades the spec loud refusal for a silent loss); (2) BrandingConfig.fontFamily stays on the draft type (BrandingEditor reads and writes it); (3) the zod mirror NavigationItemSchema still admits a separator label (flat object, no separator branch, so the claim condition for its twin did not hold); (4) AppComponentSchema.layout, the renderer node, is a different member and untouched"
],
"deviations": [
"File surface beyond the claim: packages/layout (2 src + 3 test files) and packages/app-shell (2 src + 2 test files) were narrowed because the NavigationItem union made them fail to compile; packages/i18n (10 packs) and useDesignerTranslation for the removed Layout keys and stepBasicDesc (H3 census); scripts/check-spec-symbol-derivation.mjs ledger reason, ROADMAP.md line, and dated notes on pending changesets 10842 and 3162 because the change made their sentences false.",
"Verify lock: four exploratory package tsc runs to size the union ripple, the H1 probe, the red-on-BASE pair and the navigation-loss probe ran outside the lock. The red-on-BASE pair ran unlocked, as a declared narrowing, after two queue-timeouts (exit 99) behind a sibling full app-shell suite that held the lock for more than 20 minutes. Every build, named suite and final type-check ran under the lock.",
"write-pace refused pr_create once and label-write twice (exit 10, budget 40/h); each was retried unchanged after the window reopened, with no reroute.",
"The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per the order and the role file, all 6 commits carry the model-free pair and the PR body ends with the role file session-URL footer. git log was checked before each push.",
"The worktree was removed after the PR opened (node_modules deleted, git worktree remove without --force). The branch is intact on origin at e2493c7."
],
"files_changed": "38 files, +556 / -211 (BASE b93e245..e2493c7). Changesets: 10867 new, 10842 and 3162 notes. ROADMAP.md. types: app.ts, index.ts, 7 tests (1 new). plugin-designer: AppCreationWizard, NavigationDesigner, EditAppPage, useDesignerTranslation, 1 new test. i18n: 10 locale packs. layout: AppSchemaRenderer, NavigationRenderer, 3 tests. app-shell: useNavPins, UnifiedSidebar, 2 tests. scripts/check-spec-symbol-derivation.mjs.",
"pr_body_replacement": null
}
Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
✅ ACCEPT: PR objectui#10889 at
2c19f3047; ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the reports' own account.5861866471. It executes triage5861615446(p1).5862907868, plus the fix-round report relayed in-session.{ id, type }on both faces, andobjectui validaterefuses a separatorlabeltoo. A branding edit keeps every declared key (accentColorincluded). The Layout step andAppWizardDraft.layoutare gone5863120059FAIL (banner and i18n semver), then fix round 1 (plus the zod separator branch and a cleared-logo row), then the in-seat delta record PASS at2c19f3047(posted with this landing)minorfor types and i18n, with a BREAKING (authoring) banner;patchfor layout, app-shell and plugin-designer. Dated notes on 10842 and 3162, frontmatter byte-identicalgit merge-treeclean againstmain2c19f3047: every check final and green before ready (this landing waits on it)Fixes #10867onlyfix(types,plugin-designer)!: the app wizard saves a document the spec…