Skip to content

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

Closed

Description

@objectstack-fleet

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 to blockingReport, 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

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 29, 2026
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    Claim: PM loop round 1
    Session: session_01Utp6CaJoinvGQSbHeDaWBe
    Account: os-bill
    Branch: claude/project-thread-9u7v4h (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27629
    Domain: domain:ui
    Seat: domain:ui#3
    File 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.tsx and 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 in ui/packages/i18n/src/namespaces/studio/en.ts / zh.ts only 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 --tier on 178b5238: no path-derived mandate), effort: high
    Clause-②: 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/main before the PR; no open PR edits ResourceEditPage.tsx or ObjectValidationsPanel.tsx (checked at claim) · useDraftAutoSave.ts untouched by ruling

    Ruling: 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

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    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)"
      ]
    }
  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    ACCEPT → PR #27697 comment 6506586076 · 2026-10-29T19:40Z

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

Metadata

Metadata

Assignees

Labels

area:formulabugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions