@cyning/harness 2.10.0 → 2.11.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 CHANGED
@@ -4,6 +4,22 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.11.0] - 2026-07-25
8
+
9
+ ### Added
10
+
11
+ - **`discipline show [--json]`(Post-2.10 Epic E)**:只读展示 `harness/discipline-coverage.yaml`(镜像 `lifecycle show`)。**无** `audit --discipline` UI。
12
+
13
+ ### Changed
14
+
15
+ - **`lifecycle dry-run` 守卫扩面(Post-2.10 Epic A)**:`--task` + `to_30` 增接 `HG-TASK-DRAFT` · `audit_D5` · `task_lint`(与既有 `HG-AUDIT-R1` / `reviews_retention`)。`task_lint` 仍为 yaml **warn**;`--allow-lint-fail` 可将 fail 豁免为 warn。`close_*` 仍 `unevaluated`。**无** `--apply` / G7 / N2-C。
16
+
17
+ ### Notes
18
+
19
+ - SPEC:`docs/spec/SPEC-lifecycle-guard-expand_v1.md` · `docs/spec/SPEC-discipline-show_v1.md`
20
+ - minor · `lifecycle show` / verify 硬闸语义不变
21
+ - `discipline-coverage.yaml` `as_of_package_version` → **2.11.0**
22
+
7
23
  ## [2.10.0] - 2026-07-25
8
24
 
9
25
  ### Added
@@ -19,8 +35,8 @@
19
35
  ### Notes
20
36
 
21
37
  - SPEC:`docs/spec/SPEC-lifecycle-engine-min_v1.md` · `docs/spec/SPEC-discipline-coverage-yaml_v1.md`
22
- - Epic 统一发版窗 · 维护者 publish 前复检
23
38
  - minor · `lifecycle show` 行为不变
39
+ - **已发布**:`@cyning/harness@2.10.0`(npm `latest` · 2026-07-25)· tag `v2.10.0` 已推送
24
40
 
25
41
  ## [2.9.0] - 2026-07-25
26
42
 
@@ -63,11 +63,16 @@ npx @cyning/harness verify --spec docs/spec/SPEC-xxx_v1.md \
63
63
  npx @cyning/harness lifecycle show
64
64
  npx @cyning/harness lifecycle show --json
65
65
  # 转移资格 dry-run(v2.10+ · 旁路报告 · 不替代 verify)
66
+ # v2.11+ to_30 已接线:HG-* · reviews · audit_D5 · task_lint(close_* 仍可 unevaluated)
66
67
  npx @cyning/harness lifecycle dry-run --transition to_30 --from draft \
67
68
  --task docs/tasks/active/task_xxx.md
68
69
  # 无 --task:仅结构 + 守卫清单 unevaluated
69
70
  npx @cyning/harness lifecycle dry-run --transition to_30 --from draft
70
71
 
72
+ # 机械化率资产只读(v2.11+ · SoT=discipline-coverage.yaml)
73
+ npx @cyning/harness discipline show
74
+ npx @cyning/harness discipline show --json
75
+
71
76
  # 仅人工闸
72
77
  npx @cyning/harness gate-check --target /path/to/your-repo
73
78
  npx @cyning/harness gate-check --graph --target /path/to/your-repo
@@ -90,6 +95,7 @@ npx @cyning/harness sync index --target /path/to/your-repo
90
95
  | **lint** | task 结构(仅 `--task`) | v2.7+ E 级 → `WARN: task lint`(不改 exit / `may_start_30`) |
91
96
 
92
97
  生命周期真值:[`harness/lifecycle.yaml`](../harness/lifecycle.yaml)(`lifecycle show` 只读 · `lifecycle dry-run` 资格判定 v2.10+)。
98
+ 机械化率资产:[`harness/discipline-coverage.yaml`](../harness/discipline-coverage.yaml)(`discipline show` 只读 · v2.11+)。
93
99
 
94
100
  机械化率覆盖资产(Starter):[`harness/discipline-coverage.yaml`](../harness/discipline-coverage.yaml)(SoT · 随版本改 statements/gaps;**无** audit UI)。
95
101
 
@@ -133,6 +133,7 @@ npx @cyning/harness verify --target . \
133
133
  # 只读生命周期登记(方向二 · harness/lifecycle.yaml · 登记真值)
134
134
  npx @cyning/harness lifecycle show [--json]
