Skip to content

[Decision] Should the contract guarantee the ambient UI-predicate roots (app, features, os.user, data) — or do they stay renderer-provided-but-unpromised? #11603

Description

@os-steve

Filed by the spec-lane PM (session_01T9cDbY2NBiVJWYx3BpWfH2) at #11256's ACCEPT, per its dev's recommendation. Decision-class — maintainer ruling required; NOT buildable as dispatched work in its current form. Do not promote to pm:queue without a ruling: every option below either amends an ADR or changes a shipping renderer.

The question

PR #11600 (#11256) landed the honest middle: visibleWhen's describe now states record + current_user (ADR-0068 aliases user/ctx.user) + page.<var> as contract, and records app, features, os.user, data as renderer behaviour, not guaranteed (ADR-0068's Non-goals fence its ruling to the user object; ADR-0058 rules dialects/backends/fail-policy, not the UI root set — nothing rules the ambient four today).

But the platform itself already relies on the ambient set: action-param visible gates on features.*, and action.zod.ts:377 documents current_user/app/data/features as its scope. "Unpromised but universally relied on" is the current de-facto state — a permanent declared-vs-delivered gap unless ruled.

Options (from #11600's measurement)

  • A — status quo (what landed): contract stays user-object + record + page state; ambient roots documented as measured behaviour. Zero risk, honest, gap persists. This is the answer of record for finding: PageComponentSchema.visibleWhen's describe names three roots; the renderer binds seven — user / ctx.user / os.user / app / features are undocumented on that surface #11256 only — it deliberately did not settle this card.
  • B — widen the contract via a new ADR (or ADR-0068 amendment): app/features/data become guaranteed roots on UI predicate surfaces. Closes the gap, but promises a surface with no conformance test and no server-side counterpart — the ADR-0049 class — so B should only land WITH a conformance test. Precondition either way: data's two meanings (data-source ADAPTER on component nodes vs record ROW on page:tabs items, measured at objectui pin 190fbd01d061 and identical at their origin/main f2732afe) must be reconciled or explicitly blessed as surface-dependent first.
  • C — narrow the renderer to the declared roots (objectui behaviour change). Measured as breaking: the platform's own sys_user ctx.user alert gate survives (contract), but every features.* action gate and the ambient consumers do not. Effectively rejected by measurement unless the ambient consumers migrate first.

Constraints a ruling should respect

  • AI-authoring safety currently points the right way under A: an author reading "not contract-guaranteed" avoids the ambient roots.
  • If B: conformance test in the same stroke, and the data double-meaning settled BEFORE the widening (guaranteeing a root that means two things would bake the ambiguity into the contract).
  • os.user is not a fourth user alias: ADR-0068 names it only as the legacy FORMULA namespace; objectui's conformance clause lists exactly three spellings.

Refs: #11256 · PR #11600 (measurement map + root table) · #11601 (nested describe text never reaches the MDX — relevant to where any future promise would be visible) · ADR-0068 · ADR-0058.

Activity

  1. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    Contributor

    分诊(Routine 席,小时轮):入决策箱,needs-user-decision 已挂,type Feature(扩契约面即人工地板)。补标准四棱块如下;卡内 A/B/C 选项与测量已完整,此处按四轴从业务角度收敛。

    os-decision-facets

    ① 实际业务需求:平台自己已经在依赖 ambient 根(features.* 动作门、action.zod.ts 的 scope 文档),这是实测到的真实用法,不是投机面。但「依赖它的都是平台自身代码」——没有测到外部 app 作者在用,所以把它升成契约的拉动今天还不存在。这条轴指向 A(维持现状)。

    ② 项目长远合理性:「普遍依赖却不承诺」是永久的 declared≠delivered 缺口,长期要收敛。但 B 若不带 conformance test 就落地,等于又造一个 ADR-0049 类(声明无强制)——卡自己也说 B 必须连测试同笔。C 已被测量否决(平台自身的 features.* 门会碎)。长期方向是 B,但它是「有排期的将来」不是「现在」。

    ③ 防 AI 犯错:A 下作者读到「非契约保证」会避开 ambient 根——这是当前最安全的姿态。B 若先落而 data 的双义(adapter vs row)未裁,等于把歧义烤进契约,AI 作者会两种理解各写一半。data 双义是 B 的硬前置。

    ④ 创业阶段不扩散需求:B = 新 ADR + conformance test + data 双义裁决,三件套;在零外部拉动下这是典型的能力面扩张。A 零成本。

    推荐:A(维持已落地的诚实中间态),把 B 记为「出现外部作者拉动或 data 双义先被裁掉时再启动」的条件式方向。 本分析看不见的:维护者是否已有把 ambient 根作为公开授权面的产品意图——若有,直接裁 B 并按卡内约束(conformance 同笔 + 先裁 data)排期。


    Generated by Claude Code

  2. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    Contributor

    Maintainer ruling recorded — A (status quo of record); closing

    Provenance: maintainer, 2026-08-24, live PM chat, batch acceptance, verbatim: 「四维分析一致的,接手你的建议。」 The four-facet block above is aligned on A, so A is adopted.

    Ruled: the contract stays user-object + record + page state as landed in PR #11600; the ambient roots (app, features, os.user, data) remain documented measured renderer behaviour, not guaranteed. B stays a conditional future direction, reopenable when either trigger fires: (1) measured external-author reliance on the ambient roots appears, or (2) the data double-meaning (adapter vs row) is settled first — and B then lands only WITH a conformance test in the same stroke, per the card's own constraint.

    Closing as completed — the decision is made and the answer of record required no further work. Reopen against the named triggers.


    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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions