You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Follow-up to #514: remaining behaviour fixes, conventions, and the action-sandbox test gap #575
Activity
yinlianghui commentedon Jul 31, 2026
B 组方案已定 —— 三条可直接开工,两处待业务确认
方案基于实测,不是偏好。逐条给结论和证据。
B1 — 删掉 validation,保留 hook ✅ 可开工
实测(16.1.0,
3ed27b26):造一条已转换线索,PATCH company→回来的是 hook 的文案。
lead.object.ts:311那条cannot_edit_convertedvalidation 永远轮不到发言。这与
revenue_positive的实测结果一模一样(当时也是 hook 先抛、validation 是死配置,已在 #571 删除)。代码注释里写的「双层分工」是意图,不是运行时事实——hook 的 beforeUpdate 先抛错,validation 没有机会产生它承诺的「可恢复的友好报错」。留着它就是下一个
revenue_positive:两份实现慢慢漂移,其中一份还是死的。做法:删除
lead.object.ts的cannot_edit_convertedvalidation;hook 的文案已经写得不错(点出了具体字段),保持。补一条守卫测试断言「已转换线索的身份字段不可改,且错误来自 hook」。B2 — 拆开处理:一个删,一个补写入方
crm_opportunity.created_date→ 删 ✅ 可开工平台已自动注入
created_at,这是重复字段。连带要改:opportunity.view.ts:149的startDateField改指created_at,清掉zh-CN.ts两处翻译。crm_case.first_response_date→ 保留并补写入方 ⏸ 语义待确认不是遗留垃圾。查了 SLA 字段家族的写入情况:
sla_due_dateresolution_time_hoursis_sla_violatedcase_sla_monitorflowfirst_response_date四个字段里三个都有写入方,只有它没有——它是一套成体系指标里缺的那一块,而「首次响应时间」是客服领域最标准的 SLA 指标之一。删掉等于砍掉一个真实指标。
建议实现:先用简单代理——状态首次离开
new时打戳。比接活动/评论时间线便宜得多,语义也站得住;将来真要精确到「首次对外沟通」再换实现。待确认:这个代理语义服务团队是否接受。如果他们要的是「客服第一次回复客户的时刻」,那状态变更不等价(有人可能先改状态再回复)。
B3 — 保留 changesets,补上消费端 ⏸ 发版节奏待确认
40 个堆积说明机制只装了一半:CI 已经强制每个 PR 附 changeset(#503),输入一直在收集,却没有任何 workflow 消费它们。
不建议废除机制——那会把已建立的每 PR 记录纪律一起扔掉,40 条历史记录也会烂在那儿。
建议:补一个发布 workflow,打 tag 时跑
changeset version(生成 CHANGELOG + 版本号),不跑publish——这个仓库走 marketplace 分发,root 包是private: true,不发 npm。一次性动作:先跑一次把 40 条折进 CHANGELOG,之后每次发版自动消化。
待确认:发版节奏和版本号策略。改错会影响版本号,建议先跟领导对齐。
B4 — 只给 quote 和 contract 加 ✅ 可开工
判断依据是非法转换有没有业务后果:
加 —
crm_quote(draft → in_review → presented → accepted/rejected)和crm_contract。报价直接从草稿跳到「已接受」、合同未签署就激活,在 CPQ 和法务上是真实风险。而且查过:这两个对象的 hook 里目前连状态守卫都没有,完全不设防。不加 —
crm_campaign和crm_task。它们的status是描述性的(活动在跑/暂停、任务待办/进行中),不是受控生命周期,强加转换表只会给用户添堵。所以 #514 项 11 说的「只有 3 个对象声明了 state machine」不是缺陷——缺的只是 quote 和 contract 这两个,其余是合理的。
派发状态
created_date部分、B4first_response_date写入语义、B3 的发版节奏yinlianghui commentedon Jul 31, 2026
更正 B2 的实现方案,并给 B3 定性
B2 —— 撤回「状态离开
new时打戳」,改为「首条活动时打戳」上一条评论里我建议用「状态首次离开
new」作为first_response_date的代理。这个方案是错的,撤回。为什么错:客服可以把工单改成「处理中」然后去排查,客户那边一个字都没收到。用状态打戳会让 SLA 显示「已响应」而客户仍在等待——等于把指标造假写进 schema。这正是本仓库近期一直在清理的那类「看着像生效、实际测不到真东西」的缺陷。
行业标准定义:Salesforce 的
FirstResponseDateTime、Zendesk 的 first reply time,衡量的都是客户第一次收到人工回复的时刻,而非内部状态变更。HotCRM 里的落地方式:工单上唯一的对客沟通记录是
log_call/log_meeting,它们写sys_activity行(object_name+record_id+metadata.kind),工单详情页的record:activity时间线也在读它们。因此:在该工单第一条
sys_activity产生时打戳。实现位置很干净——#569 已把这两个 action 收敛成单一构造器logActivityAction(spec)(src/actions/global.actions.ts),所以只需在一处添加:若目标工单的first_response_date为空,则写入当前时间。要在代码注释里写明的约定:将来若为工单增加「回复邮件」等对客沟通路径,该路径也必须打戳,否则指标会漏记。
这个方案不再需要业务方确认语义——它就是标准定义本身。仍建议向服务团队知会一次口径(「首次响应 = 首次记录的通话/会议」),以便他们理解报表数字的来源。
B3 —— 不是缺陷,可以无限期推迟
澄清定性:这不是 bug,没有任何运行时影响,用户无法感知,不会报错。它只关乎版本号与 CHANGELOG 生成。
不处理的后果仅两条:CHANGELOG 不再反映实际发布内容;40 个文件继续堆积。
唯一值得记住的成本:CI 强制每个 PR 附 changeset(#503),而没有任何流程消费它们——等于每个贡献者都在做一份被丢弃的功课。所以长期只有两个合理终局:接上消费端(发版时跑
changeset version,不跑publish——本仓库走 marketplace、root 包private: true),或取消该强制。维持现状是在持续支付一份没有回报的税。建议:下次真正发版前再定,现在不必占用排期。
Merge pull request #576 from objectstack-ai/claude/issue-575-a1-quick…
Merge pull request #578 from objectstack-ai/claude/issue-575-group-b-…
fix(task): drop the shadowed assignment field group (#582)
yinlianghui commentedon Aug 5, 2026
关闭核验(PM 派发循环,会话
session_0194QUW67v7vyLToEd9NSeRM,基线 main@5a78f88):本 issue 的可开工项已全部落地,逐条对照:
a4a5ac0)disqualification_reason强制 / A3fieldGroups/ A4priority_rank统一28e87c9)+ 修正 #582(7709114)cannot_edit_converted已从lead.object.ts移除(现仅存说明注释,lead.object.ts:218)created_date删除opportunity.object.ts:128注释确认平台created_at替代;view 已改指first_response_date写入方global.actions.ts:293-323state_machine(PR #578)B3(40 个 changeset 堆积):按 2026-07-31 评论定性为非缺陷、零运行时影响,「下次真正发版前再定」。不再占用本单;届时随发版流程另立专项。
按 completed 关闭;如有异议可重开(否决窗口)。
Generated by Claude Code
test: run action and hook bodies through the real QuickJS sandbox
Enforce lead disqualification reason, group campaign/task fields, uni…
Retire dead lead/opportunity rules, stamp first response, guard CPQ l…
docs(administration): list all five objects that have a state machine (…
fix(service): retire crm_case.created_date; every reader moves to the…