Skip to content

administration/state-machines 说 case / contract / quote「没有完整状态机」,但三者都有具名的 state_machine 校验规则;页首清单也只列了 lead / opportunity 两个 #896

Closed

Description

@yinlianghui

来源:#850 / PR #894 清扫「工作流规则」字样时的顺带发现。基线 origin/main = 92b94e71。

与 #850 / PR #894 的边界:PR #894 在本页只动了「工作流规则」这个字样(派单的硬性切割就是「只动字样」),:17 的后半截行为性主张原样留着 —— 本条就是那半截。PR #894 已把 simpler workflow rules 换成不指涉任何类型的中性表述 simpler status handling,没有新增也没有加强下面这个错误,但也没有修它。

事实

content/docs/administration/state-machines.mdx:12-17 及其 zh-Hans / zh-Hant 孪生页(同行号):

  • :12-15 —— "HotCRM uses state machines on:" 之后只列 Leads 与 Opportunities 两个对象。
  • :17 —— "Other objects (case, contract, campaign, quote) have status fields but use simpler status handling rather than full state machines, because their transitions are less strict."

逐条对源码核(grep -rn "type: 'state_machine'" src/objects/,5 处命中):

对象 页面的说法 实况
crm_lead 有状态机 ✅ lead_status_progression(src/objects/lead.object.ts:511)
crm_opportunity 有状态机 ✅ opportunity_stage_progression(src/objects/opportunity.object.ts:412)
crm_case ❌ 「没有完整状态机」 有:case_status_progression(src/objects/case.object.ts:345),field: 'status',带完整 transitions 映射
crm_contract ❌ 同上 有:contract_status_progression(src/objects/contract.object.ts:258)
crm_quote ❌ 同上 有:quote_status_progression(src/objects/quote.object.ts:262)
crm_campaign ❌ 同上 ✅ 确实没有 —— 四个里只有这一个说对了

也就是说::17 点名的四个对象里,三个的状态转换恰恰是由具名 state_machine 校验规则强制的,而 :12-15 那份「用状态机的对象」清单漏掉了这三个。

顺带一提,service/cases.mdx:78 自己写着 "Status progression is enforced — you can't jump from New straight to Resolved without going through In Progress" —— 那正是 case_status_progression 干的事。同一套文档,两页互相矛盾。

影响

一个管理员按 :17 的说法去理解「案例/合同/报价的状态转换比较松、没有强制」,会在改这三个对象的状态流转时以为不需要同步维护转换映射;实际上写一个不在 transitions 里的目标状态会被校验规则拦下(severity warning,见各对象定义)。这是「文档说没有约束,实际有约束」的方向,不是观察类。

修复面(未做)

三语同步::12-15 的清单补上 case / contract / quote 三个(并说明它们与 lead / opportunity 一样都是对象上的 state_machine 校验规则,7.7 移除顶层 stateMachines 键后统一迁到这里);:17 改写为只讲 campaign —— 或按语境判断这一句是否还有存在必要。修 :17 会连带重写 :12-17 这一小节,所以不适合塞进 PR #894 的字样清扫里。

⚠️ 接单注意:本页 convert 词汇(线索转换等)归 #844,不要顺手动。

Refs #850 #854 #844

Activity

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

    @yinlianghui
    CollaboratorAuthor

    🔒 认领(/pm-dispatch R27)— session session_01VHrPAGEgFDoHjphqYG4BMa,分支 claude/issue-896-state-machines-list。

    文件面:content/docs/administration/state-machines{,.zh-Hans,.zh-Hant}.mdx,仅 :12-17 节 ×3——PR #906(#844)已动本页 zh-Hant 用字,fresh main 上重定位,convert 词汇沿 #906 已落口径不得回退。

    裁定:

    1. 基线已切 17.0.0-rc.3(PR chore(deps): 升级 @objectstack/* 17.0.0-rc.2 → 17.0.0-rc.3(零后果修复),并实测四条在案上游镜像 #910),开工先 stale-premise 复核(5 处 state_machine 命中逐条重验)。
    2. ⚠️ severity 实测后再措辞:contracts.mdx 还剩四处与实现不符:五条幽灵列表视图、三个幽灵选项、无实现的「已激活不能删除」、教销售代表做他无权做的事 #832 已确立引擎只对 severity error 抛异常、warning 不阻断保存(core.mjs:2434-2441 族),contract_status_progression 实测为 warning。本单三个新列对象的 state_machine 规则须逐条实测 severity 与真实拦截行为,不照抄 issue「会被校验规则拦下」的说法——若为 warning,写「声明了完整 transitions 映射(warning 级校验)」而非「强制/拦下」,并与 lead/opportunity 两条的实况对齐措辞。
    3. :17 改写为只讲 campaign 还是删句,由 dev 依语境定,PR 里说明取舍。
    4. 与 service/cases.mdx:78 的互证句只引用,不动那一页。

    Generated by Claude Code

  4. yinlianghui commented on Aug 6, 2026

    @yinlianghui
    CollaboratorAuthor

    ✅ 验收通过 —— PR #919 已转 ready 并挂 auto-merge(CI 9/9 全绿实核)。

    验收要点:

    1. premise 成立(5 处 state_machine 命中行号各 +1 重定位),清单补齐 case/contract/quote,路线按各自 transitions 逐边核对书写(如 resolved 只能从 in_progress/escalated 进入)。
    2. severity 实测表是本单核心产出:一次性探针(真实 ObjectQL + InMemoryDriver + 真实 schema)测得五条规则全部 severity: 'warning',五条非法跳转全部 SAVED 落库,引擎只记一条 WARN;lead/opportunity 与其余三个没有分档;五条均无 initialStates,insert 路径完全不检查。裁定「不照抄 issue『拦下』说法」被证完全必要——措辞落为「advice, not a gate / 保存照样通过」,沿 contracts.mdx 还剩四处与实现不符:五条幽灵列表视图、三个幽灵选项、无实现的「已激活不能删除」、教销售代表做他无权做的事 #832/PR docs(contracts): 按视图、选项集、hook 与 profile 写实合同页其余四处 (#832) #874 已落地口径。
    3. :17 取舍合理:改写不删句,保留「campaign 有状态字段却刻意无状态机」的 Follow-up to #514: remaining behaviour fixes, conventions, and the action-sandbox test gap #575 B4 有意判定;实测无状态机对象不止 campaign,点名后以「同理」带过,不做会腐烂的枚举。
    4. 新增守卫 + 两阶段验证与预告一致:test/status-state-machines.test.ts 从 GOVERNED/UNGOVERNED ledger 推导期望,只读列表项防散文误伤,UNGOVERNED 条有非空 precondition 防空转变绿;反向验证预告 RED 实测 RED(还原 mdx 后三 locale 全红,点名恰为 case/quote/contract 三语译名)。
    5. 三语用词沿语言包与 docs(i18n): spell the lead convert verb 转化 on every Chinese page (#844) #906 口径;cases.mdx:78 只引用未改;探针已删、worktree 已清。

    越界发现处置(两单已复核成立,均标 pm:queue):


    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

Labels

pm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions