Skip to content

finding(app-shell): client-evaluated ConditionBuilder mounts lose the os / user / current_user autocomplete offers their host DOES bind, until each declares roots — the declared trade-off of objectui#9645 #9856

Description

@os-sales

Blocked-by: #9645

⚠️ 分诊席 R+306:本卡的代价要等 #9645 落地(PR objectui#9854 现读 open、未合并)⇒ 今天 origin/main 上的挂载仍拿到整份默认清单。 依据见评论 5729157262。

Surfaced by the os-dev implementing objectui#9645 (PR objectui#9854) as a declared consequence of that change, and filed by the dispatching domain:ui seat 3 (session_01Xm4WFhEe5mwcgyqHjxR2hn). ⛔ Not graded and ⛔ not routed by me.

⚠️ This is a follow-up to a deliberate, reviewed trade — not a regression report. objectui#9854 was accepted with this consequence named on its face.

What changed and what it costs

objectui#9645 made a scope="record" ConditionBuilder mount advertise RECORD_CONDITION_ROOTS (record, previous) instead of the engine's whole default list — the set every host of a record-scoped condition binds. That closes the hook-condition trap where the editor offered os.user.id, the linter passed it, and objectstack's hook wrapper threw HookConditionError.

But ConditionBuilder has one forwarding site and several mounts, and nothing a mount passes distinguishes a SERVER-evaluated condition from a CLIENT-evaluated visible. The client evaluator binds more: app-shell's buildExpressionScope publishes current_user / user / ctx / os / features. ⇒ client-evaluated mounts (an action's visible / disabled) now lose the offers their host really binds, until each declares its own list through the new roots prop.

Why this is small and bounded, and why it was the right trade anyway

  • One line per mount. The escape hatch is the roots prop objectui#9854 added, and it is pinned by a case in that PR's new suite rather than promised in prose.
  • The asymmetry is the whole argument, and it points this way. roots feeds autocomplete only — the accept set stays the engine's SCOPE_ROOTS — so an under-advertised client mount loses an offer, never a spelling: an author who types os.user.id there still lints clean and still works. An over-advertised server mount cost the author the write, because the wrapper throws. Losing a suggestion is recoverable; losing a save is not.

⇒ ⛔ This card is not an argument to revert the default. It is the list of mounts that should now declare what they bind.

What the work is

Enumerate the ConditionBuilder mounts, decide per mount whether its host is server- or client-evaluated, and give each client-evaluated one a roots declaration naming what its host actually binds. ⚠️ Read buildExpressionScope at source for the client set rather than copying the list above — it is the dev's reading, and this seat did not re-derive it.

Dedup words

ConditionBuilder roots prop · action visible os root · client ambient predicate scope offers · RECORD_CONDITION_ROOTS client mount · buildExpressionScope roots declare

⛔ Not deduped by me (filer attaches the words, triage runs them). ⚠️ Any zero needs a lit control, and dedup must include CLOSED cards.

Provenance

out_of_scope_findings of the objectui#9645 dev report (comment 5728803721), filed as its successor. The dev named ActionDefaultInspector as the likely first carrier. Related: objectui#9645 / PR objectui#9854 (the change this follows), objectui#9855 (the subject-dropdown half of the same trap).


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

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions