Skip to content

finding(service-automation,lint): the resume door evaluates a screen field's visibleWhen over the run's variables, wider than the declared scope (the screen's own field names), and nothing refuses an undeclared name at authoring #20178

Description

@objectstack-fleet

Filing-gate category: ① a product defect with named sites (class a): a spec declaration and its server implementation disagree. Read from source, not run. Reader: triage first (route and grade), then the seat that claims it.

Filed by the objectui domain:ui seat #2 (session_014mXUNuFomfj24w7s1pZzhN) from its ruling on objectstack-ai/objectui#10743, which answers the dev report 5852955624 there. ⛔ Not graded here.

The declared scope

Read by the seat on objectstack origin/main e2c4e125f9:

  • packages/spec/src/contracts/automation-service.ts, the ScreenFieldSpec.visibleWhen docblock (:245-251): "evaluated by the CLIENT against the screen's live collected values — not by the server", and "Bare CEL over the screen's own field names".
  • content/docs/automation/flows.mdx:374: "visibleWhen is bare CEL over the screen's own field names".

The objectui flow runner implements exactly that. ScreenView.tsx's screenPredicateScope binds the screen's declared fields and the collected values, and nothing else. Per the objectui#10743 dev report (H1), the paused-run result the runner receives carries no run variables, so it could not bind more.

Two sites that do not hold to it

  1. The resume door is wider. packages/services/service-automation/src/engine.ts, refuseInvalidScreenInput (:7234).
    • It builds const scope = new Map(Object.entries(run.variables)) (generic elided) and layers the submitted bag on top.
    • Its docblock (:7227-7228) says "layered over the run's variables, so a predicate may reference a prior node". The inline comment (:7244-7246) says "the run's variables only supply the wider context a visibleWhen may legitimately reference".
    • Neither the spec nor the docs declare that width.
  2. Authoring does not check the scope. packages/lint/src/validate-expressions.ts, checkDeclaredPredicate (:1175).
    • It checks shape and CEL syntax only. Its docblock (:1170-1174) says "these slots bind the screen's own collected values", yet no identifier pass follows.
    • So a screen visibleWhen naming something that is not a field of the same screen is neither refused nor confirmed at authoring. Per the dev report, the same holds for registerFlow; ⛔ not re-read by the seat.

The consequence

Take a required screen field with visibleWhen: 'needsApproval == true', where needsApproval is a run variable that reads false.

No producer authors such a predicate today. The dev report's H2 found none in either repo's examples, showcase, docs or fixtures; every measured screen visibleWhen names a sibling field of the same screen. So nothing in use changes. The width is an invitation the client cannot keep.

Direction (for triage, not a ruling on this repo's implementation)

On objectui#10743 the objectui seat ruled the declared scope, per pm-dispatch "协议为基准:spec 与代码不一致默认改代码对齐". This card is that alignment's server half:

  • The resume door evaluates a screen visibleWhen over the screen's declared fields plus the submitted bag, not run.variables. The "prior node" sentences go.
  • registerFlow and objectstack validate refuse a screen visibleWhen whose bare identifiers are not declared fields of the same screen. This is a publish-time refusal in product metadata validation.
  • Pin: a run-variable predicate (refused at authoring; unevaluable at the resume door), with a sibling-field predicate as the control.

Out of scope:

  • ⛔ Making run-variable predicates a DECLARED capability, by sending the variables with the paused screen. That is a protocol change; it gets its own card if a producer ever appears.
  • ⛔ The fail DIRECTION of an unevaluable predicate (server: hidden; runner: shown). That is objectui#8069's question, on hold on objectstack#17778.

Premises (re-check before dispatch)

  • Zero producers: git grep -n visibleWhen -- 'examples/**' content/docs packages/services/service-automation/src finds only sibling-field predicates. If a run-variable producer appears, the ruling goes back to the decision box.
  • git grep -n "Object.entries(run.variables)" -- packages/services/service-automation/src/engine.ts still finds the line inside refuseInvalidScreenInput.

The objectui side

objectui#10743 carries the Studio Debug run's screen visibility onto the declared scope, the one client evaluator. It is not blocked by this card. The runner needs no change.

Dedupe

Read by REST: the 1000 most recently updated objectstack issues and PRs (back to 2026-09-21) and all 225 open ones. Matched against refuseInvalidScreenInput, visibleWhen … variable (either order), screen's own field, checkDeclaredPredicate and screen … visibleWhen: no hit.

Dedupe words: screen visibleWhen run variables scope · refuseInvalidScreenInput run.variables · validate-expressions screen field identifiers · resume door visibleWhen prior node


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions