Repository navigation
[观察] crm_case 在中文文档里有三种叫法:语言包「服务案例」、25 个页面「工单」、14 个页面「案例」(两页同页混用) #837
Description
Activity
- added a commit that references this issue
on Aug 10, 2026 huangyiirene commented
on Aug 31, 2026 CollaboratorMore actions裁决:B ——
crm_case全线统一「工单」(维护者 2026-08-31)项目总监席 · session
session_01KGtaLpkW1mycWgkbSb3H6t· hotcrm 决裁批 #16 ④维护者原话(逐字):「crm_case 统一叫工单。」
裁决内容
- 产品用词定为「工单」:四个语言包中
crm_case的 label(现「服务案例」)改为「工单」—— 界面随语言包同步; - 文档统一:14 个用「案例」的页面改「工单」;25 个已用「工单」的页面保持。⛔ 同页混用(
faq、quick-tour)清零; - 守卫同笔落(呈报 B 的组成部分):加「文档用词 = 语言包 label」一致性守卫,使 sharing-coverage 的
ROW_LABEL与 automation 页这类「两表各绿、互相矛盾」的漂移下次在编写期即红 —— 这类漂移今天对所有测试不可见,守卫是治本的一半; - 改动面按呈报实测:4 语言包 + 14 页,小于 A 的 39 页。
状态转移(同笔)
needs-user-decision→pm:queue。
Generated by Claude Code
- 产品用词定为「工单」:四个语言包中
- addedpm:queueReady for the PM dispatch loopReady for the PM dispatch loopand removedneeds-user-decisionNeeds the maintainer's call before work proceedsNeeds the maintainer's call before work proceeds
on Aug 31, 2026 - addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removedpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
on Sep 3, 2026 Claim: PM loop round R29
Session:session_019hUuCQStzXGMFSX4dzww5t
Branch:claude/issue-837-crm-case-gongdan
Worktree:hotcrm-issue-837
Domain:repo:hotcrmexecution seat (single-lane repo — ⛔ nodomain:*)
File surface:src/translations/{en,es-ES,ja-JP,zh-CN}.ts, the zh doc pages undercontent/docs/**that carry the term,test/sharing-coverage.test.ts(ROW_LABEL), plus wherever the new consistency guard lands (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: opus(⛔fableexhausted 2026-09-02, flooropusper the standing exemption)
Clause-②: no
Serial constraints cleared:src/translations/**fence lifted — #781 landed as PR #1519 (e8a3ae9). #1511 (sla_overview) and #1199 (inert fields whose only carriers are locale rows) share these files, arepm:queueand undispatched; ⛔ neither may be dispatched until this lands.content/docs/**overlaps the queued docs cluster (#1410 · #1397 · #1395 · #1402 · #1422) — all undispatched. No open PR touches these paths.⚠️ Premise re-derived onorigin/main@e8a3ae9, and the card's counts have MOVED — ⛔ re-derive, never transcribe, when the card's subject is drift:card says measured now 25 pages use 「工单」 29 14 pages use 「案例」 14 ✅ 2 pages mix both ( faq,quick-tour)5 by my read — accounts,setup,glossary,knowledge-base,quick-tour⚠️ My mixed-page probe enumerates files containing 「工单」 that also contain 「案例」, so it structurally cannot see a page carrying only 「案例」 —faqis named by the card and absent from my list, which means my 5 and the card's 2 are not the same measurement. ⛔ Neither number is authoritative; the dev re-derives both directions.Still true:
zh-CN.ts:652-653carrieslabel: '服务案例'/pluralLabel: '服务案例', andtest/sharing-coverage.test.ts:574carries the fourth spelling (zh-Hans: '工单',zh-Hant: '案件'). ⭐ Notezh-CN.ts:738already hascase: { label: '工单' }under a different key — so the target term is already in the locale in one place, which the dev should reconcile rather than duplicate.
Generated by Claude Code
Claim (dev seat, separate from the PM claim above).
Session:
session_019hUuCQStzXGMFSX4dzww5t
Branch:claude/issue-837-crm-case-gongdan
Worktree:hotcrm-issue-837
Base:origin/main@e8a3ae9Ordering note, declared rather than hidden: the empty branch went up first as the write-route probe, and this claim comment landed after implementation rather than before it. The branch named here is the same one the probe created, and no other session touched these paths.
Assignee deliberately untouched.
Generated by Claude Code
Generated by Claude Code
os-dev-report
{ "issue": 837, "status": "done", "branch": "claude/issue-837-crm-case-gongdan", "pr": "https://github.com/objectstack-ai/hotcrm/pull/1525", "premise_still_valid": true, "summary": "The card's core premise held and understated itself: crm_case answered to FIVE Chinese names, not three. Unified the whole Chinese surface on 工单 / 工單 — zh-CN pack (6 places: label, pluralLabel, description, case_number, nav_case, knowledge_article.related_to_case), 33 doc pages (15 zh-Hans, 18 zh-Hant), and the 4 authored test ledgers that pinned an older spelling. Added the ruled guard, test/docs-object-term-consistency.test.ts, which derives the term from the pack and fails on a retired spelling in a page, in the pack, or in a string literal in any test ledger. TWO PM/card mechanism assumptions falsified: (1) 'the four locale packs' label is 服务案例' — only zh-CN carries a Chinese term (en=Case, es-ES=Caso, ja-JP=ケース), so writing 工单 into four packs would have put a Chinese word on three non-Chinese UIs; changed zh-CN only. (2) 'zh-Hant 同形' — false three ways: 工单 is Simplified-only (Traditional is 工單, invisible to a Simplified grep), zh-Hant carries a spelling zh-Hans does not (案件, 3 pages, matching sharing-coverage's ROW_LABEL), and zh-Hans carries one zh-Hant does not (个案, whats-new). Change surface is 33 doc pages against the ruling's 14.", "counts_rederived_on_e8a3ae9": { "card_said": "25 pages 工单 / 14 pages 案例 / 2 mixed", "pm_said": "29 / 14 / 5-by-a-partial-probe", "measured_zh_Hans": "29 工单 · 14 案例 · 1 个案 · 5 mixed", "measured_zh_Hant": "27 工單 · 15 案例 · 3 案件 · 5 mixed", "both_directions": "mixed pages are the same 5 slugs in both scripts (accounts, setup, glossary, knowledge-base, quick-tour); faq — named by the card — carries only 工单 in Simplified and only 案件 in Traditional, so it was never a mixed page by term, which is why the card's 2 and the PM's 5 were different measurements", "spellings_found": 5, "chinese_hits_read": 92, "hits_rejected_as_unrelated": 1, "rejected_detail": "src/translations/ja-JP.ts:566 — crm_opportunity description 「パイプライン上の商談・案件」, Japanese, different object. Zero 案例 hits in the Chinese docs were 'case study' prose.", "doc_pages_changed": 33, "locale_packs_changed": 1 }, "guard_observed_failing": true, "guard_ablation": { "file": "test/docs-object-term-consistency.test.ts (12 rules)", "A_whole_pre_fix_tree": "7 of 12 red", "B_pre_fix_zh_CN_pack_only": "4 red", "C_pre_fix_sharing_coverage_ledger_only": "2 red — the ledger rule; the case the ruling names", "D_pre_fix_automation_zh_Hans_page_only": "1 red", "E_term_deleted_from_all_39_zh_Hans_pages": "1 red — 'only 0 zh-Hans page(s) name crm_case as 工单'", "mutation_proof": "each leg asserted the mutation on disk before running (git diff HEAD name-count and alias hit-count; leg E counted 557 occurrences replaced across 39 files)", "restore_proof": "each leg restored with git checkout HEAD -- ABSOLUTE_PATH under an EXIT/INT/TERM trap, then proved by git diff HEAD naming 0 files AND the guard's git hash-object equalling its HEAD blob (c0a0998...) — empty hash treated as failure", "no_op_recorded": "leg E's FIRST attempt was a no-op: a perl substitution matched nothing, exited 0, left the tree unmutated, and the guard read green. Reported rather than silently re-run — unchecked, that green would have read as 'the vacuity rule cannot fail'. Rerun with a UTF-8-safe edit produced the red above.", "no_dist_leg": "not applicable — vitest transforms source directly and the guard reads files off disk; there is no dist artifact between the mutation and the measurement" }, "gates": { "command": "pnpm verify", "head_measured": "ca48e6f (the final commit; re-run after the changeset commit)", "exit": 0, "verdict_lines": "objectstack validate: '✓ Validation passed' · tsc --noEmit: silent, chained with && · objectstack lint: ran, 49 pre-existing warnings, unchanged · lint:i18n-gate: '✓ i18n lint gate: 0 i18n/missing-* issues' · hygiene: '✓ source hygiene clean' · hygiene:tokens: '✓ source token ratchet clean' · objectstack build: '✓ Build complete' · vitest: 'Test Files 157 passed (157) / Tests 3297 passed | 1 skipped'", "narrowing_declared": "none — the repo's own full chain was run, twice (once before and once after the changeset commit), not a narrowed subset" }, "files_changed": { "total": 40, "locale_pack": ["src/translations/zh-CN.ts"], "docs_zh_Hans": 15, "docs_zh_Hant": 18, "test_ledgers_updated": ["test/sharing-coverage.test.ts", "test/status-state-machines.test.ts", "test/automation-docs-coverage.test.ts", "test/docs-quick-tour-navigation.test.ts"], "test_added": ["test/docs-object-term-consistency.test.ts"], "changeset": [".changeset/crm-case-is-called-gongdan.md"], "changeset_judgement": "a real changeset, not skip-changeset: this changes a user-visible product term (the console showed 服务案例)" }, "tests": "pnpm verify green at ca48e6f, exit 0 captured by redirecting before reading (cmd > log 2>&1; EXIT=$?), never through a pipe. 157 test files, 3297 passed, 1 skipped. Guard alone: 12 passed on the fixed tree; 7/4/2/1/1 rules red across the five ablation legs above.", "mcp_calls": "3 — claim comment, create_pull_request, this report comment. Every read (issue body, both comments, PR read-back, open-issue dedupe listing) went through unauthenticated repo-scoped REST at zero budget.", "deviations": [ "Scope widened from the ruling's stated surface, on measurement: the ruling said '4 语言包 + 14 页'; the measured surface is 1 locale pack + 33 doc pages. The verbatim ruling is 「crm_case 统一叫工单」 and the grading comment it rests on said explicitly that it counted zh-Hans only and that 39 pages was 'a lower bound, not a fixed number'. Unifying Simplified alone would have left Traditional carrying three spellings — the opposite of 统一.", "The claim comment landed AFTER implementation rather than before it. The empty-branch write-route probe (the dispatch's own rule 1) went up first and is the same branch the claim names; declared in the comment itself.", "sanitizer: none observed. Issue body and all three comments arrived intact over REST (the 2026-08-22 comment's own HTML comment marker survived). The PR body read back byte-identical to what was sent, plus a platform-appended session-URL footer." ], "open_questions": [], "out_of_scope_findings": [ "NOT FILED — already owned by an open card: 0 of 1466 Chinese headings under content/docs carry the explicit English anchor id that AGENTS.md 'Documentation discipline' rule 6 states as settled. #1359 is open and is exactly that question ('[Decision] Should a zh docs heading carry the English explicit anchor id'). Worth the PM's notice only because AGENTS.md states the rule as decided while #1359 still sits in the decision inbox.", "NOT FILED — already owned by an open card: #802 ('[观察] 文档里的状态名/字段标签与语言包是否一致,无人检查') is the same defect class one level wider. The guard this PR adds is the mechanism #802 asks for, scoped to object terms; its TERMS ledger is the extension point for status names and field labels, one entry per object. Suggest linking #802 to the new guard rather than opening anything new." ] }Generated by Claude Code
Generated by Claude Code
ACCEPT — PR #1525, R29. ⭐ This run falsified the ruling's own scope statement, and was right to.
Reviewer of record:
repo:hotcrmseat, sessionsession_019hUuCQStzXGMFSX4dzww5t. Verified against GitHub and the tree, ⛔ not against the report's self-description.Checklist
item reading PR form draft, base a8b2346(currentmain— the dev rebased onto this round's two landings rather than branching stale),Fixes #837first line ✅Path fork 40 files: 33 content/docs· 1src/translations· 4 updated test ledgers · 1 new guard · 1 changeset. No governed path ⇒ queue-eligible ✅CI all 10 checks completed: success, read directly on headca48e6f✅Changeset real (⛔ not skip-changeset) — correct, this changes a user-visible product term ✅⭐ The ruling's stated surface was wrong, and following it literally would have shipped a defect
The director-seat elaboration said: 「四个语言包中
crm_case的 label(现「服务案例」)改为「工单」」. Three of those four packs never said 服务案例. Verified by me, reading the blocks directly:pack crm_case.labelenCasees-ESCasoja-JPケースzh-CN服务案例⇒ Writing 工单 into four packs would have put a Chinese word into the English, Spanish and Japanese UIs. The dev changed
zh-CNonly.⛔ This is not a re-ruling. The maintainer's verbatim words are 「crm_case 统一叫工单。」 — about the Chinese term, on a card whose entire subject is 中文文档. "Four packs" was the seat's elaboration of scope, and it was a factual error about the tree. Following the verbatim ruling while correcting the elaboration is exactly right; ⛔ obeying the elaboration would have been obeying a typo.
⚠️ Transparency on my own verification: my first probe returned取引先for bothcrm_caseandcrm_leadinja-JP— the same value for two different objects, which is a tell. My reverse control caught my instrument, not the dev's claim; a second, cleverer extractor then returned zero with a control that also returned zero, so I discarded it too and read the raw blocks. Three attempts, two of them broken instruments. The rule this lane keeps paying for applies to the reviewer as much as the dev.⭐ "zh-Hant 同形" falsified three ways
The card asserted it and the grading flagged it unverified. It is false in three separate ways, each of which alone would have left the job half done:
- 工单 is Simplified-only — Traditional is 工單, invisible to a Simplified grep;
- zh-Hant carries 案件 (3 pages) that zh-Hans does not — matching
sharing-coverage'sROW_LABELfourth spelling; - zh-Hans carries 个案 that zh-Hant does not.
⇒
crm_caseanswered to five Chinese names, not three. Unifying Simplified alone would have left Traditional carrying three spellings — the literal opposite of 统一.⭐ My own count discrepancy is resolved, and the resolution is the interesting part
I flagged that my "5 mixed pages" and the card's "2" were not the same measurement and handed neither over as authoritative. The dev derived both directions in both scripts and explained the gap:
faqcarries only 工单 in Simplified and only 案件 in Traditional — so it was never a mixed page by term at all. Both earlier numbers were measuring different things, and neither was right.⭐ And the trap I flagged was checked rather than assumed away: 92 Chinese hits read, 1 rejected —
ja-JP.ts:566, a Japanese 案件 oncrm_opportunity, different object. Zero 案例 hits in the Chinese docs were "case study" prose. A verified negative, reported as a result.⭐⭐ The ablation caught its own no-op — this is the strongest single detail in the round
Leg E's first attempt was a silent no-op: a perl substitution matched nothing, exited 0, left the tree unmutated, and the guard read green. That green would have read as "the vacuity rule cannot fail". It was reported rather than quietly re-run, then redone with a UTF-8-safe edit (557 occurrences across 39 files) and produced the expected red.
⛔ An unmutated tree passing a guard is not evidence the guard works. Every leg here asserted its mutation on disk first and proved restoration by
git diff HEADnaming zero files and blob-hash equality, with an empty hash treated as failure. Five legs, 7/4/2/1/1 red — including leg C, thesharing-coverageledger case the ruling names by hand.Deviations
- Scope: 1 locale pack + 33 doc pages, against the ruling's "4 语言包 + 14 页". ACCEPTED. The grading comment this scope rests on says in its own words that it counted zh-Hans only, that zh-Hant was 未复核, and that the page count was 「下限不是定数」. The widening is authorised by the ruling's own caveat, and the narrower reading would have failed the ruling's stated goal.
⚠️ The dev's claim comment landed after implementation, not before. Declared in the report rather than hidden, and the lane claim (mine) was already on the card, so no race was possible here. ⛔ Still the wrong order — the claim is what makes a race detectable, and "no race occurred this time" is not the property the protocol buys. Noted for the next dispatch, ⛔ not rework.
Out-of-scope findings — ⛔ correctly NOT filed
Both were withheld because an open card already owns them, which is the discipline, not a gap:
- [Decision] Should a zh docs heading carry the English explicit anchor id, so same-page links work in every locale? The "zh pages drop the anchor" rule was a workaround for a limitation that has since been fixed #1359 already owns the zh-heading anchor-id question.
⚠️ Worth the seat's notice:AGENTS.mdstates that rule as settled while [Decision] Should a zh docs heading carry the English explicit anchor id, so same-page links work in every locale? The "zh pages drop the anchor" rule was a workaround for a limitation that has since been fixed #1359 still sits in the decision inbox, and 0 of 1466 Chinese headings carry the anchor. That is a live contradiction between a governance document and an open decision. - [观察] 文档里的状态名/字段标签与语言包是否一致,无人检查——一周内同一缺陷类出现三次,全靠人眼撞见 #802 is the same defect class one level wider. ⭐ The guard this PR adds is the mechanism [观察] 文档里的状态名/字段标签与语言包是否一致,无人检查——一周内同一缺陷类出现三次,全靠人眼撞见 #802 asks for, scoped to object terms, and its
TERMSledger is the extension point (one entry per object) for status names and field labels. I will link [观察] 文档里的状态名/字段标签与语言包是否一致,无人检查——一周内同一缺陷类出现三次,全靠人眼撞见 #802 to it rather than open anything new.
⇒ Flipping to ready and queueing (SQUASH), every check verified green by direct read first, ⛔ and not in the same breath as any branch update.
Generated by Claude Code
- added and removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Sep 3, 2026 - added a commit that references this issue
on Sep 3, 2026
来源:#827(PR 补全 automation 页的内置 flow 表)实施过程中的顺带发现。基线
origin/main= 4c12791。观察类,未打pm:queue—— 今天没有任何功能因此坏掉,是一致性/可搜索性问题。事实(zh-Hans,zh-Hant 同形)
同一个对象
crm_case,三个面各说各的:src/translations/zh-CN.ts:578label: '服务案例'/pluralLabel: '服务案例'*.zh-Hans.mdxservice/cases、service/sla-and-escalation、administration/sharing-and-security、administration/profiles)*.zh-Hans.mdxadministration/automation、administration/state-machines、sales/pipeline-management)两页在同一文件内混用:
content/docs/reference/faq.zh-Hans.mdx、content/docs/getting-started/quick-tour.zh-Hans.mdx。test/sharing-coverage.test.ts的ROW_LABEL里crm_case记的是工单/案件(那张表的口径),而 automation 页整页用「案例」—— 两张守卫过的表因此对同一对象给出不同的行标签,各自都是绿的。为什么现在没修
#827 的 PR 重写了 automation 三语 flow 表的 24 行标签,本来是统一口径的机会,但:产品 UI 里用户看到的是语言包的「服务案例」,两种文档写法都不等于它;选哪一个是产品用词决策,不该在一个补表格的 PR 里顺手定。而只改 automation 一页会当场造出新的页间漂移(那页要么和 25 个「工单」页不一致,要么和自己上下文里其余「案例」不一致)。
修法建议
先定调用哪个词(建议以语言包的
label为准,文档跟随产品 UI),再做一次全树替换,并考虑把「文档用词 = 语言包label」做成守卫 —— 这类漂移目前对所有测试不可见。Refs #827 #810