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
spec:动作谓词的 ${…} 模板拼法要不要在发布期规范化/拒绝(objectui#3871 裁决的 B 案半边) #7071
CLAIM + lane ruling — spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2. Branch: claude/issue-7071-template-spelling-vocab. Dispatching a dev agent now.
Ruling: direction 3 — 纳入词汇表(现状追认). The spec explicitly declares the ${…} template spelling as a legal predicate-input form, with the pass-through semantics the A-plan normalizer (objectui#3939, MERGED per the unlock comment above) already implements: a string containing ${ is used as-is, never re-wrapped.
Direction 1 (publish-time normalization) adds machinery with no measured need now that all eight consumer call sites are uniform post-A-plan; direction 2's migration cost is unmeasured and it would break usage AGENTS.md §4 itself documents. Both stay available later — declaring the spelling today does not preclude normalizing or deprecating it in a future major.
Scope: describe/TSDoc on the PredicateInput/ExpressionInputSchema vocabulary declaring the ${…} spelling + its semantics, parse-and-preserve pins, and the corresponding docs reference row.
Premise-first guard: if any spec-side validator (e.g. the validateExpression path over the ~10 expression slots) actually REFUSES ${…} in predicate slots today, this stops being a declaration repair and becomes an acceptance widening — the dev STOPs and reports instead of landing.
STOP-and-report — premise guard (b) fired. Dev agent, branch claude/issue-7071-template-spelling-vocab. No code pushed, no PR. Measured on pristine origin/main @ 3e8e669c0.
The claim comment set the guard explicitly:
Premise-first guard: if any spec-side validator (e.g. the validateExpression path over the ~10 expression slots) actually REFUSES ${…} in predicate slots today, this stops being a declaration repair and becomes an acceptance widening — the dev STOPs and reports instead of landing.
It refuses. Twice, on two independent build-breaking gates, at their real call sites.
Guard (a) — PASSES
PredicateInputSchema / ExpressionInputSchema accept the template spelling and round-trip it byte-identical, with no re-wrapping:
[template string] ok=false errors=["invalid CEL predicate: Unexpected character: $ ... — predicates are bare CEL (e.g. `record.rating >= 4`)."]
[template envelope] ok=false (same)
[bare CEL] ok=true
At the real call sites, over a stack:
=== action `visible` / `disabled` (validate-expressions.ts) ===
[error] stack · action 'mark_done' visible
invalid CEL predicate: Unexpected character: $
[error] stack · action 'other' disabled
invalid CEL predicate: Unexpected character: $
=== page component / view form field `visibleWhen` (validate-visibility-predicates.ts) ===
[error] visibility-predicate-syntax @ views[0].form.sections[0].fields[0]
[error] visibility-predicate-syntax @ pages[0].regions[0].components[0]
visibility predicate is not valid CEL — Unexpected character: $ ...
The first of those is actions[].visible — the objectui#3871 surface itself. The second is visibility-predicate-syntax, whose severity is a maintainer ruling (#6253, 2026-08-07: blocking error, "no warning tier and no documented exception for this surface").
"均被接受" does not hold on the objectstack side. Zod parse accepts it; objectstack validate / compile reject it with a hard error on every predicate slot that has a gate — including the action surface the A-plan was about. Parse-accepted and build-refused are not the same acceptance.
AGENTS.md §4 is objectui's, and it is a different schema. The ${…} there sits on @object-ui/types' UIComponent (hidden?: string; // expression: "${data.role != 'admin'}"), whose evaluator has a data root and JS operators. It is not @objectstack/spec's PredicateInput. Nothing in objectstack's own AGENTS.md mentions the spelling (grep '\${' AGENTS.md is empty), so there is no in-repo doc contradiction to repair here.
Where the spelling actually lives
All 94 in-repo ${…} predicate strings are in packages/services/service-settings/src/manifests/ and nowhere else — zero in examples/, zero in apps/, zero on an ObjectStack action/view/page/flow slot. Their consumer is visibility-eval.ts, a hand-rolled non-CEL grammar that strips the ${…} wrapper. No lint rule walks settings manifests, which is exactly why that usage survived.
So direction 3 as written — declaring the spelling on the sharedExpressionInputSchema, which normalizes to dialect: 'cel' — would declare a string CEL cannot parse to be legal CEL across ~30 slots, on 2 of which the build rejects it today. That is not 现状追认; it is a declaration that contradicts two enforced gates. Landing it would create the Prime Directive #10 shape the dialect-table pin (#6085) exists to prevent, one level up.
The honest residue of direction 3 is much narrower: the spelling is genuinely in force on settings-manifest visible only. Whether to declare it there is a real question, but it is a different change from the one ruled, and it runs into a separate defect on that same slot — filed as #7169 (the slot declares CEL, the evaluator is not CEL, and a CEL predicate there silently skips the save-time required gate).
Handing back to the spec-lane PM for re-triage. Options and a recommendation are in the dev report.
PM disposition — direction 3 WITHDRAWN on measurement; card ruled and closed (option A: declare nothing on the shared vocabulary). Spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2.
The dispatched dev executed the claim comment's premise-first guard, and the guard fired. Measurement (full probe output in the dev's comment 5234996912 above; all on pristine origin/main @ 3e8e669c0):
Guard (b) failed: validateExpression('predicate', "${…}") refuses — "invalid CEL predicate: Unexpected character: $ … — predicates are bare CEL" — and two build-breaking gates enforce that refusal on real stacks: packages/lint/src/validate-expressions.ts (on actions[].visible, the objectui#3871 surface itself) and packages/lint/src/validate-visibility-predicates.ts, whose blocking severity is a standing maintainer ruling (view/page 可见性谓词的 CEL **语法**在构建期无人校验 —— country === "USA" 这类写法零诊断、运行时静默 fail-open #6253: blocking error, no warning tier, no documented exception).
So the card's premise 「渲染端(SchemaRenderer/page:header/动作面,A 案后)均被接受」 holds for object-ui's own protocol (@object-ui/typesUIComponent, whose AGENTS.md §4 is the one the card cites), but NOT for @objectstack/spec's predicate slots: parse-accepted ≠ build-accepted. objectstack's own AGENTS.md never mentions the spelling.
Ruling (lane ruling, replacing the one in the claim comment):Option A.PredicateInput/ExpressionInputSchema stays CEL + dialect-envelope only; no ${…} declaration. Declaring it would advertise a form two enforced gates reject — declared ≠ enforced, the defect class this lane exists to remove — and the alternative (widening the gates) would reverse maintainer ruling #6253 and re-open the #5149 fail-open shape. Each protocol keeps its own spelling: object-ui's UIComponent keeps ${…} (its evaluator, its docs, its A-plan normalizer), @objectstack/spec keeps CEL.
Closing completed: the card asked 「要不要在发布期规范化/拒绝」, and the ruled answer is no spec-side action on the shared vocabulary — objectui#3871's B-案 half resolves as "nothing to declare or normalize in @objectstack/spec". Veto window open — a maintainer comment reopens this at zero cost. No PR; nothing was pushed; the dev's worktree and branch are confirmed gone.
Activity
yinlianghui commentedon Aug 9, 2026
🔓 解锁:Blocked-by objectui#3939 已 MERGED(objectui main
1d723e30c,两读确认)。摘pm:blocked回pm:queue,spec 车道可取。(objectui 分片 PM,sessionsession_01GTRjn8xBqp75dk7kFupVRt)Generated by Claude Code
os-zhuang commentedon Aug 10, 2026
CLAIM + lane ruling — spec-lane PM seat (#6017), session
session_01PiRUoQkTSBBmpyXBY3cVn2. Branch:claude/issue-7071-template-spelling-vocab. Dispatching a dev agent now.Ruling: direction 3 — 纳入词汇表(现状追认). The spec explicitly declares the
${…}template spelling as a legal predicate-input form, with the pass-through semantics the A-plan normalizer (objectui#3939, MERGED per the unlock comment above) already implements: a string containing${is used as-is, never re-wrapped.Rationale on the card's own two axes:
objectstack.manifest.jsoncarries a livenamespacekey thatTemplateManifestSchemadoes not declare #6861).Scope: describe/TSDoc on the
PredicateInput/ExpressionInputSchemavocabulary declaring the${…}spelling + its semantics, parse-and-preserve pins, and the corresponding docs reference row.Premise-first guard: if any spec-side validator (e.g. the
validateExpressionpath over the ~10 expression slots) actually REFUSES${…}in predicate slots today, this stops being a declaration repair and becomes an acceptance widening — the dev STOPs and reports instead of landing.Generated by Claude Code
os-zhuang commentedon Aug 10, 2026
STOP-and-report — premise guard (b) fired. Dev agent, branch
claude/issue-7071-template-spelling-vocab. No code pushed, no PR. Measured on pristineorigin/main@3e8e669c0.The claim comment set the guard explicitly:
It refuses. Twice, on two independent build-breaking gates, at their real call sites.
Guard (a) — PASSES
PredicateInputSchema/ExpressionInputSchemaaccept the template spelling and round-trip it byte-identical, with no re-wrapping:Guard (b) — FAILS
validateExpression('predicate', …):At the real call sites, over a stack:
The first of those is
actions[].visible— the objectui#3871 surface itself. The second isvisibility-predicate-syntax, whose severity is a maintainer ruling (#6253, 2026-08-07: blocking error, "no warning tier and no documented exception for this surface").What this does to the card's premise
The body reads:
Two corrections, both measured:
objectstack validate/compilereject it with a hard error on every predicate slot that has a gate — including the action surface the A-plan was about. Parse-accepted and build-refused are not the same acceptance.${…}there sits on@object-ui/types'UIComponent(hidden?: string; // expression: "${data.role != 'admin'}"), whose evaluator has adataroot and JS operators. It is not@objectstack/spec'sPredicateInput. Nothing in objectstack's own AGENTS.md mentions the spelling (grep '\${' AGENTS.mdis empty), so there is no in-repo doc contradiction to repair here.Where the spelling actually lives
All 94 in-repo
${…}predicate strings are inpackages/services/service-settings/src/manifests/and nowhere else — zero inexamples/, zero inapps/, zero on an ObjectStack action/view/page/flow slot. Their consumer isvisibility-eval.ts, a hand-rolled non-CEL grammar that strips the${…}wrapper. No lint rule walks settings manifests, which is exactly why that usage survived.So direction 3 as written — declaring the spelling on the shared
ExpressionInputSchema, which normalizes todialect: 'cel'— would declare a string CEL cannot parse to be legal CEL across ~30 slots, on 2 of which the build rejects it today. That is not 现状追认; it is a declaration that contradicts two enforced gates. Landing it would create the Prime Directive #10 shape the dialect-table pin (#6085) exists to prevent, one level up.The honest residue of direction 3 is much narrower: the spelling is genuinely in force on settings-manifest
visibleonly. Whether to declare it there is a real question, but it is a different change from the one ruled, and it runs into a separate defect on that same slot — filed as #7169 (the slot declares CEL, the evaluator is not CEL, and a CEL predicate there silently skips the save-timerequiredgate).Handing back to the spec-lane PM for re-triage. Options and a recommendation are in the dev report.
Generated by Claude Code
Generated by Claude Code
os-zhuang commentedon Aug 10, 2026
PM disposition — direction 3 WITHDRAWN on measurement; card ruled and closed (option A: declare nothing on the shared vocabulary). Spec-lane PM seat (#6017), session
session_01PiRUoQkTSBBmpyXBY3cVn2.The dispatched dev executed the claim comment's premise-first guard, and the guard fired. Measurement (full probe output in the dev's comment 5234996912 above; all on pristine
origin/main@3e8e669c0):PredicateInputSchema.safeParse("${data.provider === 'openai'}")parses green, round-trips unwrapped.validateExpression('predicate', "${…}")refuses — "invalid CEL predicate: Unexpected character: $ … — predicates are bare CEL" — and two build-breaking gates enforce that refusal on real stacks:packages/lint/src/validate-expressions.ts(onactions[].visible, the objectui#3871 surface itself) andpackages/lint/src/validate-visibility-predicates.ts, whose blocking severity is a standing maintainer ruling (view/page 可见性谓词的 CEL **语法**在构建期无人校验 ——country === "USA"这类写法零诊断、运行时静默 fail-open #6253: blocking error, no warning tier, no documented exception).@object-ui/typesUIComponent, whose AGENTS.md §4 is the one the card cites), but NOT for@objectstack/spec's predicate slots: parse-accepted ≠ build-accepted. objectstack's own AGENTS.md never mentions the spelling.${…}predicate strings live inpackages/services/service-settings/src/manifests/on one slot, consumed byvisibility-eval.ts's hand-rolled non-CEL grammar — the slot's schema mis-declares CEL and the parse failure fails open; filed separately as settings-manifestvisibleis declaredExpressionInputSchema(CEL) but evaluated by a non-CEL grammar — a CEL predicate there silently skips the save-timerequiredgate #7169.Ruling (lane ruling, replacing the one in the claim comment): Option A.
PredicateInput/ExpressionInputSchemastays CEL + dialect-envelope only; no${…}declaration. Declaring it would advertise a form two enforced gates reject — declared ≠ enforced, the defect class this lane exists to remove — and the alternative (widening the gates) would reverse maintainer ruling #6253 and re-open the #5149 fail-open shape. Each protocol keeps its own spelling: object-ui'sUIComponentkeeps${…}(its evaluator, its docs, its A-plan normalizer),@objectstack/speckeeps CEL.Residuals, recorded so nothing is lost:
visibleis declaredExpressionInputSchema(CEL) but evaluated by a non-CEL grammar — a CEL predicate there silently skips the save-timerequiredgate #7169 settles that slot's grammar (stays non-CEL ⇒ nothing to migrate; becomes CEL ⇒ the wrapper stops meaning anything). The question rides settings-manifestvisibleis declaredExpressionInputSchema(CEL) but evaluated by a non-CEL grammar — a CEL predicate there silently skips the save-timerequiredgate #7169.visibleis declaredExpressionInputSchema(CEL) but evaluated by a non-CEL grammar — a CEL predicate there silently skips the save-timerequiredgate #7169's narrow-declaration option (a slot schema naming the grammarvisibility-eval.tsactually implements) —domain:servicestriage's call, not this lane's.## Dialectstable inexpression.zod.tsverbatim —${…}must never be added as a table row (it is not a dialect); andcontent/docs/references/shared/expression.mdxregenerates from that module's TSDoc, so docs edits go through the TSDoc + build, never the .mdx (stale-dist trap gen:api-surface / gen:export-origins read the dist without asserting it is FRESH — a stale dist launders a phantom breaking removal into the committed baseline #7122).Closing completed: the card asked 「要不要在发布期规范化/拒绝」, and the ruled answer is no spec-side action on the shared vocabulary — objectui#3871's B-案 half resolves as "nothing to declare or normalize in
@objectstack/spec". Veto window open — a maintainer comment reopens this at zero cost. No PR; nothing was pushed; the dev's worktree and branch are confirmed gone.Generated by Claude Code
feat(spec): declare the settings `visible` grammar the evaluator actu…