135
135
  # 转移资格 dry-run(v2.10+ · 引擎消费 yaml · 旁路报告 · 非 runner / 非 G7)
136
+ # v2.11+ to_30 已接线 HG-* / reviews / audit_D5 / task_lint(close_* 仍可 unevaluated)
136
137
  npx @cyning/harness lifecycle dry-run --transition to_30 --from draft \
137
138
  [--task docs/tasks/active/task_xxx.md] [--json] [--allow-no-review]
138
139
 
@@ -189,7 +190,7 @@ Schema:[`schema/verify_result.v1.schema.json`](../schema/verify_result.v1.sche
189
190
  | `npx @cyning/harness verify` | 全量:双路径 + reviews(v2.9+);`--task`:30 前聚合;`--spec`:SPEC→00(v2.8+ · 互斥) |
190
191
  | `npx @cyning/harness lifecycle show` | 只读展示 `harness/lifecycle.yaml`(登记 · v2.7+) |
191
192
  | `npx @cyning/harness lifecycle dry-run` | 转移资格判定(引擎消费 yaml · v2.10+ · 旁路 · 非 G7) |
192
- | 机械化率资产 | 包内 `harness/discipline-coverage.yaml`(SoT · v2.10+ · audit UI) |
193
+ | `npx @cyning/harness discipline show` | 只读展示 `harness/discipline-coverage.yaml`(v2.11+ · audit UI) |
193
194
  | `npx @cyning/harness gate-check` | 仅人工闸(`--graph` / `--json`) |
194
195
  | `npx @cyning/harness audit` | ICVO 机械审计(D3/D5/S5) |
195
196
  | `npx @cyning/harness sync index` | 生成 `.cyning-harness/invoke_index.json` |
@@ -0,0 +1,89 @@
1
+ # SPEC:discipline show CLI(Post-2.10 Epic E)(v1)
2
+
3
+ > **状态**:`signed`(维护者签收 2026-07-25 · 对话「签收 A+E」)
4
+ > **track**:`feature`
5
+ > **上游**:Epic [`EPIC_post_210_menu_serial_a_e_j_v1_zh.md`](../../../docs/harness/guides/EPIC_post_210_menu_serial_a_e_j_v1_zh.md) · RETRO 候选 **E** · T3 SPEC [`SPEC-discipline-coverage-yaml_v1.md`](./SPEC-discipline-coverage-yaml_v1.md)(资产已落地 · 本波补发现性)
6
+ > **前置**:`@cyning/harness@2.10.0` · Epic **A CLOSE** 后方可进本棒 30(串行)
7
+ > **下游**:人签 → 00 draft task(可与 A 签收同批起草,**30 仍串行**)→ … → 30
8
+ > **目标版本**:与 A 统一 **`2.11.0`**
9
+
10
+ ---
11
+
12
+ ## Harness 元信息
13
+
14
+ | 字段 | 值 |
15
+ |------|-----|
16
+ | **spec_slug** | `discipline-show` |
17
+ | **invoke_slug** | `cyning-harness-discipline-show` |
18
+ | **test_strategy** | `required` |
19
+ | **test_strategy_note** | show 人读/JSON · 非法 yaml exit · 与 loadDisciplineCoverage 同源;lifecycle show 回归 |
20
+ | **Open Folder(实现)** | `cyning-harness/` |
21
+ | **epic_serial** | E(J → A → **本棒**) |
22
+
23
+ ---
24
+
25
+ ## 1. 背景与目标
26
+
27
+ T3 已落盘 `harness/discipline-coverage.yaml` + schema + `npm test`,但 **无 CLI**,发现性弱(T3 residual)。
28
+
29
+ **一句话目标**:提供 **`discipline show [--json]`**,镜像 `lifecycle show` 的只读体验,不引入 `audit --discipline` 大 UI。
30
+
31
+ ---
32
+
33
+ ## 2. 范围
34
+
35
+ ### D1 · CLI
36
+
37
+ - `npx @cyning/harness discipline show [--json]`
38
+ - 人读:摘要 `version` · `as_of_package_version` · `scope` · statements 计数按 status · gaps 计数按 status;可选短表(id/status/summary 截断)
39
+ - `--json`:输出 `loadDisciplineCoverage` 校验后的数据对象(或稳定包装 `{ ok, data }`——30 选一并写进测试;**推荐直接 dump data** 对齐 lifecycle show)
40
+ - 非法 / 缺失 yaml → exit **1**(与 lifecycle 风格一致)
41
+
42
+ ### D2 · 库
43
+
44
+ - 扩展 `lib/discipline-coverage.js`:`formatDisciplineShow(data)`(或等价)
45
+ - 复用既有 `loadDisciplineCoverage` / `validateDisciplineCoverage`;**不**改 schema 必填
46
+
47
+ ### D3 · 文档 / 测试 / 版本
48
+
49
+ - help / USER_GUIDE / ONBOARDING 挂点;CHANGELOG **2.11.0**
50
+ - 单测:包内 yaml show 成功;损坏 fixture exit ≠0
51
+
52
+ ---
53
+
54
+ ## 3. 非范围
55
+
56
+ - `audit --discipline` 交互视图 / 过滤 UI / HTML
57
+ - 全量人工重盘周 / 改 statements 真值内容(除非 show 发现明显自相矛盾且 A 波已改——默认 **不**改矩阵正文)
58
+ - A 的守卫扩面(不得同未 CLOSE 的 A 抢 PR;本棒 30 在 A CLOSE 后)
59
+ - apply / G7 / N2-C
60
+
61
+ ---
62
+
63
+ ## 4. 验收清单
64
+
65
+ - [ ] `discipline show` 与 `discipline show --json` 对包内 yaml 成功
66
+ - [ ] 人读含 version / as_of / 计数;JSON 可被 `JSON.parse`
67
+ - [ ] help 列出 `discipline show`
68
+ - [ ] `npm test` 全绿 · lifecycle show 不回归
69
+ - [ ] 文档一句说明 SoT 仍为 yaml,show 只读
70
+
71
+ ---
72
+
73
+ ## 5. 思考轮控制表(摘要)
74
+
75
+ | 字段 | 值 |
76
+ | --- | --- |
77
+ | `actual_last_round` | R1 |
78
+ | `early_stop` | yes |
79
+ | `early_stop_reason` | 与 lifecycle show 同构;T3 已预留「下波 mirror」 |
80
+ | `residual_risks` | ① 人读表格过长需截断;② 与 audit 子命令命名空间未来冲突——本波用顶级 `discipline`,不做 audit 子命令 |
81
+
82
+ ---
83
+
84
+ ## 8. 下一棒 Prompt(人签后 · A CLOSE 后 30)
85
+
86
+ ```text
87
+ 【30】cyning-harness-discipline-show · 实现 discipline show [--json]
88
+ 约束:只读;无 audit UI;A 已 CLOSE;目标进 2.11.0 CHANGELOG
89
+ ```
@@ -0,0 +1,100 @@
1
+ # SPEC:lifecycle dry-run 守卫扩面(Post-2.10 Epic A)(v1)
2
+
3
+ > **状态**:`signed`(维护者签收 2026-07-25 · 对话「签收 A+E」)
4
+ > **track**:`feature`
5
+ > **上游**:Epic [`EPIC_post_210_menu_serial_a_e_j_v1_zh.md`](../../../docs/harness/guides/EPIC_post_210_menu_serial_a_e_j_v1_zh.md) · RETRO [`RETRO_post_210_next_menu_v1_zh.md`](../../../docs/harness/guides/RETRO_post_210_next_menu_v1_zh.md) 候选 **A**
6
+ > **前置**:`@cyning/harness@2.10.0`(dry-run 骨架)· Epic **J CLOSE ✅**
7
+ > **下游**:人签 → 00 draft task → 20-task-audit → HG-AUDIT-R1 → 30
8
+ > **目标版本**:Epic 统一 **`2.11.0`**(与 E 同窗)
9
+
10
+ ---
11
+
12
+ ## Harness 元信息
13
+
14
+ | 字段 | 值 |
15
+ |------|-----|
16
+ | **spec_slug** | `lifecycle-guard-expand` |
17
+ | **invoke_slug** | `cyning-harness-lifecycle-guard-expand` |
18
+ | **test_strategy** | `required` |
19
+ | **test_strategy_note** | to_30 新 adapter 的 pass/fail/warn/unevaluated;既有 HG-AUDIT-R1 / reviews 回归;CLI dry-run exit;无 apply |
20
+ | **Open Folder(实现)** | `cyning-harness/` |
21
+ | **epic_serial** | A(J → **本棒** → E) |
22
+
23
+ ---
24
+
25
+ ## 1. 背景与目标
26
+
27
+ T2(v2.10)已落地 `lifecycle dry-run`,但 `to_30` 仅接线 **`HG-AUDIT-R1`** 与 **`reviews_retention`**;`HG-TASK-DRAFT` · `audit_D5` · `task_lint` 及 `to_00` / `close_*` 仍为 **`unevaluated`**,报告易被误读。
28
+
29
+ **一句话目标**:在**仍无 `--apply` / 仍非 runner / 仍非 G7** 的前提下,把 **`to_30` 剩余守卫**(及可选 `to_00`)接到薄 adapter,降低 unevaluated 面。
30
+
31
+ ---
32
+
33
+ ## 2. 范围
34
+
35
+ ### D1 · 必须接线(`--task` + `to_30`)
36
+
37
+ | guard id | 语义(对齐既有) | 说明 |
38
+ | --- | --- | --- |
39
+ | `HG-TASK-DRAFT` | human_gate 表 `approved` | 同 HG-AUDIT-R1 解析路径 |
40
+ | `audit_D5` | test_strategy vs 测试文件存在 | 复用 audit/verify 既有判定,禁止盲 spawn 全量 verify |
41
+ | `task_lint` | `lintTaskFile`;severity=**warn** | fail→报告 `warn` 或 `fail` 按 yaml severity;`--allow-lint-fail` 抑制为非 block(本波 lint 仍非 block) |
42
+
43
+ 既有 `HG-AUDIT-R1` / `reviews_retention` **行为不得回归**。
44
+
45
+ ### D2 · 可选同波(若成本低)
46
+
47
+ - `to_00` · `spec_reviews_retention`(复用 `findSpecReview` / verify `--spec` 语义)
48
+ - 若 30 评估成本高 → 记 residual,**不**阻塞 CLOSE
49
+
50
+ ### D3 · 仍允许 unevaluated
51
+
52
+ - 全部 `close_*` 守卫(本波不扩 close 转移,除非顺手且单测充分)
53
+ - 无 `--task` 时:除结构外全部 unevaluated(语义同 T2)
54
+
55
+ ### D4 · 文档 / 测试 / 版本
56
+
57
+ - CHANGELOG **2.11.0** 条目;USER_GUIDE / ONBOARDING 一句:扩面守卫列表
58
+ - 单测覆盖新 adapter 三态 + unevaluated 计数下降(相对 T2 fixture)
59
+ - **无** schema 必填扩张(除非缺字段阻塞)
60
+
61
+ ---
62
+
63
+ ## 3. 非范围
64
+
65
+ - `--apply` / 写回 task status / 事件溯源(候选 B)
66
+ - G7 / `harness run` / 完整 runner
67
+ - N2-C · lint severity 升 **block**(候选 D;J 已测 FAIL≈93%)
68
+ - 改变 `verify` / `close` 硬闸语义(dry-run 仍旁路)
69
+ - E · `discipline show`(下一棒)
70
+
71
+ ---
72
+
73
+ ## 4. 验收清单
74
+
75
+ - [ ] `to_30` + fixture:`HG-TASK-DRAFT` · `audit_D5` · `task_lint` 均出现非 `unevaluated` 的 `pass|fail|warn`
76
+ - [ ] 既有两 adapter 回归绿
77
+ - [ ] `--allow-lint-fail` 对 `task_lint` 行为可测
78
+ - [ ] 无 `--task`:unevaluated 语义不变
79
+ - [ ] `npm test` 全绿 · 文档列出已接线守卫
80
+ - [ ] **无** `--apply` 旗
81
+
82
+ ---
83
+
84
+ ## 5. 思考轮控制表(摘要)
85
+
86
+ | 字段 | 值 |
87
+ | --- | --- |
88
+ | `actual_last_round` | R2 |
89
+ | `early_stop` | yes |
90
+ | `early_stop_reason` | 扩面集合由 yaml to_30 未接线项冻结;与 T2 SPEC 方案 B 同构,争议面小 |
91
+ | `residual_risks` | ① D5 与 verify 路径细微漂移;② close_* 仍 unevaluated 须文档标明;③ 与 E 同窗发版叙述勿漏 |
92
+
93
+ ---
94
+
95
+ ## 8. 下一棒 Prompt(人签后)
96
+
97
+ ```text
98
+ 【00】draft task · slug cyning-harness-lifecycle-guard-expand · Open Folder cyning-harness/
99
+ 约束:本 SPEC D1 必须接线;无 apply;无 N2-C;E 不得同 PR 抢做
100
+ ```
@@ -6,7 +6,7 @@
6
6
  # 禁止:把本文件当「每周全量重盘」流程;不做 audit --discipline UI(本波)
7
7
 
8
8
  version: "1"
9
- as_of_package_version: "2.10.0"
9
+ as_of_package_version: "2.11.0"
10
10
  scope: "Starter · harness/prompts (10/22/30/40 + FRAGMENT)+ TEMPLATE_invoke"
11
11
  source_audit: "rethink/2026-07-mechanization-rate · 02 转录 + 03 聚合 · 状态已按 G1–G4/N1–N4 刷新(非第二轮通读盘点)"
12
12
 
@@ -2,6 +2,8 @@
2
2
  #
3
3
  # 登记真值:状态 / 转移 / 守卫。yaml 本身不是引擎。
4
4
  # 由 `lifecycle dry-run` 引擎消费(v2.10+ · 资格判定旁路报告 · 不写盘)。
5
+ # v2.11+ to_30 已接线:HG-AUDIT-R1 · HG-TASK-DRAFT · reviews_retention · audit_D5 · task_lint
6
+ # (close_* / 可选 to_00 仍可 unevaluated)
5
7
  # 只读展示:npx @cyning/harness lifecycle show [--json]
6
8
  # Schema:schema/lifecycle.v1.schema.json
7
9
 
package/lib/audit.js CHANGED
@@ -45,7 +45,11 @@ function runGateCheck(target, taskFile) {
45
45
  };
46
46
  }
