Blocked-by: objectstack-ai/objectstack#16737
⬆️ 裁定 1C(维护者,2026-09-09,第 1 批):阻塞源是平台缺陷 ⇒ 去平台修。解锁判据是消费方可安装 (本仓升到含该修复的版本后那条错路确实报错),⛔ 不是「上游 PR 已合并」。详见本卡 2026-09-09 的裁定评论,含一条对 1C 的公开更正:平台在飞的 PR #16778 选的补法是拒绝 而非提供 ,所以修完之后各段时长仍然算不出来。
维护者速读
事情 :设计方案第 9 章要两样东西,卡 10(#29 / PR #30 )照着做时发现平台这一版给不了:
平均周转 / 各段时长 ——需要「两个时间戳相减」。语义层不收 SQL 也不收表达式(ADR-0021),没有地方做减法。
超 SLA ——需要拿合同的 review_started_at 去比另一个对象 的列(clm_contract_type.review_sla_days,九种类型分别是 2/3/5/10 天)。分析层既不能按公式过滤(§12 缺口 [Decision] Two states in DESIGN.md §03 are dead ends: a started obligation cannot go overdue, a partly paid instalment cannot be completed #10 ),跨对象过滤也被直接拒绝。
两问的补法是同一个:让日任务把结果盖成合同上的持久字段 ,之后分析层直接读那个数就行。这正是 §12 缺口 #7 已经为另一个日期运算问题选定的形状(「到期、逾期由日任务盖戳字段」),所以不是新机制。
为什么必须你拍板 :字段叫什么、语义是什么,是公开契约;而且它落在卡 09(日任务那张卡)的地盘上,不是卡 10 能自己加的。
你要做的 :回两个字母,比如「1A 2A」。
第一问 —— 各段时长
这里最值得你看一眼的,是它差点怎么错
开发 agent 先按直觉写了 derived: { op: 'difference', of: [avg_activated, avg_submitted] }。它不报错。它解析通过、运行成功、渲染出一个数:-0.849999999999909。
原因实测如下:
sqlite> select typeof(submitted_at), submitted_at from clm_contract limit 1;
text|2026-05-19T00:00:00.000Z
sqlite> select avg(submitted_at) from clm_contract;
2025.9166666666667 ← 平均「年份」,不是平均日期
Field.datetime 在 SQLite 上存的是 ISO 文本 ,AVG() 触发 SQLite 的文本→数字强制转换,取到开头的年。于是那个 -0.85 是两个平均年份之差 ——一个干净、合理、可以直接进仪表盘的错数。
这就是本来会发布出去的形态。 卡 10 因此改为交付「各阶段覆盖数」(已提交 60 · 已开始审查 41 · 已批准 34 · 已签署 72 · 已生效 72)和一块标明为「审批吞吐 」的砖,§09 要的「本月 vs 上月」对比则用平台自己的 compareTo: { kind: 'previousPeriod' } 原语实现,没有硬编码差值。
选项
做法
代价 / 收益
1A(推荐)
在 clm_contract 上加持久的时长字段,由日任务盖戳——与 §12 缺口 #7 同形
需要 §03 加字段 + 卡 09 加一次盖戳;字段名与语义要你定。收益:§09 字面兑现,且时长可被分析层过滤与排序
1B
接受卡 10 的替代物,改 §09 的措辞为「阶段覆盖与吞吐」
零工作量,今天的板子如实。但让出一项真实的分析能力,且要改 §09
1C
向平台提需求(datediff 类度量,或 Field.datetime 改存数值时间戳),在它落地前维持替代物
一次修好所有应用;但时间不可控,期间两块砖一直是近似
1D
砍掉 contract_cycle_time 数据集
⛔ §09 点名四个数据集,静默砍掉一个正是卡片明令禁止的。列出仅为明确否决
第二问 —— 超 SLA
卡 10 交付的是固定 30 天 阈值,并把砖的标题写成「审查超 30 天」而不是「超 SLA」——因为九种类型的 SLA 是 2/3/5/10 天,30 天高于全部,且标题自己说明了阈值,读者不会误以为它是按类型的违约。
做法
代价 / 收益
2A(推荐)
并入 1A:同一个日任务顺手按类型 SLA 盖一个 review_due_at(或违约布尔),砖改为过滤持久列
一个任务、一次写入,两块砖同时不再是近似
2B
保留固定阈值,改 §09 措辞
零工作量,但「超 SLA」这项能力就没有了
2C
固定阈值作为过渡,§09 保持目标,等卡 09 落地再回头
拖延,且过渡期无期限
四棱分析(两问共用)
实际业务需求 — 偏 A。「合同平均要走多久」和「哪些审查压过了 SLA」是 CLM 买家评估流程效率时最先问的两个问题,也是对标 Ironclad/Agiloft 时销售会被追问的两个数。1B/2B 等于承认这个产品答不出来。
项目长远合理性 — 明确偏 A,理由是一致性 :这个设计对完全相同的问题(日期运算算不了)已经在 §12 缺口 #7 选过一次答案,就是「日任务盖戳字段」。同一个问题给两种答案,是下一个作者最容易踩空的地方。而且持久数值列可过滤、可排序、可聚合——这正是 clm_contract 那五个汇总字段被做成 summary 而不是公式的同一个理由。
防 AI 写错 — 这一棱最偏 A,而且差距最大。今天的状态是:语义层里存在一条能跑通、能渲染、结果错 的路径(op: 'difference' 那个 -0.85)。只要这条路还开着,下一个作者——人或 AI——照直觉写就会写出它,而且没有任何闸门会拦。1A 把正确答案变成一个现成的持久字段,等于把那条错路的诱因移走。1B 反而更危险:它把「这里算不出时长」写进文档,却不改变「随手一写就能得到一个假时长」这个事实。
创业阶段不扩散 — 略偏 B。1A 要加字段、改 §03、给卡 09 加活。但卡 09 本来就要建一个跑在这些对象上的日任务,所以边际成本是「一个字段加一次盖戳」,不是一套新机制。2A 更是搭同一趟车。
结论 :三棱同向 A,第四棱的成本因为卡 09 已有日任务而被大幅摊薄。推荐 1A 2A。 若你更想省,1B 2B 也自洽,但必须写进 §09 ——沉默不可接受,理由同 #10 :把矛盾留给下游卡片,就是把它推给一个更没权限、也更有压力悄悄编一个答案的位置。
⛔ 字段名与语义我没有替你定 ,那是公开契约。
影响
不阻塞。PR #30 本身不声称任何时长,可以按现状合并(正在做第一轮 rework,原因与本卡无关)。这两问的落地在卡 09 ——那张卡同时还等着 #6 、#10 、#14 三张决策卡,所以一并回答可以让卡 09 一次派发到位。
关联
#29 / PR #30 (来源)· 卡 09(落地处,尚未派发)· #6 #10 #14 (同样卡住卡 09 的三张)· DESIGN.md §09、§12 缺口 #7 与 #10 。
Blocked-by: objectstack-ai/objectstack#16737
维护者速读
事情:设计方案第 9 章要两样东西,卡 10(#29 / PR #30)照着做时发现平台这一版给不了:
review_started_at去比另一个对象的列(clm_contract_type.review_sla_days,九种类型分别是 2/3/5/10 天)。分析层既不能按公式过滤(§12 缺口 [Decision] Two states inDESIGN.md§03 are dead ends: a started obligation cannot go overdue, a partly paid instalment cannot be completed #10),跨对象过滤也被直接拒绝。两问的补法是同一个:让日任务把结果盖成合同上的持久字段,之后分析层直接读那个数就行。这正是 §12 缺口 #7 已经为另一个日期运算问题选定的形状(「到期、逾期由日任务盖戳字段」),所以不是新机制。
为什么必须你拍板:字段叫什么、语义是什么,是公开契约;而且它落在卡 09(日任务那张卡)的地盘上,不是卡 10 能自己加的。
你要做的:回两个字母,比如「1A 2A」。
第一问 —— 各段时长
这里最值得你看一眼的,是它差点怎么错
开发 agent 先按直觉写了
derived: { op: 'difference', of: [avg_activated, avg_submitted] }。它不报错。它解析通过、运行成功、渲染出一个数:-0.849999999999909。原因实测如下:
Field.datetime在 SQLite 上存的是 ISO 文本,AVG()触发 SQLite 的文本→数字强制转换,取到开头的年。于是那个-0.85是两个平均年份之差——一个干净、合理、可以直接进仪表盘的错数。这就是本来会发布出去的形态。 卡 10 因此改为交付「各阶段覆盖数」(已提交 60 · 已开始审查 41 · 已批准 34 · 已签署 72 · 已生效 72)和一块标明为「审批吞吐」的砖,§09 要的「本月 vs 上月」对比则用平台自己的
compareTo: { kind: 'previousPeriod' }原语实现,没有硬编码差值。选项
clm_contract上加持久的时长字段,由日任务盖戳——与 §12 缺口 #7 同形datediff类度量,或Field.datetime改存数值时间戳),在它落地前维持替代物contract_cycle_time数据集第二问 —— 超 SLA
卡 10 交付的是固定 30 天阈值,并把砖的标题写成「审查超 30 天」而不是「超 SLA」——因为九种类型的 SLA 是 2/3/5/10 天,30 天高于全部,且标题自己说明了阈值,读者不会误以为它是按类型的违约。
review_due_at(或违约布尔),砖改为过滤持久列四棱分析(两问共用)
实际业务需求 — 偏 A。「合同平均要走多久」和「哪些审查压过了 SLA」是 CLM 买家评估流程效率时最先问的两个问题,也是对标 Ironclad/Agiloft 时销售会被追问的两个数。1B/2B 等于承认这个产品答不出来。
项目长远合理性 — 明确偏 A,理由是一致性:这个设计对完全相同的问题(日期运算算不了)已经在 §12 缺口 #7 选过一次答案,就是「日任务盖戳字段」。同一个问题给两种答案,是下一个作者最容易踩空的地方。而且持久数值列可过滤、可排序、可聚合——这正是
clm_contract那五个汇总字段被做成summary而不是公式的同一个理由。防 AI 写错 — 这一棱最偏 A,而且差距最大。今天的状态是:语义层里存在一条能跑通、能渲染、结果错的路径(
op: 'difference'那个-0.85)。只要这条路还开着,下一个作者——人或 AI——照直觉写就会写出它,而且没有任何闸门会拦。1A 把正确答案变成一个现成的持久字段,等于把那条错路的诱因移走。1B 反而更危险:它把「这里算不出时长」写进文档,却不改变「随手一写就能得到一个假时长」这个事实。创业阶段不扩散 — 略偏 B。1A 要加字段、改 §03、给卡 09 加活。但卡 09 本来就要建一个跑在这些对象上的日任务,所以边际成本是「一个字段加一次盖戳」,不是一套新机制。2A 更是搭同一趟车。
结论:三棱同向 A,第四棱的成本因为卡 09 已有日任务而被大幅摊薄。推荐 1A 2A。 若你更想省,1B 2B 也自洽,但必须写进 §09——沉默不可接受,理由同 #10:把矛盾留给下游卡片,就是把它推给一个更没权限、也更有压力悄悄编一个答案的位置。
⛔ 字段名与语义我没有替你定,那是公开契约。
影响
不阻塞。PR #30 本身不声称任何时长,可以按现状合并(正在做第一轮 rework,原因与本卡无关)。这两问的落地在卡 09——那张卡同时还等着 #6、#10、#14 三张决策卡,所以一并回答可以让卡 09 一次派发到位。
关联
#29 / PR #30(来源)· 卡 09(落地处,尚未派发)· #6 #10 #14(同样卡住卡 09 的三张)·
DESIGN.md§09、§12 缺口 #7 与 #10。