Repository navigation
administration/state-machines 还剩两处 #920 没枚举到的行为性主张::79-84 的四条「The system also enforces」(审批阈值写成 $500K,实际入口是 $100K)、:114-122 的 Copilot 一节在 src/ 里零支撑 #940
Description
来源:#920 / PR #939 实施过程的顺带发现(改 :8 / :86-94 / :106 / :110-112 / :133-134 时逐条回源核对同页其余的行为性主张)。基线 origin/main = 4855d50b(平台 17.0.0-rc.3),行号为 fresh main 上的行号,三语同址。
与 #920 / #921 的边界:#920 的裁定面是「状态机会拦下非法转换」那一族,逐行枚举为 :8 / :82-88(现 :86-94)/ :106 / :110 / :111 / :134,PR #939 已按该枚举清空;#921 是状态词表。下面两处都不在这两份枚举里,也不由 PR #939 的改动导致。
两处证据强度不同,刻意分开写,请分别裁。
一、:79-84「The system also enforces」四条 —— 强证据,其中一条是数字错
The system also enforces:
- **Close Date is required** before moving to *Proposal*.
- **Amount is required** before moving to *Negotiation*.
- **Won/Lost reason is required** when entering *Closed Lost* or *Closed Won*.
- **Approval may be required** to enter *Closed Won* if amount > $500K and discount approval hasn't been granted.
| 页面主张 | src/ 实况 |
|---|---|
| Close Date 在进入 Proposal 前必填 | opportunity.object.ts:122-124 的 close_date 是无条件 required: true —— 从建单第一秒就必填,不存在「进入 Proposal 前」这个时点。页面把一条更强的约束描述成了阶段性的 |
| Amount 在进入 Negotiation 前必填 | 同上,opportunity.object.ts:82-84 的 amount 也是无条件 required: true |
| 赢单/丢单原因在进入 Closed Won / Closed Lost 时必填 | ✅ 属实,且机制真实:win_reason 的 requiredWhen 是 record.stage == "closed_won"(:303),loss_reason 是 closed_lost(:327) |
| 金额 > $500K 且未获折扣审批时「可能需要审批」 | 数字错。opportunity-approval.flow.ts:88 的 START 条件是 record.amount > 100000 —— $100K 就进审批,走 Sales Manager 一档;$500K 是 :235 那条更高的 Sales Director 加签档(vars.oppRecord.amount > 500000)。页面把二档阈值写成了入口阈值,于是一个 $200K 的单子按页面读是「不需要审批」,实际会进审批 |
前两条是「描述得比实际更宽松」,第四条是具体数字与源码不符,代表读者会据此错判一笔真实交易要不要走审批。第三条正确,不要顺手改掉。
另注:这一节的小标题「The system also enforces」在这里是成立的 —— required 与 requiredWhen 确实会拒绝保存(与状态机那族不同),所以本条不是 #920 的延续,不要套用 PR #939 的「advice, not a gate」口径去改它。
二、:114-122「State machines and the AI Copilot」—— 证据只到「本仓零支撑」,判不了平台侧
The Copilot understands the state machine. When suggesting an action:
- *"Qualify this lead"* → only suggested if status is *Working*.
- *"Convert this lead"* → only suggested if status is *Qualified*.
- *"Mark this opportunity Closed Won"* → only suggested if win conditions are met (...).
This prevents the Copilot from suggesting illegal transitions.
本仓侧实测:grep -rniE "state.?machine|transition|legalNext" src/skills/ src/actions/ 零命中 —— 六个 *.skill.ts 与全部 *.actions.ts 没有任何一处提到转换表、状态机或 legalNextStates。技能的 instructions 里也没有任何一条把状态/阶段的合法后继写进提示词(grep -rniE "qualified|status|stage" src/skills/ 只命中 Customer 360° 与 Revenue Forecasting 里读取字段的说明)。
能证的到此为止。 剩下的部分证不了:平台侧的 agent 在装载对象元数据时是否会把 validations[] 里的 state_machine 一并读进上下文并据以收窄建议,是 @objectstack/runtime / agent 侧的行为,不是本仓能从源码断言的。所以这一条既没被证实也没被证伪,PR #939 因此刻意没动它 —— 同一 PR 里我自己写的初稿有一句「Copilot 只建议转换表允许的那些转换」,正因为证不了而被删掉重写。
要闭合这一条,需要的是一次平台侧探针(起一个 agent 会话,在一条 qualified 的线索上问「Qualify this lead」,看建议是否出现),而不是再读一遍 src/。若探针证明平台不读转换表,那么与 :110(下拉零实现)同型;若证明它读,那这一节是本页唯一真正改变用户所见的地方,应当在 PR #939 改写过的「What a state machine buys you」一节里被点名。
影响
第一处::83 的 $500K 会让读者对一笔 $100K–$500K 的交易做出相反的判断(以为不用审批,实际会被拦进审批流并锁字段)。前两条程度较轻,属于「约束比描述的更严」,读者不会因此漏做什么,但会疑惑为什么建单时就被要求填。
第二处:如果平台确实不读转换表,那么它与 :110 / :111 / :134 是同一批「文档说有、实际没有」的说法,只是躲过了 #920 的枚举。
边界
- 与
administration/state-machines通篇声称状态机会「拦下」非法转换,实测五条规则全是warning:保存照样通过;连「只显示合法下一状态」「bypass state machine 权限」都无实现 #920 不重叠:其枚举面已由 PR docs(service): write the cases and state-machine pages' remaining claims to source (#912, #920, #925, #926) #939 清空,本条两处均不在枚举内。 - 与
administration/state-machines用的一整套状态词在src/里查无此值:lead 的 Working / Disqualified 是导入别名不是状态,opportunity 的 Closed Without Decision 根本不存在,Needs Analysis 被漏掉;:60的「Disallowed」举例反了 #921 不重叠:那是状态词表(Working/Disqualified/Closed Without Decision);本条不涉及词表。⚠️ 但:118的 Copilot 举例句同时被administration/state-machines用的一整套状态词在src/里查无此值:lead 的 Working / Disqualified 是导入别名不是状态,opportunity 的 Closed Without Decision 根本不存在,Needs Analysis 被漏掉;:60的「Disallowed」举例反了 #921 点名(它用了Working),若两单先后落地,注意:118的改法:administration/state-machines用的一整套状态词在src/里查无此值:lead 的 Working / Disqualified 是导入别名不是状态,opportunity 的 Closed Without Decision 根本不存在,Needs Analysis 被漏掉;:60的「Disallowed」举例反了 #921 改词、本条判整节去留。 - 与 SLA policy matrix: per-priority × tier clocks, first-response stamping, escalation that reassigns #595 不重叠,不预判审批阈值应该是多少 —— 本条只要求把
$500K与源码对齐。 - ⛔ 不要顺手改第三条(赢单/丢单原因),它是对的。
Activity
yinlianghui commentedon Aug 6, 2026
🔒 已随 #921 并单认领(/pm-dispatch R30,session
session_01VHrPAGEgFDoHjphqYG4BMa,分支claude/issue-921-940-state-machines-truth)——裁定与文件面见 #921 认领评论。Generated by Claude Code
docs(administration): write the state-machine status vocabulary and t…