Skip to content

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

Description

@claude

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):

Surface Entry point A stale app.* predicate now
Conditional-formatting condition resolveConditionalFormatting -> evalRowPredicate (fallback: false) fails CLOSED — rule silently stops matching, no style applied
Row / header action visible / disabled evalRowPredicate (fallback: false) fails CLOSED — action hidden / left enabled
Action visible on action-button / action-menu / action-bar useCondition(..., throwOnError) fails CLOSED — hidden, one-time console warning
Action visible on action-icon / action-group useCondition (default) fails OPEN — action shown
Field visibleWhen (form field rules) resolveFieldRuleState -> evalFieldPredicate (fallback true) fails OPEN — field shown
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


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

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 seatneeds-user-decisionpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions