Skip to content

视图声明 calendar 可视化但缺 calendar 配置块时,平台不报错——直接渲染成一屏错位画面(全部记录堆在今天) #13748

Description

@yinlianghui

来源:宣传视频车道 #147 为排镜所做的只读实拍。未改动任何平台代码、未改任何配置。

本单只描述现象,不预设修正方向。 是否算缺陷、以及该往哪个方向处理(构建期校验、运行期报错、界面降级提示、或视为可接受的宽松默认),留给负责人裁定。故不带 pm:queue——请先分级。

现象

同一个对象 crm_leave_request 下的两个视图,都能切到日历呈现,但只有一个真的能用:

视图 声明 切到日历后的画面
all_leave_requests 只写了 appearance.allowedVisualizations: ['grid','calendar'],没有 calendar: 配置块(无 startDateField / endDateField) 整月空白;全部 9 条记录堆在「今天」那一格(标题显示 LR-00008 / LR-00007 / … / +5 more)。翻到下一月则整月全空
team_leave_calendar 有 calendar: 配置块(startDateField: 'start_date' / endDateField: 'end_date' / titleField / colorField) 正常月历,请假条按起止日期落在对应格子,跨天条正常

关键在于前者没有任何提示:工具条上的 Grid ⇄ Calendar 切换按钮正常显示、正常可点,点下去也不报错——直接渲染出一屏在业务上完全错误的画面(所有人的假看起来都在同一天)。

为什么记下来

声明是不完整的,但不完整没有被任何环节拦下:

  • 构建期没有报错——allowedVisualizations 里写了 calendar,但没有配套的日期字段映射,元数据校验放行了;
  • 运行期没有报错——切换按钮照常可用,没有禁用、没有提示、没有空态说明;
  • 呈现层做了静默兜底——拿不到 startDateField 就把记录都落到当天,而这个兜底的结果看起来像数据本身的样子,不像故障。

对一个「按描述长出模块」的平台,这个组合的后果是:一份写了一半的声明,会渲染出一个看起来能用、实际全错的界面,而搭建方没有任何信号知道自己漏了什么。

⚠ 另有一层:这两个视图是同一次 AI agent 依据一句业务需求生成的(同一批产出、同一个视图文件)——即 agent 在一个视图里写全了日历配置、在另一个里只写了 allowedVisualizations。本单不评价 agent 的产出质量,只记录平台在收到这种不完整声明时的行为。

复现最小路径

  1. 在一个对象上声明两个列表视图;
  2. 视图 A:appearance.allowedVisualizations: ['grid','calendar'],不写 calendar: 块;视图 B:同样允许 calendar,并写全 startDateField / endDateField;
  3. 准备若干条记录,其日期字段分布在不是今天的若干天上;
  4. 打开视图 A → 点工具条的 Calendar 切换 → 所有记录堆在今天那一格,其余日期全空;
  5. 打开视图 B → 记录按各自日期正常分布。

取证环境

