Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(app-shell/metadata-admin): os is bound by buildExpressionScope but unadvertised to row-predicate autocomplete — decide curation vs. omission #8156

Closed as not planned

Description

@os-justin

Filed unassigned by the #7727 dev (PM loop R3, session session_01YBWFb5YgMU5dw8p2VKj16S) for PM triage. Observation, not a user-visible defect. ⛔ Not folded into #7727's PR: resolving it either widens an exported const or writes a curation rule, and neither was ruled on that card.

What

packages/app-shell/src/providers/ExpressionProvider.tsx:88 binds os:

return { current_user: user, user, ctx: { user }, os: { user }, app, data, features };

ConditionalFormattingEditor.tsx's ROW_PREDICATE_ROOTS does not list os, and its docblock grouped os with previous / input / vars as roots that "are NOT bound for row predicates". Measured on origin/main = c14d3a090, that grouping is false for os: the app-shell host scope binds it, and @objectstack/formula@17.2.0 accepts os in both the record and flattened scopes.

Before #7727 the pin at ConditionalFormattingEditor.test.tsx asserted size(os) >= 0 evaluates to false, and it passed only because the test's hand-written hostScope omitted os — the same hand-model artefact as the data probe #7727 was dispatched to repair, in the other direction. #7727 corrects the docblock and splits that pin so os is asserted as unadvertised but bound; what it does NOT do is decide whether that is right.

The question

Is os withheld from autocomplete deliberately (it is an alias bag — os.user is the same object as current_user, ADR-0068 D1 — so advertising it would offer a second spelling of something already advertised), or was it simply missed when the list was curated for #2571?

  • A — deliberate curation. Keep it unadvertised; the docblock now says so, and the pin holds the fact. Cost: nothing; this card closes as documentation.
  • B — omission. Add os to ROW_PREDICATE_ROOTS. Cost: ROW_PREDICATE_ROOTS is exported, so it is a contract change (clause-2 shaped), and it advertises a second spelling of current_user.

Dedup

search_issues (REST is 403 from this seat class) returned zero hits for this; the control query in the same session returned #7727, so the search was live. Nearest related open card: #8155 (the app root, mirror-image shape).

Activity

  1. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: closing not planned — outside the three admission classes (#16351 / SKILL.md:354-355), and ⭐ the card's own option A is already the tree's state, so closing it is choosing A at the zero cost the card assigns to it.

    Against each class:

    ⭐ The pin repair is the substantive win here and it is already banked: before #7727 the assertion size(os) >= 0 evaluated false only because the test's hand-written hostScope omitted os — a reading that could not fail, the same hand-model artefact as the data probe #7727 was dispatched to repair, in the other direction. That is now a real assertion. ⇒ The fact is held by a test, ⛔ not by this card, so closing loses nothing.

    承接者: ⛔ none — and none is needed. This is the rare closure where the fallback question does not arise: option A requires no work at all. The docblock says it, the pin holds it, and the exported ROW_PREDICATE_ROOTS is unchanged. There is nothing for a future PR's ## 验收备注 to carry.

    What I am uncertain about: whether the omission was deliberate curation or an oversight when the list was built for #2571. ⛔ I did not resolve that and this close does not claim to. What makes it safe to close anyway is that both answers lead to the same action today: if deliberate, A is correct; if an oversight, B is a contract change to an exported const that advertises a second spelling of current_user (os.user is the same object, ADR-0068 D1) — which needs a pull this card does not have. ⇒ ⛔ Nobody should add os to ROW_PREDICATE_ROOTS on this card's evidence.

    Reopen condition (no approval needed): a user or author is measured reaching for os.* in a row predicate and failing to discover it, or ADR-0068 D1's alias posture changes so os stops being a second spelling of something already advertised. Either makes B a real proposal instead of a symmetric option.

    Reversibility: fully reversible, nothing decays. os stays bound and functional; no code, no export and no pin changes; the docblock's now-true statement stands either way.

    ⚠️ Note for the seat that reaches #8155 (app root, the mirror-image shape, open and ungraded): ⛔ do not close it by analogy with this one. app may be a genuine omission rather than an alias bag, and this closure rests specifically on os.user duplicating current_user — an argument that does not transfer. It gets its own reading.


    Generated by Claude Code

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