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
console: a bare-string CEL predicate (nav visible, page visibleWhen) runs on the legacy evaluator and fails, though the spec defines a bare string as CEL shorthand #27457
Filing gate: ① a product defect. A QA run met it on two item clauses (studio-authoring.app-and-nav-properties acceptance[3], and studio-authoring.authored-page-slots-and-variables acceptance[1] / negative[0]).
Reproduction A: app navigation visible
Boot the showcase. Create a writable package (POST /api/v1/packages {"manifest":{"id":"com.qa.rnine","name":"QA R9","version":"0.1.0","type":"app","namespace":"qnine"}}), an object qnine_note, and an app whose navigation holds {"type":"object","id":"nav_admin_only","label":"Admin Only Entry","objectName":"qnine_note","visible":"'org_owner' in current_user.positions"} (PUT /api/v1/meta/app/APP?mode=draft&package=com.qa.rnine). Then POST /api/v1/packages/com.qa.rnine/publish-drafts. Studio's menu-entry inspector (VISIBLE WHEN) writes exactly this bare string and labels it "Valid CEL".
As the seeded admin, whose GET /api/v1/auth/get-session positions include org_owner, open the app.
Expected: the entry is shown to the admin and hidden from a member without that position.
Actual: the entry is hidden from everyone. The console logs [ObjectUI] A visibility predicate could not be evaluated - node "app-shell:visible" … Unexpected token "i" at position 12.
Control: the same source as an envelope, {"dialect":"cel","source":"'org_owner' in current_user.positions"}, is shown to the admin and hidden from the member.
Reproduction B: page block visibleWhen
In the same package: PUT /api/v1/meta/page/qnine_vars_page2?mode=draft&package=com.qa.rnine with {"type":"app","variables":[{"name":"items","type":"array","defaultValue":["a"]}],"regions":[{"name":"main","components":[{"type":"element:text","id":"b_items","visibleWhen":"size(page.items) > 0","properties":{"content":"VAR-ITEMS array nonempty"}}]}]}, then publish.
Open /_console/apps/com.qa.rnine/page/qnine_vars_page2.
Expected: "VAR-ITEMS array nonempty" renders.
Actual: the block is absent. Console: Failed to evaluate expression "size(page.items) > 0": "size" is not a function. The envelope control renders it.
Both reproduced at least twice on fresh loads.
Mechanism
ui/packages/core/src/evaluator/ExpressionEvaluator.ts ~L363–368 routes only an explicit { dialect: 'cel' } envelope to the CEL engine; "Bare strings and ${…} templates stay on the legacy path (back-compat deprecation window)". The spec's EvaluatedExpressionInputSchema defines a bare string as CEL shorthand, the metadata door serves the stored bare string without normalizing it, and Studio authors the bare string. CEL-only syntax (in, size()) therefore faults on the legacy grammar and fails closed. Fix either side: normalize to the envelope at the door or the loader, or route bare strings in CEL-declared slots to CEL.
Read fresh. A bare-string CEL predicate (nav visible, page visibleWhen) runs on the legacy evaluator and fails, though the spec defines a bare string as CEL shorthand. From the 18.3.0 RC run ([sweep] v18.3.0 release test sweep #27377 §5); it is retested on the next wave.
⛔ It uses one evaluator (ADR-0032): the console normalises a bare string to the CEL envelope at the same point the server does, with no legacy path.
Dispatch order · domain:ui#1 · session_01L6bhgXU26UBEjd1KKHgNEx · 2026-10-29T11:28Z
You are the os-dev developer agent for exactly ONE card: #27457, 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/27457" -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 "ui 席 1" one message with your branch name and wait. Worktree objectstack-issue-27457 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":…}], draft forced, ⛔ no assignees and ⛔ no review request: the seat hands the PR to a person after its ACCEPT; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=27457 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}; first line the signature domain:ui#1 · os-sales · <your session>). ⛔ 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 (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的), Fixes #27457, Clause-②: and Metadata-protocol: lines as in the claim. 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/ named 27457-<slug>.md when a published package changes. ⛔ ui/.github/** and the root ci.yml are out of bounds. Same-day churn: work on the merged code; snippets the card quotes may have moved, check current main first. Hand back: when the PR and report are up, send the seat thread "ui 席 1" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.
Ruling (cannot be re-ruled)
No maintainer ruling on this card. Triage direction (on the card), verbatim: 「⛔ It uses one evaluator (ADR-0032): the console normalises a bare string to the CEL envelope at the same point the server does, with no legacy path.」 Governing text: ADR-0032 and the spec's definition of a bare string as CEL shorthand (protocol is the baseline: code aligns to spec).
PM mechanism assumptions (measured read-only on origin/main57c51aab4d; re-measure)
ui/packages/core/src/evaluator/ExpressionEvaluator.tsevaluateCondition (~341) routes only an explicit {dialect:'cel'} envelope to CEL (~361–369, comment "Bare strings and ${…} templates stay on the legacy path"); a bare string goes to evaluateExpression (~404–410).
Nav visible reaches it through evaluateNavigationVisibility / evaluateVisibility (ui/packages/app-shell/src/providers/ExpressionProvider.tsx ~597/668/681; a fault withholds the entry for everyone); page visibleWhen through ui/packages/react/src/SchemaRenderer.tsxVISIBILITY_SHOW_KEYS (~369) and evaluateCondition (~1451/1472/1588).
core/src/evaluator/predicateInput.tstoPredicateInput (~179) wraps bare strings with wrapIfBare into the legacy ${} form; the server-side normaliser is packages/formula/src/normalize.tsnormalizeExpression (~33). Find the single point where the console should apply the same normalisation and say in the PR body why it is that point.
Risk to measure first: how many authored bare-string predicates in this repository (examples, ui/examples, app metadata, tests) are legacy-grammar only (do not parse as CEL). Report the count with the grep. If they are fixable in this diff, fix them; if a published sample or the server itself depends on the legacy reading, stop and report needs_decision (four-axis analysis, SKILL.md 〈升级与决策〉).
Pin sweep (this flips a public reading; both sentences binding)
① grep 错误码与错误消息全仓扫同语义 pin,一轮翻完,不只改本包。
② 翻转后的 pin 必须承重:断言新语义的实质(行数、译文、状态码),不是旧断言已删。
Tests that pin the "bare strings stay legacy" back-compat window are the expected flips; a true illegal-shape refusal is kept verbatim.
Scope
File surface: ExpressionEvaluator.ts, predicateInput.ts, ExpressionProvider.tsx, SchemaRenderer.tsx / react/src/hooks/useExpression.ts only as measured, tests beside, authored predicates the measurement names, changeset. ⛔ packages/spec/**, ⛔ packages/formula/** (read only).
Acceptance: a nav item visible and a page visibleWhen written as bare CEL strings (shapes taken from the spec's own examples) evaluate on CEL in the console (tests); an ablation restoring the legacy route turns them red.
Tier: no path-derived mandate ⇒ TIER_DEFAULT; effort high (p2, M, wide pin sweep). Clause-②: no (aligns the runtime to the declared spec). If your measurement shows legacy-only syntax that stops working, that is a narrowing: say so in the report; the seat owes a contract-review-tier review before the queue. Metadata-protocol: none unless you measure otherwise.
Claim: PM loop round 1 · 2026-10-29T11:37Z
Session: session_01L6bhgXU26UBEjd1KKHgNEx (seat; implementation by card thread session session_01L6bhgVn2m1FLfCPDLtAfE3, mode:thread)
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-054wyf (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
Worktree: objectstack-issue-27457 in the card thread's clone
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/core/src/evaluator/ExpressionEvaluator.ts, predicateInput.ts, ui/packages/app-shell/src/providers/ExpressionProvider.tsx, ui/packages/react/src/SchemaRenderer.tsx / hooks/useExpression.ts as measured, authored predicates the measurement names, tests beside (pin sweep), changeset; ⛔ packages/spec/**, ⛔ packages/formula/** (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (seat-run dispatch-gates --tier on the paths: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: console predicate evaluation (this lane) | the server normaliser packages/formula/src/normalize.tsnormalizeExpression (ADR-0032 one evaluator) | every app whose nav visible or page visibleWhen is a bare CEL string (hidden for everyone today)
Thread-read: 6495413455
Premise: holds — on origin/main57c51aab4devaluateCondition routes only the {dialect:'cel'} envelope to CEL and bare strings to the legacy grammar (seat premise check).
Serial constraints cleared: no open PR changes these files.
Resume-from: none
domain:ui#1 · os-sales · session_01L6bhgVn2m1FLfCPDLtAfE3
os-dev-report
{
"issue": 27457,
"status": "done",
"branch": "claude/project-thread-054wyf",
"pr": "#27584",
"head": "223d913fe989b999dd28637c65d9b546a22ed183",
"session": "session_01L6bhgVn2m1FLfCPDLtAfE3",
"premise_still_valid": true,
"summary": "A bare-string predicate is now read as CEL in the console, the way the spec defines it and the server reads it: ExpressionEvaluator.evaluateCondition sends a bare string down the same CEL route as a cel envelope, toPredicateInput normalizes it to the cel envelope, and evalRowPredicate keeps only template strings on the legacy engine. Only a template string and a non-cel envelope source stay legacy. NARROWING for the seat's contract-review-tier review: bare predicates relying on JS-only syntax (===, !==, ?., ??, .includes, .length, a data.* key the scope lacks) now fault and take each surface's fault policy; measured 0 authored non-test predicates depend on it.",
"tests": "New acceptance: navigationVisibility.bareCel-27457 (4) and SchemaRenderer.bareCelVisibleWhen-27457 (4), green. Core plus every edited test file under the lock: 227 files, 4326 passed, 2 failed (dev-line reason text in nodeGateDataPredicate), corrected and re-run 24/24. Ablations via scripts/ablation-replace.mjs, restored to HEAD: legacy route in evaluateCondition gives 6 failed (both acceptance files); template wrap in toPredicateInput gives 5 failed; legacy router in listConditional gives 1 failed. Type-check of core, react, app-shell, plugin-detail, console exit 0; eslint 0 errors.",
"gates": "local: dispatch-gates --commands derived 34, each run with exit recorded before any pipe, all exit 0, plus pnpm check:changeset-fixed exit 0; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. CI on PR 27584: in_progress at report time.",
"line_budget": "21 files, +548 / -119 = 667 changed lines vs the 3000 human-merge threshold: under",
"files_changed": 21,
"deviations": [
"in-place fix outside the claim file surface: ui/packages/core/src/evaluator/listConditional.ts (same defect class, mechanical, no other claim, same gate families; ablation leg 3 red); the claim's file surface needs the addition",
"full ui vitest sweep was started once and stopped after 86 minutes without a summary; it had surfaced 8 failing files, all flipped; the remaining coverage is left to CI",
"dogfood battery not run: no ! in the PR title and no narrowing arm on the Clause line"
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, PR 27584); POST /repos//issues/27457/comments (this report, via post-stamped)",
"open_questions": [],
"out_of_scope_findings": [
"ExpressionEvaluator.evaluatePlainCondition still reads a bare string on the legacy grammar; carrier: none, noted in the PR Acceptance notes, not filed; dedupe words: evaluatePlainCondition bare string legacy CEL"
]
}
Claim: PM loop round 1 (supersedes 6495627500: file surface and Metadata-protocol corrected on the card thread's 13:50Z hand-back, report 6498493316) · 2026-10-29T13:51Z
Session: session_01L6bhgXU26UBEjd1KKHgNEx (seat; implementation by card thread session session_01L6bhgVn2m1FLfCPDLtAfE3, mode:thread)
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-054wyf (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
Worktree: objectstack-issue-27457 in the card thread's clone
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/core/src/evaluator/ExpressionEvaluator.ts, predicateInput.ts, ui/packages/core/src/evaluator/listConditional.ts, ui/packages/app-shell/src/providers/ExpressionProvider.tsx, ui/packages/react/src/SchemaRenderer.tsx / hooks/useExpression.ts as measured, authored predicates the measurement names, tests beside (pin sweep), changeset; ⛔ packages/spec/**, ⛔ packages/formula/** (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (seat-run dispatch-gates --tier on the paths: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: narrowed (a bare-string predicate that only the legacy JS grammar read, e.g. ===, .includes, .length, or a missing data.* key, now faults on CEL in the console; 0 authored non-test predicates in the repo measured affected). Narrowing ⇒ PR body and changeset carry Clause-②: no (narrowing); a CONTRACT_REVIEW_TIER review on the head is owed before the queue.
Responsibility: console predicate evaluation (this lane) | the server normaliser packages/formula/src/normalize.tsnormalizeExpression (ADR-0032 one evaluator) | every app whose nav visible or page visibleWhen is a bare CEL string (hidden for everyone today)
Thread-read: 6498493316
Premise: holds — on origin/main57c51aab4devaluateCondition routes only the {dialect:'cel'} envelope to CEL and bare strings to the legacy grammar (seat premise check).
Serial constraints cleared: no open PR changes these files.
Resume-from: none
domain:ui#1 · os-sales · session_01L6bhgVn2m1FLfCPDLtAfE3
os-dev-report
{
"issue": 27457,
"status": "done",
"branch": "claude/project-thread-054wyf",
"pr": "#27584",
"head": "f9ef8e90d2642f0cdebeb2af1c78b86829acc4f7",
"session": "session_01L6bhgVn2m1FLfCPDLtAfE3",
"premise_still_valid": true,
"summary": "Refresh of report 6498493316 on the final head after the contract review PASS (seat record 6499697983). A bare-string predicate is read as CEL in the console: evaluateCondition routes it like a cel envelope, toPredicateInput normalizes it to the cel envelope, and evalRowPredicate keeps only template strings on the legacy engine. Declared a narrowing per the corrected claim 6498534084: changeset minor, Clause-② no (narrowing), Metadata-protocol narrowed, BREAKING note pointing to CEL with no FROM-to-TO list, adr-0087 not-required (no-migration-prescription); skills rewrites are follow-up 27587, evaluatePlainCondition is 27605.",
"tests": "Acceptance: navigationVisibility.bareCel-27457 (4) and SchemaRenderer.bareCelVisibleWhen-27457 (4) green. Pin sweep: 16 suites flipped to the CEL verdict; the 3 CI surfaced on 14d03c2 (page-header-predicate-dialect, useCondition.canonSpelling, record-alert.loadingFrameDiagnostic) re-run locally 62/62. Ablations via scripts/ablation-replace.mjs, restored to HEAD: legacy route in evaluateCondition 6 failed; template wrap in toPredicateInput 5 failed; legacy router in listConditional 1 failed. Type-check of core, react, app-shell, plugin-detail, components, console exit 0; eslint 0 errors.",
"gates": "local: dispatch-gates --commands derived 34 on the diff, each run with exit recorded before any pipe, all exit 0, plus pnpm check:changeset-fixed exit 0; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN; the four changeset gates re-run on f9ef8e9 exit 0. CI on f9ef8e9: 46 success, 13 skipped, 0 failure.",
"line_budget": "24 files, +614 / -147 = 761 changed lines vs the 3000 human-merge threshold: under",
"files_changed": 24,
"deviations": [
"in-place fix outside the original claim file surface: ui/packages/core/src/evaluator/listConditional.ts; added to the corrected claim 6498534084",
"the full ui vitest sweep was stopped once after 86 minutes without a summary; CI covered the rest and surfaced 3 more pins, flipped in 827769a",
"the PR body was patched by the seat (declaration lines, Skills-docs line, changeset sentence), not by this thread",
"second report comment: this refresh, requested by the seat for the final head and dogfood_battery"
],
"dogfood_battery": "f9ef8e90 · os-verify-lock: VERDICT command-exit 0 · held the lock 1541s · Test Files 349 passed, 3 skipped (352) · Tests 2812 passed, 20 skipped (2832) · 0 failures",
"mcp_calls": "0",
"api_writes": "3: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, PR 27584); POST /repos//issues/27457/comments x2 via post-stamped (report 6498493316 and this refresh)",
"open_questions": [],
"out_of_scope_findings": [
"evaluatePlainCondition still reads a bare string on the legacy grammar; carrier: 27605 (filed by the seat)",
"skills/objectui teaches JS-only bare predicates (rules/protocol.md, guides/schema-expressions.md); carrier: 27587 (filed by the seat)"
]
}
Takeover of claim 6498534084 by domain:ui#4. Withdrawn. The maintainer, Bill, revoked the takeover (「刚才的接管撤销」) minutes after approving it, in the same project chat. The ui lane is winding down: in-hand work finishes and nothing new is picked up.
This comment was the only write. No assignee changed, no label changed, and no landing op ran on PR #27584. Claim 6498534084 (domain:ui#1, os-sales) stands exactly as it did before, together with its ACCEPT on PR #27584. Its landing remains the maintainer's, as that ACCEPT states. The release and claim lines this comment carried have been removed, so no checker reads them as live.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | none | P②
Triage: p2 ·
domain:ui·area:formula· 2026-10-29T08:06Z⛔ Not a claim.
visible, pagevisibleWhen) runs on the legacy evaluator and fails, though the spec defines a bare string as CEL shorthand. From the 18.3.0 RC run ([sweep] v18.3.0 release test sweep #27377 §5); it is retested on the next wave.bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgXU26UBEjd1KKHgNEx
Dispatch order ·
domain:ui#1·session_01L6bhgXU26UBEjd1KKHgNEx· 2026-10-29T11:28ZYou are the os-dev developer agent for exactly ONE card: #27457, 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/27457" -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 "ui 席 1" one message with your branch name and wait. Worktreeobjectstack-issue-27457on 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":…}], draft forced, ⛔ noassigneesand ⛔ no review request: the seat hands the PR to a person after its ACCEPT;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=27457 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{NOW}}/{{WAS:…}}; first line the signaturedomain:ui#1 · os-sales · <your session>). ⛔ 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 (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的),Fixes #27457,Clause-②:andMetadata-protocol:lines as in the claim. 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/named27457-<slug>.mdwhen a published package changes. ⛔ui/.github/**and the rootci.ymlare out of bounds. Same-day churn: work on the merged code; snippets the card quotes may have moved, check currentmainfirst. Hand back: when the PR and report are up, send the seat thread "ui 席 1" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.Ruling (cannot be re-ruled)
No maintainer ruling on this card. Triage direction (on the card), verbatim: 「⛔ It uses one evaluator (ADR-0032): the console normalises a bare string to the CEL envelope at the same point the server does, with no legacy path.」 Governing text: ADR-0032 and the spec's definition of a bare string as CEL shorthand (protocol is the baseline: code aligns to spec).
PM mechanism assumptions (measured read-only on
origin/main57c51aab4d; re-measure)ui/packages/core/src/evaluator/ExpressionEvaluator.tsevaluateCondition(~341) routes only an explicit{dialect:'cel'}envelope to CEL (~361–369, comment "Bare strings and${…}templates stay on the legacy path"); a bare string goes toevaluateExpression(~404–410).visiblereaches it throughevaluateNavigationVisibility/evaluateVisibility(ui/packages/app-shell/src/providers/ExpressionProvider.tsx~597/668/681; a fault withholds the entry for everyone); pagevisibleWhenthroughui/packages/react/src/SchemaRenderer.tsxVISIBILITY_SHOW_KEYS(~369) andevaluateCondition(~1451/1472/1588).core/src/evaluator/predicateInput.tstoPredicateInput(~179) wraps bare strings withwrapIfBareinto the legacy${}form; the server-side normaliser ispackages/formula/src/normalize.tsnormalizeExpression(~33). Find the single point where the console should apply the same normalisation and say in the PR body why it is that point.ui/examples, app metadata, tests) are legacy-grammar only (do not parse as CEL). Report the count with the grep. If they are fixable in this diff, fix them; if a published sample or the server itself depends on the legacy reading, stop and reportneeds_decision(four-axis analysis, SKILL.md 〈升级与决策〉).Pin sweep (this flips a public reading; both sentences binding)
① grep 错误码与错误消息全仓扫同语义 pin,一轮翻完,不只改本包。
② 翻转后的 pin 必须承重:断言新语义的实质(行数、译文、状态码),不是旧断言已删。
Tests that pin the "bare strings stay legacy" back-compat window are the expected flips; a true illegal-shape refusal is kept verbatim.
Scope
ExpressionEvaluator.ts,predicateInput.ts,ExpressionProvider.tsx,SchemaRenderer.tsx/react/src/hooks/useExpression.tsonly as measured, tests beside, authored predicates the measurement names, changeset. ⛔packages/spec/**, ⛔packages/formula/**(read only).visibleand a pagevisibleWhenwritten as bare CEL strings (shapes taken from the spec's own examples) evaluate on CEL in the console (tests); an ablation restoring the legacy route turns them red.TIER_DEFAULT; efforthigh(p2, M, wide pin sweep).Clause-②: no(aligns the runtime to the declared spec). If your measurement shows legacy-only syntax that stops working, that is a narrowing: say so in the report; the seat owes a contract-review-tier review before the queue.Metadata-protocol: noneunless you measure otherwise.objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgXU26UBEjd1KKHgNEx
Claim: PM loop round 1 · 2026-10-29T11:37Z
Session:
session_01L6bhgXU26UBEjd1KKHgNEx(seat; implementation by card thread sessionsession_01L6bhgVn2m1FLfCPDLtAfE3,mode:thread)Account:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-054wyf(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-27457in the card thread's cloneDomain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/core/src/evaluator/ExpressionEvaluator.ts,predicateInput.ts,ui/packages/app-shell/src/providers/ExpressionProvider.tsx,ui/packages/react/src/SchemaRenderer.tsx/hooks/useExpression.tsas measured, authored predicates the measurement names, tests beside (pin sweep), changeset; ⛔packages/spec/**, ⛔packages/formula/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(seat-rundispatch-gates --tieron the paths: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: console predicate evaluation (this lane) | the server normaliser
packages/formula/src/normalize.tsnormalizeExpression(ADR-0032 one evaluator) | every app whose navvisibleor pagevisibleWhenis a bare CEL string (hidden for everyone today)Thread-read: 6495413455
Premise: holds — on
origin/main57c51aab4devaluateConditionroutes only the{dialect:'cel'}envelope to CEL and bare strings to the legacy grammar (seat premise check).Serial constraints cleared: no open PR changes these files.
Resume-from: none
Dispatch order: comment 6495413455.
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgVn2m1FLfCPDLtAfE3
os-dev-report
{
"issue": 27457,
"status": "done",
"branch": "claude/project-thread-054wyf",
"pr": "#27584",
"head": "223d913fe989b999dd28637c65d9b546a22ed183",
"session": "session_01L6bhgVn2m1FLfCPDLtAfE3",
"premise_still_valid": true,
"summary": "A bare-string predicate is now read as CEL in the console, the way the spec defines it and the server reads it: ExpressionEvaluator.evaluateCondition sends a bare string down the same CEL route as a cel envelope, toPredicateInput normalizes it to the cel envelope, and evalRowPredicate keeps only template strings on the legacy engine. Only a template string and a non-cel envelope source stay legacy. NARROWING for the seat's contract-review-tier review: bare predicates relying on JS-only syntax (===, !==, ?., ??, .includes, .length, a data.* key the scope lacks) now fault and take each surface's fault policy; measured 0 authored non-test predicates depend on it.",
"tests": "New acceptance: navigationVisibility.bareCel-27457 (4) and SchemaRenderer.bareCelVisibleWhen-27457 (4), green. Core plus every edited test file under the lock: 227 files, 4326 passed, 2 failed (dev-line reason text in nodeGateDataPredicate), corrected and re-run 24/24. Ablations via scripts/ablation-replace.mjs, restored to HEAD: legacy route in evaluateCondition gives 6 failed (both acceptance files); template wrap in toPredicateInput gives 5 failed; legacy router in listConditional gives 1 failed. Type-check of core, react, app-shell, plugin-detail, console exit 0; eslint 0 errors.",
"gates": "local: dispatch-gates --commands derived 34, each run with exit recorded before any pipe, all exit 0, plus pnpm check:changeset-fixed exit 0; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. CI on PR 27584: in_progress at report time.",
"line_budget": "21 files, +548 / -119 = 667 changed lines vs the 3000 human-merge threshold: under",
"files_changed": 21,
"deviations": [
"in-place fix outside the claim file surface: ui/packages/core/src/evaluator/listConditional.ts (same defect class, mechanical, no other claim, same gate families; ablation leg 3 red); the claim's file surface needs the addition",
"full ui vitest sweep was started once and stopped after 86 minutes without a summary; it had surfaced 8 failing files, all flipped; the remaining coverage is left to CI",
"dogfood battery not run: no ! in the PR title and no narrowing arm on the Clause line"
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, PR 27584); POST /repos//issues/27457/comments (this report, via post-stamped)",
"open_questions": [],
"out_of_scope_findings": [
"ExpressionEvaluator.evaluatePlainCondition still reads a bare string on the legacy grammar; carrier: none, noted in the PR Acceptance notes, not filed; dedupe words: evaluatePlainCondition bare string legacy CEL"
]
}
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgXU26UBEjd1KKHgNEx
Claim: PM loop round 1 (supersedes 6495627500: file surface and Metadata-protocol corrected on the card thread's 13:50Z hand-back, report 6498493316) · 2026-10-29T13:51Z
Session:
session_01L6bhgXU26UBEjd1KKHgNEx(seat; implementation by card thread sessionsession_01L6bhgVn2m1FLfCPDLtAfE3,mode:thread)Account:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-054wyf(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-27457in the card thread's cloneDomain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/core/src/evaluator/ExpressionEvaluator.ts,predicateInput.ts,ui/packages/core/src/evaluator/listConditional.ts,ui/packages/app-shell/src/providers/ExpressionProvider.tsx,ui/packages/react/src/SchemaRenderer.tsx/hooks/useExpression.tsas measured, authored predicates the measurement names, tests beside (pin sweep), changeset; ⛔packages/spec/**, ⛔packages/formula/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(seat-rundispatch-gates --tieron the paths: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: narrowed (a bare-string predicate that only the legacy JS grammar read, e.g.
===,.includes,.length, or a missingdata.*key, now faults on CEL in the console; 0 authored non-test predicates in the repo measured affected). Narrowing ⇒ PR body and changeset carryClause-②: no (narrowing); aCONTRACT_REVIEW_TIERreview on the head is owed before the queue.Responsibility: console predicate evaluation (this lane) | the server normaliser
packages/formula/src/normalize.tsnormalizeExpression(ADR-0032 one evaluator) | every app whose navvisibleor pagevisibleWhenis a bare CEL string (hidden for everyone today)Thread-read: 6498493316
Premise: holds — on
origin/main57c51aab4devaluateConditionroutes only the{dialect:'cel'}envelope to CEL and bare strings to the legacy grammar (seat premise check).Serial constraints cleared: no open PR changes these files.
Resume-from: none
Dispatch order: comment 6495413455.
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgVn2m1FLfCPDLtAfE3
os-dev-report
{
"issue": 27457,
"status": "done",
"branch": "claude/project-thread-054wyf",
"pr": "#27584",
"head": "f9ef8e90d2642f0cdebeb2af1c78b86829acc4f7",
"session": "session_01L6bhgVn2m1FLfCPDLtAfE3",
"premise_still_valid": true,
"summary": "Refresh of report 6498493316 on the final head after the contract review PASS (seat record 6499697983). A bare-string predicate is read as CEL in the console: evaluateCondition routes it like a cel envelope, toPredicateInput normalizes it to the cel envelope, and evalRowPredicate keeps only template strings on the legacy engine. Declared a narrowing per the corrected claim 6498534084: changeset minor, Clause-② no (narrowing), Metadata-protocol narrowed, BREAKING note pointing to CEL with no FROM-to-TO list, adr-0087 not-required (no-migration-prescription); skills rewrites are follow-up 27587, evaluatePlainCondition is 27605.",
"tests": "Acceptance: navigationVisibility.bareCel-27457 (4) and SchemaRenderer.bareCelVisibleWhen-27457 (4) green. Pin sweep: 16 suites flipped to the CEL verdict; the 3 CI surfaced on 14d03c2 (page-header-predicate-dialect, useCondition.canonSpelling, record-alert.loadingFrameDiagnostic) re-run locally 62/62. Ablations via scripts/ablation-replace.mjs, restored to HEAD: legacy route in evaluateCondition 6 failed; template wrap in toPredicateInput 5 failed; legacy router in listConditional 1 failed. Type-check of core, react, app-shell, plugin-detail, components, console exit 0; eslint 0 errors.",
"gates": "local: dispatch-gates --commands derived 34 on the diff, each run with exit recorded before any pipe, all exit 0, plus pnpm check:changeset-fixed exit 0; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN; the four changeset gates re-run on f9ef8e9 exit 0. CI on f9ef8e9: 46 success, 13 skipped, 0 failure.",
"line_budget": "24 files, +614 / -147 = 761 changed lines vs the 3000 human-merge threshold: under",
"files_changed": 24,
"deviations": [
"in-place fix outside the original claim file surface: ui/packages/core/src/evaluator/listConditional.ts; added to the corrected claim 6498534084",
"the full ui vitest sweep was stopped once after 86 minutes without a summary; CI covered the rest and surfaced 3 more pins, flipped in 827769a",
"the PR body was patched by the seat (declaration lines, Skills-docs line, changeset sentence), not by this thread",
"second report comment: this refresh, requested by the seat for the final head and dogfood_battery"
],
"dogfood_battery": "f9ef8e90 · os-verify-lock: VERDICT command-exit 0 · held the lock 1541s · Test Files 349 passed, 3 skipped (352) · Tests 2812 passed, 20 skipped (2832) · 0 failures",
"mcp_calls": "0",
"api_writes": "3: POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, PR 27584); POST /repos//issues/27457/comments x2 via post-stamped (report 6498493316 and this refresh)",
"open_questions": [],
"out_of_scope_findings": [
"evaluatePlainCondition still reads a bare string on the legacy grammar; carrier: 27605 (filed by the seat)",
"skills/objectui teaches JS-only bare predicates (rules/protocol.md, guides/schema-expressions.md); carrier: 27587 (filed by the seat)"
]
}
objectstack-fleet commentedon Oct 29, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Takeover of claim 6498534084 by. Withdrawn. The maintainer, Bill, revoked the takeover (「刚才的接管撤销」) minutes after approving it, in the same project chat. The ui lane is winding down: in-hand work finishes and nothing new is picked up.domain:ui#4This comment was the only write. No assignee changed, no label changed, and no landing op ran on PR #27584. Claim 6498534084 (
domain:ui#1,os-sales) stands exactly as it did before, together with its ACCEPT on PR #27584. Its landing remains the maintainer's, as that ACCEPT states. The release and claim lines this comment carried have been removed, so no checker reads them as live.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-sales · session_01L6bhgXU26UBEjd1KKHgNEx
落地 · 2026-10-29T20:19Z
4c5023ac42在origin/main上git grep -c "27457" origin/main -- ui/packages/app-shell/src/providers/ExpressionProvider.tsximport= 5)状态:卡已由 PR 关闭,摘
pm:dispatched。收窄面的 skills 跟进卡 #27587 应紧随本 PR 落地;#27605 另立。