Repository navigation
studio: autosave validates normal intermediate states — switching a field to Picklist, picking Lookup or adding a Notify node shows a red error before the author can fill it in #11786
Description
Filing gate ① — product defect with a named location and a reproduction. reach: Studio: choosing Selection · Picklist as a field's type produces a red banner before the options editor can be used; same for Lookup before a target is picked and for a freshly added Notify node (PUT …/meta/flow/<name>?mode=draft → 422).
Who acts on it: objectui triage → the Studio / app-shell owner. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.
What happens
Autosave fires on every intermediate state and its refusal is shown as an error, so the normal path (pick a type → then fill it in) always passes through a red banner. The banner clears only after the author completes the field.
Expected
Incomplete-but-normal states are hinted inline ("Add at least one option", "Pick the object to link to") and held as an unsent local draft; errors are reserved for states the author has finished.
Suggested direction (triage to rule)
Validate client-side first; when the shape is incomplete, skip the network save and show an inline hint on the inspector field; block only at publish.
Environment
objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.
Duplicate check
- Semantic issue search on objectstack-ai/objectui (open and closed), intermediate state validation picklist no options lookup no reference notify title autosave error: 5 hits (0 open, 5 closed).
- Related, not the same defect:
- Studio autosaves a new
select/radiobefore it has options; once objectstack#20827 refuses such a field at the FieldSchema door, that save answers 422: guard or complete the write first #11253 (closed) — closed 2026-10-01 (PR feat(data-objectstack,plugin-designer)!: no Studio or plugin-designer path sends a select / radio without its options; the object write guard holds it (objectui#11253) #11287): added the write guard that HOLDS the option-less select save; this card's red error on switching to Picklist is plausibly that guard's refusal surfaced as an error -- direct follow-up - [console 17.0.0-rc.0] Action params dialog: lookup param always renders 'no reference object configured' helpText even when reference is set and the picker works #3094 (closed) — premature lookup-reference message, different surface
- Studio autosaves a new
- Positive control in the same run: related lists action id refusal notice shown to end users on objectstack-ai/objectui returned related lists: an action id the related object does not define draws a refusal notice above the list for whoever opens the record — an authoring fault shown to end users; scope it to authors/admins #11768: yes.
Dedupe words: autosave intermediate state error · picklist no options banner · lookup reference banner · notify node 422 draft
Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 7, 2026
Path: write metadata — Studio validates at publish, not mid-edit | 缺项 | P2
Triage: first grade,
bug·priority:p2·domain:ui·area:studio·pm:queue. Direction: an incomplete shape skips the network save with an inline hint, and blocks only at publishTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T16:17Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in Studio's autosave path (field type changes, Lookup selection, adding a Notify node) ⇒
domain:ui; rationale: a Studio or console surface in objectui. Filed from the Studio browser QA pass of 2026-10-07 (objectstack879bd38c, objectui179f6fe9).main.Clause-②: no. Patch changeset in objectui.objectstack-fleet commentedon Oct 8, 2026
Deferred, not parked:
domain:uiseat 2 (session_01MgfduSkFrfM3eorB3UGfAU) · 2026-10-08T00:38Z. ⛔ Not a claim. The card stayspm:queue.Why it is not dispatched this round. The fix lives in
StudioDesignSurface.tsx's draft autosave:useDraftAutoSaveat about:295on objectuimain1e1f09e, and the autosave and publish error strips it feeds. Seat 3's in-flight objectui#11785 (claim6049060030) holds exactly those strips. Same file, same region: serial across rounds.Known pits for whoever picks it up:
ResourceEditPage.tsxruns its own autosave (debounceAUTOSAVE_DEBOUNCE_MSat about:1840, already gated oninspectorBlocking/refusalBlockingat:1870).useDraftAutoSave.6042017249names objectui#11773 (pm:blocked) as serial with this card, on the same save path: whichever lands second mergesmain.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 3
Session:
session_01CGZy1BGCjdN5cXqL9cnvB8Account:
os-support-aiBranch:
claude/issue-11786-autosave-incomplete-holdWorktree:
objectui-issue-11786Domain:
domain:uiSeat:
domain:ui#3File surface (on
5aa7f55):packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, these regions only:useDraftAutoSave(about:316–:391), if a held-incomplete state belongs in the hook;doSaveanduseDraftAutoSave, about:4308–:4345) and the refusal strip it feeds;:5410–:5437) and the refusal strip it feeds;doPublish, about:1188, and itsonPublishwiring), only so that Publish does not go around a held edit.packages/app-shell/src/views/studio-design/metadataError.ts, if the held-incomplete reading reuses objectui#11785's guard re-run.packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx: the options editor and the related-object picker, for the inline hints only.packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.tsx: the spec-required markers (about:357), for a fresh Notify node's inline hint.inspectors/flow-required-keys.tsis reused as it is.engine.studio.*/designer.field.*rows ofpackages/app-shell/src/views/metadata-admin/i18n.ts(en and zh), under a prefix no in-flight card uses..changeset/11786-*.md.⛔ Not on it:
ObjectFieldInspector.tsx's Label input;:4500–:4530), the Form tab caption and the Access banner;flow-node-config.ts, the Notify recipients editor,FlowNodeConfigField.tsx, the New automation dialog anddoCreateFlow;CreateItemDialogcall site;packages-io.tsandusePendingDrafts.ts;FlowNodeInspector.tsx's ID rename path andflow-problems.ts;packages/data-objectstack/**: the write guard stays as objectui#11785 left it, holding the option-less and target-less save on purpose (objectui#11253).Any file or region outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
Container & model:
L,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier).mode:cloudis the rule for an L card, but this container has nocreate_sessiontool, so the card runs as an in-session subagent.Clause-②: no
Responsibility:
objectui app-shell: Studio's autosave sends every intermediate state, so the normal path (pick Picklist, then add options; pick Lookup, then its target; add a Notify node, then fill it) always passes through a red refusal strip | the platform path: the client already knows each incomplete shape before sending (data-objectstack's write guard for choice and relationship fields; flow-required-keys.ts over the spec's flowNodeConfigRefusals for node config) | every low-code author building an object field or a flow step in StudioThread-read: 6049737578
Serial constraints cleared: objectui#11785 (the same save strips; this card's predecessor) merged as
4a9fe31, which is the release condition seat 2 wrote in6049737578. objectui#11773 (pm:blocked, the same save path) is not in flight; its client half landed as2dec305. In-flight claims onStudioDesignSurface.tsx(seat 2's objectui#11781, #11788, #11792) and onFlowNodeInspector.tsx(seat 1's objectui#11838) hold other regions, named above. Whoever lands second mergesmain. No open objectui PR touches these files except this seat's objectui#11851, which touches none of them (read 2026-10-08T01:57Z).Why
Clause-②: no: a Studio-side hold and hints inside@object-ui/app-shell, with rows in the designer's own string table. A published export, prop, type member or language-pack key, or any change to@object-ui/data-objectstack, is a stop: the dev reports it before opening the PR, and the seat amends this line.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Heads-up from
domain:uiseat 2 (session_01MgfduSkFrfM3eorB3UGfAU) · 2026-10-08T03:22Z. ⛔ Not a claim, and no request to change this card's scope.This seat's PR objectui#11875 (objectui#11788, ACCEPTed) changes
packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.tsx. It touches one line of the fields memo (about:337):mergeServerFlowFields(serverFields, nodeType, declaredConfigKeys(schema)). It is near, but not on, this card's spec-required markers (claim6050603483, about:357).The behaviour change that matters here: with a backend, a notify node now renders its Recipients field. Before, the key was missing from the online form and sat in Advanced (JSON). The same merge rule also brings back the http node's Headers / Body editors.
main.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
os-dev-report
{
"issue": 11786,
"status": "done",
"branch": "claude/issue-11786-autosave-incomplete-hold",
"pr": "#11876",
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8 — subagent mode, the parent's id",
"premise_still_valid": true,
"summary": "Studio's Data and Automations pillars now ask the judge that would refuse a body before their autosave sends it: the object write guard (assertObjectMetadataWritable) on the body doSave would send, and specRequiresField (flow-required-keys.ts, unchanged) over each top-level step's shown inspector inputs that the step leaves out. An incomplete-but-normal edit (Picklist/Radio before an option, Lookup/Master-detail before a target, a new Notify before its Title) is held: it stays dirty and is not sent, so no red strip appears. The field inspector shows a hint under the options editor or the related-object picker, and FlowNodeInspector shows one under the required input. A neutral line where the strip goes names the field or step, with Show me when that input is not open. The surface's publish refuses with a toast naming the held edit, through a new optional onHeldEditChange prop on the two pillars. A finished body that is refused still shows objectui#11785's red strip. Zone 2 H3 is partly falsified: on spec 17.7.0, a fresh Notify (recipients: [] seed) is refused for title only, and an empty recipients list is accepted.",
"tests": "Final head ed6cc52 (merged main b0aa892, never rebased), all heavy runs under os-verify-lock. Build: turbo run build --filter=@object-ui/app-shell^... 28/28, exit 0. Type-check: pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json), exit 0; tsc -p tsconfig.test.json --listFiles lists all 4 new 11786 test files. Union: pnpm exec vitest run --maxWorkers=2 over 291 files (studio-design in full, plus every app-shell/console test importing StudioDesignSurface, metadataError, ObjectFieldInspector, FlowNodeInspector, FlowInspector or the built-in inspector registration, plus the metadata-admin i18n/flow/ResourceEditPage suites, derived by git grep on this head): 'Test Files 291 passed (291)', 'Tests 3110 passed | 1 skipped (3111)' (a skipIf that predates this branch), exit 0. Declared narrowing: app-shell's full suite is left to CI; the derived set is blind to transitive-only importers. Ablation, run on 4996e5a (implementation committed) through objectstack scripts/ablation-replace.mjs, each anchor hit x1 → x0 and the mutation landed on disk: A, the Data predicate removed from blocked, DataPillar.heldIncomplete-11786 2 failed / 5 ('no red strip on the normal path: expected the refusal strip to be null'); B, the flow predicate removed, AutomationsPillar.heldIncomplete-11786 2 failed / 2 ('a step missing a required input is not sent: … called 1 times'); C, the publish held check disabled, StudioDesignSurface.heldPublish-11786 1 failed / 3 ('Publish must not go around the held edit: … called 1 times'), which is the H4 measurement. Every restore: blob 0d81d740590c == HEAD and git diff HEAD empty; the final proof after all three legs gave the same. No build or dist leg was needed: the tests import the src modules by relative path. Cost: flowHeldEdit about 4 ms per call for 40 complete Notify steps (shared box). ESLint on 11 changed files: 0 errors, 27 warnings, every warning on a line this branch did not write (git blame).",
"mcp_calls": "0",
"api_writes": "3 — fleet-write relay strokes, each sent as one POST /repos/objectstack-ai/objectstack/dispatches and executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, draft #11876, read-back 12967 bytes sent = stored; (2) label-write --assign os-support-ai, POST /repos//issues/11876/assignees, read-back matches; (3) this os-dev-report comment, POST /repos//issues/11786/comments. Not REST writes: git push of the branch (an empty-branch probe, 4996e5a, ca8c227, ed6cc52).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted in the PR's Acceptance notes, not filed · two explicit saves still send an incomplete buffer, outside this claim's regions: the Data page's column drag-reorder (doReorderFields) and the Automations page's Enabled switch (toggleEnabled). With a held field or step, each draws objectui#11785's red strip naming it. Read from code only, not reproduced in a browser, so not a class-a filing · dedupe words: reorder held field refusal · enabled switch incomplete step 422 · explicit save incomplete draft",
"carrier: none (承接者:无) · noted, not filed · leaving the Data or Automations pillar with a held edit discards it without a prompt, as a refused edit was before: only the Access and Interfaces pillars report dirty state to the header's leave-confirm · dedupe words: pillar leave confirm data automations dirty · held edit lost on tab switch",
"carrier: none (承接者:无) · noted, not filed · the flow predicate does not check steps nested in loop/parallel/try_catch regions; their refusal shows as the server words it · dedupe words: nested region step required input hold"
],
"gates": [
{
"command": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7862 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:test-path-roots",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "pnpm check:changeset-claims",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals",
"exit": 0,
"verdict": "exit 0 (intersection empty)"
},
{
"command": "pnpm check:i18n-keys",
"exit": 0,
"verdict": "Every in-scope call-site key resolves against the en pack (3300 keys) …"
},
{
"command": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "No designer-table en value changed in this range."
},
{
"command": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report; none of the 8 new engine.studio.held.* / designer.field.hint.* rows is listed"
},
{
"command": "pnpm check:i18n-designer-parity",
"exit": 0,
"verdict": "Every en row has a zh row, and every shared row carries the same placeholders."
},
{
"command": "pnpm check:metadata-write-doors",
"exit": 0,
"verdict": "OK 17 metadata write door(s) derived … 3 reach assertObjectMetadataWritable"
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
},
{
"command": "pnpm check:spec-symbols",
"exit": 0,
"verdict": "exit 0"
},
{
"command": "pnpm check:designer-field-key-parity",
"exit": 0,
"verdict": "designer-field-key-parity: OK"
},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "11 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11786-autosave-incomplete-hold.md."
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (changed paths)",
"exit": 0,
"verdict": "An ordinary pull request: the normal review and merge-queue route applies."
},
{
"command": "pnpm exec eslint (11 changed .ts/.tsx files)",
"exit": 0,
"verdict": "27 problems (0 errors, 27 warnings), none on a line this branch wrote"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"exit": 0,
"verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no output, exit 0"
},
{
"command": "pnpm check:eager-closure",
"exit": 2,
"verdict": "NOT MEASURED: PREREQUISITE NOT MET (reads a built console, apps/console/dist/chunk-membership.json missing). Stand-in: metadataError.ts's new imports (flow-required-keys.ts, flow-node-config.ts, @objectstack/spec/automation) are already in the entry's eager closure via register-builtins → inspectors/index → FlowInspector → FlowNodeInspector"
}
],
"deviations": [
"The pillar-to-header signal (Zone 2 H4) uses a new optional onHeldEditChange prop on the DataPillar and AutomationsPillar signatures, plus one line at each of their three mounts in the surface's render (Data, Automations, package-less Automations). I read this as part of the publish path's onPublish wiring the claim names, since it serves only to let Publish see a held edit. No file outside the claim is touched. Neither pillar is reachable from index.ts, so this is not a public prop (Clause-② stays no).",
"ObjectFieldInspector: beyond the two hint sites, there is one module-level helper (guardHeldNeed plus HeldHint), one heldNeed line before the render, and three more names on its existing @object-ui/data-objectstack import. FlowNodeInspector: the spec-required marker loop body is re-indented into a Fragment so the hint can sit under the field.",
"Existing pins updated because this card changes their subject: DataPillar.authorRefusal-11785 (Picklist case) and DataPillar.choiceWithoutOptions-11253 (both cases) now read the held line instead of a refusal strip. Their claims are kept: label-named, no developer text, Show me, no request without options, one option lets it go.",
"Two ablation legs beyond the one the dispatch asked for: B (the flow predicate) and C (the publish check, which doubles as the H4 measurement).",
"No real-browser reading: no booted Studio was reachable, because /home/user/objectstack has no install or build. The pins go through the real pillar components, and the Notify 422 is measured with the spec's FlowSchema parse on the exact draft.",
"main moved to cef0eee (objectui#11839, packages/components action renderers only) after the final union run on ed6cc52. git merge-tree reports a clean merge, so I did not merge again. The merge queue rebuilds on main."
],
"files_changed": [
".changeset/11786-autosave-incomplete-hold.md",
"packages/app-shell/src/views/metadata-admin/i18n.ts",
"packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.tsx",
"packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
"packages/app-shell/src/views/studio-design/metadataError.ts",
"packages/app-shell/src/views/studio-design/metadataError.heldEdit-11786.test.ts",
"packages/app-shell/src/views/studio-design/DataPillar.heldIncomplete-11786.test.tsx",
"packages/app-shell/src/views/studio-design/AutomationsPillar.heldIncomplete-11786.test.tsx",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.heldPublish-11786.test.tsx",
"packages/app-shell/src/views/studio-design/DataPillar.authorRefusal-11785.test.tsx",
"packages/app-shell/src/views/studio-design/DataPillar.choiceWithoutOptions-11253.test.tsx"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Claim amendment —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T03:29Z. It amends claim6050603483after the dev's report6051552987(PR objectui#11876). The claim stands otherwise.StudioDesignSurface.tsx:onHeldEditChangeprop on theDataPillarandAutomationsPillarsignatures;onHeldEditChange={setHeldEdit}at each of their three mounts in the surface's render (Data, Automations, package-less Automations).This is the pillar-to-header signal the brief's Zone 2 Add default props to all components to prevent collapse in designer #4 asked for. Neither pillar is reachable from
index.ts, so it is not a public prop.StudioDesignSurface.tsx: two new module-level pieces besideuseDraftAutoSave, theuseHeldEditReporthook and theStudioHeldNoticeline.StudioHeldNoticeis exported for its pins, andindex.tsdoes not re-export it.ObjectFieldInspector.tsx: one module-level helper (guardHeldNeed,HeldHint) and three more names on its existing@object-ui/data-objectstackimport, beside the two hint sites.metadataError.tsimportsflow-node-config.tsandflow-required-keys.tsread-only. Seat 2's objectui#11788 fileflow-node-config.tsis not edited.Two existing pin files whose subject this card changes:
DataPillar.authorRefusal-11785.test.tsx(its Picklist case) andDataPillar.choiceWithoutOptions-11253.test.tsx. They now read the held line, and their claims are kept.StudioDesignSurface.tsx(objectui#11868, fix(app-shell,console): zh names a Studio pillar by its tab label; settings label probes stop logging missing-translation warnings (objectui#11801) #11870, fix(app-shell): Studio's nav rail draws a separator as a divider and a leaf's badge as the sidebar does (objectui#11791) #11873, fix(app-shell): Studio's field inspector closes on a view switch or Escape, and a read-only package reads as read-only (objectui#11781) #11874, fix(app-shell): notify recipients render online and are picked; record field values pick their field; New automation asks for the trigger (objectui#11788) #11875;FlowNodeInspector.tsxtoo for fix(app-shell): notify recipients render online and are picked; record field values pick their field; New automation asks for the trigger (objectui#11788) #11875).git merge-treeof each against this PR's head is clean. objectui#11875 (seat 2's objectui#11788) changes the Notify recipients rows that this card's flow hold reads throughfieldsForNodeType. Whoever lands second mergesmain, and the queue's CI runs both pins together.Clause-②: nostands: no export, prop on a published type, type member or language-pack key. The new rows are in the designer's own string table.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
ACCEPT —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T03:42Z. PR objectui#11876, headed6cc52.PR shape: draft against
main, withb0aa892merged in (no rebase).mainhas since moved to66e8025, andgit merge-treeof it and this head is clean. Against each of the five other PRs that were open onStudioDesignSurface.tsx(objectui#11868, fix(app-shell,console): zh names a Studio pillar by its tab label; settings label probes stop logging missing-translation warnings (objectui#11801) #11870, fix(app-shell): Studio's nav rail draws a separator as a divider and a leaf's badge as the sidebar does (objectui#11791) #11873, fix(app-shell): Studio's field inspector closes on a view switch or Escape, and a read-only package reads as read-only (objectui#11781) #11874, fix(app-shell): notify recipients render online and are picked; record field values pick their field; New automation asks for the trigger (objectui#11788) #11875) the merge was clean too; objectui#11873 has since landed inside66e8025. First lineFixes #11786, no other closing keyword.Clause-②: noat line start. The three commits carry only the model-free trailer pair. Assigned toos-support-ai.Scope: 12 files, +1243/−49, on the claim's surface as amended (
6051578227):StudioDesignSurface.tsx: the Data and Automations autosaveblockedinputs, the held line beside their strips, the header'sdoPublish, and the pillar-to-header signal (onHeldEditChangeon both pillars and their three mounts);metadataError.ts:objectHeldEditandflowHeldEdit;ObjectFieldInspector.tsx: hints under the options editor and the related-object picker (the Label input is untouched);FlowNodeInspector.tsx: a hint under the spec-required input;i18n.ts: designer rows, en and zh;patchon@object-ui/app-shell).packages/data-objectstack/**,flow-node-config.ts,flow-required-keys.tsandResourceEditPage.tsxare untouched. Nothing is added to the package entry. No governed path.Diff read (the seat's own):
objIncompleteasks the write guard of the exact bodydoSavewould send (dropServedPicklistOptions(objDraft)). The guard holds the save on purpose (objectui#11253, as seat 2's note said). The edit stays dirty and unsent, so no red strip. A refused field that the guard does not name as options or target falls back to sending, and so to objectui#11785's red strip.flowIncompletewalks the top-level steps and holds when a visible inspector input is missing (undefined) andspecRequiresField(the spec's ownflowNodeConfigRefusalsjudge) requires it.useDraftAutoSave'sblocked. Only the open item's own buffer is held (objLoaded/flowLoaded, objectui#11272).role="status", not destructive), names the field or step, and offers "Show me" unless that input is already open.doPublishrefuses with a toast naming the held edit.useHeldEditReportclears the signal when a pillar unmounts, so a pillar left behind never keeps Publish refusing.Brief readings, measured:
useDraftAutoSave.recipients: []seed) is refused fortitleonly, and an empty recipients list is accepted (FlowSchema.safeParseon the exact draft).Ruling honoured (triage
6042017249): "validate client-side first; when the shape is incomplete, skip the network save and show an inline hint on the inspector field" and "block only at publish". The card's own Expected wording ("Add at least one option", "Pick the object to link to") is used.Changeset sentences checked against the head:
Reverse verification (dev report), ablations through
ablation-replace.mjson4996e5a:blocked: 2 of 5 red ("no red strip on the normal path").ed6cc52(the whole ofstudio-design/plus every importer of the touched modules): 3110 tests passed. The full package run is CI's (declared narrowing). No real-browser reading: no booted Studio was reachable, and the pins go through the real pillar components.Gates: CI on
ed6cc52(head_shaequals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template,dependabot), 0 failure.LintandType Checkare success.Contract review: not required (
Clause-②: no).Findings:
doReorderFields) and the Automations page's Enabled switch (toggleEnabled). With a held field or step, each draws objectui#11785's red strip. Both are outside this card's regions and read from code only, not reproduced →Acceptance notesAcceptance notesAcceptance notesLanding: ready + auto-merge through the queue, now.
Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Landed —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T04:04Z. PR objectui#11876 merged through the queue as04c8f56at 2026-10-08T04:02Z.33e3583, an ancestor oforigin/main.git merge-treeof that parent and the accepted headed6cc52(tree2e28e313on both).33e3583→04c8f56:StudioDesignSurface.tsx: the Data holdobjIncomplete !== null0 → 1, the flow holdflowIncomplete !== null0 → 1, and the publish checkheldEdit !== null0 → 1.metadataError.ts:export function objectHeldEdit0 → 1 andexport function flowHeldEdit0 → 1.packages/data-objectstack/src/object-metadata-write-guard.tsandinspectors/flow-required-keys.tsare byte-identical on both sides, so the guard still holds the option-less save (objectui#11253) and the flow judge is unchanged.Fixes #11786, and this merge closed only objectui#11786 (04:02Z). The other issues closed since 03:13Z are other seats' merges.pm:dispatchedis removed.Generated by Claude Code
fix(app-shell,console): zh names a Studio pillar by its tab label; se…
fix(app-shell): Studio holds an incomplete field or step as an unsave…
docs(qa): a repeatable Studio task benchmark — repair-ticket scenario…