Skip to content

ADR-0089 D3a: flip .strict() on view/page schemas so mis-layered visibility keys are loud errors #2902

Description

@os-zhuang

Follow-up to #2642 / #2900 (ADR-0089). D1 (canonical visibleWhen) + D2 (deprecated visibleOn/visibility aliases normalized at parse) have landed. This tracks D3a.

Goal

Per ADR-0049 (enforce-or-remove) and ADR-0078 (no-silently-inert), a mis-layered or stale visibility key must be a loud parse error, not a silent strip. Tighten the relevant object schemas with .strict() so e.g. a raw visibleOn surviving past the deprecation window, or a visibleWhen on a schema with no visibility semantics, fails validation.

Why it's staged separately

.strict() on FormFieldSchema / FormSectionSchema / PageComponentSchema rejects every unknown key, not just visibility ones — a large blast radius. The ADR requires sweeping the monorepo + example apps first, then flipping strict. That sweep is bigger than the alias mechanism and risky to land alongside it under parallel-agent development.

Tasks

  • Sweep packages/ + examples/ (and platform metadata) for any keys these schemas currently strip silently; fix or file them.
  • Add .strict() (or a targeted unknown-key guard with UNKNOWN_KEY_GUIDANCE tombstones) to the view form + page component schemas.
  • Confirm the deprecated visibleOn/visibility aliases still parse (they are declared keys, so strict must keep accepting them until removal).
  • Ensure the rejection message points authors at visibleWhen.

References

Activity

  1. self-assigned this
    on Aug 3, 2026
  2. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    🔒 认领(A 道 · ADR-0049 enforce-or-remove 批次第一单;v17 双源账已收口,#4535 见记录)

    • 会话:session_0176qgxgCXTJCUv4YFLtusP9
    • 分支:claude/issue-2902-strict-view-page-schemas
    • 方向:enforce(ADR-0089 D3a)—— 先扫仓(packages/ + examples/ + 平台元数据)找现被静默 strip 的键,再给 view form / page component schemas 上 .strict() 或 UNKNOWN_KEY_GUIDANCE 式定向守卫;弃用别名 visibleOn/visibility 须仍可解析;拒绝信息指向 visibleWhen。
    • 窗口:.changeset/pre.json 实测仍 mode: pre / tag: rc(2026-08-03 00:30Z),breaking 单可发;若实施期间窗口关闭,按纪律顺延 v18 并在本单写明。

    Generated by Claude Code

  3. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    ⚠️ 复核结论:本单早已实现并合并,属遗留未关单 —— 无剩余工作,建议直接关闭(completed)

    今日(2026-08-03)对 origin/main d52d4fe3b 的逐项验收复核

    验收项 状态 证据
    扫仓(packages/ + examples/ + 平台元数据) ✅ 已在 #2943 完成 全仓唯一脏键:objectql protocol-meta.test.ts fixture 的 {id, title},已修为 {name, label}(见该 PR 正文)
    翻闸 .strict() ✅ FormFieldSchema/FormSectionSchema(view.zod.ts)与 PageComponentSchema(page.zod.ts)均为 .strict().transform(normalizeVisibleWhen) + strictVisibilityError;后续 #4001/#4534 已把整个 view 面推广到 strictObject
    弃用别名仍活 ✅ 实测 FormFieldSchema.parse({field:'state', visibleOn:"record.a == 1"}) → {"field":"state","span":"auto","visibleWhen":{"dialect":"cel","source":"record.a == 1"}};page 层 visibility 同样归一
    拒绝信息指向 visibleWhen ✅ 实测 sabotage visibleWhenn 实际输出:Unrecognized key(s) on this view/page schema: \visibleWhenn`. … If this is the conditional-visibility predicate, the canonical key is `visibleWhen` (ADR-0089) — `visibleOn` (view form) and `visibility` (page component) are still accepted as deprecated aliases.`

    回归验证:pnpm vitest run src/ui/view.test.ts src/ui/page.test.ts → 2 files / 292 tests 全绿(含 ADR-0089 D3a describe 块:strict 拒收未知键、typo 提示 visibleWhen、别名存活、跨层粘贴拒收)。严格性台账 docs/audits/2026-07-unknown-key-strictness-ledger.md 亦已登记(L74、L444、L451)。

    依 AGENTS.md 反 #4588(重复实现)纪律,本会话未新开分支/PR,已撤销临时 worktree。


    Generated by Claude Code

  4. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    ✅ 关单:已由 PR #2943 于 2026-07-15 实现并合并(@objectstack/spec 15.0.0 major),本单因 PR 正文写 "Implements" 而非 "Fixes" 未被自动关闭,搁置成了陈旧开单。

    上面的证据评论已在当前 main(d52d4fe3b)复核四条验收标准全部成立:三个 schema .strict() + strictVisibilityError 处方、弃用别名仍解析并归一、拒绝信息指向 visibleWhen、严格性台账与 ADR-0089 状态行均已记账。按防重复实现纪律(#4588 教训)未写任何代码。

    PM 复核:PR #2943 的 diff 与本单四个 task 一一对应,agent 实测输出(292 测试 + 活体 sabotage)可信。关为 completed,凭证 = PR #2943。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions