kc-beta 0.7.5 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +47 -0
  2. package/package.json +3 -2
  3. package/src/agent/engine.js +390 -100
  4. package/src/agent/pipelines/_advance-hints.js +92 -0
  5. package/src/agent/pipelines/_milestone-derive.js +247 -13
  6. package/src/agent/pipelines/skill-authoring.js +30 -1
  7. package/src/agent/tools/agent-tool.js +2 -2
  8. package/src/agent/tools/consult-skill.js +15 -0
  9. package/src/agent/tools/dashboard-render.js +48 -1
  10. package/src/agent/tools/document-parse.js +31 -2
  11. package/src/agent/tools/phase-advance.js +17 -13
  12. package/src/agent/tools/release.js +250 -7
  13. package/src/agent/tools/sandbox-exec.js +65 -8
  14. package/src/agent/tools/worker-llm-call.js +95 -15
  15. package/src/agent/workspace.js +25 -4
  16. package/src/cli/components.js +4 -1
  17. package/src/cli/index.js +97 -1
  18. package/src/config.js +19 -2
  19. package/src/marathon/driver.js +217 -0
  20. package/src/marathon/prompts.js +93 -0
  21. package/template/.env.template +16 -0
  22. package/template/skills/en/bootstrap-workspace/SKILL.md +14 -0
  23. package/template/skills/en/quality-control/SKILL.md +9 -0
  24. package/template/skills/en/skill-authoring/SKILL.md +39 -0
  25. package/template/skills/en/skill-to-workflow/SKILL.md +53 -0
  26. package/template/skills/en/work-decomposition/SKILL.md +34 -0
  27. package/template/skills/phase_skills.yaml +5 -0
  28. package/template/skills/zh/bootstrap-workspace/SKILL.md +14 -0
  29. package/template/skills/zh/compliance-judgment/SKILL.md +37 -37
  30. package/template/skills/zh/document-chunking/SKILL.md +21 -14
  31. package/template/skills/zh/document-parsing/SKILL.md +65 -65
  32. package/template/skills/zh/entity-extraction/SKILL.md +68 -68
  33. package/template/skills/zh/quality-control/SKILL.md +9 -0
  34. package/template/skills/zh/skill-authoring/SKILL.md +39 -0
  35. package/template/skills/zh/skill-creator/SKILL.md +204 -200
  36. package/template/skills/zh/skill-to-workflow/SKILL.md +53 -0
  37. package/template/skills/zh/tree-processing/SKILL.md +67 -63
  38. package/template/skills/zh/work-decomposition/SKILL.md +34 -0
  39. package/template/workflows/common/llm_client.py +168 -0
  40. package/template/workflows/common/utils.py +132 -0
@@ -4,61 +4,61 @@ tier: meta
4
4
  description: Extract specific entities, values, and text segments from documents as required by verification rules. Use after tree processing has located the relevant section, when a rule needs a specific number, date, name, amount, clause, or any domain-specific entity extracted. Covers extraction method selection (regex vs LLM), schema design, postprocessing, and confidence annotation. Also use when designing the extraction step of a workflow for worker LLMs.
5
5
  ---
6
6
 
7
- # Entity Extraction
7
+ # 实体提取
8
8
 
9
- An entity is the thing you need to check. A number, a date, a name, a clause, a percentage, a statement. The rule says what to check; extraction is how you get the value to check it against.
9
+ 实体就是你需要核查的对象:一个数字、一个日期、一个名称、一个条款、一个百分比、一段陈述。规则告诉你要核查什么,提取负责把可核查的值从原文中取出来。换句话说,规则定义了"核查目标",而实体提取是把这个目标从纸面化为程序可比较、可判定的结构化数据的关键一步。没有可靠的提取,后续的判定和报告都是空中楼阁;提取阶段每多一分误差,下游的判定和汇总就会把这分误差放大。在金融与监管合规这类对数字、口径、时点极其敏感的场景里,提取的稳定性直接决定整套验证流程能否被信任。
10
10
 
11
- ## Extraction Type Taxonomy
11
+ ## 提取场景分类
12
12
 
13
- Different extraction scenarios call for different approaches:
13
+ 不同的提取场景需要不同的策略。先对照下面四类,识别当前规则属于哪一种,再去选具体的实现方法:
14
14
 
15
- ### Single Entity from Single Section
16
- The simplest case. One rule needs one value from one place.
17
- - Example: "Extract the capital adequacy ratio from the Key Metrics table."
18
- - Approach: Locate the section, apply regex or LLM extraction.
15
+ ### 单一章节中的单一实体
16
+ 最简单的情况。一条规则只需要从一个固定位置取一个值。
17
+ - 示例:"从关键指标表中提取资本充足率。"
18
+ - 思路:先通过树处理定位到对应章节,再用正则或 LLM 对该段文本做一次提取即可。
19
19
 
20
- ### Multiple Entities from Single Section
21
- One rule needs several related values from the same place.
22
- - Example: "Extract the borrower's name, loan amount, interest rate, and maturity date from the loan agreement summary."
23
- - Approach: Design a single extraction call that returns all values. More efficient than multiple calls.
20
+ ### 单一章节中的多个实体
21
+ 一条规则需要从同一段落或同一张表里取出多个相关的值。
22
+ - 示例:"从贷款协议摘要中提取借款人姓名、贷款金额、利率和到期日。"
23
+ - 思路:设计一次提取调用,让模型或脚本一次性返回所有字段。比拆成多次调用更高效,也更容易保持字段之间的一致性,避免重复加载相同的上下文。
24
24
 
25
- ### Single Entity from Multiple Sections
26
- One value is scattered across multiple places, or needs cross-referencing.
27
- - Example: "Extract the total collateral value, which may be listed in the collateral section or in Appendix A."
28
- - Approach: Collect content from all relevant sections, then extract. Note which source the value came from.
25
+ ### 多个章节中的单一实体
26
+ 同一个值分散在多个位置,或需要交叉比对、汇总。
27
+ - 示例:"提取抵押物总价值,该值可能列在抵押物章节,也可能列在附件 A"
28
+ - 思路:先把所有可能含有该值的章节内容汇总,再做一次提取。务必在结果中标注该值的来源章节,方便后续追溯和审计。
29
29
 
30
- ### Entity from Full Document
31
- The value could be anywhere, or the rule applies to the document as a whole.
32
- - Example: "Check whether the document contains a valid signature page."
33
- - Approach: For the coding agent, scan the full document. For worker LLM workflows, design a two-pass approach: first pass identifies the location, second pass extracts the value.
30
+ ### 全文档级别的实体
31
+ 该值可能出现在任意位置,或者规则本身是针对整份文档的属性。
32
+ - 示例:"核查文档是否包含有效的签章页。"
33
+ - 思路:对于编码 agent,可以直接扫描整份文档。对于 worker LLM 工作流,建议设计两遍流程:第一遍粗扫整篇定位候选位置,第二遍只对候选段做精提取。这样能避免把整篇文档塞进单次调用导致上下文超限,也便于在候选阶段做并行化处理。
34
34
 
35
- ## Method Selection
35
+ ## 方法选择
36
36
 
37
- Extraction method selection is a cost-accuracy search. The goal is finding the cheapest method that meets the accuracy threshold. Regex is the smallest, cheapest "model" — zero cost, instant, deterministic. Worker LLM is more capable but costs tokens and time. Any search strategy is valid: try the cheapest first and escalate, try the most capable first and downgrade, bisect, or jump directly to a known-good method based on past experience in AGENT.md.
37
+ 提取方法的选择本质上是一次成本-准确率的搜索。目标是找到能稳定达到准确率阈值的最低成本方案。正则表达式是最小、最便宜的"模型"——零成本、即时、确定性、可重放、可被单元测试覆盖。Worker LLM 能力更强,覆盖语义层面的提取需求,但消耗 tokens 和时间,且每次输出可能存在细微差异,需要后处理与校验来兜底。任何搜索策略都成立:可以先试最便宜的方法再逐步升级,也可以先试最强的方法再逐步降级,可以在中间档位做二分查找,也可以基于 AGENT.md 中沉淀的历史经验直接跳到已验证可行的方法上,不必每次都从零开始重新试错。重要的是先想清楚"达标"的标准是什么,再开始搜索,否则容易在没有目标的情况下无限抬高成本。
38
38
 
39
- ### Available Methods
39
+ ### 可用方法
40
40
 
41
- **Regex / Python** Cost: zero. Speed: instant. Deterministic.
42
- Works well for: dates, monetary amounts, percentages, identifiers, fixed phrases, any value with a predictable format.
41
+ **正则 / Python** —— 成本:零。速度:即时。结果确定。
42
+ 适用场景:日期、金额、百分比、标识符、固定短语、编号、电话、地址等任何格式可预测的值。任何能写出清晰格式约束的字段,都应该优先考虑正则。
43
43
 
44
- **Worker LLM** Cost: API tokens. Speed: seconds. Semantic understanding.
45
- Works well for: contextual interpretation, conditional values, semantic matching, ambiguous structures, suggestive or misleading language detection, table interpretation, anything requiring understanding rather than pattern matching.
44
+ **Worker LLM** —— 成本:API tokens。速度:秒级。具备语义理解能力。
45
+ 适用场景:需要结合上下文判断、条件性取值、语义匹配、结构模糊、识别误导性或暗示性表述、表格语义解读,凡是依赖理解而非模式匹配的任务。Worker LLM 在表面形式不稳定但语义清晰的场景下尤其有价值。
46
46
 
47
- Many real verification tasks require semantic understanding — "is this description misleading?", "does this clause adequately disclose risk?", "is this guarantor's business description consistent with their stated industry?" — regex cannot handle these. Use worker LLM without hesitation for such tasks.
47
+ 实际验证任务中存在大量需要语义理解的场景——"这段描述是否具有误导性?""该条款是否充分披露风险?""该担保人的业务描述是否与其所述行业一致?"、"产品类型表述与底层资产是否匹配?"——这些都不是正则能处理的问题。遇到此类任务,毫不犹豫地使用 worker LLM;不要为了节省 tokens 而把不适合的任务硬塞给正则,否则就是用低成本换高漏报或高误报,最终在审计或复核环节付出更大代价。
48
48
 
49
- ### The Search
49
+ ### 搜索过程
50
50
 
51
- If a method's results fall below the accuracy threshold, try a different method or a more capable model. If regex works and meets accuracy — keep it, it's free. If regex produces results below threshold, escalate to worker LLM. If a cheap worker LLM isn't accurate enough, try a more capable tier. Record what works for each extraction type in AGENT.md for future reference.
51
+ 如果某个方法的结果低于准确率阈值,就换一种方法或换一档更强的模型。正则可行且达标——保留它,反正免费、稳定、可回放。正则结果不达标,升级到 worker LLM。便宜档的 worker LLM 不够准确,再换更高一档的模型。每个项目都应当把"哪类提取适用哪个方法"沉淀到 AGENT.md 里,作为后续同类规则的参考;这样下一条规则上来就能直接选对档位,而不是每次都从最便宜的方法重新搜索一遍。同时记录失败案例和阈值不达标的边界条件,让后续同类规则可以提前避坑、节省迭代成本。
52
52
 
53
- ## Project Glossary
53
+ ## 项目术语表
54
54
 
55
- The project glossary (built and maintained by `rule-extraction`, stored at `rules/glossary.json`) is a useful resource when designing extraction. It records canonical names and known aliases for entities that appear across rules. Reading it before extracting helps keep entity names schema-aligned and avoids parallel labels for the same thing.
55
+ 项目术语表(由 `rule-extraction` 构建并维护,存储在 `rules/glossary.json`)是设计提取时的有用资源。它记录了在多条规则中反复出现的实体的规范名称以及已知别名。在动手提取前先读一遍术语表,有助于保持实体命名与项目 schema 对齐,避免对同一事物使用并列的不同标签——例如同一个字段在不同规则里被叫作"资本充足率"、"资本充足比例"、"CAR"等,最终汇总报告时就会出现重复或漏匹配。
56
56
 
57
- Whether the glossary becomes more than a naming convention — for instance, driving cheap pattern matching for entities with stable surface forms — is a per-project judgment. Apply the same cost-accuracy logic as elsewhere: whatever method meets the accuracy threshold for the task at hand.
57
+ 术语表是否要承担命名约定之外的角色——例如,对表面形式稳定的实体直接驱动便宜的模式匹配——是逐项目判断的。在这里同样适用成本-准确率逻辑:在当前任务上能达到准确率阈值的方法就是合适的方法。如果术语表里某个实体的别名集合稳定且可枚举,那么基于术语表生成正则可能是性价比最高的方案;如果别名在新文档中持续扩展、随业务术语演化,那不如直接交给 worker LLM 做语义识别。术语表的另一个隐藏价值在于:它把命名约定固化成项目级单一事实来源,减少跨规则、跨技能之间因为称呼不同而产生的不一致问题。
58
58
 
59
- ## Schema Design
59
+ ## Schema 设计
60
60
 
61
- Define the expected output for each extraction. Keep it simple and JIT:
61
+ 为每次提取定义清晰的预期输出。保持简单、按需扩展(JIT 原则):
62
62
 
63
63
  ```json
64
64
  {
@@ -72,50 +72,50 @@ Define the expected output for each extraction. Keep it simple and JIT:
72
72
  }
73
73
  ```
74
74
 
75
- The schema should capture:
76
- - **value**: The extracted value, normalized.
77
- - **unit**: If applicable (%, 元, days, etc.).
78
- - **raw_text**: The original text fragment where the value was found. This is evidence for the judgment step.
79
- - **source_location**: Where in the document the value was found.
80
- - **confidence**: How sure you are (see `confidence-system`).
81
- - **extraction_method**: What extracted it (regex, LLM-TIER2, etc.).
75
+ Schema 通常需要包含以下信息:
76
+ - **value**:提取出的值,已经过归一化处理。
77
+ - **unit**:单位(如 %、元、天等),如果适用就填写。
78
+ - **raw_text**:值所在的原文片段。这是后续判定步骤的核心证据,也是出现争议时最容易回溯定位的字段。
79
+ - **source_location**:值在文档中的位置(章节号、表名、行列号等)。
80
+ - **confidence**:置信度,详见 `confidence-system`。
81
+ - **extraction_method**:使用的提取方法(regexLLM-TIER2 等),便于事后做方法效果分析。
82
82
 
83
- Do not over-engineer the schema. Add fields as needed during testing.
83
+ 不要过度设计 schema。最开始保持最小集合,在测试中遇到判定需要什么信息再补充对应字段;不要在第一次就把可能用到的字段全部塞进去。冗余字段不仅增加 prompt 体量、增加 worker LLM 的失误面,还会让后续维护时不清楚哪些字段是真正被消费的、哪些是历史残留。schema 一旦写错或扩张得太快,回头清理的成本会很高。
84
84
 
85
- ## Postprocessing
85
+ ## 后处理
86
86
 
87
- Raw extracted values often need normalization:
87
+ 提取出的原始值通常需要归一化才能与规则中的阈值或目标值做严格比较:
88
88
 
89
- - **Chinese numerals digits**: 一百二十万 → 1200000
90
- - **Date standardization**: 2024年3月15日 → 2024-03-15
91
- - **Unit conversion**: 万元 multiply by 10000 if comparing to a threshold in 元.
92
- - **Whitespace and noise removal**: Strip extra spaces, line breaks, formatting artifacts.
93
- - **Percentage normalization**: 0.125 → 12.5% or vice versa, depending on what the rule expects.
89
+ - **中文数字阿拉伯数字**:一百二十万 → 1200000
90
+ - **日期标准化**:2024年3月15日 → 2024-03-15
91
+ - **单位换算**:万元若规则的阈值以元为单位,需要乘以 10000 再比较。
92
+ - **空白与噪声清理**:去除多余空格、换行符、转义符、表格分隔符等格式残留。
93
+ - **百分比归一化**:0.125 → 12.5%,或反向转换,取决于规则期望的形式。
94
94
 
