Repository navigation
service/sla-and-escalation 的 SLA 跟踪一节仍有四处行为性失实:只有 Critical 拿得到 sla_due_date、违约标记并非只读、"实时倒计时"零实现、High/Medium/Low 的"违约长什么样"描述的其实是优先级行色 #903
Description
发现自 #886 / #890 的实施过程(PR 见下)。#886 的裁定面被定死在 :16(Critical 违约行)、:57-60(升级触发条件)、:128→:134(管理员提示),本条是同页另外一族说法——SLA 是怎么被计算和被跟踪的——不在那个切割里,故单独立单,未在该 PR 里顺手改。
基线 origin/main = 90686a4f(含 PR #885 / #894 / #895)。行号为该基线上的原始行号;PR #886/#890 使 :57 一节增长 4 行,故其后的行号在该 PR 合并后 +4。
事实
A. :12 —— "每个工单在创建的那一刻就会获得一个 SLA 截止日期"
content/docs/service/sla-and-escalation.mdx:12(zh-Hans / zh-Hant 同行号):
> Every case gets an SLA due date the moment it's created. The target is based on priority:
src/objects/case.hook.ts:60-64 只为 critical 打这个戳:
if (priority === 'critical' && !input.sla_due_date && !ctx.previous?.sla_due_date) {
const due = new Date();
due.setHours(due.getHours() + 4);
input.sla_due_date = due.toISOString();
}
其余三个优先级一律留空。该字段(src/objects/case.object.ts:197)不是 readonly,所以人可以手工填,src/data/service.seed.ts 也确实为若干非 critical 的种子工单显式写了值——但没有任何自动化会给它们打戳。
这一条现在与同页的另一处直接打架:PR #886/#890 按 #886 的裁定,在"何时触发升级"一节写实了"SLA 钩子只为 critical 填 sla_due_date,其余优先级一律留空"。:12 与它相隔 45 行,说的是反话。两处必须由同一个人一次改齐,这也是本单立在这里的主要原因。
B. :32 —— "违约标记对客服是只读的——他们无法篡改"
> The breach flag is read-only for agents — they can't fudge it. It's auto-calculated by the system.
src/objects/case.object.ts:205-210 明确不是 readonly,且注释写明了为什么不能是:
// NOT `readonly`: the case_sla_monitor flow stamps this, and 16.x drops
// writes to readonly fields (#2948) — readonly here silently disabled
// SLA violation tracking.
is_sla_violated: Field.boolean({ label: 'SLA Violated', group: 'sla', defaultValue: false }),
它同时出现在 src/views/case.view.ts:28 的列表列与 src/pages/case_detail.page.ts 的字段面上。也就是说:一个有 crm_case 编辑权的客服可以直接把它改掉,页面承诺的那道门不存在。("由系统自动计算"那半句是对的——case_sla_monitor 会写它。)
C. :34-38 —— "工单详情页在页眉中显示实时 SLA 倒计时"
> The case detail page shows a live SLA countdown in the header:
> - ⏱ 2h 14m remaining — fine
> -
> - 🚨 BREACHED – 1h 32m over — escalation territory
grep -rni "countdown\|remaining" src/ 在整个 app 里零命中(两处 remaining 是 dataset / dashboard 里的无关注释)。src/pages/case_detail.page.ts:61-68 的注释自己写着 crm_case 只带一个 sla_due_date 加派生字段——页眉里是这两个字段的普通渲染,没有任何倒计时组件、阈值配色或"超时多久"的计算。#886 的正文已记过这一处,但把它排除在该单的切割之外。
D. :17-19 —— High / Medium / Low 那三行的"违约长什么样"
> | High | 8 hours | Red badge in list views |
> | Medium | 2 business days | Amber badge |
> | Low | 7 business days | Grey badge |
src/views/case.view.ts:39-42 里唯一的颜色声明是 all_cases 视图的 rowColor,而且它键在 priority 上,不是键在违约上:
rowColor: {
field: 'priority',
colors: { critical: '#dc2626', high: '#f97316', medium: '#eab308', low: '#94a3b8' },
},
三重不符:(1) 它是行底色,不是徽章;(2) 它按优先级恒常渲染,跟有没有违约无关——一个刚建、离截止还有 8 小时的 High 工单就已经是这个颜色了;(3) 连颜色都对不上——High 是橙色 #f97316 而不是红色,Medium 是黄色 #eab308。列表视图里真正表示违约的是 is_sla_violated 这一列(case.view.ts:28)。同时这三行的目标值(8 小时 / 2 个工作日 / 7 个工作日)在 A 的意义上也不是系统会盯的截止时间,而是团队的服务承诺。
为什么要紧
A 与 B 是会让人做错事的两条:一个服务经理读完 A,会以为所有工单都在 SLA 时钟上跑,于是不给 High 工单排人工巡检(#886 修的升级面已经写实了这一点,但 :12 还在反着说);读完 B,会以为违约率这个指标防篡改,于是拿它做考核。C 与 D 是纯粹的界面失实,代价是读者按图找不到东西。
边界
- 与
service/sla-and-escalation三语还剩两处行为性失实:升级触发条件多出一个不存在的 High+Customer 分支,Critical 违约行承诺「红色横幅 + 通知支持经理」 #886 / service 三页仍写「建议一个解决方案」会检索知识库并起草回复 / Copilot 用知识库对相似历史工单做模式匹配——两个技能都做不到 #890 不重叠:那两单落在:16、:57-60、:105、:134,本单是:12、:17-19、:32、:34-38,行集互斥,PR 的 hunk 头可证。 - SLA policy matrix: per-priority × tier clocks, first-response stamping, escalation that reassigns #595 不预判:High / Medium / Low 是否应该有 SLA 时钟、违约标记是否应该只读,都是 SLA policy matrix: per-priority × tier clocks, first-response stamping, escalation that reassigns #595(SLA policy matrix)的产品问题。本单只要求把当前行为写实。
- B 的修法与 readonly: true 在 insert 路径上完全不生效,且 update 路径的剥离会连 hook 自己写的戳一起删掉 —— 已发布文章可落成 published_at = null #788(平台侧 readonly 语义)无关:这里不需要改字段,只需要页面别承诺一道不存在的门。
- 三语同步,口径沿用 docs(automation): 按 flow 源码写实内置流程表两行,并修 opportunity_won_alert 的 description (#851) #870 / docs(flows): name what the flow nodes do, not what they were once meant to do #877 / docs(service): 按 flow 与 hook 写实 SLA 页的升级说明(#876) #885 / docs: 清扫 automation 页之外的「工作流规则」并写实 cases 两条虚构通知 (#850, #887) #894:点名说清不做什么 + 真实归属,不静默删名。
Activity
yinlianghui commentedon Aug 6, 2026
🔒 认领(/pm-dispatch R27)— session
session_01VHrPAGEgFDoHjphqYG4BMa,分支claude/issue-903-sla-tracking-fidelity。文件面:
content/docs/service/sla-and-escalation{,.zh-Hans,.zh-Hant}.mdx,仅 A(:12)/ B(:32)/ C(:34-38)/ D(:17-19)四族——行号为基线 90686a4 原始值,PR #907(#886+#890)与 #906(#844)已动同页,fresh main 上重定位。裁定:
service/sla-and-escalation三语还剩两处行为性失实:升级触发条件多出一个不存在的 High+Customer 分支,Critical 违约行承诺「红色横幅 + 通知支持经理」 #886 已写实的「钩子只为 critical 填戳」句必须一次改齐,消除同页自相矛盾;service/sla-and-escalation三语还剩两处行为性失实:升级触发条件多出一个不存在的 High+Customer 分支,Critical 违约行承诺「红色横幅 + 通知支持经理」 #886/service 三页仍写「建议一个解决方案」会检索知识库并起草回复 / Copilot 用知识库对相似历史工单做模式匹配——两个技能都做不到 #890 已落地的 :16/:57 族/:105/:134 改动不得回退。Generated by Claude Code
yinlianghui commentedon Aug 6, 2026
实施完成,draft PR #918。四族里 A / C / D 三族前提成立并已写实,B 族前提复核后证伪 —— 详情与证据见 PR 正文,这里只记 B 的结论,因为它改变了本单的结果面。
B
:32「违约标记对客服是只读的」—— 不是失实本单的依据是
src/objects/case.object.ts:205-210不带readonly,推论「页面承诺的那道门不存在」。字段确实不是 readonly(注释写明原因),但门在另一层:fields是PermissionSetSchema的一等键(PERMISSION_SET_KEYS含fields;FieldPermissionSchema={ readable, editable },.strict()),不是会被静默丢弃的未识别键。本仓自己的文档也已列过这条遮罩 ——content/docs/administration/profiles.mdx:82:「crm_case.is_sla_violated/resolution_time_hours| Service agent | Nobody — they are computed」;sharing-and-security.mdx:194写 FLS「enforced everywhere」。其余 profile 里sales_manager/sales_rep对crm_case本就allowEdit: false,marketing_user无授权,guest_portal只能 insert。所以「对客服只读」这句是对的,照本单原样改写会把一句正确的话改成新的失实。处理:保留该判断,补写真实机制(字段级安全而非字段属性)并链到 Profiles 的 FLS 表。
B 这一族真正失实的是相邻的
:30,字段定义行:「SLA Breached? —truewhen the resolution time exceeds the target」。字段标签是 SLA Violated,不存在叫 SLA Breached? 的字段;置真条件也不是「解决时间超过目标」,而是每小时扫描命中「status 不在 resolved/closed +sla_due_date已过」(case-sla-monitor.flow.ts:40-47)。这条已按裁定 2 的口径改写,并与 A 咬合(没有截止日期的工单永远不入选)。行号重定位
四族在 fresh main(
7df29789)上未位移,:12/:17-19/:32/:34-38逐一原址命中 —— PR #907 / #906 的增删都落在:57一节及其后。顺带按裁定 1 一次改齐的同族回声
:8导语(「gives every case a deadline … surfaces breaches in real time」)是 A 与 C 的同一句话换位置。:124给客服的提示(「关注你的 SLA 倒计时——当你看到琥珀色区域时」)是 C 的回声。:21(「SLA 目标可按优先级配置」)随 A / D 收窄。只改被点名的四行会把矛盾留在更显眼的位置,故一并改。#886 / #890 已落地的
:16/:57族 /:105/:134逐字未回退。另一族失实已单独立单
施工中发现同页另一族(页面指向的视图 / 报表 / 配置项是否存在)6 处失实,行集与本单互斥,已先搜重复后立单 #917,未在本 PR 顺手改。
Generated by Claude Code
yinlianghui commentedon Aug 6, 2026
✅ 验收通过 —— PR #918 已转 ready 并挂 auto-merge(CI 8/8 全绿实核,head a036d7a)。
验收要点:
service-agent.profile.ts:52的字段级安全('crm_case.is_sla_violated': { editable: false },FieldPermissionSchema 一等键非静默丢弃,profiles.mdx:82 与 sharing-and-security.mdx:194 互证)而非字段属性——照 issue 字面改写会把一句正确的话改成新失实。dev 保留正确判断、补写真实机制,并连带改写了 B 族里真正失实的相邻 :30(标签名 SLA Violated、置真条件是每小时扫描而非「解决超时」、两个边界后果与 A 咬合)。service/sla-and-escalation三语还剩两处行为性失实:升级触发条件多出一个不存在的 High+Customer 分支,Critical 违约行承诺「红色横幅 + 通知支持经理」 #886 已写实句一次改齐,同族回声 :8/:21/:124 一并收口;service/sla-and-escalation三语还剩两处行为性失实:升级触发条件多出一个不存在的 High+Customer 分支,Critical 违约行承诺「红色横幅 + 通知支持经理」 #886/service 三页仍写「建议一个解决方案」会检索知识库并起草回复 / Copilot 用知识库对相似历史工单做模式匹配——两个技能都做不到 #890 已落地行逐字未回退;四个名字(SLA Breached?/红色徽章/琥珀区/倒计时)全部点名说清「不存在/是别的东西」,无一静默删名;SLA policy matrix: per-priority × tier clocks, first-response stamping, escalation that reassigns #595 一句未评并在 changeset 显式指回;src/ 零改动。workflows残留族 —— 引擎里没有「重新评估 5 次」这个计数器,报价对象上也没有可调的计划 (#899) #916→docs(service): SLA 跟踪一节按实测行为改写(#903) #918),处置正确。越界发现处置:#917(同页第三族六处:营业时间、报表维度语义不可达、Breached SLA 视图、Service Board 名、排序键、Waiting 暂停时钟)已复核成立且行集与本单互斥,标 pm:queue;⚠️ 与 #913/#918 同页,派发须在 #918 合并后重定位,R28 候选。
Generated by Claude Code
docs(service): SLA 跟踪一节按实测行为改写(objectstack-ai#903) (objectstack-ai#918)