You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Studio: the Validations tab holds the autosave on a served CEL verdict at the rule's own path, as the RLS arm does (#27482 layer 2 of 2) #27644
Sub-issue of #27482 (layer 2 of 2: the console). Filed by triage on the pm:retriage request 6501208028 from domain:ui#3. ⛔ Not a claim.
Blocked-by: #27643 (lint emits validations.N.condition), on main.
What is wrong
PR #27612 made a served CEL error at a CelPredicateField's own verdict path hold the Permission matrix autosave (draftVerdict.tsserverHoldAt / useServerHoldAt, through onLintChange). The Validations tab has no such hold:
DataPillar (studio-design/StudioDesignSurface.tsx) drops the served _diagnostics.
ConditionBuilder carries no verdictPath.
So a rule the engine refuses (the nullable-compare rule) still reads "Valid CEL" and autosaves (PUT 200) until Publish refuses it.
Expected
DataPillar keeps the draft read's _diagnostics.
ConditionBuilder and ObjectValidationsPanel carry the rule's verdictPath.
The served error at that path holds the save through the existing serverHoldAt while the judged text stands. Editing the text releases it.
Pinned like PermissionMatrixEditor.serverVerdictHold-27482.test.tsx.
Claim: PM loop round 1
Session: session_01Utp6CbDAucNyQ4UtzCJKyh
Account: os-bill
Branch: claude/project-thread-aewbdy (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27644
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (DataPillar only), ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx, ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx, ui/packages/app-shell/src/views/metadata-admin/{draftVerdict.ts,CelPredicateField.tsx} (reuse only), their tests, .changeset/*.md (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on fec60e00: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the Validations tab keeps the draft read's served _diagnostics, carries each rule's verdictPath, and holds the autosave through #27612's serverHoldAt while the judged text stands; no second hold, no client copy of the publish rule
Thread-read: 6501879879
Premise: holds
Serial constraints cleared: #27643 closed on main; draft PR #27988 (#27896) edits StudioDesignSurface.tsx in InterfacesPillar only (disjoint hunks from DataPillar), merge origin/main before the PR
Dispatched 2026-10-30T06:44Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
{
"issue": 27644,
"status": "done",
"branch": "claude/project-thread-aewbdy",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28027",
"session": "session_01Utp6CZjUkAAB57j1TQa8sE",
"premise_still_valid": true,
"summary": "DataPillar now keeps the object draft read's served _diagnostics and judged body, re-reads the draft after each save, and provides both (DraftVerdictContext / DraftVerdictBodyContext) to the Validations tab only. ObjectValidationsPanel passes each guard verdictPath validations.N.condition (or .when), N = index in the raw draft.validations list. ConditionBuilder forwards verdictPath to CelPredicateField in raw mode (the #27612 onLintChange hold) and, in row mode, which mounts no CEL editor, reads the same useServerHoldAt itself to show and count the served error. Measured: the stored nullable-compare guard opens in ROW mode, so the raw-only half would not have held the card's shape (ablation 2).",
"tests": "head 479a7575: new ConditionBuilder.serverHold-27644 + DataPillar.validationVerdictHold-27644: 2 files / 9 tests passed; 169 related app-shell files (ObjectValidationsPanel*, DataPillar*, StudioDesignSurface*, ConditionBuilder*, CelPredicateField*, serverVerdict*): Test Files 169 passed, Tests 1234 passed (lock VERDICT command-exit 0); pnpm --filter @object-ui/app-shell type-check exit 0 (both tsc projects). Ablation 1 (DraftVerdictContext value objVerdict to undefined, ablation-replace anchor 1 to 0): DataPillar 5 failed / 1 passed (control), restored blob == HEAD, git diff HEAD empty. Ablation 2 (raw ? celErrors : held.length to 0): 4 failed / 5 passed (both row-builder cases + DataPillar a, e), restored blob == HEAD. Both ablations on src (relative imports in app-shell tests, no dist leg). Full packages/app-shell/ suite (~1950 files) NOT MEASURED locally: stopped after 1h+ when #27988 landed and main was merged again; declared to CI Test UI.",
"gates": "local, head 479a7575: dispatch-gates --commands 34 derived (same list at 23227677, ae70f346, 479a7575); each recorded before any pipe: 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:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm check:type-check-debt :: exit 0. --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Extra: pnpm check:new-line-citations 0 new (exit 0); eslint on 5 changed ui files 0 errors. CI check-runs on 28027: in_progress at report time.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no GitHub MCP tool used (one claude-code-remote subscribe_pr_activity, not GitHub MCP)",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create to PR 28027), POST /repos/objectstack-ai/objectstack/issues/27644/comments (this report via post-stamped)",
"line_budget": "465 insertions / 11 deletions vs origin/main 066ff51e: ConditionBuilder.tsx +30/-3, ObjectValidationsPanel.tsx +14, StudioDesignSurface.tsx +38/-7, two new test files +99 and +275, changeset +10",
"files_changed": [
".changeset/27644-validation-rule-served-verdict-hold.md",
"ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx",
"ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.serverHold-27644.test.tsx",
"ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
"ui/packages/app-shell/src/views/studio-design/DataPillar.validationVerdictHold-27644.test.tsx"
],
"deviations": [
"StudioDesignSurface.tsx: one name (DraftVerdictBodyContext) added to the shared draftVerdict import block, outside DataPillar; every other hunk is inside DataPillar.",
"ConditionBuilder.tsx reads useServerHoldAt directly in row mode: the same #27612 helper, not a second hold; needed because a stored refused guard opens as a row with no CelPredicateField mounted.",
"draftVerdict.ts and CelPredicateField.tsx not edited.",
"PR body attribution link: used the session context's thread link (this card thread) rather than the dispatch's seat-thread link; the session context requires its block verbatim.",
"PR body order: Fixes and the two declaration lines precede the maintainer summary, per os-dev.md (the order wins over the dispatch).",
"Harness after-PR assignee/review step skipped, as the dispatch orders; the PR has no assignee and no reviewer.",
"Subscribed this thread to PR 28027 activity so CI reds reach it (dispatch: drive CI to green).",
"Narrowed: full packages/app-shell/ suite not completed locally (declared to CI Test UI).",
"Not reproduced live: the pre-fix PUT 200 was not reproduced on a running stack; ablations are the before-state evidence."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in PR Acceptance notes, not filed: serverHoldAt compares the judged value at the path with the on-screen text, so a guard stored as an expression envelope (dialect + source) is never held; no producer of envelope-form validation guards found (none in examples/)"
]
}
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | studio-authoring.validation-rules-authoring | P③
Triage: p2 ·
domain:ui·area:studio· layer 2 of #27482 ·pm:blockedon #27643 · 2026-10-29T16:06Z⛔ Not a claim. Filed by triage on #27482's retriage. It reuses #27612's
serverHoldAt, with no second hold and no client copy of the rule.bug,pm:blocked.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-aewbdy(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27644Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(DataPillar only),ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx,ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx,ui/packages/app-shell/src/views/metadata-admin/{draftVerdict.ts,CelPredicateField.tsx}(reuse only), their tests,.changeset/*.md(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieronfec60e00: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: the Validations tab keeps the draft read's served
_diagnostics, carries each rule'sverdictPath, and holds the autosave through #27612'sserverHoldAtwhile the judged text stands; no second hold, no client copy of the publish ruleThread-read: 6501879879
Premise: holds
Serial constraints cleared: #27643 closed on main; draft PR #27988 (#27896) edits StudioDesignSurface.tsx in InterfacesPillar only (disjoint hunks from DataPillar), merge origin/main before the PR
Dispatched 2026-10-30T06:44Z 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
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CZjUkAAB57j1TQa8sE
os-dev-report
{ "issue": 27644, "status": "done", "branch": "claude/project-thread-aewbdy", "pr": "https://github.com/objectstack-ai/objectstack/pull/28027", "session": "session_01Utp6CZjUkAAB57j1TQa8sE", "premise_still_valid": true, "summary": "DataPillar now keeps the object draft read's served _diagnostics and judged body, re-reads the draft after each save, and provides both (DraftVerdictContext / DraftVerdictBodyContext) to the Validations tab only. ObjectValidationsPanel passes each guard verdictPath validations.N.condition (or .when), N = index in the raw draft.validations list. ConditionBuilder forwards verdictPath to CelPredicateField in raw mode (the #27612 onLintChange hold) and, in row mode, which mounts no CEL editor, reads the same useServerHoldAt itself to show and count the served error. Measured: the stored nullable-compare guard opens in ROW mode, so the raw-only half would not have held the card's shape (ablation 2).", "tests": "head 479a7575: new ConditionBuilder.serverHold-27644 + DataPillar.validationVerdictHold-27644: 2 files / 9 tests passed; 169 related app-shell files (ObjectValidationsPanel*, DataPillar*, StudioDesignSurface*, ConditionBuilder*, CelPredicateField*, serverVerdict*): Test Files 169 passed, Tests 1234 passed (lock VERDICT command-exit 0); pnpm --filter @object-ui/app-shell type-check exit 0 (both tsc projects). Ablation 1 (DraftVerdictContext value objVerdict to undefined, ablation-replace anchor 1 to 0): DataPillar 5 failed / 1 passed (control), restored blob == HEAD, git diff HEAD empty. Ablation 2 (raw ? celErrors : held.length to 0): 4 failed / 5 passed (both row-builder cases + DataPillar a, e), restored blob == HEAD. Both ablations on src (relative imports in app-shell tests, no dist leg). Full packages/app-shell/ suite (~1950 files) NOT MEASURED locally: stopped after 1h+ when #27988 landed and main was merged again; declared to CI Test UI.", "gates": "local, head 479a7575: dispatch-gates --commands 34 derived (same list at 23227677, ae70f346, 479a7575); each recorded before any pipe: 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:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm check:type-check-debt :: exit 0. --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Extra: pnpm check:new-line-citations 0 new (exit 0); eslint on 5 changed ui files 0 errors. CI check-runs on 28027: in_progress at report time.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0 — no GitHub MCP tool used (one claude-code-remote subscribe_pr_activity, not GitHub MCP)", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create to PR 28027), POST /repos/objectstack-ai/objectstack/issues/27644/comments (this report via post-stamped)", "line_budget": "465 insertions / 11 deletions vs origin/main 066ff51e: ConditionBuilder.tsx +30/-3, ObjectValidationsPanel.tsx +14, StudioDesignSurface.tsx +38/-7, two new test files +99 and +275, changeset +10", "files_changed": [ ".changeset/27644-validation-rule-served-verdict-hold.md", "ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx", "ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.serverHold-27644.test.tsx", "ui/packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "ui/packages/app-shell/src/views/studio-design/DataPillar.validationVerdictHold-27644.test.tsx" ], "deviations": [ "StudioDesignSurface.tsx: one name (DraftVerdictBodyContext) added to the shared draftVerdict import block, outside DataPillar; every other hunk is inside DataPillar.", "ConditionBuilder.tsx reads useServerHoldAt directly in row mode: the same #27612 helper, not a second hold; needed because a stored refused guard opens as a row with no CelPredicateField mounted.", "draftVerdict.ts and CelPredicateField.tsx not edited.", "PR body attribution link: used the session context's thread link (this card thread) rather than the dispatch's seat-thread link; the session context requires its block verbatim.", "PR body order: Fixes and the two declaration lines precede the maintainer summary, per os-dev.md (the order wins over the dispatch).", "Harness after-PR assignee/review step skipped, as the dispatch orders; the PR has no assignee and no reviewer.", "Subscribed this thread to PR 28027 activity so CI reds reach it (dispatch: drive CI to green).", "Narrowed: full packages/app-shell/ suite not completed locally (declared to CI Test UI).", "Not reproduced live: the pre-fix PUT 200 was not reproduced on a running stack; ablations are the before-state evidence." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted in PR Acceptance notes, not filed: serverHoldAt compares the judged value at the path with the on-screen text, so a guard stored as an expression envelope (dialect + source) is never held; no producer of envelope-form validation guards found (none in examples/)" ] }objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
ACCEPT → PR #28027 comment 6519399127 · 2026-10-30T09:23Z
Generated by Claude Code