Repository navigation
Studio Data pillar panels and ResourceEditPage: a CEL parse-fault hold still ends when the tab or selection changes; port the draft-stamped hold ruled on #27485 #27629
Description
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Filing gate: ③ maintainer-directed. The maintainer's ruling on #27485 (comment 6500685972, maintainer 「同意」 2026-10-29T15:17Z), item 3: "Sibling surfaces are NOT widened in this PR: the Data pillar's panel family (objectui#4527, tab-keyed) and the environment door ResourceEditPage (selection-keyed) keep their mechanism until their own card. domain:ui#3 files that card: S/M, domain:ui · area:formula, "port the draft-stamped CEL hold to the Data pillar's panel family and to ResourceEditPage", with the residual flush-inside-250-ms edge named in it. Not paired with this PR."
What is wrong
The ruling on #27485 makes a CEL parse-fault hold belong to the draft: it lasts while the draft still carries the text the editor judged, and ends when that text is edited, the item is removed or the buffer reloads. PR #27617 does that for the Data pillar's field inspector only. Two sibling surfaces keep the old selection-keyed mechanism, so the same defect form stays there (read from the code, not yet measured on these surfaces; PR #27617 Acceptance notes 5). The first step of the card is one measured repro on each:
- Data pillar panel family (
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, the panel report next toblockingReport, objectui#4527): the Validations, Actions and Settings panels report their CEL faults keyed by tab. Leaving the tab with a broken expression in the draft zeroes the count, so the autosave would send the broken text. ResourceEditPage(ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx,inspectorBlocking = blockingReport.key === selectionKey ? … : 0): changing the selection releases the hold the same way.
Expected (per the ruling): the same rule as the field inspector after #27617. A kept verdict stamped to the judged text holds the save with the inspector or panel closed; the held line names the item with a "Show me" that reopens it; editing the text, removing the item or reloading ends the hold; the open editor's live verdict always wins. ⛔ No dialog on close, no silent revert, no second autosave path, no change to useDraftAutoSave's timer or single-flight (ruling item 4).
Residual edge to name and close
The editors lint 250 ms after the last keystroke. A flush (the Data rail switch from #27511) inside that window can read the previous verdict; reopening a held item reports 0 for about 250 ms until its lint runs. The timer path is safe (a falling blocked re-arms a fresh 1.5 s), so only flush inside the window can reach the server. PR #27617 Acceptance notes 4 records it.
Business reason
Every Studio and environment-admin author who writes a validation rule, action condition or resource CEL expression: closing or switching is the usual way to finish an edit, and today it lets a predicate the engine refuses into the draft, surfacing only at publish with no item named (QA checklist studio-authoring.expression-editors P1 acceptance[4], negative[1]). AI-authored expressions fail to parse routinely (ADR-0033), so the loud, named hold matters most there.
Who acts
domain:ui seat 3 dispatches it after PR #27617 merges (it reuses that PR's fieldCelStamp / kept-verdict shape). ResourceEditPage sits in metadata-admin, shared with ui seat 2's admin pages: the claim declares it.
Duplicate check
search_issues "CEL hold released when panel closes or tab changes, Data pillar panel family ResourceEditPage" on objectstack-ai/objectstack: 2 hits (#27485 open, the field inspector, ruled; #26705 closed, held edits dropped on pillar leave). Neither covers these surfaces.
Size: S/M (ruling). Related: #27485, #27511, PR #27617, objectui#4306, objectui#4527.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Claim: PM loop round 1
Session:
session_01Utp6CaJoinvGQSbHeDaWBeAccount:
os-billBranch:
claude/project-thread-9u7v4h(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27629Domain:
domain:uiSeat:
domain:ui#3File surface: the panel-family CEL report region and its held line in
DataPillar(ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx), the panels' report call sites (ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsxand the Actions / Settings panels) only if they must pass a stamp,ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx(CEL hold region only; shared with ui seat 2), studio held-clause keys inui/packages/i18n/src/namespaces/studio/en.ts/zh.tsonly if a new clause is needed, tests beside, root.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieron178b5238: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: ui code produces the defect | no platform path covers it | every Studio / console author reaches it today
Thread-read: none
Premise: holds
Serial constraints cleared: open PRs on StudioDesignSurface.tsx are #27575 (dataset pickers) and #27557 (seat 1, InterfacesPillar): other regions, merge
origin/mainbefore the PR; no open PR edits ResourceEditPage.tsx or ObjectValidationsPanel.tsx (checked at claim) ·useDraftAutoSave.tsuntouched by rulingRuling: maintainer ruling on #27485 (comment 6500685972), letter A, item 3 asks for this card; item 4 bars a close dialog, a silent revert, a second autosave path and any change to
useDraftAutoSave's timer or single-flight. Reference implementation: PR #27617 (merged).Dispatched 2026-10-29T17:36Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Generated by Claude Code
wip(studio): panel family and ResourceEditPage keep the CEL hold with…
fix(studio): panel family and ResourceEditPage keep a CEL hold with t…
objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CYaLJTMXdChBaqK9KL
os-dev-report
{ "issue": 27629, "status": "done", "branch": "claude/project-thread-9u7v4h", "pr": "https://github.com/objectstack-ai/objectstack/pull/27697", "head": "7484a82795ca27cd73f7d1b36fcbd03a821a9e8c", "session": "session_01Utp6CYaLJTMXdChBaqK9KL (card thread; seat session_01Utp6CaJoinvGQSbHeDaWBe)", "premise_still_valid": true, "surfaces": { "validations_panel": "reproduced, fixed", "actions_panel": "reproduced, fixed", "settings_panel": "not reproduced: ObjectDefaultInspector mounts no CEL editor; left out", "resource_edit_page": "reproduced, fixed" }, "summary": "Measured one repro per surface first: on main (5d759b1e) leaving the Validations or Actions tab, or clearing or changing the ResourceEditPage selection, let the autosave send the broken predicate (8/8 new cases failed). The Validations and Actions panels now also report verdicts per item (onCelVerdictsChange); DataPillar keeps them in panelCelVerdicts stamped by panelItemCelStamp (the item plus field names, the fieldCelStamp counterpart) and folds the held item into objHeld (held line with Show me; Validations gains a focus prop), so the rail switch, Publish refusal and held-edit report read it unchanged. ResourceEditPage keeps each selection's last verdict in inspectorVerdicts stamped with issueSliceFingerprint over the slice selectionSlicePath locates (id as path, else id/name/key identity, else whole document), shows an inspector-held line, and Show me reselects. useDraftAutoSave.ts untouched; no dialog, no revert, no second autosave path.", "tests": "Repro on main: 2 files, 8 failed/8. After fix, pre-merge head efe3f9a0: 198 affected test files (DataPillar.*, StudioDesignSurface.*, Object{Validations,Actions,Settings}Panel*, ResourceEditPage.*) 1283/1283 passed under the lock. After merging origin/main (head 7484a827): install, app-shell^... build, app-shell type-check exit 0; 6 CEL-gate files 27/27 passed. Ablation (ablation-replace, restored blob==HEAD): StudioDesignSurface kept-panel condition -> if (false): 2 'keeps the hold' cases red; ResourceEditPage kept-inspector condition -> if (false): 3/3 red. app-shell tests import src, no dist leg.", "gates": [ "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0", "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --self-test :: exit 0", "node scripts/check-sdui-manifest.mjs :: exit 0", "node scripts/check-sdui-manifest.mjs --self-test :: exit 0", "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0", "node scripts/release-pending-publish.mjs --self-test :: exit 0", "pnpm --dir ui exec vitest run scripts/ :: exit 0", "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0", "pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:closed-ceremony-text :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:dispatcher-error-vocabulary :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:pm-changeset-deadline-census :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:skill-identifier-liveness :: exit 0", "pnpm check:test-source-alias :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:type-check-debt :: exit 0", "pnpm check:undeclared-dep-imports :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0", "dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN", "ui check-new-cross-file-line-citations :: exit 0 (0 new)", "PR check-runs: in_progress at report time" ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "line_budget": "10 files, +787 / -43 vs merge base (tests ~+420 of that)", "files_changed": [ ".changeset/27629-studio-panel-cel-hold.md", "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx", "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.celHold-27629.test.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx", "ui/packages/app-shell/src/views/studio-design/ObjectActionsPanel.tsx", "ui/packages/app-shell/src/views/studio-design/DataPillar.panelHold-27629.test.tsx", "ui/packages/app-shell/src/views/studio-design/DataPillar.panelGate.test.tsx", "ui/packages/i18n/src/namespaces/studio/en.ts", "ui/packages/i18n/src/namespaces/studio/zh.ts" ], "deviations": [ "Commit 49b01042 carries the seat's session id in its Claude-Session trailer instead of this run's; not rewritten (branch not claude/issue-*, no force push).", "PR attribution line 2 links this card thread (the harness's required block) rather than the seat thread link the order quoted.", "Residual 250 ms flush-inside-lint edge not closed: needs a lint-pending signal from every CEL editor, outside the file surface; named in Acceptance notes 1.", "DataPillar.panelGate.test.tsx case 'expires the panel count when the author leaves the Rules tab' flipped to the ruled behaviour (ruling on #27485, letter A)." ], "mcp_calls": "0 — no GitHub MCP calls (claude-code-remote get_session / subscribe_pr_activity only)", "api_writes": "2 — relay pr_create (repository_dispatch, PR #27697); this report comment via post-stamped (POST issues/27629/comments)", "open_questions": [], "out_of_scope_findings": [ "carrier: seat · inspector-registry.ts MetadataInspectorProps.onBlockingIssuesChange doc still tells hosts to reset the count on selection change; both hosts now keep it with the draft (doc line, noted in Acceptance notes 4, not filed)" ] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
ACCEPT → PR #27697 comment 6506586076 · 2026-10-29T19:40Z