47
47
 
48
- function runTestCheck(target, taskFile) {
48
+ /**
49
+ * D5 · test_strategy vs 测试/CI 制品(供 audit / lifecycle dry-run 复用)。
50
+ * @returns {{ ok: boolean, skipped?: boolean, reason: string }}
51
+ */
52
+ export function runTestCheck(target, taskFile) {
49
53
  // 未指定 task 文件时,D5 跳过(在 active task 上跑 gate-check 已覆盖 D3)
50
54
  if (!taskFile) {
51
55
  return { ok: true, skipped: true, reason: '未指定 --task,跳过 D5' };
package/lib/cli.js CHANGED
@@ -43,6 +43,7 @@ function usage(version = 'unknown') {
43
43
  npx @cyning/harness gate-check [--target PATH] [--task FILE] [--graph] [--json]
44
44
  npx @cyning/harness verify [--target PATH] [--task FILE | --spec FILE] [--graph] [--json] [--agent-hint] [--workspace-root PATH]
45
45
  npx @cyning/harness lifecycle show [--json]
46
+ npx @cyning/harness discipline show [--json]
46
47
  npx @cyning/harness sync index [--target PATH]
47
48
  npx @cyning/harness task check --file PATH [--no-circular] [--registry DIR]...
48
49
  npx @cyning/harness task close --file PATH [--target PATH] [--yes] [--allow-unchecked]
@@ -63,7 +64,8 @@ function usage(version = 'unknown') {
63
64
  audit ICVO 机械审计:复用 gate-check · D5 测试声明检查 · S5 git-clean 提醒
64
65
  gate-check 调用 wizard/gate-check.sh(业务仓无需 clone 即可用)
65
66
  verify 30 前聚合(--task)或 SPEC→00 审查文闸(--spec · v2.8+)
66
- lifecycle 只读展示 harness/lifecycle.yaml(状态/转移/守卫 · v2.7+)
67
+ lifecycle 只读展示 harness/lifecycle.yaml(状态/转移/守卫 · v2.7+;dry-run v2.10+)
68
+ discipline 只读展示 harness/discipline-coverage.yaml(机械化率资产 · v2.11+)
67
69
  sync index 生成 .cyning-harness/invoke_index.json
68
70
  task check 校验 task.harness.v1.json sidecar · --no-circular 检测 depends_on 环
69
71
  task close 受闸归档:5 项机械校验(invoke/自检结论/勾选/slug/状态)后 mv active→done(v2.2+)
@@ -134,6 +136,10 @@ export async function runCli(argv) {
134
136
  await cmdLifecycle(rest);
135
137
  return;
136
138
  }
139
+ if (cmd === 'discipline') {
140
+ await cmdDiscipline(rest);
141
+ return;
142
+ }
137
143
  if (cmd === 'sync') {
138
144
  await cmdSync(rest);
139
145
  return;
@@ -599,6 +605,44 @@ dry-run · 转移资格判定(引擎消费 yaml · v2.10+ · 旁路报告 ·
599
605
  throw err;
600
606
  }
601
607
 
608
+ async function cmdDiscipline(args) {
609
+ const { loadDisciplineCoverage, formatDisciplineShow } = await import(
610
+ './discipline-coverage.js'
611
+ );
612
+ const [sub, ...rest] = args;
613
+ if (!sub || sub === '--help' || sub === '-h' || args.includes('--help') || args.includes('-h')) {
614
+ console.log(`用法:
615
+ npx @cyning/harness discipline show [--json]
616
+
617
+ show · 只读展示 harness/discipline-coverage.yaml(机械化率资产 · v2.11+ · 非 audit UI)
618
+ `);
619
+ return;
620
+ }
621
+
622
+ if (sub === 'show') {
623
+ const json = rest.includes('--json');
624
+ const unknown = rest.filter((a) => a !== '--json');
625
+ if (unknown.length > 0) {
626
+ const err = new Error(`discipline show 未知参数: ${unknown.join(' ')}`);
627
+ err.exitCode = 1;
628
+ throw err;
629
+ }
630
+ const { data } = loadDisciplineCoverage();
631
+ if (json) {
632
+ console.log(JSON.stringify(data, null, 2));
633
+ } else {
634
+ console.log(formatDisciplineShow(data));
635
+ }
636
+ return;
637
+ }
638
+
639
+ const err = new Error(
640
+ `discipline 子命令未知: ${sub ?? '(空)'}\n用法: discipline show [--json]`,
641
+ );
642
+ err.exitCode = 1;
643
+ throw err;
644
+ }
645
+
602
646
  async function cmdSync(args) {
603
647
  if (args.includes('--help') || args.includes('-h')) {
604
648
  console.log(`用法: npx @cyning/harness sync index [--target PATH]`);
@@ -94,3 +94,55 @@ export function loadDisciplineCoverage(options = {}) {
94
94
 
95
95
  return { data, filePath, harnessRoot };
96
96
  }
97
+
98
+ /**
99
+ * 人读摘要(镜像 lifecycle show · 只读)。
100
+ */
101
+ export function formatDisciplineShow(data) {
102
+ const byStatus = {};
103
+ for (const s of data.statements ?? []) {
104
+ byStatus[s.status] = (byStatus[s.status] ?? 0) + 1;
105
+ }
106
+ const gapBy = {};
107
+ for (const g of data.gaps ?? []) {
108
+ gapBy[g.status] = (gapBy[g.status] ?? 0) + 1;
109
+ }
110
+
111
+ const lines = [
112
+ `discipline-coverage v${data.version}`,
113
+ `as_of: ${data.as_of_package_version}`,
114
+ `scope: ${data.scope}`,
115
+ '',
116
+ `## statements (${data.statements?.length ?? 0})`,
117
+ ...Object.entries(byStatus)
118
+ .sort(([a], [b]) => a.localeCompare(b))
119
+ .map(([k, n]) => `- ${k}: ${n}`),
120
+ '',
121
+ `## gaps (${data.gaps?.length ?? 0})`,
122
+ ];
123
+ if ((data.gaps?.length ?? 0) === 0) {
124
+ lines.push('- (无)');
125
+ } else {
126
+ lines.push(
127
+ ...Object.entries(gapBy)
128
+ .sort(([a], [b]) => a.localeCompare(b))
129
+ .map(([k, n]) => `- ${k}: ${n}`),
130
+ );
131
+ }
132
+
133
+ lines.push('', '## sample statements(最多 12)');
134
+ for (const s of (data.statements ?? []).slice(0, 12)) {
135
+ const sum =
136
+ s.summary.length > 72 ? `${s.summary.slice(0, 69)}…` : s.summary;
137
+ lines.push(`- [${s.status}] ${s.id}: ${sum}`);
138
+ }
139
+ if ((data.statements?.length ?? 0) > 12) {
140
+ lines.push(`- … +${data.statements.length - 12} more`);
141
+ }
142
+
143
+ lines.push(
144
+ '',
145
+ '注: SoT = harness/discipline-coverage.yaml · show 只读 · 非 audit --discipline UI',
146
+ );
147
+ return lines.join('\n');
148
+ }
package/lib/lifecycle.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import yaml from 'js-yaml';
4
+ import { runTestCheck } from './audit.js';
4
5
  import { resolveHarnessRoot } from './paths.js';
5
6
  import { findReview, parseHumanGates } from './task-meta.js';
7
+ import { lintTaskFile } from './task-lint.js';
6
8
 
7
9
  const SEVERITIES = new Set(['block', 'warn']);
8
10
 
@@ -121,10 +123,13 @@ export function formatLifecycleShow(data) {
121
123
  return lines.join('\n').trimEnd();
122
124
  }
123
125
 
124
- /** 本波已接线的守卫(其余 unevaluated */
126
+ /** 已接线的守卫(未登记者 unevaluated;close_* 本波仍未接线) */
125
127
  const GUARD_ADAPTERS = {
126
- 'HG-AUDIT-R1': evaluateHgAuditR1,
128
+ 'HG-AUDIT-R1': evaluateHgGate('HG-AUDIT-R1'),
129
+ 'HG-TASK-DRAFT': evaluateHgGate('HG-TASK-DRAFT'),
127
130
  reviews_retention: evaluateReviewsRetention,
131
+ audit_D5: evaluateAuditD5,
132
+ task_lint: evaluateTaskLint,
128
133
  };
129
134
 
130
135
  function findRepoRootFromTask(absTask) {
@@ -144,19 +149,21 @@ function flagsAllow(flags, allowFlag) {
144
149
  return false;
145
150
  }
146
151
 
147
- function evaluateHgAuditR1({ taskPath }) {
148
- const content = fs.readFileSync(taskPath, 'utf8');
149
- const gates = parseHumanGates(content);
150
- const audit = gates.find((g) => g.id === 'HG-AUDIT-R1');
151
- if (!audit) {
152
- return { status: 'fail', detail: '闸表无 HG-AUDIT-R1 行' };
153
- }
154
- if (audit.status === 'approved') {
155
- return { status: 'pass', detail: 'HG-AUDIT-R1=approved' };
156
- }
157
- return {
158
- status: 'fail',
159
- detail: `HG-AUDIT-R1=${audit.status}(须 approved)`,
152
+ function evaluateHgGate(gateId) {
153
+ return ({ taskPath }) => {
154
+ const content = fs.readFileSync(taskPath, 'utf8');
155
+ const gates = parseHumanGates(content);
156
+ const row = gates.find((g) => g.id === gateId);
157
+ if (!row) {
158
+ return { status: 'fail', detail: `闸表无 ${gateId} 行` };
159
+ }
160
+ if (row.status === 'approved') {
161
+ return { status: 'pass', detail: `${gateId}=approved` };
162
+ }
163
+ return {
164
+ status: 'fail',
165
+ detail: `${gateId}=${row.status}(须 approved)`,
166
+ };
160
167
  };
161
168
  }
162
169
 
@@ -174,6 +181,32 @@ function evaluateReviewsRetention({ taskPath, target, flags }) {
174
181
  return { status: 'fail', detail: 'missing R<n> review' };
175
182
  }
176
183
 
184
+ function evaluateAuditD5({ taskPath, target }) {
185
+ const result = runTestCheck(target, taskPath);
186
+ if (result.ok) {
187
+ return {
188
+ status: 'pass',
189
+ detail: result.skipped
190
+ ? `D5 skipped · ${result.reason}`
191
+ : result.reason,
192
+ };
193
+ }
194
+ return { status: 'fail', detail: result.reason };
195
+ }
196
+
197
+ function evaluateTaskLint({ taskPath, target }) {
198
+ try {
199
+ const result = lintTaskFile(taskPath, { cwd: target });
200
+ if (result.ok) {
201
+ return { status: 'pass', detail: 'task lint PASS' };
202
+ }
203
+ const rules = (result.errors ?? []).map((e) => e.rule).join(',') || 'errors';
204
+ return { status: 'fail', detail: `task lint FAIL · ${rules}` };
205
+ } catch (err) {
206
+ return { status: 'fail', detail: `task lint 异常: ${err.message}` };
207
+ }
208
+ }
209
+
177
210
  /**
178
211
  * 转移 dry-run(引擎最小骨架 · v2.10+)。
179
212
  * 默认不写盘;无 --apply。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyning/harness",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "description": "cyning-harness discipline package · init / upgrade / check CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",