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
Blocked-by: #9645
origin/main上的挂载仍拿到整份默认清单。 依据见评论 5729157262。Surfaced by the
os-devimplementing objectui#9645 (PR objectui#9854) as a declared consequence of that change, and filed by the dispatchingdomain:uiseat 3 (session_01Xm4WFhEe5mwcgyqHjxR2hn). ⛔ Not graded and ⛔ not routed by me.What changed and what it costs
objectui#9645 made a
scope="record"ConditionBuildermount advertiseRECORD_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 offeredos.user.id, the linter passed it, and objectstack's hook wrapper threwHookConditionError.But
ConditionBuilderhas one forwarding site and several mounts, and nothing a mount passes distinguishes a SERVER-evaluatedconditionfrom a CLIENT-evaluatedvisible. The client evaluator binds more: app-shell'sbuildExpressionScopepublishescurrent_user/user/ctx/os/features. ⇒ client-evaluated mounts (an action'svisible/disabled) now lose the offers their host really binds, until each declares its own list through the newrootsprop.Why this is small and bounded, and why it was the right trade anyway
rootsprop objectui#9854 added, and it is pinned by a case in that PR's new suite rather than promised in prose.rootsfeeds autocomplete only — the accept set stays the engine'sSCOPE_ROOTS— so an under-advertised client mount loses an offer, never a spelling: an author who typesos.user.idthere 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⚠️ Read
ConditionBuildermounts, decide per mount whether its host is server- or client-evaluated, and give each client-evaluated one arootsdeclaration naming what its host actually binds.buildExpressionScopeat 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_findingsof the objectui#9645 dev report (comment5728803721), filed as its successor. The dev namedActionDefaultInspectoras 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