Repository navigation
fix(studio): a Data rail switch sends the pending edit first; a broken CEL formula stays held after the inspector closes and keeps its returnType (#27511, #27485) - #27617
Draft
objectstack-fleet[bot] wants to merge 8 commits into
Conversation
…ommit The WIP commit carried both cards' code. The close arm (the CEL verdict kept with the draft after the inspector closes, its held line and its clause key) leaves here and lands again as its own commit, so it can be dropped on its own if the objectui#4306 sub-decision A ruling stands. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
…fore it switches objects (#27511) An edit made less than 1.5 s before a click on another object was dropped: the autosave's timer sends nothing once the open object has changed. The rail's switch now sends it with the autosave's own flush and opens the next object once the save has landed, waits out a save in flight, and asks before it drops an edit that cannot be sent. Pins the switch in DataPillar.railSwitchFlush-27511 and moves the objectui#11232 Data control to the new behaviour. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
…ver a held formula asks (#27485) The inspector settles returnType from the formula editor's lint and inferred type on one source: a source with a lint error proves no type, so the stored one stays. The object switch over an edit the CEL verdict holds asks first (the #27511 switch). Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
…aft (#27485) The inspector's CEL verdict was stamped with the selection, so closing it (Close, Escape, another field, another tab) released the hold and the autosave sent the broken expression. Each field's last verdict is now kept with a stamp of the CEL text it judged and holds while the draft carries that text; the held line names the field with a Show me that reopens it. Reverses the mechanism of objectui#4306 sub-decision A (reset on close) while keeping its invariants; separable on purpose. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
…-ufaqzz Brings in #27340 (ObjectFieldInspector, studio i18n) before the PR opens; no conflicts. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 29, 2026
…d sub-decision A's reset-on-close (#27485) The maintainer ruled letter A on #27485 (comment 6500685972, 2026-10-29T15:17Z): the Data pillar keeps the inspector's CEL hold on the draft, and objectui#4306 sub-decision A stands as its two invariants. The suite's header now names that ruling as what replaced the mechanism. Comment only. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
…-ufaqzz Brings in #27591 (ObjectFieldInspector API-name input, card #27517) and the rest of main; no conflicts. Claude-Session: https://claude.ai/code/session_01Utp6CbCrKUjGeTReNEmUJx Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 29, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Requested by Bill · project thread
维护者速读
useDraftAutoSave现有的flush把 1.5 秒防抖内的编辑发出去,存不了的先问;CEL 拦截从「检查器开着」改为跟草稿走,关检查器不再放行坏公式;坏公式不再清掉字段已存的returnType。returnType),切换对象会静默丢掉被拦的编辑。StudioDesignSurface.tsx的openObject与 CEL 判定保留(celVerdicts/fieldCelStamp);ObjectFieldInspector.tsx的settleFormulaType。record.est_hours > (,按 Esc 关检查器,出现「未保存」提示,点名该字段并带「Show me」,且没有发出保存。Fixes #27511
Fixes #27485
Clause-②: no
Metadata-protocol: none
What changes
#27511, the rail switch inside the autosave delay. The Data pillar's rail now opens an object through one
openObjectgate. With an edit pending inside the 1.5 s debounce, it calls the autosave's existingflushand opens the next object once that save has landed; a save already in flight is waited out the same way. An edit that cannot be sent (its save was refused, or Studio holds it as unfinished) goes through the existingconfirmDropUnsavedWorkquestion; declining keeps the open object and its edit. TherequestedSurfacedeep-link path uses the same gate. No second autosave path: the timer, the target guard and the single-flight ofuseDraftAutoSaveare untouched (only its comment now names the caller that flushes).#27485, returnType. The field inspector stamped
returnTypefrom the formula's inferred type on every edit, and a source that does not parse infersunknown, so each broken keystroke cleared the stored type.settleFormulaTypenow settles the stamp only once the editor's lint verdict and inference verdict are both in for the same source: a source with a lint error keeps the stored type; a clean source stamps its proven type, or clears it when none is proven, as before. The order of the two async callbacks does not matter.#27485, switch arm. A switch over a held edit (a CEL error) never flushes; it asks through the same gate as above.
#27485, close arm (own commit 73b0ad8). The inspector's CEL count used to be keyed to the open field selection, so closing the inspector (Close, Escape, another field card, another tab) zeroed it and the autosave sent the broken expression. The pillar now keeps each inspector verdict with a stamp of the field's CEL-bearing properties and the field list (
fieldCelStamp). A kept verdict holds the save while the draft still carries that exact text, and ends when that text is edited, the field is removed, or the object reloads. While it holds, the pillar shows the existing held line with a new clause (engine.studio.held.celInvalid, en + zh) and Show me, which reopens the field; Studio's Publish refusal names it through the existing held-edit report.Why
Both cards are one defect form: a pending or held Studio draft edit was tied to the current selection (open inspector, object in the rail) rather than to the draft, so changing the selection dropped the edit or released its hold. Triage asked for exactly this: "The rail switch calls useDraftAutoSave's existing flush, or confirms first … with no second autosave path" and "Tie the CEL hold to the draft rather than to the inspector's selection, and preserve returnType."
Tests
DataPillar.railSwitchFlush-27511.test.tsx(new, 4): flush then switch sends one save to the old object with the new field and none to the new one; a save in flight is waited out; a refused save asks, a declined ask stays, an agreed ask drops it unsent; a switch with nothing pending opens at once and sends nothing.ObjectFieldInspector.returnTypeHeld-27485.test.tsx(new, 3): the card's repro keepsnumber; a source that parses again stampstext; a clean source that proves no type still clears it.DataPillar.celGate.test.tsx: new switch-arm case (asks; declined stays; agreed drops unsent); close arm: the hold survives the Close button, Escape, another field card and the Records tab, and the held line names the field; Show me reopens it and a fix releases the hold; removing the field ends the hold. The old case "drops the count when the inspector closes, so the draft cannot wedge unsaved" is removed (see Acceptance notes).StudioDesignSurface.autosaveSwitch-11232.test.tsx: the Data control case now expects the pending edit to go to its own object and still nothing to the newly opened one.Ablations, each through
scripts/ablation-replace.mjs, restored to HEAD with an emptygit diff HEADafterwards:setCurrent(o)settleFormulaTypewithout itserrors > 0guardconfirmDropUnsavedWorkline removed fromopenObjectAcceptance notes
File surface widened, seat-approved.
ui/packages/i18n/src/namespaces/studio/en.tsandzh.tsgain one key,engine.studio.held.celInvalid, for the held clause. The ui seat 3 seat approved this widening at 13:14:22Z on 2026-10-29.Conflict with objectui#4306 sub-decision A (ruled by the maintainer 2026-10-29T15:17Z: the close arm stays; sub-decision A's reset-on-close mechanism is replaced, its two invariants stand). The base test file restated the ruling as: "the host RESETS its own count when the selection changes or the inspector unmounts (ruling sub-decision A) — writability must never depend on a child's teardown running, or closing the panel on a faulty formula leaves Save wedged shut with no editor on screen to fix it", and pinned it with the case "drops the count when the inspector closes, so the draft cannot wedge unsaved". Studio Data › Form: closing the field inspector releases the CEL error hold and autosaves the broken formula (returnType dropped); switching object discards the held edit silently #27485's triage asks for the opposite at the close: "Tie the CEL hold to the draft rather than to the inspector's selection". This PR follows the card and keeps the ruling's two invariants instead of its mechanism: writability does not depend on a child's teardown (the verdict lives in host state, stamped to the draft), and the draft never wedges with no editor on screen (the held line names the field and Show me reopens it; editing the text, removing the field or reloading ends the hold). objectui#4306 itself was not readable from this session (403), so the quote above is the in-repo restatement. The close arm is its own commit, 73b0ad8, separable: at its parent 19ceb5d the four touched suites pass 25/25, so if the ruling stands, reverting 73b0ad8 leaves Studio object designer: an edit made less than 1.5 s before switching to another object in the rail is silently discarded (the autosave debounce never sends it and no confirm is shown) #27511, returnType and the switch arm intact (Studio Data › Form: closing the field inspector releases the CEL error hold and autosaves the broken formula (returnType dropped); switching object discards the held edit silently #27485 would then stay open for its close arm).
Ruling-ref: 6500685972
Commit shape deviation. The dispatch asked for one commit per card. A WIP commit holding both cards' code (5002d07) was pushed before the split; with no force push allowed, it stays, and 59a0510 takes the close arm back out so the following commits are one per card (e72223f Studio object designer: an edit made less than 1.5 s before switching to another object in the rail is silently discarded (the autosave debounce never sends it and no confirm is shown) #27511, 19ceb5d Studio Data › Form: closing the field inspector releases the CEL error hold and autosaves the broken formula (returnType dropped); switching object discards the held edit silently #27485 returnType and switch arm, 73b0ad8 Studio Data › Form: closing the field inspector releases the CEL error hold and autosaves the broken formula (returnType dropped); switching object discards the held edit silently #27485 close arm). A merge of
mainbrings in feat(ui): record-mode currency — each record shows its own currency; ISO 4217 code select pre-filled with the organization currency; no cross-currency totals; Studio currency section #27340, which also touchesObjectFieldInspector.tsxin another region; no conflict.Residual windows (not fixed here). The inspector lints 250 ms after the last keystroke. Escape or a switch inside that window can still read the previous verdict (a stale 0 releases nothing new, but the last keystroke's fault is unjudged). Reopening a held field: the inspector's mount report of 0 releases the hold for about 250 ms until its lint runs. Closing inside the window right after a fix can leave a false hold; reopening the field clears it.
Same defect class, not measured. The panel family's CEL hold (Validations and the other tabs, keyed by tab) has the same selection-keyed shape. Out of scope for both cards; noted, not filed.
CelPredicateFieldwas not touched; the returnType fix is wholly in the inspector.Verification
On head efb181a (after merging
mainat 1ed3360):pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design packages/app-shell/src/views/metadata-admin/inspectors: 460 files, 4610 passed, 1 skipped, 0 failed (under the verification lock).pnpm --filter @object-ui/app-shell type-check: exit 0 (after rebuilding@object-ui/core, whose newmeasureCellCurrencyexport feat(ui): record-mode currency — each record shows its own currency; ISO 4217 code select pre-filled with the organization currency; no cross-currency totals; Studio currency section #27340 brought in; the first run read the stale dist).pnpm --filter @object-ui/i18n type-check: exit 0.eslinton the 9 changed TS/TSX files: 0 errors (warnings are pre-existingreact-hooks/set-state-in-effectlines elsewhere in the surface).node scripts/pm/dispatch-gates.mjs --ran: 34 derived, 34 run, 0 not measured. 33 exit 0.pnpm --dir ui exec vitest run scripts/exited 1 on five 15 s timeouts while the 460-file run held the box; alone under the lock it was 1 timeout (check-vi-mock-inherit, a whole-tree sweep at 16 s), and that file alone is 83/83 green. None of the five reads a file this PR touches.node scripts/check-sdui-manifest.mjs: exit 0.node scripts/check-nul-bytes.mjs: exit 0.Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintis left to CI).main, one pull request. (two folded cards, one PR, per the dispatch)packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code