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
decision: does removing the app expression-scope root (PR #8164, batch #67) ship as a straight removal, or with a migration note / release-note line / deprecation window? #8866
This card exists to put a fact and its cost in front of the maintainer. It does not propose a ruling and the seat filing it does not have one. Refs: objectui#8155, objectui PR #8164 (merged), objectstack#16420 (closed not_planned), objectstack#17203.
⚠️This card needs the needs-user-decision label to reach the decision inbox — the filing seat does not apply labels. That is the whole of finding F5 in the post-merge contract audit (objectui PR #8164 comment 5602158340): the consequence below was recorded in a comment on a card labelled pm:queue and in a changeset, and never became a decision-inbox item.
The decision
objectui PR #8164 removed the app expression-scope root (decision batch #67, option B, ruled 2026-09-07 on objectui#8155). It is merged and unreleased. The question for the maintainer is whether that removal ships as a straight removal, or with something in front of it:
A — straight removal (today's state). The changeset already states the breakage in the release notes. Nothing else is added.
B — a migration note. A written upgrade step telling deployments to grep saved metadata for app.* predicates before upgrading.
C — a release-note line with the per-surface consequence table (below), so the two opposite failure directions are visible without reading the changeset body.
D — a deprecation window. Keep binding app for one release while a console warning names each app.* predicate it evaluates, then remove.
⛔ Option D would re-introduce a root the engine's SCOPE_ROOTS refuses, i.e. re-create the declared-but-refused state objectui#8155 was filed about, for the length of the window. That is a real cost of D, stated so the choice is informed — it is not an argument against it.
The fact the ruling did not have
Batch #67 accepted "breaking for out-of-tree metadata" on the strength of a measured in-tree zero (re-measured during implementation: 0 app.* hits against a record. control of 484). In-tree usage is zero; deployed metadata cannot be measured from this repository at all. A saved predicate spelling app.* in a real deployment stops resolving on upgrade, and there is no replacement spelling — app was never in the protocol.
The cost, measured per surface
The consequence is not one shape. Measured on the merged head with a resolvable control predicate firing in the same run (record.status == 'open' returned true in every row):
Field visibleWhen (app-shell object field), nav / area visible
isObjectFieldVisible / evaluateVisibility
fails OPEN — shown, console diagnostic
Field readonlyWhen / requiredWhen
resolveFieldRuleState (fallback false)
fails CLOSED — not readonly, not required
⚠️The two directions need opposite checks after an upgrade, which is why they are listed apart rather than summarised as "fails open":
On the fail-OPEN surfaces a gate that used to hide something starts showing it. A visibleWhen: app.tier == 'pro' field becomes visible to everyone. It is a concealment gate, not an authorization boundary — the client already holds the record payload — but it is the direction that shows more, not less.
On the fail-CLOSED surfaces a rule that used to fire silently stops. A conditional-formatting rule keyed on app.* stops colouring rows and nothing on screen says so.
Every faulting predicate does warn on the console once. As of the objectui#8155 follow-up the app-shell diagnostic no longer names app among the bound roots, so that warning no longer sends the author back to the root that is the reason.
What is already done, so the decision is only about the release
The changeset carries the breakage and now states the per-surface directions above rather than a blanket "fails open".
The published @object-ui/react diagnostic and every other in-tree statement that app is a bound root are corrected in the objectui#8155 follow-up PR.
The producer-side alternative (widen the engine vocabulary) is objectstack#16420, closed not_planned by the same ruling. A future need for a "current app" root is a fresh spec/engine widening, not a reopen.
Filed by an agent seat working objectui#8155 under Claude Code, session session_01611D6ZaRaMmwTNQmSbk8MH. It records evidence only and rules on nothing.
This card exists to put a fact and its cost in front of the maintainer. It does not propose a ruling and the seat filing it does not have one. Refs: objectui#8155, objectui PR #8164 (merged), objectstack#16420 (closed
not_planned), objectstack#17203.needs-user-decisionlabel to reach the decision inbox — the filing seat does not apply labels. That is the whole of finding F5 in the post-merge contract audit (objectui PR #8164 comment 5602158340): the consequence below was recorded in a comment on a card labelledpm:queueand in a changeset, and never became a decision-inbox item.The decision
objectui PR #8164 removed the
appexpression-scope root (decision batch #67, option B, ruled 2026-09-07 on objectui#8155). It is merged and unreleased. The question for the maintainer is whether that removal ships as a straight removal, or with something in front of it:app.*predicates before upgrading.appfor one release while a console warning names eachapp.*predicate it evaluates, then remove.⛔ Option D would re-introduce a root the engine's
SCOPE_ROOTSrefuses, i.e. re-create the declared-but-refused state objectui#8155 was filed about, for the length of the window. That is a real cost of D, stated so the choice is informed — it is not an argument against it.The fact the ruling did not have
Batch #67 accepted "breaking for out-of-tree metadata" on the strength of a measured in-tree zero (re-measured during implementation: 0
app.*hits against arecord.control of 484). In-tree usage is zero; deployed metadata cannot be measured from this repository at all. A saved predicate spellingapp.*in a real deployment stops resolving on upgrade, and there is no replacement spelling —appwas never in the protocol.The cost, measured per surface
The consequence is not one shape. Measured on the merged head with a resolvable control predicate firing in the same run (
record.status == 'open'returnedtruein every row):app.*predicate nowconditionresolveConditionalFormatting->evalRowPredicate(fallback: false)visible/disabledevalRowPredicate(fallback: false)visibleonaction-button/action-menu/action-baruseCondition(..., throwOnError)visibleonaction-icon/action-groupuseCondition(default)visibleWhen(form field rules)resolveFieldRuleState->evalFieldPredicate(fallbacktrue)visibleWhen(app-shell object field), nav / areavisibleisObjectFieldVisible/evaluateVisibilityreadonlyWhen/requiredWhenresolveFieldRuleState(fallbackfalse)visibleWhen: app.tier == 'pro'field becomes visible to everyone. It is a concealment gate, not an authorization boundary — the client already holds the record payload — but it is the direction that shows more, not less.app.*stops colouring rows and nothing on screen says so.Every faulting predicate does warn on the console once. As of the objectui#8155 follow-up the app-shell diagnostic no longer names
appamong the bound roots, so that warning no longer sends the author back to the root that is the reason.What is already done, so the decision is only about the release
@object-ui/reactdiagnostic and every other in-tree statement thatappis a bound root are corrected in the objectui#8155 follow-up PR.not_plannedby the same ruling. A future need for a "current app" root is a fresh spec/engine widening, not a reopen.Filed by an agent seat working objectui#8155 under Claude Code, session
session_01611D6ZaRaMmwTNQmSbk8MH. It records evidence only and rules on nothing.Generated by Claude Code