@cyning/harness 2.5.0 → 2.6.0
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.
- package/CHANGELOG.md +20 -0
- package/docs/rethink/2026-07-mechanization-rate/03_coverage_matrix.md +1 -1
- package/docs/rethink/2026-07-mechanization-rate/04_next_steps.md +1 -1
- package/docs/spec/SPEC-task-lint-thinking-rounds_v1.md +144 -0
- package/harness/prompts/10-task-requirements.md +2 -0
- package/lib/cli.js +3 -1
- package/lib/task-lint.js +83 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.6.0] - 2026-07-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **task lint · 思考轮结构规则组(G4)**:条件触发(行首 `### R0` 或 `##/###` 标题含「思考轮」)后检查:
|
|
12
|
+
- **E8** R0–R5 槽位标题齐全(`^### R\d` 前缀宽容)
|
|
13
|
+
- **E9** 控制表字段 `actual_last_round` / `early_stop` / `residual_risks`
|
|
14
|
+
- **E10** `early_stop=yes` 时 `early_stop_reason` 非空
|
|
15
|
+
- **W4** 无思考轮节(SPEC 承载 / bugfix 合法豁免提示)
|
|
16
|
+
- **W5** 存在 `### R6+` 但缺 `round_extension_note`
|
|
17
|
+
- 槽内容 `(待填)` / `(跳过 · 见思考轮控制)` 合法;**不**查思考内容质量(20 帽职责)。
|
|
18
|
+
- SPEC:`docs/spec/SPEC-task-lint-thinking-rounds_v1.md`
|
|
19
|
+
|
|
20
|
+
### Notes
|
|
21
|
+
|
|
22
|
+
- 背景:机械化率审计 G4(rethink 矩阵 P1 · 第三波);与 G1 同命令、分开交付。
|
|
23
|
+
- minor · 无 verify 行为变更 · `npm test` 含既有回归全绿
|
|
24
|
+
- **待发布**:`@cyning/harness@2.6.0`(维护者 CLOSE 后 npm publish + tag)
|
|
25
|
+
|
|
7
26
|
## [2.5.0] - 2026-07-24
|
|
8
27
|
|
|
9
28
|
### Changed
|
|
@@ -18,6 +37,7 @@
|
|
|
18
37
|
- 背景:机械化率审计 G2(rethink 矩阵 P0 最后一块);22/20 帽自此脱离「全帽零机械」。
|
|
19
38
|
- dogfood:工作区 approved 任务全过(含版本后缀变体 ops_clarify · 恰好是 R1 审查抓出的案例)。
|
|
20
39
|
- minor · verify 行为变更(本版核心 · 见上)· `npm test` 118 全绿 · SPEC `docs/spec/SPEC-reviews-retention-gate_v1.md`
|
|
40
|
+
- **已发布**:`@cyning/harness@2.5.0`(npm `latest` · 2026-07-24)· tag `v2.5.0` 已推送
|
|
21
41
|
|
|
22
42
|
## [2.4.0] - 2026-07-24
|
|
23
43
|
|
|
@@ -37,7 +37,7 @@ description: 机械化率统计矩阵 + 缺口聚类 + 候选闸优先级排序
|
|
|
37
37
|
| ~~P0~~ ✅ | **G1 · task md 结构 lint** | 高(下游全部闸的输入假设) | 低(解析与 M5 共享) | **已落地 v2.3.0**:`harness task lint`(E1–E7/W1–W3)· 不接入 verify(dogfood 后另议) | 10 产出时 |
|
|
38
38
|
| ~~P0~~ ✅ | **G2 · reviews 留档闸** | 高(与 invoke 失守同构,且是 HG-AUDIT-R1 的签署依据) | 低(glob 命名模式) | **已落地 v2.5.0**:verify blocking(`missing R<n> review`)+ close 检查 6 · 豁免 `--allow-no-review` · 匹配两侧剥离版本后缀 | verify(30 前)· close(归档前) |
|
|
39
39
|
| ~~P1~~ ✅(task 部分) | **G3 · 文本纪律 grep 闸** | 中 | 极低(正则) | **已落地 v2.3.0**(E6 绝对路径);invoke 预写 approved grep 缓做(SPEC R2:误报不可控) | 同 G1 |
|
|
40
|
-
|
|
|
40
|
+
| ~~P1~~ ✅ | **G4 · 思考轮结构检查** | 中(阶段 C 纪律,漏槽=思考轮形同虚设) | 中(格式变体多,须宽容:只查槽位存在与控制表字段,不查内容质量) | **已落地 v2.6.0**:`task lint` 条件触发 E8–E10 / W4–W5(有节才查 · 形态 B/C 仅 W4) | 10 产出时 |
|
|
41
41
|
| **P2** | **G7 · 执行证据** | 高但难(「真跑过」本质要 runner 见证) | 高 | `harness run -- <验证命令>`:包装执行、留 exit code + 输出摘要到 `.cyning-harness/runs/`,40 回填引用 run id | 方向二状态机内再做 |
|
|
42
42
|
| **P3** | **G6 · git 行为层** | 中 | 高(需 hook/平台集成) | 暂留 prompt 层;远期 Agent 契约(方向三)的行为审计范畴 | 方向三 |
|
|
43
43
|
|
|
@@ -27,7 +27,7 @@ description: 结论与立项建议 · 缺口到 SPEC/task 的转化路径 + 与
|
|
|
27
27
|
- `close` 可选增第 6 项检查(归档时 R1 审查文应仍在)
|
|
28
28
|
- 注意与现有流程的兼容:`findReviewPath` 已被 `verify --json` 消费(handoff.review_path),本次是把它从「信息」升级为「闸」
|
|
29
29
|
|
|
30
|
-
### 第三波 · 思考轮结构检查(G4)·
|
|
30
|
+
### 第三波 · 思考轮结构检查(G4)· ✅ v2.6.0
|
|
31
31
|
|
|
32
32
|
- 并入 `task lint` 但作为独立规则组;宽容度设计需 dogfood 一轮(工作区 task 的槽位写法变体多)
|
|
33
33
|
- 只查结构(槽位存在、控制表字段),**不查**内容质量——质量判定永远留在 22 帽
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# SPEC:task lint 思考轮结构规则组(G4)(v1)
|
|
2
|
+
|
|
3
|
+
> **状态**:`signed`(维护者签收 2026-07-24 · 对话「签收,继续」)
|
|
4
|
+
> **track**:`feature`
|
|
5
|
+
> **关联图谱**:无(纯 Harness 工具链)
|
|
6
|
+
> **上游思考**:[`docs/rethink/2026-07-mechanization-rate/`](../rethink/2026-07-mechanization-rate/)(缺口 G4 · P1)
|
|
7
|
+
> **前置**:v2.3.0 `task lint`(G1+G3)· 本 SPEC 为其规则组扩展
|
|
8
|
+
> **下游**:00 已起草 task → 20-task-audit → HG-AUDIT-R1 → 30
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Harness 元信息
|
|
13
|
+
|
|
14
|
+
| 字段 | 值 |
|
|
15
|
+
|------|-----|
|
|
16
|
+
| **spec_slug** | `task-lint-thinking-rounds` |
|
|
17
|
+
| **test_strategy** | `required` |
|
|
18
|
+
| **test_strategy_note** | 条件触发三形态 + 每条 E/W 规则的 fail/pass fixture;`npm test` 全绿含回归 |
|
|
19
|
+
| **entry_invoke_10_spec** | `Projects/docs/harness/invokes/by-task/cyning-harness-task-lint-thinking-rounds/invoke_20260724_10_spec_task_lint_thinking_rounds.md` |
|
|
20
|
+
| **entry_invoke_00_draft** | 工作区 `docs/harness/prompts/PROMPT_00_draft_spec_or_task_v1_zh.md` |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. 背景与目标
|
|
25
|
+
|
|
26
|
+
rethink 02 D3:10 帽「预置 R0–R5 思考轮槽 + 思考轮控制表」是纯 Prompt 纪律(零机械)。v2.3.0 `task lint` 落地时本项被显式推迟(SPEC R1:写法变体多 · 宽容度需独立 dogfood)——本 SPEC 即第三波。
|
|
27
|
+
|
|
28
|
+
**变体实测(2026-07-24 · SPEC 设计依据)**:
|
|
29
|
+
|
|
30
|
+
| 形态 | 实例 | 占比(active 16) |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| **A · task 内嵌**(### R0–R5 + 控制表) | hat_chain_assessment · v0_2_d3_ide · ops_desk_kimi_code_spec_10_refine | ~2-3/16 |
|
|
33
|
+
| **B · SPEC 承载**(task 无槽位 · 链 SPEC) | 近三波 task(lint/reviews-gate 等)· 3 份 SPEC 均有完整结构 | ~2/16 |
|
|
34
|
+
| **C · 无思考轮**(bugfix 轨 / Issue≈SPEC) | hat_v2_split 等 | ~12/16 |
|
|
35
|
+
|
|
36
|
+
**目标**:`task lint` 新增思考轮规则组——**条件触发**(有思考轮节才查结构完整性),只查结构不查内容质量;形态 B/C 不挡(W 级提示)。
|
|
37
|
+
|
|
38
|
+
## 2. 范围
|
|
39
|
+
|
|
40
|
+
- **D1 · `lib/task-lint.js` 规则组扩展**:
|
|
41
|
+
- 触发条件:文件含思考轮节(标题含「思考轮」或存在 `### R0` 槽标题)
|
|
42
|
+
- **E 级**(触发后):E8 R0–R5 槽位标题齐全 · E9 控制表必填字段齐全(`actual_last_round` / `early_stop` / `residual_risks`)· E10 `early_stop=yes` 时 `early_stop_reason` 非空
|
|
43
|
+
- **W 级**:W4 无思考轮节(提示 · 注明 SPEC 承载/bugfix 轨合法豁免)· W5 存在 `### R6`+ 但 `round_extension_note` 缺失或为空
|
|
44
|
+
- 槽位内容为 `(待填)`/`(跳过 · 见思考轮控制)` **合法**(draft 期语义 · 同自检结论占位原则)
|
|
45
|
+
- **D2 · 测试**:三形态(A 完整 pass / A 缺槽或缺字段 fail / B·C 仅 W4)+ E10 逻辑用例 + W5 用例;`npm test` 全绿含 118 例回归
|
|
46
|
+
- **D3 · dogfood**:工作区 active + done tasks 全量 lint,三形态分布与规则命中落自检结论(只报告)
|
|
47
|
+
- **D4 · 文档**:`harness/prompts/10-task-requirements.md` 思考轮摘要节补「v2.6+ task lint 机械检查结构」;CHANGELOG + 版本 **v2.6.0**;rethink 03 G4 行 ❌→✅
|
|
48
|
+
|
|
49
|
+
## 3. 非范围
|
|
50
|
+
|
|
51
|
+
- 思考轮**内容质量**判定(是否「真思考」)—— 20 帽职责,永不在 lint
|
|
52
|
+
- SPEC 文件的 lint(E1 元信息字段不同 · 规则组设计为可复用,SPEC lint 下一轮)
|
|
53
|
+
- `verify` 接入 lint(维持 v2.3 裁定 · 独立命令)
|
|
54
|
+
- 强制所有 task 必须有思考轮(形态 B/C 合法 · 本闸不消灭变体)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 4. 验收标准
|
|
59
|
+
|
|
60
|
+
- [ ] 形态 A 完整(R0–R5 + 三字段 + early_stop 逻辑一致)→ 无 E · exit 0
|
|
61
|
+
- [ ] 形态 A 缺槽(如缺 `### R3`)→ E8 exit 2;缺控制表字段 → E9;`early_stop=yes` 无 reason → E10
|
|
62
|
+
- [ ] 形态 B/C(无思考轮节)→ 仅 W4 · exit 0
|
|
63
|
+
- [ ] `### R6` 存在且 `round_extension_note` 空 → W5 · exit 0
|
|
64
|
+
- [ ] 槽位 `(待填)`/`(跳过 · 见思考轮控制)` 不触发任何 E
|
|
65
|
+
- [ ] `npm test` 全绿(新增用例 + 118 例回归)
|
|
66
|
+
- [ ] dogfood 三形态分布落自检结论
|
|
67
|
+
- [ ] 10-task Prompt + CHANGELOG(v2.6.0);rethink G4 行 ❌→✅
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 5. failure_paths
|
|
72
|
+
|
|
73
|
+
| 触发条件 | 系统行为 | 可重试 |
|
|
74
|
+
|----------|----------|--------|
|
|
75
|
+
| 有思考轮节但结构不全 | exit 2 · 逐条列出(E8/E9/E10)· 不改文件 | 补齐后重跑 |
|
|
76
|
+
| 形态 B/C | W4 提示 · exit 0 | — |
|
|
77
|
+
| 槽标题变体(如 `### R3 · 边界`) | 槽匹配按 `^### R\d` 前缀(形式宽容)| 误报则 dogfood 期调整 |
|
|
78
|
+
| 既有 task 大量 W4 | 不影响 exit · dogfood 记录分布 | — |
|
|
79
|
+
| 业务仓未升级 2.6.0 | 旧 lint 无本规则组 · 行为不变 | upgrade |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 6. 依赖与引用
|
|
84
|
+
|
|
85
|
+
- 复用:`lib/task-lint.js`(规则组框架 · E/W 分级)· `lib/task-meta.js`(`extractSection` 行首锚定)
|
|
86
|
+
- 纪律原文:`harness/prompts/10-task-requirements.md`「OSS 阶段 C · 思考轮」节;工作区 `FRAGMENT_rethink_backfill_spec_v1_zh.md`(控制表字段定义)
|
|
87
|
+
- 变体实测:2026-07-24 扫描(§1 表)
|
|
88
|
+
- 缺口出处:rethink 02(D3)· 03(G4 行)· SPEC-task-lint-structure-gate R1(推迟裁定)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 7. 思考轮(10-spec 回填 · R0–R5)
|
|
93
|
+
|
|
94
|
+
### R0 · 读入与约束
|
|
95
|
+
|
|
96
|
+
读入:rethink 02 D3 / 03 G4 / 04 第三波定义;v2.3 SPEC 的推迟裁定;变体实测数据(§1);10-task 新帽思考轮摘要节(v2.4.0)。约束:只查结构不查内容是 04 定下的硬边界;不消灭形态 B/C(它们是 R1 审查已接受的合法轨)。
|
|
97
|
+
|
|
98
|
+
### R1 · 范围 / 非范围 / 场景
|
|
99
|
+
|
|
100
|
+
变体实测驱动设计:active 16 个中仅 ~3 个形态 A——**无条件强制槽位 = 误伤 80% 存量**,故核心设计是**条件触发**(有节才查)。场景:① 形态 A task 的 10 产出自查(主);② 22/20 审查时辅助核对控制表;③ 维护者批量体检。SPEC 文件的结构与本规则组同构,但 E1 元信息字段不同(spec_slug ≠ task_slug),SPEC lint 不在本波(非范围已列)。
|
|
101
|
+
|
|
102
|
+
### R2 · 方案对比
|
|
103
|
+
|
|
104
|
+
| 决策点 | 选项 | 裁定 | 理由 |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| 触发方式 | 全员强制 / 条件触发 / 只对阶段 C 标记 task | **条件触发(有节才查)** | 变体实测:强制 = 80% 误伤;「阶段 C 标记」本身无机械标记可锚 |
|
|
107
|
+
| 无思考轮节 | 沉默 / W4 提示 / E 级 | **W4** | 形态 B/C 合法但值得可见(提示里也写明豁免路径,教育新用户) |
|
|
108
|
+
| 槽内容 | 查非占位 / 不查 | **不查**(`(待填)`/`(跳过)` 合法) | draft 期语义与自检结论占位原则一致;填没填的思考质量是 20 帽职责 |
|
|
109
|
+
| early_stop 逻辑 | 查 / 不查 | **查(E10)** | `yes` 必须配 reason 是控制表自身的逻辑完整性,属结构非内容 |
|
|
110
|
+
| R6+ | 不查 / W5 / E | **W5** | 扩展理由缺失值得提示,但 R6 使用率低,E 级过重 |
|
|
111
|
+
| 槽标题匹配 | 精确 `### R0` | **`^### R\d` 前缀宽容**(允许 `### R3 · 边界` 后缀) | 实测槽标题带主题后缀是惯例 |
|
|
112
|
+
|
|
113
|
+
### R3 · 边界 / 失败语义 / 安全
|
|
114
|
+
|
|
115
|
+
- **E/W 分界原则**:触发后结构残缺 = E(有节就等于承诺了结构);未触发 = 最多 W(不承诺不查)。
|
|
116
|
+
- **触发条件假阳性**:文件正文提到「思考轮」三字但无槽位 → 触发条件要求「标题含思考轮 **或** 存在 `### R0` 槽标题」——纯文本提及(如本段)不触发,因为 `### R0` 必须行首锚定(extractSection 同款锚定)。「标题含思考轮」单独触发会不会误伤?一个写着「## 思考轮说明」但无槽的文件 → E8 fail。裁定:触发 = 存在 `^### R0` 槽标题 **或** `^#{2,3}.*思考轮` 标题;两者任一即按形态 A 要求。dogfood 验证误伤面(D3)。
|
|
117
|
+
- **安全**:纯只读;无 git 动作;不影响既有 E1–E7 行为(118 例回归兜底)。
|
|
118
|
+
|
|
119
|
+
### R4 · 验收 / 可测性 / test_strategy
|
|
120
|
+
|
|
121
|
+
`test_strategy: required`。fixture:形态 A 完整 / 缺槽 / 缺字段 / early_stop 无 reason / R6 无扩展理由 / 形态 B / 形态 C / 槽标题带后缀宽容 / 正文提及「思考轮」不触发。dogfood 落三形态分布与 W4 计数。
|
|
122
|
+
|
|
123
|
+
### R5 · SPEC 签收就绪 · 是否可交 00 出 task
|
|
124
|
+
|
|
125
|
+
SPEC 自足:条件触发模型有三形态实测支撑,E/W 边界清晰,宽容条款逐条在案。**可交 00 起草 task**。图谱:纯工具链。版本 v2.6.0(lint 规则组扩展 · 无 verify 行为变更)。落地后 rethink 矩阵 ❌ 8 → 7;P1 队列余 SPEC 审查闸与 verify 全量模式决策。
|
|
126
|
+
|
|
127
|
+
### 思考轮控制
|
|
128
|
+
|
|
129
|
+
| 字段 | 值 |
|
|
130
|
+
|------|-----|
|
|
131
|
+
| `actual_last_round` | `R5` |
|
|
132
|
+
| `early_stop` | `no` |
|
|
133
|
+
| `early_stop_reason` | — |
|
|
134
|
+
| `residual_risks` | ① 触发条件的假阳性(文件有「思考轮」标题但槽在别处)——dogfood D3 实测,必要时触发条件收紧为仅 `### R0`;② 历史形态 A 文件可能结构不全被 E 挡(存量仅 ~3 个 · 影响面小且可豁免豁免阀之外直接修复);③ SPEC lint 复用需求可能提前到来(规则组已按可复用设计) |
|
|
135
|
+
| `round_extension_note` | — |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 修订记录
|
|
140
|
+
|
|
141
|
+
| 日期 | 摘要 |
|
|
142
|
+
|------|------|
|
|
143
|
+
| 2026-07-24 | 10-spec R0–R5 同会话回填(维护者点菜「1」)· 基于 rethink G4 + 变体实测(形态 A/B/C 分布) |
|
|
144
|
+
| 2026-07-24 | 维护者签收(对话「签收,继续」)· 下游 00 起草 task |
|
|
@@ -40,12 +40,14 @@
|
|
|
40
40
|
- 10-task 草稿 **须预置 R0 + R1–R5** 五槽 + **思考轮控制** 表(见 `wizard/templates/TASK_TEMPLATE_upstream_pr_v1.md`)。
|
|
41
41
|
- **可提前停 / 可增 R6+**;须填 reason · residual_risks(无则 `none`)。
|
|
42
42
|
- **20-task-audit 审思考是否充分**;不通过 → **退回 10-task** 补轮后再审 R+1。
|
|
43
|
+
- **v2.6+ 机械检查结构**(条件触发):`task lint` 在存在 `### R0` 或思考轮标题时查 E8–E10(槽位/控制表/`early_stop` 逻辑);无节仅 W4(SPEC 承载 / bugfix 合法);不查内容质量。
|
|
43
44
|
|
|
44
45
|
## 修订记录
|
|
45
46
|
|
|
46
47
|
| 日期 | 摘要 |
|
|
47
48
|
|------|------|
|
|
48
49
|
| 2026-07-24 | V2 拆分收编:自 `10-requirements.md` 改名为 `10-task-requirements.md`(来源:工作区 `10-task-requirements.md` · 2026-06-12 v2) |
|
|
50
|
+
| 2026-07-24 | G4:思考轮摘要节补 v2.6+ `task lint` 条件触发结构检查 |
|
|
49
51
|
|
|
50
52
|
## 给 Cursor
|
|
51
53
|
|
package/lib/cli.js
CHANGED
|
@@ -630,10 +630,12 @@ async function cmdTaskLint(args) {
|
|
|
630
630
|
if (args.includes('--help') || args.includes('-h')) {
|
|
631
631
|
console.log(`用法: npx @cyning/harness task lint --file PATH [--json]
|
|
632
632
|
|
|
633
|
-
task md 结构闸(G1)+ 文本规则包(G3)· 纯只读:
|
|
633
|
+
task md 结构闸(G1)+ 文本规则包(G3)+ 思考轮结构(G4)· 纯只读:
|
|
634
634
|
E 级(exit 2):E1 元信息/task_slug · E2 状态行 · E3 验收标准含勾选项
|
|
635
635
|
E4 失败路径节 · E5 自检结论节 · E6 绝对本机路径 · E7 slug 一致
|
|
636
|
+
E8–E10(条件触发:有 ### R0 或思考轮标题):槽位齐全 · 控制表字段 · early_stop 逻辑
|
|
636
637
|
W 级(仅 warn):W1 状态 token 词表外 · W2 缺人工闸节 · W3 自检结论占位
|
|
638
|
+
W4 无思考轮节(形态 B/C 豁免提示)· W5 R6+ 缺 round_extension_note
|
|
637
639
|
末行协议:LINT: PASS · <file> / LINT: FAIL · <file>
|
|
638
640
|
--json:{ok, errors[], warnings[], file, slug}(errors 元素 {rule, message, line?})
|
|
639
641
|
`);
|
package/lib/task-lint.js
CHANGED
|
@@ -17,6 +17,14 @@ import {
|
|
|
17
17
|
*/
|
|
18
18
|
const ABS_PATH_RE = /(\/(?:Users|home|root)\/[^\s/`\\]|[A-Za-z]:\\Users\\[^\s`\\])/;
|
|
19
19
|
const FAILURE_HEADING_RE = /^#{2,4}\s.*(失败路径|failure_paths)/i;
|
|
20
|
+
/** G4 触发:行首 ### R0(可带后缀) */
|
|
21
|
+
const R0_HEADING_RE = /^###\s+R0(\b|[^\d]|$)/m;
|
|
22
|
+
/** G4 触发(叠加):行首 ##/### 标题含「思考轮」 */
|
|
23
|
+
const THINK_HEADING_RE = /^#{2,3}\s+.*思考轮/m;
|
|
24
|
+
/** 槽位标题:### Rn(前缀宽容) */
|
|
25
|
+
const RN_HEADING_RE = /^###\s+R(\d+)\b/gm;
|
|
26
|
+
/** 控制表字段行:| `field` | / | **field** | / | field | */
|
|
27
|
+
const CTRL_FIELD_RE = /^\|\s*`?\*{0,2}([a-z_]+)\*{0,2}`?\s*\|\s*(.*?)\s*\|/i;
|
|
20
28
|
|
|
21
29
|
function err(rule, message, line) {
|
|
22
30
|
return line ? { rule, message, line } : { rule, message };
|
|
@@ -25,8 +33,79 @@ function warn(rule, message, line) {
|
|
|
25
33
|
return line ? { rule, message, line } : { rule, message };
|
|
26
34
|
}
|
|
27
35
|
|
|
36
|
+
function parseControlFields(lines) {
|
|
37
|
+
const fields = {};
|
|
38
|
+
for (const l of lines) {
|
|
39
|
+
const m = l.match(CTRL_FIELD_RE);
|
|
40
|
+
if (!m) continue;
|
|
41
|
+
const key = m[1].toLowerCase();
|
|
42
|
+
let val = m[2].trim();
|
|
43
|
+
if (val.startsWith('`') && val.endsWith('`')) val = val.slice(1, -1).trim();
|
|
44
|
+
fields[key] = val;
|
|
45
|
+
}
|
|
46
|
+
return fields;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isEmptyCtrlValue(val) {
|
|
50
|
+
if (val == null) return true;
|
|
51
|
+
const v = String(val).trim();
|
|
52
|
+
return v === '' || v === '—' || v === '-' || v === '–';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* G4 · 思考轮结构规则组(条件触发)。
|
|
57
|
+
* 触发优先:存在 ### R0;叠加:行首 ##/### 含「思考轮」。
|
|
58
|
+
* 正文提及「思考轮」不触发。
|
|
59
|
+
*/
|
|
60
|
+
function lintThinkingRounds(content, lines, errors, warnings) {
|
|
61
|
+
const hasR0 = R0_HEADING_RE.test(content);
|
|
62
|
+
const hasThinkHeading = THINK_HEADING_RE.test(content);
|
|
63
|
+
const triggered = hasR0 || hasThinkHeading;
|
|
64
|
+
|
|
65
|
+
if (!triggered) {
|
|
66
|
+
warnings.push(
|
|
67
|
+
warn('W4', '无思考轮节(SPEC 承载 / bugfix 轨合法豁免 · 有节则查 R0–R5 与控制表)'),
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// E8 · R0–R5 槽位齐全
|
|
73
|
+
const found = new Set();
|
|
74
|
+
const rnRe = new RegExp(RN_HEADING_RE.source, 'gm');
|
|
75
|
+
let m;
|
|
76
|
+
while ((m = rnRe.exec(content)) !== null) {
|
|
77
|
+
found.add(Number(m[1]));
|
|
78
|
+
}
|
|
79
|
+
const missing = [];
|
|
80
|
+
for (let i = 0; i <= 5; i += 1) {
|
|
81
|
+
if (!found.has(i)) missing.push(`R${i}`);
|
|
82
|
+
}
|
|
83
|
+
if (missing.length) {
|
|
84
|
+
errors.push(err('E8', `思考轮槽位不全,缺:${missing.join(', ')}`));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// E9 / E10 · 控制表字段
|
|
88
|
+
const fields = parseControlFields(lines);
|
|
89
|
+
const required = ['actual_last_round', 'early_stop', 'residual_risks'];
|
|
90
|
+
const missFields = required.filter((k) => !(k in fields));
|
|
91
|
+
if (missFields.length) {
|
|
92
|
+
errors.push(err('E9', `思考轮控制表缺字段:${missFields.join(', ')}`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const early = (fields.early_stop || '').toLowerCase();
|
|
96
|
+
if (early === 'yes' && isEmptyCtrlValue(fields.early_stop_reason)) {
|
|
97
|
+
errors.push(err('E10', 'early_stop=yes 时 early_stop_reason 须非空'));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// W5 · R6+ 须有 round_extension_note
|
|
101
|
+
const hasR6Plus = [...found].some((n) => n >= 6);
|
|
102
|
+
if (hasR6Plus && isEmptyCtrlValue(fields.round_extension_note)) {
|
|
103
|
+
warnings.push(warn('W5', '存在 ### R6+ 但 round_extension_note 缺失或为空'));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
28
107
|
/**
|
|
29
|
-
* task lint · task md 结构闸(G1)+ 文本规则包(G3)。
|
|
108
|
+
* task lint · task md 结构闸(G1)+ 文本规则包(G3)+ 思考轮结构(G4)。
|
|
30
109
|
* 纯只读;E 级 → ok:false(CLI exit 2),W 级仅提醒。
|
|
31
110
|
*/
|
|
32
111
|
export function lintTaskFile(filePath, options = {}) {
|
|
@@ -114,6 +193,9 @@ export function lintTaskFile(filePath, options = {}) {
|
|
|
114
193
|
warnings.push(warn('W2', '缺 ### 人工闸 节(轻量 task 可忽略本提醒)'));
|
|
115
194
|
}
|
|
116
195
|
|
|
196
|
+
// G4 · 思考轮结构(条件触发)
|
|
197
|
+
lintThinkingRounds(content, lines, errors, warnings);
|
|
198
|
+
|
|
117
199
|
return {
|
|
118
200
|
ok: errors.length === 0,
|
|
119
201
|
errors,
|