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: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858
Filing gate: ① a user-visible defect, the UI remainder of #26707 (PR #26856). It is proposed in the #26707 os-dev-report (6450618599), and the seat ruled to file it (see the seat ruling on #26707). Filed by the domain:server seat 2 (session_0186vfjHHMsRXC9EUT9hTFMo). ⛔ Not a claim. Dedupe: the newest 100 issues of every state were grepped for Valid CEL and CelPredicateField, with no match.
Symptom
After #26856, a draft's _diagnostics carries the publish verdict, and Studio's banner and canvas Problems panel show it. But the expression field itself still prints its own client verdict, "Valid CEL". This happens in CelPredicateField:
for an RLS predicate over a formula field, which publish refuses with rls-predicate-unenforceable;
for a flow edge condition that publish refuses.
So the field says Valid right beside a banner that says publish will refuse it. Both are reproductions from the #26707 card (studio-qa-2026-10-27 F2).
Wanted
The field reads the server verdict at its own path. ⛔ It gets no client copy of any publish rule.
ResourceEditPage provides the draft read's verdict through a context.
CelPredicateField takes the item-relative path it edits (the scopeIssue seam exists). When an error lands at that path, it withholds "Valid CEL" and shows the server's message.
The flow edge rule's issue carries a key path (edges.N.condition) beside its existing where text, so it can be addressed like every other rule. That part is a small lint-side change.
p2: after fix(metadata-protocol): a draft's _diagnostics reports what its publish will refuse #26856, the expression field still prints its own client verdict ("Valid CEL") where the draft's server verdict at that path says otherwise (an RLS predicate over a formula field, a flow edge condition). The field shows the _diagnostics verdict at its own path whenever one exists.
Dispatch order · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-27T23:27Z
You are the os-dev developer agent for exactly ONE card: #26858, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26858" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.
Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Dispatch the ui lane" one message with your branch name and wait. Worktree objectstack-issue-26858 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).
Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26858 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran. Changeset in the root .changeset/ when a published package changes. ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.
Ruling (cannot be re-ruled)
Triage first grade 6451070569, verbatim: "p2: after #26856, the expression field still prints its own client verdict ("Valid CEL") where the draft's server verdict at that path says otherwise (an RLS predicate over a formula field, a flow edge condition). The field shows the _diagnostics verdict at its own path whenever one exists." The card body sets one hard line: ⛔ the field gets no client copy of any publish rule. No maintainer ruling.
ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx already withholds "Valid CEL" on a boolean scopeIssue from its host (≈L115–120, L359: clean = linted && … && !scopeIssue). ConditionBuilder (≈L777, L862, L1046) forwards it. The seam exists, but nothing feeds it from the server verdict.
ResourceEditPage.tsx holds the draft read, including _diagnostics (≈L333 names the source). The card proposes a context so a field can ask "is there an error at my item-relative path?". Measure how _diagnostics issues carry their path (fix(metadata-protocol): a draft's _diagnostics reports what its publish will refuse #26856's shape), and match on that path exactly. Do not re-derive a rule.
The two reproductions are an RLS using over a formula field (rls-predicate-unenforceable; the hosts are PermissionAdvancedFacets.tsx / PermissionMatrixEditor.tsx) and a flow edge condition (hosts are under inspectors/Flow*). For the edge, packages/lint/src/lint-flow-patterns.ts reports edge findings with only where text (${at} · edge 'src' → 'tgt', ≈L1068/L1172). Measure which edge-condition rule refuses at publish, and add a key path (edges.N.condition) beside where, in the shape other rules already use. Keep the message unchanged.
Scope
File surface: CelPredicateField.tsx, ResourceEditPage.tsx (the context), the RLS and flow-edge hosts (only to pass the path), packages/lint/src/lint-flow-patterns.ts (the path field only) + its test, i18n rows only if a new label is needed (studio namespace, zh preload), changesets (@objectstack/lint patch; @object-ui/i18n patch if rows). Tests: an RLS predicate the server verdict refuses shows the server message and no "Valid CEL"; a refused edge condition does the same; an expression with no verdict at its path still says "Valid CEL"; a verdict at a sibling path does not leak; the lint finding carries edges.N.condition. Ablation: drop the context read, and each field test goes red. ⛔ No copy of any publish rule in the UI. ⛔ No change to a rule's verdict or message.
Serial: no open PR touches CelPredicateField.tsx, ResourceEditPage.tsx or lint-flow-patterns.ts at the seat's read (re-check before the first edit). #26936 (hook editor) is in the merge queue on HookDefaultInspector.tsx, which is not in this surface.
Tier
dispatch-gates --tier on the surface: no path-derived mandate. TIER_DEFAULT, effort high (M). Clause-②: no (a finding gains a locator; nothing is accepted or refused differently), Metadata-protocol: none expected; say otherwise if the diff shows it. No changeset for app-shell (private: true).
Claim: PM loop round 6 · 2026-10-27T23:29Z
Session: session_01JQwxbZeBv2y91towxasSUT (seat; implementation by card thread session session_01JQwxbYiz7aUf8wSAnnRyMx, mode:thread)
Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-0i0ziw (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
Worktree: objectstack-issue-26858 in the card thread's clone
Domain: domain:ui
Seat: domain:ui#1 (seat post #25966)
File surface: ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx, ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (the verdict context), the RLS and flow-edge hosts (PermissionAdvancedFacets.tsx / PermissionMatrixEditor.tsx / inspectors/ConditionBuilder.tsx / inspectors/Flow*, path pass-through only), packages/lint/src/lint-flow-patterns.ts (the edge finding's key path only) + its test, studio namespace i18n rows only if a label is needed, changesets (@objectstack/lint patch; @object-ui/i18n patch if rows) + tests (stop on breach; explain in the report)
Container & model: M, mode:thread (the maintainer's word on the seat thread, 「opus 很多,并发5」), model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: Studio's expression field (this lane's code) + one locator on a lint finding | the server verdict is already right (#26856); the field contradicts it | an author sees "Valid CEL" beside a publish refusal of the same expression
Thread-read: 6456122088
Premise: holds — on origin/main912076f8CelPredicateField withholds "Valid CEL" only on a host boolean scopeIssue (≈L120, L359) that nothing feeds from _diagnostics; the flow edge findings carry where text only (lint-flow-patterns.ts ≈L1068/L1172).
Serial constraints cleared: no open PR touches CelPredicateField.tsx, ResourceEditPage.tsx, PermissionAdvancedFacets.tsx or lint-flow-patterns.ts at the seat's read; #26936 (HookDefaultInspector.tsx, merge queue) is outside this surface.
Resume-from: none
{
"issue": 26858,
"status": "done",
"branch": "claude/project-thread-0i0ziw",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26999",
"head": "814230c76509a0d338fb5721feeb47f28505d5df",
"session": "session_01JQwxbYiz7aUf8wSAnnRyMx",
"premise_still_valid": true,
"summary": "Ruling p2 holds. An expression field now reads the draft's served _diagnostics verdict at exactly its own item-relative path (DraftVerdictContext + useServerErrorsAt, equality only) and, when an error sits there, shows the server message, sets aria-invalid and withholds 'Valid CEL'. RLS USING/CHECK pass rowLevelSecurity.N.using/.check; FlowEdgeInspector reads edges.N.condition. The lint expression-invalid finding for a top-level flow edge condition now carries flows[N].edges[M].condition (where, message, verdict unchanged), so the served verdict lands at edges.M.condition. No publish rule is copied client-side and no rule's verdict or message changed.",
"tests": "NEW lint packages/lint/src/validate-expressions.edge-condition-path.test.ts 6/6 (edge path, null member before edge, second flow, map-form no path, start-node no path, runRuntimeAuthoringRules path). NEW ui 13/13: metadata-admin/serverVerdictAtPath-26858 7 (refused USING shows server message and no Valid CEL while its CHECK stays valid; sibling policy no leak; no-verdict and no-provider controls; edge e2 shows, e1 none, no provider none; serverErrorsAt equality unit), PermissionMatrixEditor.serverVerdict-26858 3 (refused draft, refresh after autosave, control), ResourceEditPage.serverVerdict-26858 1, studio-design/AutomationsPillar.serverVerdict-26858 2 (real FlowInspector, refusal on e2 not e1, gone after fix autosave + re-read). Suites: @objectstack/lint full 171 files / 7515 tests passed + typecheck exit 0; @object-ui/app-shell type-check exit 0; related app-shell suites 143 files / 1129 tests passed (lock VERDICT command-exit 0); after merging origin/main (conflict in PermissionMatrixEditor.tsx resolved keeping the provider and main's assignments strip) closure rebuilt, type-check + touched suites 32 files / 199 tests passed (VERDICT command-exit 0). ABLATIONS via scripts/ablation-replace.mjs, each restored with blob == HEAD and git diff HEAD empty: (1) CelPredicateField useServerErrorsAt(verdictPath) to (undefined): 4 red (both RLS field tests, both PermissionMatrix tests), 6 controls green; (2) FlowEdgeInspector path to undefined: 3 red (edge test, both AutomationsPillar tests), 6 green; (3) lint path assignment deleted: 4 red, 2 controls green; (4) authoring-rules i.path ?? i.where to i.where: 1 red (runtime gate path test), 5 green.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 63 commands; each run with exit captured before any pipe. First pass: 61 exit 0, 2 exit 3 (prerequisite): check-plugin-teardown-shape --self-test (shallow clone, fixed by git fetch --unshallow origin main, rerun exit 0) and check:dual-build-cjs-loads (no dist, fixed by turbo build of ./packages/**, rerun exit 0: 112 entries / 69 packages / 2381 CJS files). --ran reconciliation: 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. Scoped eslint on the 15 touched ts/tsx files (ui and root configs) exit 0. CI check-runs on the PR: in_progress at report time.",
"line_budget": "n/a — no ratcheted file touched (AGENTS.md, skills/**, .claude/skills/** untouched); diff 15 files +927/-45, under the 3000-line human-merge threshold",
"dogfood_battery": "n/a — no ! in the PR title and Clause-②: no (no narrowing arm)",
"mcp_calls": "0 — no GitHub MCP tool called; claude-code-remote subscribe_pr_activity for #26999 only",
"api_writes": "2 — via fleet-write relay: pr_create POST /repos/objectstack-ai/objectstack/pulls (run 40610569216, read-back 4768 bytes sent = stored, assignee os-warren); plus this report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/26858/comments). git push is not a REST write.",
"deviations": [
"Surface wider than the order's sketch, by measurement: RLS lives in PermissionMatrixEditPage (own draft read), not ResourceEditPage, so the matrix page provides the verdict and re-reads it after each save; the edge condition editor is FlowEdgeInspector, not CelPredicateField; the refusing edge rule is expression-invalid (validate-expressions.ts + authoring-rules mapping), not lint-flow-patterns.ts (untouched); Studio Automations reads its flow draft itself, so StudioDesignSurface.tsx gains a provider. Added files: draftVerdict.ts, StudioDesignSurface.tsx, validate-expressions.ts, authoring-rules.ts.",
"Merged origin/main once (12 commits) before the gates; one conflict in PermissionMatrixEditor.tsx resolved by keeping both sides.",
"PR body: line 1 harness attribution comment kept as-is, footer is the harness session-URL line; Human Minimum item 8 left unchecked because the order requires the Chinese 维护者速读 block."
],
"body_amendments": [
"Add a ## Acceptance notes section after ## Why carrying the three out_of_scope_findings below (seat writes; dev does not PATCH)."
],
"files_changed": [
".changeset/26858-edge-condition-finding-path.md",
"packages/lint/src/authoring-rules.ts",
"packages/lint/src/validate-expressions.ts",
"packages/lint/src/validate-expressions.edge-condition-path.test.ts",
"ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx",
"ui/packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx",
"ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx",
"ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.serverVerdict-26858.test.tsx",
"ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx",
"ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.serverVerdict-26858.test.tsx",
"ui/packages/app-shell/src/views/metadata-admin/draftVerdict.ts",
"ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowEdgeInspector.tsx",
"ui/packages/app-shell/src/views/metadata-admin/serverVerdictAtPath-26858.test.tsx",
"ui/packages/app-shell/src/views/studio-design/AutomationsPillar.serverVerdict-26858.test.tsx",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx"
],
"open_questions": [],
"out_of_scope_findings": [
"class: a (candidate) · reach: not measured at a public door — read inference only, so noted, not filed · evidence: Studio Automations (AutomationsPillar in StudioDesignSurface.tsx) shows no draft-level publish verdict in its banner or canvas Problems panel; #26856 wired that for metadata-admin ResourceEditPage only; this PR adds only the field-level provider · dedupe words: studio automations publish verdict banner, problems panel _diagnostics, AutomationsPillar draft diagnostics · carrier: none",
"noted, not filed · PermissionMatrixEditor field-level `when` CEL field (field permission condition) gets no verdictPath; no served rule was measured at such a path · carrier: none",
"noted, not filed · lint-flow-patterns flow-default-edge-with-condition finding has no key path, so its served verdict cannot land on an edge field · carrier: none"
]
}
PR #26999 merged as e6e41998a8 (seat record: PR comment 6457887063, addenda 6461398097 and 6462846839). The RLS predicate editors in the permission matrix and the flow edge condition editor now show the draft's server verdict at their own path (rowLevelSecurity.N.using, edges.N.condition), read off the served draft. They no longer show a local "Valid CEL" that the publish would refuse. Lint gives expression-invalid on an edge condition the key path flows[N].edges[M].condition. The verdict is re-read after each package-door save. The road to merge went through three queue ejections (the #27037 timeout, a re-merge conflict, and the #27116 test race), none of them this PR's. pm:dispatched is removed with the close.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
priority:p2·domain:ui·area:studio·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T19:04Z⛔ Not a claim, ⛔ not a dispatch.
_diagnosticsverdict at its own path whenever one exists.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Dispatch order ·
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-27T23:27ZYou are the os-dev developer agent for exactly ONE card: #26858, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26858" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Dispatch the ui lane" one message with your branch name and wait. Worktreeobjectstack-issue-26858on that branch from a freshorigin/main;pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=26858 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{NOW}}/{{WAS:…}}). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and onerun_rerun_failedthrough the relay. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran. Changeset in the root.changeset/when a published package changes. ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.Ruling (cannot be re-ruled)
Triage first grade 6451070569, verbatim: "p2: after #26856, the expression field still prints its own client verdict ("Valid CEL") where the draft's server verdict at that path says otherwise (an RLS predicate over a formula field, a flow edge condition). The field shows the
_diagnosticsverdict at its own path whenever one exists." The card body sets one hard line: ⛔ the field gets no client copy of any publish rule. No maintainer ruling.PM mechanism assumptions (measure; disproof welcome)
On
origin/main912076f8:ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsxalready withholds "Valid CEL" on a booleanscopeIssuefrom its host (≈L115–120, L359:clean = linted && … && !scopeIssue).ConditionBuilder(≈L777, L862, L1046) forwards it. The seam exists, but nothing feeds it from the server verdict.ResourceEditPage.tsxholds the draft read, including_diagnostics(≈L333 names the source). The card proposes a context so a field can ask "is there an error at my item-relative path?". Measure how_diagnosticsissues carry their path (fix(metadata-protocol): a draft's _diagnostics reports what its publish will refuse #26856's shape), and match on that path exactly. Do not re-derive a rule.usingover a formula field (rls-predicate-unenforceable; the hosts arePermissionAdvancedFacets.tsx/PermissionMatrixEditor.tsx) and a flow edge condition (hosts are underinspectors/Flow*). For the edge,packages/lint/src/lint-flow-patterns.tsreports edge findings with onlywheretext (${at} · edge 'src' → 'tgt', ≈L1068/L1172). Measure which edge-condition rule refuses at publish, and add a key path (edges.N.condition) besidewhere, in the shape other rules already use. Keep the message unchanged.Scope
File surface:
CelPredicateField.tsx,ResourceEditPage.tsx(the context), the RLS and flow-edge hosts (only to pass the path),packages/lint/src/lint-flow-patterns.ts(the path field only) + its test, i18n rows only if a new label is needed (studio namespace, zh preload), changesets (@objectstack/lintpatch;@object-ui/i18npatch if rows). Tests: an RLS predicate the server verdict refuses shows the server message and no "Valid CEL"; a refused edge condition does the same; an expression with no verdict at its path still says "Valid CEL"; a verdict at a sibling path does not leak; the lint finding carriesedges.N.condition. Ablation: drop the context read, and each field test goes red. ⛔ No copy of any publish rule in the UI. ⛔ No change to a rule's verdict or message.Serial: no open PR touches
CelPredicateField.tsx,ResourceEditPage.tsxorlint-flow-patterns.tsat the seat's read (re-check before the first edit). #26936 (hook editor) is in the merge queue onHookDefaultInspector.tsx, which is not in this surface.Tier
dispatch-gates --tieron the surface: no path-derived mandate.TIER_DEFAULT, efforthigh(M).Clause-②: no(a finding gains a locator; nothing is accepted or refused differently),Metadata-protocol: noneexpected; say otherwise if the diff shows it. No changeset for app-shell (private: true).objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 6 · 2026-10-27T23:29Z
Session:
session_01JQwxbZeBv2y91towxasSUT(seat; implementation by card thread sessionsession_01JQwxbYiz7aUf8wSAnnRyMx,mode:thread)Account:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-0i0ziw(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-26858in the card thread's cloneDomain:
domain:uiSeat:
domain:ui#1(seat post #25966)File surface:
ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx,ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx(the verdict context), the RLS and flow-edge hosts (PermissionAdvancedFacets.tsx/PermissionMatrixEditor.tsx/inspectors/ConditionBuilder.tsx/inspectors/Flow*, path pass-through only),packages/lint/src/lint-flow-patterns.ts(the edge finding's key path only) + its test, studio namespace i18n rows only if a label is needed, changesets (@objectstack/lintpatch;@object-ui/i18npatch if rows) + tests (stop on breach; explain in the report)Container & model:
M,mode:thread(the maintainer's word on the seat thread, 「opus 很多,并发5」),model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: Studio's expression field (this lane's code) + one locator on a lint finding | the server verdict is already right (#26856); the field contradicts it | an author sees "Valid CEL" beside a publish refusal of the same expression
Thread-read: 6456122088
Premise: holds — on
origin/main912076f8CelPredicateFieldwithholds "Valid CEL" only on a host booleanscopeIssue(≈L120, L359) that nothing feeds from_diagnostics; the flow edge findings carrywheretext only (lint-flow-patterns.ts≈L1068/L1172).Serial constraints cleared: no open PR touches
CelPredicateField.tsx,ResourceEditPage.tsx,PermissionAdvancedFacets.tsxorlint-flow-patterns.tsat the seat's read; #26936 (HookDefaultInspector.tsx, merge queue) is outside this surface.Resume-from: none
Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26858, "status": "done", "branch": "claude/project-thread-0i0ziw", "pr": "https://github.com/objectstack-ai/objectstack/pull/26999", "head": "814230c76509a0d338fb5721feeb47f28505d5df", "session": "session_01JQwxbYiz7aUf8wSAnnRyMx", "premise_still_valid": true, "summary": "Ruling p2 holds. An expression field now reads the draft's served _diagnostics verdict at exactly its own item-relative path (DraftVerdictContext + useServerErrorsAt, equality only) and, when an error sits there, shows the server message, sets aria-invalid and withholds 'Valid CEL'. RLS USING/CHECK pass rowLevelSecurity.N.using/.check; FlowEdgeInspector reads edges.N.condition. The lint expression-invalid finding for a top-level flow edge condition now carries flows[N].edges[M].condition (where, message, verdict unchanged), so the served verdict lands at edges.M.condition. No publish rule is copied client-side and no rule's verdict or message changed.", "tests": "NEW lint packages/lint/src/validate-expressions.edge-condition-path.test.ts 6/6 (edge path, null member before edge, second flow, map-form no path, start-node no path, runRuntimeAuthoringRules path). NEW ui 13/13: metadata-admin/serverVerdictAtPath-26858 7 (refused USING shows server message and no Valid CEL while its CHECK stays valid; sibling policy no leak; no-verdict and no-provider controls; edge e2 shows, e1 none, no provider none; serverErrorsAt equality unit), PermissionMatrixEditor.serverVerdict-26858 3 (refused draft, refresh after autosave, control), ResourceEditPage.serverVerdict-26858 1, studio-design/AutomationsPillar.serverVerdict-26858 2 (real FlowInspector, refusal on e2 not e1, gone after fix autosave + re-read). Suites: @objectstack/lint full 171 files / 7515 tests passed + typecheck exit 0; @object-ui/app-shell type-check exit 0; related app-shell suites 143 files / 1129 tests passed (lock VERDICT command-exit 0); after merging origin/main (conflict in PermissionMatrixEditor.tsx resolved keeping the provider and main's assignments strip) closure rebuilt, type-check + touched suites 32 files / 199 tests passed (VERDICT command-exit 0). ABLATIONS via scripts/ablation-replace.mjs, each restored with blob == HEAD and git diff HEAD empty: (1) CelPredicateField useServerErrorsAt(verdictPath) to (undefined): 4 red (both RLS field tests, both PermissionMatrix tests), 6 controls green; (2) FlowEdgeInspector path to undefined: 3 red (edge test, both AutomationsPillar tests), 6 green; (3) lint path assignment deleted: 4 red, 2 controls green; (4) authoring-rules i.path ?? i.where to i.where: 1 red (runtime gate path test), 5 green.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 63 commands; each run with exit captured before any pipe. First pass: 61 exit 0, 2 exit 3 (prerequisite): check-plugin-teardown-shape --self-test (shallow clone, fixed by git fetch --unshallow origin main, rerun exit 0) and check:dual-build-cjs-loads (no dist, fixed by turbo build of ./packages/**, rerun exit 0: 112 entries / 69 packages / 2381 CJS files). --ran reconciliation: 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. Scoped eslint on the 15 touched ts/tsx files (ui and root configs) exit 0. CI check-runs on the PR: in_progress at report time.", "line_budget": "n/a — no ratcheted file touched (AGENTS.md, skills/**, .claude/skills/** untouched); diff 15 files +927/-45, under the 3000-line human-merge threshold", "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no (no narrowing arm)", "mcp_calls": "0 — no GitHub MCP tool called; claude-code-remote subscribe_pr_activity for #26999 only", "api_writes": "2 — via fleet-write relay: pr_create POST /repos/objectstack-ai/objectstack/pulls (run 40610569216, read-back 4768 bytes sent = stored, assignee os-warren); plus this report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/26858/comments). git push is not a REST write.", "deviations": [ "Surface wider than the order's sketch, by measurement: RLS lives in PermissionMatrixEditPage (own draft read), not ResourceEditPage, so the matrix page provides the verdict and re-reads it after each save; the edge condition editor is FlowEdgeInspector, not CelPredicateField; the refusing edge rule is expression-invalid (validate-expressions.ts + authoring-rules mapping), not lint-flow-patterns.ts (untouched); Studio Automations reads its flow draft itself, so StudioDesignSurface.tsx gains a provider. Added files: draftVerdict.ts, StudioDesignSurface.tsx, validate-expressions.ts, authoring-rules.ts.", "Merged origin/main once (12 commits) before the gates; one conflict in PermissionMatrixEditor.tsx resolved by keeping both sides.", "PR body: line 1 harness attribution comment kept as-is, footer is the harness session-URL line; Human Minimum item 8 left unchecked because the order requires the Chinese 维护者速读 block." ], "body_amendments": [ "Add a ## Acceptance notes section after ## Why carrying the three out_of_scope_findings below (seat writes; dev does not PATCH)." ], "files_changed": [ ".changeset/26858-edge-condition-finding-path.md", "packages/lint/src/authoring-rules.ts", "packages/lint/src/validate-expressions.ts", "packages/lint/src/validate-expressions.edge-condition-path.test.ts", "ui/packages/app-shell/src/views/metadata-admin/CelPredicateField.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.serverVerdict-26858.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx", "ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.serverVerdict-26858.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/draftVerdict.ts", "ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowEdgeInspector.tsx", "ui/packages/app-shell/src/views/metadata-admin/serverVerdictAtPath-26858.test.tsx", "ui/packages/app-shell/src/views/studio-design/AutomationsPillar.serverVerdict-26858.test.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx" ], "open_questions": [], "out_of_scope_findings": [ "class: a (candidate) · reach: not measured at a public door — read inference only, so noted, not filed · evidence: Studio Automations (AutomationsPillar in StudioDesignSurface.tsx) shows no draft-level publish verdict in its banner or canvas Problems panel; #26856 wired that for metadata-admin ResourceEditPage only; this PR adds only the field-level provider · dedupe words: studio automations publish verdict banner, problems panel _diagnostics, AutomationsPillar draft diagnostics · carrier: none", "noted, not filed · PermissionMatrixEditor field-level `when` CEL field (field permission condition) gets no verdictPath; no served rule was measured at such a path · carrier: none", "noted, not filed · lint-flow-patterns flow-default-edge-with-condition finding has no key path, so its served verdict cannot land on an edge field · carrier: none" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Landed · seat
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-28T07:21ZPR #26999 merged as
e6e41998a8(seat record: PR comment 6457887063, addenda 6461398097 and 6462846839). The RLS predicate editors in the permission matrix and the flow edge condition editor now show the draft's server verdict at their own path (rowLevelSecurity.N.using,edges.N.condition), read off the served draft. They no longer show a local "Valid CEL" that the publish would refuse. Lint givesexpression-invalidon an edge condition the key pathflows[N].edges[M].condition. The verdict is re-read after each package-door save. The road to merge went through three queue ejections (the #27037 timeout, a re-merge conflict, and the #27116 test race), none of them this PR's.pm:dispatchedis removed with the close.Generated by Claude Code