2026-08-31,载体 objectstack-ai/hotcrm,钉 @objectstack/* 17.1.0。纯只读实拍,未改数据、未改配置、未改源码。

邻近既有单(已查,非重复)

Activity

  1. os-warren commented on Aug 31, 2026

    @os-warren
    Collaborator

    分诊 → domain:spec · needs-user-decision · p2 · bug。

    这条我保留 needs-user-decision —— 与隔壁 #13751 不同。那条是「请先定级」,定级是分诊的活,我已经答了;这条问的是「平台该不该收下一份写了一半的声明」,那是契约松紧度,触人工地板(公共声明面的 accept 集收窄 + 会打断既有应用的构建),不该由分诊或车道 PM 替你定。

    锚定。 按我推荐的方向(见下)落点在视图声明 schema,packages/spec ⇒ domain:spec(唯一所有者)。⚠️ 若你裁的是「只改界面表现」,落点变成 objectui 的日历呈现层,车道随裁决改挂 repo:objectui —— 现在按推荐项挂,不是终局。


    四维分析

    ① 实际业务需求. 现象是真实取证:同一对象下两个视图,一个能用一个渲染出「所有人的假都在同一天」,而工具条上的切换按钮正常显示、正常可点、点了不报错。搭建方没有任何信号知道自己漏了 startDateField。

    ② 项目长远合理性. 本仓已有一条被你自己批过的原则 —— 声明即强制(cloud#1626 裁决的 ③ 轴 rider:一个 schema 合法的值不得是无条件运行时抛错)。这里是同一条原则的另一面:allowedVisualizations: ['calendar'] 是一个声明了但兑现不了的能力。按该原则,它应当在声明处被拒,而不是在呈现处被兜底。反过来,如果这里判「宽松默认可接受」,那 #13393 那条 postgres 枚举的裁决就出现了一个反例,两处口径会不一致 —— 这是我建议同口径处理的主要理由。

    ③ 防 AI 写代码犯错(本案最重). 立单方记下了一个关键事实:这两个视图是同一个 AI agent 依据一句业务需求、在同一批里生成的 —— agent 在一个视图里写全了日历配置,在另一个里只写了 allowedVisualizations。这不是人的疏忽,是本平台主要创作路径的一次典型产出。而平台对这份半成品的回应,是渲染出一屏自信的错误画面:它不像故障,它像数据本身。对一个「按描述长出模块」的平台,静默兜底把 agent 的一次遗漏放大成了「看起来验收通过」。

    ④ 创业阶段不扩散需求. 四个方向的成本差很大:构建期校验是一条 superRefine(视图 schema 里已有同类拒收先例);运行期报错要新错误码 + 文案;界面降级提示要新空态 UI + 文案 + 翻译;「视为可接受的宽松默认」零成本但把缺陷留在线上。最省的恰好也是最早拦下的那个。

    建议:构建期拒收 + 界面不再假装。 即 —— 声明面按 ② 收紧(allowedVisualizations 含 calendar 时必须有 calendar: 块,缺则带指引地拒收,#5099 那种「拒收并给出补法」的形状);呈现层在拿不到 startDateField 时 ⛔ 不得把记录堆到今天 —— 那个兜底的产物看起来像真数据,是本单最有害的一环,即使裁决只取界面半边,这一条也应当照做。

    ⚠️ 需要你连带裁一个我不能替你答的问题:收紧 accept 集会让既有的、已经这么写的应用构建失败(hotcrm 的 all_leave_requests 就是一个)。是(a)直接拒收并让存量应用改声明,还是(b)先落一轮 warning、下个 major 再拒?这决定了 Clause-② 的分级与是否需要迁移说明。

    ⚠️ Clause-② 适用于实现卡:路径肢 packages/spec/src/**,内容肢 = 收窄公共声明面的 accept 集。实现卡按 CONTRACT_REVIEW_TIER 派发并申报 Clause-②: yes。

    定级 p2。 无数据损失、无安全后果,且有明确绕法(把配置块写全);不判 p3 是因为 ③ 轴 —— 失败发生在平台自己的主创作路径上,且无声。

    邻近单:#13751(同为日历,但主题是导航控件步长,已单独定级 p2 / repo:objectui)、#13696(同为「声明缺一环则能力不可用」,但那条失败得明显)。立单方的查重结论我认同,均不并卡。


    Generated by Claude Code

  2. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    裁决:定级 bug · p2,方向 A 两头修 —— 实现卡 #13817(spec 半)+ objectui#7029(runtime 半),本卡关(维护者 2026-08-31)

    项目总监席 · session session_01KGtaLpkW1mycWgkbSb3H6t · 决裁批 #19 ⑤

    维护者原话(逐字):「批 #19 同意」—— 本卡呈报推荐为「A,拆两张实现卡,定级 bug + p2」。

    呈报时补齐的机制链(本席两仓实测;卡面只有现象,此为成因)

    1. spec 不拦:packages/spec/src/ui/view.zod.ts:945 的 allowedVisualizations 与 :1679 的 calendar: 块各自 optional、无交叉校验 ⇒ 写一半的声明原样通过元数据校验;
    2. objectui 臆测:packages/app-shell/src/views/ObjectView.tsx:2220 在缺块时合成配置 —— startDateField: viewDef.calendar?.startDateField || 'due_date'、titleField: … || 'name',即发明字段名(crm_leave_request 的真实字段是 start_date,不是 due_date);
    3. 渲染器静默兜底:packages/plugin-calendar/src/ObjectCalendar.tsx:445 start: startDate ? new Date(startDate) : new Date() ⇒ 读不到字段值的记录全部落「今天」;
    4. ObjectCalendar.tsx:657 本来就有拒绝画面("Calendar configuration required…"),但第 2 层永远合成一个看起来完整的配置,该防线从此路由不可达 —— 不是没有防线,是防线被上游臆测短路。三层单看各自「合理」,叠起来把一个作者错误渲染成一屏可信的假数据。

    裁决内容

    状态转移(同笔)

    定级 bug + priority:p2 已在标签(与分诊同判,读回一致);needs-user-decision 摘除;本卡关闭(completed) —— 现象记录完结,工作由两张实现卡承载。附注的一次性 prev 原地不动照卡面约定不作现象处理;同面导航缺陷 #13751 已另行分级入队,与本裁无涉。


    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