95
- Build postprocessing as Python functions in the rule skill's `scripts/` directory. They are deterministic and reusable.
95
+ 把后处理实现为规则技能 `scripts/` 目录下的 Python 函数。它们是确定性的、可复用的,且便于单元测试。提取与后处理分离也让 schema 中的 `raw_text` 保持忠实于原文,归一化后的值放进 `value`,两者各司其职。这种分层好处还在于:当后处理逻辑出现 bug 时,只要 `raw_text` 是对的,就可以重跑归一化而不必重新调用 LLM、节省成本。
96
96
 
97
- ## Confidence Annotation
97
+ ## 置信度标注
98
98
 
99
- Every extraction should carry a confidence estimate:
99
+ 每次提取都应当带上一个置信度估计,作为后续判定与汇报阶段的重要输入:
100
100
 
101
- - **Regex match, validated format**: 0.90-0.95
102
- - **LLM extraction, high certainty**: 0.80-0.85
103
- - **LLM extraction, some ambiguity**: 0.60-0.75
104
- - **Fallback or inferred value**: 0.40-0.60
105
- - **No value found**: 0.0 (flag as MISSING)
101
+ - **正则匹配,格式校验通过**:0.90-0.95
102
+ - **LLM 提取,高度确定**:0.80-0.85
103
+ - **LLM 提取,存在一定歧义**:0.60-0.75
104
+ - **回退或推断得到的值**:0.40-0.60
105
+ - **未找到值**:0.0(标记为 MISSING
106
106
 
107
- These are starting points. Calibrate based on actual accuracy (see `confidence-system`).
107
+ 以上只是起始值。随着 ground truth 累积,应根据实际准确率持续校准(详见 `confidence-system`)。低置信度的提取应在判定阶段被特别对待,例如触发人工复核或交叉比对,而不是直接当作高置信度结果使用。置信度本身不是装饰字段,而是判定阶段做风险加权的依据;如果整套流程对置信度毫无消费,那这个字段就形同虚设,反而会让团队对系统输出产生虚假的"完整感"。
108
108
 
109
- ## Prompt Design: Ask For What You Want
109
+ ## Prompt 设计:要什么,说什么
110
110
 
111
- Design prompts for what you want, not against what you don't want. "Don't include explanations" in a prompt is less reliable than stripping non-JSON text from the output in postprocessing. If you need to tell the LLM not to do something, use output filtering instead of prompt negation.
111
+ prompt 时要直接描述你想要的输出形态,而不是反复强调你不想要的内容。在 prompt 里写"不要包含解释"或"不要输出额外文本",远不如在后处理时从输出中剥离非 JSON 文本来得可靠——大模型在压力下经常会"为了帮助你"补充一些自以为有用的说明、致歉、或开场白,从而违反否定指令。如果确实必须告诉 LLM 不要做某事,那就把控制点放在后处理的输出过滤上,而不是 prompt 中的否定句。换言之:用确定性的后处理来兜底不确定的 LLM 行为,永远比单靠 prompt 措辞更稳。同理,"必须返回合法 JSON"也应当配套一段健壮的解析与修复逻辑,而不是天真地假设模型每次都能完美输出。
112
112
 
113
- ## Fitting Worker LLM Context
113
+ ## Worker LLM 上下文适配
114
114
 
115
- When designing extraction for worker LLM workflows:
115
+ worker LLM 工作流设计提取时,需要预先估算并约束上下文规模:
116
116
 
117
- 1. Calculate the prompt size: system prompt + instructions + examples + output format = N tokens.
118
- 2. Available context for document content = model's context window - N.
119
- 3. If the section exceeds available context, narrow further via tree processing.
120
- 4. Always leave room for the model's response.
121
- 5. Test with the actual model to verify the context fits — token counts from the coding agent may differ from the worker LLM's tokenizer.
117
+ 1. 估算 prompt 体量:系统 prompt + 指令 + 示例 + 输出格式 = N tokens
118
+ 2. 留给文档内容的可用上下文 = 模型上下文窗口 - N
119
+ 3. 若目标章节超出可用上下文,回到树处理进一步收窄,或将其切分为多次调用。
120
+ 4. 始终为模型的响应预留足够空间,否则可能在生成中途被截断,导致 JSON 不完整。
121
+ 5. 用真实使用的模型做端到端测试以验证上下文确实能装下——编码 agent 估算的 token 数可能与 worker LLM 自己的分词器结果不一致,尤其是在中文、表格与代码混排的场景下,差异可能达到数十个百分点,仅凭估算容易在生产环境上线后才发现窗口被打爆。
@@ -248,6 +248,15 @@ logs/qc/
248
248
 
249
249
  发布 release 后,把终端用户引导到 release 包内的仪表盘,不是工作区的那个。工作区仪表盘是你自己的开发者视图。
250
250
 
251
+ ## 实质性变更后必须重新发布
252
+
253
+ release 包是某一时刻 `workflows/` 和 `rule_skills/` 的快照。如果在 release 构建之后修改了任何 `workflows/<rule>/workflow_v*.py`、`rule_skills/<id>/SKILL.md` 或 `check.py`,已发布的产物不再反映你的实际工作。引擎的里程碑推导会标记 `releaseIsStale: true` 并列出有差异的文件。
254
+
255
+ 触发后应当:
256
+ - **实质性变更**(新增混合路径、修正判定逻辑、新增规则):重新运行 `release` 工具生成新的包。
257
+ - **仅美化编辑**(错别字、注释、格式化):在 release 目录写入 `.accept_stale_release` 表示确认 —— `touch output/releases/<slug>/.accept_stale_release`。
258
+ - **不要**在 release 已经过时的情况下宣告 finalization 完成。下游消费者(其他 agent、部署的核查系统)读的是 release 包内的 `parser_v*.py` / `workflows/`,不是工作区。
259
+
251
260
  ## 开发者用户参与
252
261
 
253
262
  质量监控不应该让开发者用户去读 JSON 文件。通过仪表盘技能生成可视化报告,开发者用户只需要关注:
@@ -28,6 +28,8 @@ rule-skills/
28
28
 
29
29
  Not every rule needs all of these. A simple threshold check might only need SKILL.md and a script. A complex semantic rule might need detailed references and many samples. Start minimal, add as needed during testing.
30
30
 
31
+ **文件名大小写很重要。** 必须使用大写 `SKILL.md`(与 `template/skills/` 中的 meta-skill 约定一致)。Linux 文件系统区分大小写;引擎的路径匹配、审计脚本、下游工具都假定为大写。不要写成 `skill.md`、`Skill.md` 或其他大小写变体。
32
+
31
33
  ## 颗粒度:默认 1 条规则 = 1 个技能目录
32
34
 
33
35
  默认**每条规则一个独立技能目录**。仅当同时满足以下两个条件时,才能把多条规则合并到同一个文件:
@@ -47,6 +49,25 @@ E2E #4 给出了代价:智能体写了一个 `unified_qc.py` 绕过它不信
47
49
 
48
50
  如果某些独立技能跑不通,正确的应对是定位并修复出问题的那几条,而不是合并所有技能。整个流水线(extraction → skill_testing → distillation → production_qc)的前提就是「一条规则 = 一个可独立验证的产物」。
49
51
 
52
+ ### 反模式:SKILL.md 是桩 或 check.py 是桩
53
+
54
+ 每个 rule_skill 目录都必须 **同时** 拥有有内容的 `SKILL.md` **和** 有内容的 `check.py`(或 check.py 通过 import 调用一个真正做事的 workflow)。任何一边是桩都破坏了契约。
55
+
56
+ **变体 1(v0.7.5 贷款 审计 § 9.1)**:桩 `SKILL.md`(19 行模板,`检查逻辑: N/A`)配上真实的 `check.py`(44-131 行正则方法论)。SKILL.md 本该是人类可读的方法论文档。读者扫一眼规则目录想了解"这条核查什么、为什么核查",结果什么都看不到。智能体把方法论塞进了 `check.py` 的注释里,引擎能跑,但产物的语义就丢了。
57
+
58
+ **变体 2(v0.7.5 资管 审计 § 3.4)**:有内容的 `SKILL.md`(真实方法论、PASS/FAIL 判定标准、法规交叉引用)配上桩 `check.py`(29 行脚手架,永远返回 `{"verdict": "NOT_APPLICABLE", "evidence": "Check requires worker LLM execution"}`)。真正的核查逻辑在 `workflows/<rule_id>/workflow.py` 里 —— 但 `check.py` 既没 import 也没调用。用户执行 `python rule_skills/R01-01/check.py document.txt` 任意输入都得到 `NOT_APPLICABLE`,结果是误导性的。
59
+
60
+ **变体 3(历史遗留 v0.7.0)**:桩 `check.py` 返回 `{"pass": null, "method": "stub"}`,SKILL.md 写得还行。方法论描述出来了,但没有可执行实现。
61
+
62
+ **契约**:
63
+ - ✓ DO:SKILL.md 描述「核查什么」「为什么核查」「什么时候触发」。要有内容 —— 通常 50-300 行,不是 19 行模板。
64
+ - ✓ DO:check.py 实现核查。**要么** 直接写有实质的逻辑,**要么** `from workflows.<rule_id>.workflow_v1 import verify` 然后委托给它。返回具体的判定。
65
+ - ✗ DON'T:SKILL.md 是桩、方法论塞在 check.py 注释里(变体 1)。
66
+ - ✗ DON'T:SKILL.md 有内容,但 check.py 返回 NOT_APPLICABLE 且不委托给 workflow(变体 2)。
67
+ - ✗ DON'T:check.py 返回 null verdict(变体 3,历史遗留)。
68
+
69
+ 未来的引擎里程碑检查(v0.8 P2-F)可能在 check.py 桩比例过高时拒绝阶段推进。现在就写得有内容更省事。
70
+
50
71
  ## Writing SKILL.md
51
72
 
52
73
  ### Frontmatter
@@ -102,6 +123,24 @@ Scripts should be self-contained Python files that can be imported or executed.
102
123
 
103
124
  Do not put LLM prompts in scripts. LLM interactions belong in the SKILL.md body or in the workflow (later phase).
104
125
 
126
+ ### 关键字匹配前先剥除审核者注解
127
+
128
+ 样本文档常带有审核者写的注解尾注(`预期命中点: ...`、`标注: ...`、`Expected: ...`),用来标注测试时的真实判定。如果你的 check.py 是用关键字/正则去匹配文档正文,这些注解会漏进匹配 —— 在违规样本上反而 false-positive PASS(规则在注解里"找到了"披露关键字,而不是在真实文档内容里)。
129
+
130
+ 规范的清理工具在 `workflows/common/utils.py`,引擎初始化时会自动写入工作区:
131
+
132
+ ```python
133
+ from workflows.common.utils import strip_annotations
134
+
135
+ def check(document_text):
136
+ text = strip_annotations(document_text)
137
+ # 真正的核查逻辑用 `text`,不要用原始的 document_text
138
+ ```
139
+
140
+ 已识别的前缀(中英文):预期命中点、预期结果、预期判定、预期验证、标注、审核标注、Expected、expected、EXPECTED、Annotation、annotation。如果你的项目用了别的标签,传 `extra_prefixes=("...", "...")`。
141
+
142
+ E2E #11 贷款 v0.8 审计:14 条规则里有 4 条独立运行 check.py 时在违规样本上 false-positive PASS,因为匹配到的是 `预期命中点: ...年化利率` 尾注而不是文档正文。v0.8.1 把这个工具作为模板文件随包发布,import 一行就能避开这个坑。
143
+
105
144
  ## Writing References
106
145
 
107
146
  `references/` holds content that the coding agent reads on demand: