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. 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

  2. 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)"
      ]
    }
  3. 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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions