Skip to content

[17.0-rc][疑似平台] console 表单无视 visibleOn,并强制其 required —— crm_lead 在 UI 上完全无法创建 #688

Closed

Description

@yinlianghui

Found during the 17.0 GA acceptance sweep on @objectstack/* 17.0.0-rc.2 (current main, commit 5a78f88). Likely the highest-impact UI defect in this run: it blocks the app's headline demo path.

Symptom

A new lead cannot be created through the console at all.

Reproduction

  1. Console → HotCRM → Leads → New.
  2. Fill First Name, Last Name, Company, Email; set Status = New.
  3. Click Create.

Observed — submit is blocked client-side with five errors for fields that cannot apply to a brand-new lead, and zero network writes fire:

Disqualification Reason is required
Duplicate Of is required
Duplicate Of Lead is required
Duplicate Of Contact is required
Duplicate Status is required

All five render with a red required asterisk. The form even prints its own helper text "Required when status is Unqualified" directly above the error "Disqualification Reason is required" — self-contradictory on screen.

The form is literally unsatisfiable: it demands the new lead be declared a duplicate of both an existing lead and an existing contact at once. duplicate_of_lead and duplicate_of_contact are mutually exclusive by design — each is gated on duplicate_of_type being the other one.

Screenshot: shots/uif-crm_lead-02-after-submit.png (acceptance run W1).

The app metadata is correct — the renderer ignores it

Every one of the five fields is declared in src/views/lead.view.ts with a visibleOn predicate that is false for a new lead:

{ field: 'disqualification_reason', required: true, visibleOn: 'status == "unqualified"' },
{ field: 'duplicate_of_type',    required: true, visibleOn: 'disqualification_reason == "duplicate"' },
{ field: 'duplicate_of_lead',    required: true, visibleOn: 'duplicate_of_type == "crm_lead"' },
{ field: 'duplicate_of_contact', required: true, visibleOn: 'duplicate_of_type == "crm_contact"' },
{ field: 'duplicate_status',     required: true, visibleOn: 'disqualification_reason == "duplicate"' },

The renderer displays these fields while their visibleOn is false, and enforces their required: true.

The server does not agree with the form. The object-level counterparts use requiredWhen predicates (lead.object.ts:369,375) and are correctly not enforced: POST /api/v1/data/crm_lead with the same field set returns 201. So the condition is honoured server-side and ignored form-side.

Scope

Any object whose form declares visibleOn together with required: true. crm_lead is where it is fatal because the conditional fields are required; elsewhere it will surface as fields that should be hidden appearing on the form.

Workaround

REST creation is unaffected (201). There is no UI workaround — the form cannot be satisfied.

Refs #515

Activity

  1. added
    bugSomething isn't working
    upstream:objectstackBlocked on / caused by the ObjectStack platform — tracked upstream
    on Aug 5, 2026
  2. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    分诊(PM 循环第 1 轮,会话 session_01VHrPAGEgFDoHjphqYG4BMa):本单拆成两半,hotcrm 半侧可修且应修,入 pm:queue;平台半侧已有既存单,不再立镜像。

    根因已定位:objectstack#5149(2026-08-04)实测了 console 的谓词求值是 fail-open(求值失败 → 默认可见),且值绑定在 record 命名空间下 —— 裸字段名谓词(status == "unqualified")引用的是未绑定标识符,永远求值失败,于是字段常显 + required 被强制,恰是本单症状。

    hotcrm 半侧(可立即修):src/views/lead.view.ts 正是两种方言混用的现场 —— 20+ 处裸字段名字符串谓词(L26–L856),而同文件 L838/L843 已有正确写法 Precord.rating >= 3,object 侧 `requiredWhen` 也全部是 `P`…record.…(服务端正确执行的那组)。把全部视图文件的裸名谓词改写成 P 标签 + record. 前缀方言,console 即可正确求值 visibleOn,P0 的「UI 无法建线索」不等平台修复即可解除。这不是 workaround,是把元数据改写成平台实际的谓词契约。下一轮派发,并加守卫测试禁止裸名谓词回流。

    平台半侧(fail-open 无诊断):Blocked-by: objectstack-ai/objectstack#5149 —— fail-closed / 响亮报错属平台修法,静默 fail-open 是 AI 作者批量犯错被掩盖的温床,本单症状就是实例,已在该单可见。


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 5, 2026
  4. self-assigned this
    on Aug 5, 2026
  5. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    认领:PM 循环(17.0 发布修复线)第 3 轮(仅 hotcrm 半侧;平台 fail-open 半侧仍 Blocked-by objectstack#5149)
    会话:session_01VHrPAGEgFDoHjphqYG4BMa
    分支:claude/issue-688-view-predicate-dialect
    Worktree:hotcrm-issue-688
    文件面:src/views/*.view.ts(裸字段名字符串谓词 → Precord.…`` 方言改写,全仓清扫)、新增守卫测试(⛔ 用新测试文件,不动 test/docs-drift.test.ts —— #685 同轮在飞)、changeset。

    派发依据(前次分诊已核):objectstack#5149 实测 console 谓词求值把值绑定在 record 命名空间、失败即 fail-open —— 裸名谓词永远求值失败、字段常显且 required 被强制,恰是本单「UI 无法建线索」的机理;lead.view.ts:838/843 已有正确的 Precord.…`` 写法与 object 侧全部 requiredWhen 同方言。修完本单,P0 症状不等平台修复即可解除。


    Generated by Claude Code

  6. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    验收 ACCEPT(PM 复核,对照 GitHub 实况):PR #726(hotcrm 半侧),CI 9/9 绿,已转 ready 并挂自动合并。

    复核要点:

    • 机理三段实测(直接驱动 console bundle 所用的 @objectstack/formula 求值器):(a) 裸名谓词对任何记录都 ok:false "Unknown variable"(值无关);(b) record. 前缀两个方向均正确;(c) 关键修正 —— 只加前缀不够:新建表单的记录键不存在,严格 CEL 报 No such key 照样 fail-open,P0 不会解除。因此 21 处谓词全部改成 P 标签 + record. 前缀 + has() 守卫(序比较补 != null)—— 这不是扩范围,是 AGENTS.md 对 visibleWhen 既有的 totality 家规(Script validations are silently SKIPPED when the merged record lacks the field key (update path) #630)在视图层的补课。已正确的两处(L838/843)也补了守卫。
    • 表单与服务端契约对齐:两个 duplicate lookup 的 visibleOn 现与 lead.object.ts 的 requiredWhen 逐字符相同 —— 显示时机 = 服务端要求时机,结构上排除了「表单不可满足」的回归。
    • 守卫测试从编译 stack 枚举全部 49 条谓词信封:命名空间集合从 buildScope 读出(跟随平台不漂移)、三种记录形态(空 / 全填 / 全 null)可求值、磁盘计数防空转、裸名前提正向 pin(平台若开始绑定裸名会响亮变红)。反向验证 6 红 5 绿与预测一致,全 null 形态还抓到 dyn<null> >= int 中止,证明该 pin 非装饰。
    • 诚实细节:PR 证据里一度写了本仓不存在的 check-nul-bytes.mjs,dev 自行更正为实际执行的 grep 自扫 —— 证据必须可复跑,这个更正是对的。
    • lead-conversion flow screen 的裸名谓词属另一语境(对 screen 自身字段求值),核过不改、注释说明,未误伤。

    状态归位:hotcrm 半侧到此完成,本单保持 open 仅跟踪平台半侧(fail-open 无诊断,Blocked-by objectstack#5149)—— 摘 assignee、pm:dispatched → pm:blocked;P0 症状(UI 无法建线索)已由本 PR 解除,优先级相应降至 p2。objectstack#5149 落地后,test/view-predicate-dialect.test.ts 的裸名前提 pin 会变红,即为复核信号。


    Generated by Claude Code

  7. removed their assignment
    on Aug 5, 2026
  8. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    [17.0-rc2验收] 测试组 A6 补充影响面量化(hotcrm@0899b4f + @objectstack 17.0.0-rc.2,17 个 crm_* 对象的新建表单逐一实测):

    波及范围:仅 crm_lead。 对 17 个对象分别对比「表单渲染的必填标记」vs「对象元数据 required」:16 个对象完全一致(crm_case 表单多出的 crm_account 必填是 case.view.ts:168 显式声明的,属有意授权),只有 crm_lead 多出本单所述 5 个条件字段(disqualification_reason / duplicate_of_type / duplicate_of_lead / duplicate_of_contact / duplicate_status)—— 即 visibleOn+required 组合被无视的对象面=1/17。

    一处修正:表单并非严格「不可满足」,但代价是数据污染。 5 个被强制的条件字段全部可在 UI 里给值(两个 lookup 都有候选),都填上后 lead 能建成。实测建出的记录(REST 读回):

    {"status":"new","disqualification_reason":"not_a_fit","duplicate_of_type":"crm_lead",
     "duplicate_of_lead":"72AlZBUF8XzrLqGx","duplicate_of_contact":"-79jZx6f6I4luy1y",
     "duplicate_status":"suspected"}

    一条全新 lead 被迫携带「不合适 + 同时是某 lead 和某 contact 的疑似重复」的自相矛盾标记 —— UI 能走通的唯一路径就是写入垃圾数据,严重度不因此降低(headline demo 路径仍等于不可用)。


    Generated by Claude Code

  9. yinlianghui commented on Aug 6, 2026

    @yinlianghui
    CollaboratorAuthor

    📡 上游动静(修复线 PM 例行扫描,2026-08-06):objectstack#5149 已裁决(平台侧 needs-user-decision 于 08:29Z 落锤):维持 fail-open 不翻转(已发货应用行为不变),但「静默」被裁定不可接受——objectui 侧两项即刻入队(evalFieldPredicate 去静默 catch,每谓词 warn 一次带源文本与失败原因;record./data. 绑定写进文档),另拆一单把裸标识符 lint 扩到 view/page 谓词(坏谓词构建期拦下)。

    对本单的影响:hotcrm 侧的 record. 前缀修复与钉子测试已随 PR #726 落地,行为面无需再动;剩余价值是「坏谓词可见性」——待 objectui 的 warn 落地并随某个 rc 到达后,本单的诊断诉求即被满足,可关单。继续 pm:blocked 跟踪,下次平台升级单探测该 warn 是否已到。


    Generated by Claude Code

  10. added and removed on Sep 9, 2026
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

    bugSomething isn't workingpm:blockedpriority:p2Medium: important, M3upstream:objectstackBlocked on / caused by the ObjectStack platform — tracked upstream

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions