coding-agent-harness 1.0.1 → 1.0.2
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 +19 -0
- package/README.en-US.md +14 -0
- package/README.md +111 -86
- package/README.zh-CN.md +270 -0
- package/SKILL.md +116 -189
- package/docs-release/README.md +72 -5
- package/docs-release/architecture/overview.md +286 -28
- package/docs-release/architecture/overview.zh-CN.md +288 -0
- package/docs-release/assets/dashboard-overview-en.png +0 -0
- package/docs-release/assets/harness-architecture.svg +163 -0
- package/docs-release/assets/harness-workflow.svg +64 -0
- package/docs-release/guides/agent-installation.en-US.md +214 -0
- package/docs-release/guides/agent-installation.md +123 -26
- package/docs-release/guides/document-audience-and-surfaces.en-US.md +112 -0
- package/docs-release/guides/document-audience-and-surfaces.md +112 -0
- package/docs-release/guides/full-legacy-migration-subagent-strategy.md +334 -0
- package/docs-release/guides/full-legacy-migration-subagent-strategy.zh-CN.md +334 -0
- package/docs-release/guides/legacy-migration-agent-prompt.md +384 -0
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +361 -0
- package/docs-release/guides/migration-playbook.en-US.md +325 -0
- package/docs-release/guides/migration-playbook.md +329 -0
- package/docs-release/guides/parent-control-repository-pattern.en-US.md +252 -0
- package/docs-release/guides/parent-control-repository-pattern.md +252 -0
- package/docs-release/guides/repository-operating-models.en-US.md +196 -0
- package/docs-release/guides/repository-operating-models.md +196 -0
- package/docs-release/intl/README.md +15 -0
- package/docs-release/intl/de-DE.md +18 -0
- package/docs-release/intl/en-US.md +18 -0
- package/docs-release/intl/es-ES.md +18 -0
- package/docs-release/intl/fr-FR.md +18 -0
- package/docs-release/intl/ja-JP.md +18 -0
- package/docs-release/intl/ko-KR.md +18 -0
- package/docs-release/intl/zh-CN.md +18 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/brief.md +13 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/lesson_candidates.md +24 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +1 -1
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/task_plan.md +4 -2
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/{visual_roadmap.md → visual_map.md} +9 -1
- package/package.json +3 -1
- package/references/agents-md-pattern.md +3 -3
- package/references/docs-directory-standard.md +47 -3
- package/references/external-source-intake-standard.md +75 -0
- package/references/harness-ledger.md +5 -3
- package/references/legacy-12-phase-bootstrap.md +41 -0
- package/references/lessons-governance.md +23 -6
- package/references/planning-loop.md +41 -3
- package/references/project-onboarding-audit.md +10 -0
- package/references/repo-governance-standard.md +2 -0
- package/references/testing-standard.md +50 -0
- package/references/walkthrough-closeout.md +6 -5
- package/scripts/check-harness.mjs +76 -35
- package/scripts/harness.mjs +303 -12
- package/scripts/lib/capability-registry.mjs +533 -0
- package/scripts/lib/check-profiles.mjs +510 -0
- package/scripts/lib/core-shared.mjs +186 -0
- package/scripts/lib/dashboard-data.mjs +389 -0
- package/scripts/lib/dashboard-workbench.mjs +217 -0
- package/scripts/lib/dashboard-writer.mjs +93 -2
- package/scripts/lib/harness-core.mjs +10 -1318
- package/scripts/lib/lesson-maintenance.mjs +145 -0
- package/scripts/lib/markdown-utils.mjs +158 -0
- package/scripts/lib/migration-planner.mjs +478 -0
- package/scripts/lib/migration-support.mjs +312 -0
- package/scripts/lib/task-lifecycle.mjs +755 -0
- package/scripts/lib/task-scanner.mjs +682 -0
- package/scripts/smoke-dashboard.mjs +22 -0
- package/scripts/test-harness.mjs +926 -14
- package/templates/AGENTS.md.template +41 -30
- package/templates/architecture/Architecture-SSoT.md +21 -0
- package/templates/architecture/README.md +49 -0
- package/templates/architecture/critical-flows.md +22 -0
- package/templates/architecture/local-repo-context.md +20 -0
- package/templates/architecture/service-catalog.md +17 -0
- package/templates/architecture/services/service-template.md +31 -0
- package/templates/architecture/system-map.md +22 -0
- package/templates/dashboard/assets/app-src/00-state.js +41 -0
- package/templates/dashboard/assets/app-src/10-router.js +76 -0
- package/templates/dashboard/assets/app-src/20-overview.js +235 -0
- package/templates/dashboard/assets/app-src/30-tasks.js +563 -0
- package/templates/dashboard/assets/app-src/40-modules.js +58 -0
- package/templates/dashboard/assets/app-src/45-review.js +128 -0
- package/templates/dashboard/assets/app-src/50-migration.js +169 -0
- package/templates/dashboard/assets/app-src/60-shared.js +61 -0
- package/templates/dashboard/assets/app-src/90-bindings.js +382 -0
- package/templates/dashboard/assets/app.css +2575 -310
- package/templates/dashboard/assets/app.js +1498 -307
- package/templates/dashboard/assets/app.manifest.json +11 -0
- package/templates/dashboard/assets/i18n.js +429 -44
- package/templates/dashboard/assets/mermaid-renderer.js +58 -8
- package/templates/development/README.md +52 -0
- package/templates/development/codebase-map.md +11 -0
- package/templates/development/cross-repo-debugging.md +18 -0
- package/templates/development/external-context/service-template.md +33 -0
- package/templates/development/external-source-packs/README.md +24 -0
- package/templates/development/external-source-packs/digest-template.md +28 -0
- package/templates/development/local-setup.md +16 -0
- package/templates/development/stubs-and-mocks.md +11 -0
- package/templates/integrations/README.md +40 -0
- package/templates/integrations/api-contract.md +42 -0
- package/templates/integrations/event-contract.md +46 -0
- package/templates/integrations/third-party/vendor-template.md +42 -0
- package/templates/integrations/webhook-contract.md +41 -0
- package/templates/planning/brief.md +32 -0
- package/templates/planning/lesson_candidates.md +58 -0
- package/templates/planning/long-running-task-contract.md +7 -0
- package/templates/planning/module_brief.md +25 -0
- package/templates/planning/module_session_prompt.md +6 -0
- package/templates/planning/task_plan.md +7 -5
- package/templates/planning/{visual_roadmap.md → visual_map.md} +24 -2
- package/templates/reference/docs-library-standard.md +31 -0
- package/templates/reference/execution-workflow-standard.md +4 -2
- package/templates/reference/external-source-intake-standard.md +82 -0
- package/templates/reference/harness-ledger-standard.md +1 -0
- package/templates/reference/repo-governance-standard.md +6 -4
- package/templates/reference/walkthrough-standard.md +2 -1
- package/templates/walkthrough/walkthrough-template.md +2 -2
- package/templates-zh-CN/AGENTS.md.template +69 -70
- package/templates-zh-CN/architecture/Architecture-SSoT.md +21 -0
- package/templates-zh-CN/architecture/README.md +51 -0
- package/templates-zh-CN/architecture/critical-flows.md +24 -0
- package/templates-zh-CN/architecture/local-repo-context.md +20 -0
- package/templates-zh-CN/architecture/service-catalog.md +17 -0
- package/templates-zh-CN/architecture/services/service-template.md +31 -0
- package/templates-zh-CN/architecture/system-map.md +22 -0
- package/templates-zh-CN/development/README.md +54 -0
- package/templates-zh-CN/development/codebase-map.md +11 -0
- package/templates-zh-CN/development/cross-repo-debugging.md +18 -0
- package/templates-zh-CN/development/external-context/service-template.md +33 -0
- package/templates-zh-CN/development/external-source-packs/README.md +24 -0
- package/templates-zh-CN/development/external-source-packs/digest-template.md +28 -0
- package/templates-zh-CN/development/local-setup.md +16 -0
- package/templates-zh-CN/development/stubs-and-mocks.md +11 -0
- package/templates-zh-CN/integrations/README.md +42 -0
- package/templates-zh-CN/integrations/api-contract.md +42 -0
- package/templates-zh-CN/integrations/event-contract.md +46 -0
- package/templates-zh-CN/integrations/third-party/vendor-template.md +42 -0
- package/templates-zh-CN/integrations/webhook-contract.md +41 -0
- package/templates-zh-CN/planning/brief.md +32 -0
- package/templates-zh-CN/planning/lesson_candidates.md +58 -0
- package/templates-zh-CN/planning/long-running-task-contract.md +1 -1
- package/templates-zh-CN/planning/module_brief.md +25 -0
- package/templates-zh-CN/planning/module_plan.md +2 -2
- package/templates-zh-CN/planning/module_session_prompt.md +4 -3
- package/templates-zh-CN/planning/task_plan.md +10 -4
- package/templates-zh-CN/planning/{visual_roadmap.md → visual_map.md} +21 -2
- package/templates-zh-CN/reference/docs-library-standard.md +35 -0
- package/templates-zh-CN/reference/execution-workflow-standard.md +9 -2
- package/templates-zh-CN/reference/external-source-intake-standard.md +82 -0
- package/templates-zh-CN/reference/harness-ledger-standard.md +5 -2
- package/templates-zh-CN/reference/repo-governance-standard.md +2 -0
- package/templates-zh-CN/reference/walkthrough-standard.md +4 -4
- package/templates-zh-CN/walkthrough/Closeout-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +2 -2
- package/templates-zh-CN/dashboard/assets/app.css +0 -399
- package/templates-zh-CN/dashboard/assets/app.js +0 -435
- package/templates-zh-CN/dashboard/assets/i18n.js +0 -47
- package/templates-zh-CN/dashboard/assets/markdown-reader.js +0 -116
- package/templates-zh-CN/dashboard/assets/mermaid-renderer.js +0 -59
- package/templates-zh-CN/dashboard/index.html +0 -18
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Historical 12-Phase Bootstrap
|
|
2
|
+
|
|
3
|
+
This document preserves the legacy bootstrap sequence used before the v1.0 capability-based installer. It is reference material for migration only. Agents should not use this as the default install protocol for new projects.
|
|
4
|
+
|
|
5
|
+
## When To Read
|
|
6
|
+
|
|
7
|
+
- You are migrating a project that was created with the older 12-phase harness flow.
|
|
8
|
+
- You need to map older documents into v1.0 capabilities and task contracts.
|
|
9
|
+
- You need to understand why a legacy project has broad reference files, embedded roadmap sections, or single-line phase planning.
|
|
10
|
+
|
|
11
|
+
## Legacy Sequence
|
|
12
|
+
|
|
13
|
+
1. Project diagnosis: read `references/project-onboarding-audit.md` and produce a project diagnosis.
|
|
14
|
+
2. Solution confirmation: decide harness scale from the diagnosis.
|
|
15
|
+
3. Delivery operating model: classify solo, team, split-repo, program, stage-gate, or kanban delivery.
|
|
16
|
+
4. Optional module registration: identify independent modules, write scopes, module registry rows, and module plans.
|
|
17
|
+
5. Directory structure: create or adapt `docs/` according to the docs directory standard.
|
|
18
|
+
6. AGENTS.md and CLAUDE.md: generate the root agent entrypoint and Claude Code shim.
|
|
19
|
+
7. Reference standards: generate project-specific reference files under `docs/11-REFERENCE/`.
|
|
20
|
+
8. Repository governance and CI/CD: define PR policy, required checks, branch protection, CI, and worktree concurrency.
|
|
21
|
+
9. Planning loop: create task templates and task directories.
|
|
22
|
+
10. Long-running task protocol: add long-running task standard and contract template.
|
|
23
|
+
11. SSoT, lessons, harness ledger, regression, cadence, walkthrough, and closeout files.
|
|
24
|
+
12. Bootstrap summary: report created files, purpose, first tasks, next actions, and checker status.
|
|
25
|
+
|
|
26
|
+
## v1.0 Mapping
|
|
27
|
+
|
|
28
|
+
| Legacy Area | v1.0 Destination |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| AGENTS.md / CLAUDE.md | Preserve existing files; merge only missing routing and residuals. |
|
|
31
|
+
| Task directory with only `task_plan.md` | Add `brief.md`, `execution_strategy.md`, `visual_map.md`, `progress.md`, `findings.md`, and `review.md` only for active tasks. |
|
|
32
|
+
| Embedded roadmap in `task_plan.md` | Move active roadmap rows into standalone `visual_map.md`; leave historical tasks untouched unless they are reopened. |
|
|
33
|
+
| Single-line progress status | Normalize active tasks through `harness task-start`, `task-block`, `task-log`, and `task-complete`. |
|
|
34
|
+
| Broad reference bundle | Declare only capabilities that are actually adopted in `.harness-capabilities.json`. |
|
|
35
|
+
| Long-running task artifacts | Add or declare `long-running-task` only when active work needs continuous autonomous execution. |
|
|
36
|
+
| Informal module lists | Adopt `module-parallel` only after modules have owners, write scopes, dependency rules, and registry maintenance. |
|
|
37
|
+
| Historical review notes | Do not rewrite all old review files. Upgrade active release-blocking reviews to the v1 review schema first. |
|
|
38
|
+
|
|
39
|
+
## Migration Rule
|
|
40
|
+
|
|
41
|
+
Do not mechanically rewrite the whole project. Use `harness add-capability safe-adoption` to add the v1.0 compatibility layer, then use `harness migrate-plan --json` to produce a staged action list. Migrate active or reopened work first; leave closed historical tasks as legacy evidence unless strict gates require them.
|
|
@@ -43,28 +43,45 @@ docs/01-GOVERNANCE/
|
|
|
43
43
|
3. 有没有踩坑经验值得记录,避免下次重复?
|
|
44
44
|
4. 有没有架构层面的洞察,值得更新架构文档?
|
|
45
45
|
|
|
46
|
-
如果任何一条答案是"有"
|
|
46
|
+
如果任何一条答案是"有",先写入任务目录的 `lesson_candidates.md`,由人工 review 决定是否进入治理 promotion。
|
|
47
|
+
人工决定后只允许以下任务级状态:
|
|
48
|
+
|
|
49
|
+
- `no-candidate-accepted`:接受本轮没有可复用 lesson。
|
|
50
|
+
- `needs-promotion`:至少一个候选已排队进入治理沉淀。
|
|
51
|
+
- `promoted`:维护命令已经写入 Lessons SSoT 和详情文档。
|
|
52
|
+
- `rejected`:候选已带理由拒绝。
|
|
53
|
+
|
|
54
|
+
`needs-promotion` 不阻塞任务 closeout,但必须在 Closeout SSoT / Harness Ledger 中记录
|
|
55
|
+
`queued-promotion: LC-YYYYMMDD-NNN`,并由后续维护命令处理。`promoted` 或人工直接创建时记录
|
|
56
|
+
`checked-created: L-YYYY-MM-DD-NNN`。如果没有候选,记录 `checked-candidate: LC-...` 或
|
|
57
|
+
`checked-none: <reason>`,其中 `checked-none` 只用于旧任务兼容或没有 candidate 文件的历史收口。
|
|
58
|
+
|
|
59
|
+
promotion 执行“双写”:
|
|
47
60
|
|
|
48
61
|
1. 选择 `templates/lessons/` 下的对应模板,先创建详情文档。
|
|
49
62
|
2. 详情文档必须写清背景、现状问题、建议改动、影响范围和冲突声明。
|
|
50
63
|
3. 再在 Lessons SSoT 追加表行,`Detail Doc` 指向这篇详情文档。
|
|
51
|
-
4. 在 Closeout SSoT / Harness Ledger 中记录 `checked-created`,并引用 lesson ID。
|
|
64
|
+
4. 在 Closeout SSoT / Harness Ledger 中记录 `checked-created` 或 `queued-promotion`,并引用 lesson/candidate ID。
|
|
52
65
|
|
|
53
|
-
如果四个问题的答案全是"没有"
|
|
54
|
-
Harness Ledger 中记录
|
|
66
|
+
如果四个问题的答案全是"没有",也不能静默跳过。新任务必须在 `lesson_candidates.md` 中使用
|
|
67
|
+
`no-candidate-accepted` 并填写 No-Candidate Reason;旧任务可在 Closeout SSoT 和 Harness Ledger 中记录
|
|
68
|
+
`checked-none: <一句话原因>`。
|
|
55
69
|
|
|
56
70
|
## Closeout 判定
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
收口时只允许以下合格状态:
|
|
59
73
|
|
|
60
74
|
- `checked-created: L-YYYY-MM-DD-NNN`:发现可沉淀经验,已创建详情文档并更新 Lessons SSoT。
|
|
61
|
-
- `
|
|
75
|
+
- `queued-promotion: LC-YYYYMMDD-NNN`:人工确认候选值得沉淀,但交给维护命令后续提升。
|
|
76
|
+
- `checked-candidate: LC-YYYYMMDD-NNN`:人工已审查 candidate 文件,结论为无候选或全部拒绝。
|
|
77
|
+
- `checked-none: <reason>`:旧任务兼容状态,已完整检查且没有 candidate 文件。
|
|
62
78
|
|
|
63
79
|
以下状态不合格:
|
|
64
80
|
|
|
65
81
|
- 只写 Lessons SSoT 表行,没有详情文档。
|
|
66
82
|
- 只写详情文档,没有 Lessons SSoT 表行。
|
|
67
83
|
- 在 walkthrough 或 progress 中说“无 lessons”,但 Closeout SSoT / Harness Ledger 没有记录。
|
|
84
|
+
- 新任务跳过 `lesson_candidates.md`,只用 `checked-none` 代替 candidate 判定。
|
|
68
85
|
- 用 `n/a` 代替检查结果,除非任务是纯只读分析且没有 closed ledger row。
|
|
69
86
|
|
|
70
87
|
## 沉淀类型
|
|
@@ -6,11 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
## 任务目录结构
|
|
8
8
|
|
|
9
|
+
任务信息架构预算决定默认脚手架:
|
|
10
|
+
|
|
11
|
+
| Budget | 适用场景 | 默认文件 |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `simple` | 单 owner、无 subagent、L0/L1 证据、可跳过正式 review gate | `brief.md`, `task_plan.md`, `visual_map.md`, `progress.md` |
|
|
14
|
+
| `standard` | 常规功能、修复、文档任务,需要完整可追溯记录 | 完整任务文件 |
|
|
15
|
+
| `complex` | L2/L3 证据、subagent/reviewer、外部参考、生成产物或 optional indexes | 完整任务文件 + 按需 optional structure |
|
|
16
|
+
|
|
17
|
+
`trivial` 不进入 CLI:小到不值得建立任务目录的修改,可以直接执行并在 commit 或交付说明中写清楚原因。
|
|
18
|
+
|
|
9
19
|
```
|
|
10
20
|
docs/09-PLANNING/TASKS/<YYYY-MM-DD-任务名>/
|
|
11
21
|
├── task_plan.md ← 计划:目标、范围、步骤、验收标准
|
|
12
22
|
├── execution_strategy.md ← 执行策略:模式、subagent、冲突控制、验证深度、handoff
|
|
13
|
-
├──
|
|
23
|
+
├── visual_map.md ← 图表集合:阶段图、架构图、时序图、数据流、状态机、完成度、证据状态
|
|
14
24
|
├── findings.md ← 发现:执行过程中的研究发现和技术决策
|
|
15
25
|
├── progress.md ← 进度:每个阶段的状态更新和验证结果
|
|
16
26
|
├── review.md ← 对抗性审查报告(需要 reviewer / subagent / release review 时必填)
|
|
@@ -43,8 +53,9 @@ slices/<slice-id>/review.md
|
|
|
43
53
|
6. **长程任务必须补合同** — 如果任务需要连续执行、多轮审查或子代理 review,先补 `long-running-task-contract.md`
|
|
44
54
|
7. **任务收口必须回写 Harness Ledger** — 只在任务完成或上下文回写状态变化时记录,不记录每次 `progress.md` 更新
|
|
45
55
|
8. **复杂任务必须记录 `execution_strategy.md`** — 是否使用 subagent、reviewer、worktree、handoff 都写入独立文件。
|
|
46
|
-
9. **非平凡任务必须记录 `
|
|
56
|
+
9. **非平凡任务必须记录 `visual_map.md`** — 这是任务图表集合,不只是 roadmap;HTML dashboard 从独立文件的 phase table 计算完成度、阻塞和证据状态。
|
|
47
57
|
10. **路径必须带来源前缀** — 使用 `PUBLIC:`, `PRIVATE:`, `TARGET:`, `EXTERNAL:`, `URL:`,避免脆弱相对路径。
|
|
58
|
+
11. **已验证切片必须主动提交** — 每个有意义的工作切片通过对应检查后,agent 默认主动 commit;只有用户明确要求暂不提交、检查失败、或 dirty diff 归属未清时才延期,并把原因写入 progress / handoff。
|
|
48
59
|
|
|
49
60
|
## task_plan.md 模板
|
|
50
61
|
|
|
@@ -68,7 +79,7 @@ slices/<slice-id>/review.md
|
|
|
68
79
|
| Contract File | Required | Purpose |
|
|
69
80
|
| --- | --- | --- |
|
|
70
81
|
| `execution_strategy.md` | yes | Execution mode, subagent use, conflict control, evidence depth, handoff rules |
|
|
71
|
-
| `
|
|
82
|
+
| `visual_map.md` | yes | Mermaid maps, phase table, architecture/sequence/data-flow/state diagrams when useful, completion, evidence status, blocking risk |
|
|
72
83
|
|
|
73
84
|
## 步骤
|
|
74
85
|
1. [步骤1]
|
|
@@ -181,12 +192,39 @@ Evidence values use `type:path:summary`.
|
|
|
181
192
|
## 状态流转
|
|
182
193
|
|
|
183
194
|
```
|
|
195
|
+
simple:
|
|
184
196
|
未开始 → 进行中 → 已完成
|
|
185
197
|
↓
|
|
186
198
|
已阻塞 → 进行中
|
|
199
|
+
|
|
200
|
+
standard / complex:
|
|
201
|
+
未开始 → 进行中 → 审查中 → 已完成
|
|
202
|
+
↓
|
|
203
|
+
已阻塞 → 进行中
|
|
187
204
|
```
|
|
188
205
|
|
|
206
|
+
`task-review` 是 standard / complex 任务进入执行审查的唯一 CLI 路径。`task-complete`
|
|
207
|
+
对 standard / complex 是硬门禁:当前状态不是 `review` 时必须拒绝。`simple`
|
|
208
|
+
可以直接从 `in_progress` 完成。
|
|
209
|
+
|
|
189
210
|
每次状态变更时,必须同时更新 progress.md 和 Feature SSoT。
|
|
190
211
|
|
|
191
212
|
任务完成时,必须在 `docs/Harness-Ledger.md` 中记录本轮 task plan、SSoT、
|
|
192
213
|
walkthrough、Lessons 检查等上下文回写结果。
|
|
214
|
+
|
|
215
|
+
## Commit Convention
|
|
216
|
+
|
|
217
|
+
非平凡任务不是等用户提醒才提交。每个已验证、有意义、范围清晰的切片都应形成 commit。
|
|
218
|
+
提交前只 stage 本任务范围内文件;无关 dirty 文件、私有文件和生成产物必须保留原样或按项目规则处理。
|
|
219
|
+
|
|
220
|
+
任务相关 commit 应在 message footer 中引用任务 ID:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
feat: implement task review gate
|
|
224
|
+
|
|
225
|
+
Harness: TASKS/2026-05-21-task-review-gate
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
格式:`Harness: <task-id>`,其中 task-id 是 `task-list --json` 输出的 `id` 字段。
|
|
229
|
+
不建目录的小修改可以使用 `Harness: trivial` 或省略 footer。1.0 只定义约定,不强制
|
|
230
|
+
扫描 git 历史;后续可通过 reconcile 命令补工具化检查。
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
- 有没有 docs/ 目录?结构如何?
|
|
26
26
|
- 有没有 README 以外的开发文档?
|
|
27
27
|
- 有没有架构设计文档?
|
|
28
|
+
- 如果项目属于微服务、多仓或前后端分仓,用户是否有外部服务文档、接口文档、架构图、会议纪要、链接或导出包?
|
|
29
|
+
- 外部资料能否复制进本仓?如果不能,是否需要只保存本地路径、URL、owner 和摘要?
|
|
28
30
|
|
|
29
31
|
### 4. 现有测试
|
|
30
32
|
- 有没有测试框架?(jest / vitest / pytest / go test 等)
|
|
@@ -98,6 +100,7 @@
|
|
|
98
100
|
| Regression 体系 | [有/无/需改造] | 🟢/🟡/🔴 |
|
|
99
101
|
| CI/CD | [有/无/需改造] | 🟢/🟡/🔴 |
|
|
100
102
|
| Repo Governance | [有/无/需改造] | 🟢/🟡/🔴 |
|
|
103
|
+
| External Source Intake | [无外部资料 / 少量 evidence 链接 / 需要 source pack / 需询问用户] | 🟢/🟡/🔴 |
|
|
101
104
|
| Branch Protection | [designed/implemented/verified/blocked] | 🟢/🟡/🔴 |
|
|
102
105
|
| Required Checks | [有/无/需改造] | 🟢/🟡/🔴 |
|
|
103
106
|
| Harness Ledger | [有/无/需改造] | 🟢/🟡/🔴 |
|
|
@@ -109,6 +112,13 @@
|
|
|
109
112
|
2. [Surface 2]:[描述]
|
|
110
113
|
...
|
|
111
114
|
|
|
115
|
+
## 外部资料判断
|
|
116
|
+
|
|
117
|
+
- 是否属于微服务 / 多仓 / 前后端分仓:[是/否/不确定]
|
|
118
|
+
- 是否已询问用户外部资料:[是/否/不适用]
|
|
119
|
+
- 外部资料规模:[无 / 1-4 份 / 5+ 份 / 未知]
|
|
120
|
+
- 推荐处理:[仅作为 Source Evidence / 创建 external-source-packs/<source-key> / 暂停等待用户提供资料 / 不适用]
|
|
121
|
+
|
|
112
122
|
## 推荐 Harness 规模
|
|
113
123
|
[Lite / Standard / Full](见下方项目类型分支)
|
|
114
124
|
|
|
@@ -91,6 +91,7 @@ Required fields:
|
|
|
91
91
|
- Branch pattern
|
|
92
92
|
- Ownership rule
|
|
93
93
|
- Subagent worker rule: each code-changing worker uses its own worktree / branch and hands off a commit SHA
|
|
94
|
+
- Checkpoint commit rule: verified, meaningful slices are committed proactively; deferred commits require an explicit reason
|
|
94
95
|
- Merge ordering rule
|
|
95
96
|
- Cleanup rule
|
|
96
97
|
|
|
@@ -129,3 +130,4 @@ Bootstrap is not complete unless repository governance is at least:
|
|
|
129
130
|
- Branch protection: `designed` with residual, or `verified`
|
|
130
131
|
- Worktree concurrency: `implemented`
|
|
131
132
|
- Harness checker: passing or blocked-with-owner with explicit residual
|
|
133
|
+
- Checkpoint commit rule: `implemented`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Testing Standard
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Define the minimum verification required before an agent claims that a change is complete.
|
|
6
|
+
|
|
7
|
+
## Minimum Evidence by Change Type
|
|
8
|
+
|
|
9
|
+
| Change Type | Minimum Evidence |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Bug fix | Focused regression test or a verification command that would have exposed the bug |
|
|
12
|
+
| Parser, lifecycle, scanner, or protocol behavior | Unit test coverage is required; prefer TDD |
|
|
13
|
+
| CLI behavior | CLI assertion for success and failure paths |
|
|
14
|
+
| Dashboard or UI behavior | Dashboard smoke plus browser/workbench interaction evidence when behavior changes |
|
|
15
|
+
| Documentation, configuration, or research | Verification command or explicit waiver with residual risk |
|
|
16
|
+
| High-risk shared code | TDD is expected; regression assertion is required |
|
|
17
|
+
|
|
18
|
+
## TDD Policy
|
|
19
|
+
|
|
20
|
+
Use TDD for behavior changes, bug fixes, lifecycle transitions, parsers, scanners, and shared protocol logic:
|
|
21
|
+
|
|
22
|
+
1. Add or update a failing test that describes the desired behavior.
|
|
23
|
+
2. Run the test and confirm it fails for the expected reason.
|
|
24
|
+
3. Implement the smallest change that makes the test pass.
|
|
25
|
+
4. Run the full relevant verification set before closeout.
|
|
26
|
+
|
|
27
|
+
If TDD is skipped, record why the change is not testable or why a smoke/manual check is the better evidence.
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
1. Tests must match the change risk. Use unit tests for isolated logic, integration tests for contracts, end-to-end or smoke tests for user workflows, and manual verification for surfaces automation cannot cover.
|
|
32
|
+
2. Do not claim success from tests that did not exercise the changed behavior.
|
|
33
|
+
3. A skipped, flaky, or unavailable test is residual risk and must be recorded with a reason.
|
|
34
|
+
4. When fixing a bug, add or update coverage that would have caught the failure unless the cost is clearly unjustified and documented.
|
|
35
|
+
5. For UI changes, verify realistic viewport and interaction states when layout, navigation, or user workflow changed.
|
|
36
|
+
6. For data, migration, security, or deployment changes, include evidence from the real contract or environment where feasible.
|
|
37
|
+
7. Final summaries must distinguish checks run, checks not run, and evidence inspected.
|
|
38
|
+
|
|
39
|
+
## Required Checklist
|
|
40
|
+
|
|
41
|
+
- Changed behavior is mapped to a verification method.
|
|
42
|
+
- Required checks were run from the correct branch or worktree.
|
|
43
|
+
- Test output, logs, screenshots, or command results are captured or summarized.
|
|
44
|
+
- Manual checks include exact path and expected result.
|
|
45
|
+
- Known gaps and residual risk are recorded.
|
|
46
|
+
- Regression SSoT is updated when the change adds or changes a protected surface.
|
|
47
|
+
|
|
48
|
+
## Closeout Expectations
|
|
49
|
+
|
|
50
|
+
Testing closeout must list commands or manual checks, summarize results, identify untested risk, and explain why the evidence is sufficient for the requested acceptance criteria.
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
- 本轮有没有发现 reference / workflow / checker 不够用或有误:[有/无,写一句理由]
|
|
36
36
|
- 有没有反复出现、跨页面/跨模块/跨阶段的共性问题:[有/无,写一句理由]
|
|
37
37
|
- 有没有下次 agent 也可能重复踩的坑:[有/无,写一句理由]
|
|
38
|
-
- Lessons 结果:[checked-created: L-YYYY-MM-DD-NNN / checked-none: 一句话原因]
|
|
39
|
-
- Lessons Detail Doc:[如 checked-created,填 `docs/01-GOVERNANCE/lessons/...md`;否则写"无"]
|
|
38
|
+
- Lessons 结果:[checked-created: L-YYYY-MM-DD-NNN / queued-promotion: LC-YYYYMMDD-NNN / checked-candidate: LC-YYYYMMDD-NNN / checked-none: 一句话原因]
|
|
39
|
+
- Lessons Detail Doc:[如 checked-created,填 `docs/01-GOVERNANCE/lessons/...md`;如 queued/checked-candidate,填 `lesson_candidates.md`;否则写"无"]
|
|
40
40
|
|
|
41
41
|
## 相关文件
|
|
42
42
|
- Task Plan: [路径]
|
|
@@ -108,11 +108,12 @@ docs/10-WALKTHROUGH/Closeout-SSoT.md
|
|
|
108
108
|
|
|
109
109
|
1. 完整读一遍 `docs/01-GOVERNANCE/Lessons-SSoT.md`
|
|
110
110
|
2. 按 `references/lessons-governance.md` 中的规则处理冲突
|
|
111
|
-
3.
|
|
112
|
-
4.
|
|
113
|
-
5. 在 Closeout SSoT 和 Harness Ledger 中记录 `checked-created: L-YYYY-MM-DD-NNN`
|
|
111
|
+
3. 先在任务目录 `lesson_candidates.md` 中登记候选并等待人工 review
|
|
112
|
+
4. 人工确认后,如需沉淀,使用 maintenance CLI 写入 `docs/01-GOVERNANCE/lessons/` 和 Lessons SSoT
|
|
113
|
+
5. 在 Closeout SSoT 和 Harness Ledger 中记录 `queued-promotion: LC-...` 或 `checked-created: L-YYYY-MM-DD-NNN`
|
|
114
114
|
|
|
115
115
|
如果所有答案都是“没有”,不能静默跳过;在 Closeout SSoT 和 Harness Ledger 中记录
|
|
116
|
+
新任务在 `lesson_candidates.md` 中写 `no-candidate-accepted` 和 No-Candidate Reason;旧任务可记录
|
|
116
117
|
`checked-none: <一句话原因>`。
|
|
117
118
|
|
|
118
119
|
## Harness Ledger 回写
|
|
@@ -63,6 +63,8 @@ const allowedWalkthroughSkip =
|
|
|
63
63
|
/walkthrough skipped-with-reason:\s*(docs-only|no-runtime|superseded|historical-backfill|owner-deferred)/i;
|
|
64
64
|
const lessonsCreatedPattern = /checked-created:\s*(L-\d{4}-\d{2}-\d{2}-\d{3}|L-\d+)/i;
|
|
65
65
|
const lessonsNonePattern = /checked-none:\s*\S+/i;
|
|
66
|
+
const lessonsCandidatePattern = /checked-candidate:\s*(LC-[A-Za-z0-9-]+)/i;
|
|
67
|
+
const lessonsQueuedPromotionPattern = /queued-promotion:\s*(LC-[A-Za-z0-9-]+)/i;
|
|
66
68
|
|
|
67
69
|
const failures = [];
|
|
68
70
|
const warnings = [];
|
|
@@ -387,15 +389,15 @@ function checkGovernanceContent() {
|
|
|
387
389
|
if (!exists(governancePath)) return;
|
|
388
390
|
const content = read(governancePath);
|
|
389
391
|
const requiredTerms = [
|
|
390
|
-
"Repo Platform Profile",
|
|
391
|
-
"Branch Model",
|
|
392
|
-
"PR Policy",
|
|
393
|
-
"Required Checks",
|
|
394
|
-
"Branch Protection",
|
|
395
|
-
"Worktree Concurrency",
|
|
392
|
+
["Repo Platform Profile", "仓库平台画像"],
|
|
393
|
+
["Branch Model", "分支模型"],
|
|
394
|
+
["PR Policy", "PR 规则"],
|
|
395
|
+
["Required Checks", "必要检查"],
|
|
396
|
+
["Branch Protection", "分支保护"],
|
|
397
|
+
["Worktree Concurrency", "Worktree 并发"],
|
|
396
398
|
];
|
|
397
|
-
for (const
|
|
398
|
-
if (!content
|
|
399
|
+
for (const terms of requiredTerms) {
|
|
400
|
+
if (!contentIncludesAny(content, terms)) fail(`${governancePath} missing section: ${terms[0]}`);
|
|
399
401
|
}
|
|
400
402
|
if (!statusWords.some((status) => content.includes(status))) {
|
|
401
403
|
fail(`${governancePath} does not use evidence status model`);
|
|
@@ -408,13 +410,13 @@ function checkCiCdContent() {
|
|
|
408
410
|
if (!exists(ciPath)) return;
|
|
409
411
|
const content = read(ciPath);
|
|
410
412
|
const requiredTerms = [
|
|
411
|
-
"CI Profile",
|
|
412
|
-
"Workflow",
|
|
413
|
-
"Required Checks",
|
|
414
|
-
"Evidence Status",
|
|
413
|
+
["CI Profile", "CI 画像"],
|
|
414
|
+
["Workflow", "工作流"],
|
|
415
|
+
["Required Checks", "必要检查"],
|
|
416
|
+
["Evidence Status", "证据状态"],
|
|
415
417
|
];
|
|
416
|
-
for (const
|
|
417
|
-
if (!content
|
|
418
|
+
for (const terms of requiredTerms) {
|
|
419
|
+
if (!contentIncludesAny(content, terms)) fail(`${ciPath} missing section: ${terms[0]}`);
|
|
418
420
|
}
|
|
419
421
|
if (!statusWords.some((status) => content.includes(status))) {
|
|
420
422
|
fail(`${ciPath} does not use evidence status model`);
|
|
@@ -428,14 +430,14 @@ function checkDeliveryOperatingModelContent() {
|
|
|
428
430
|
const content = read(deliveryPath);
|
|
429
431
|
const normalized = content.toLowerCase();
|
|
430
432
|
const requiredTerms = [
|
|
431
|
-
"operating model profile",
|
|
432
|
-
"work decomposition rule",
|
|
433
|
-
"agent visibility",
|
|
434
|
-
"integration owner",
|
|
435
|
-
"delivery ssot",
|
|
433
|
+
["operating model profile", "运行模型"],
|
|
434
|
+
["work decomposition rule", "工作拆分规则"],
|
|
435
|
+
["agent visibility", "agent 可见性"],
|
|
436
|
+
["integration owner", "集成 owner"],
|
|
437
|
+
["delivery ssot", "交付 ssot"],
|
|
436
438
|
];
|
|
437
|
-
for (const
|
|
438
|
-
if (!normalized.
|
|
439
|
+
for (const terms of requiredTerms) {
|
|
440
|
+
if (!contentIncludesAny(normalized, terms.map((term) => term.toLowerCase()))) fail(`${deliveryPath} missing section: ${terms[0]}`);
|
|
439
441
|
}
|
|
440
442
|
if (!/solo-orchestrator|team-feature-lead|split-repo-contract|program-multi-repo|waterfall-stage-gate|kanban-continuous/.test(content)) {
|
|
441
443
|
fail(`${deliveryPath} does not define a recognized operating model`);
|
|
@@ -480,7 +482,7 @@ function checkReviewTemplate() {
|
|
|
480
482
|
const reviewPath = "docs/09-PLANNING/TASKS/_task-template/review.md";
|
|
481
483
|
if (!exists(reviewPath)) return;
|
|
482
484
|
const content = read(reviewPath);
|
|
483
|
-
if (!content
|
|
485
|
+
if (!contentIncludesAny(content, ["Confidence Challenge", "信心挑战"])) {
|
|
484
486
|
fail(`${reviewPath} missing Confidence Challenge`);
|
|
485
487
|
}
|
|
486
488
|
if (/\|\s*R-001\s*\|\s*P[01]\s*\|.*\|\s*open\s*\|/i.test(content)) {
|
|
@@ -519,6 +521,14 @@ function columnIndex(header, pattern) {
|
|
|
519
521
|
return header.findIndex((cell) => pattern.test(cell));
|
|
520
522
|
}
|
|
521
523
|
|
|
524
|
+
function contentIncludesAny(content, terms) {
|
|
525
|
+
return terms.some((term) => (term instanceof RegExp ? term.test(content) : content.includes(term)));
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function columnIndexAny(header, patterns) {
|
|
529
|
+
return header.findIndex((cell) => patterns.some((pattern) => pattern.test(cell)));
|
|
530
|
+
}
|
|
531
|
+
|
|
522
532
|
function checkDuplicateIds(rows, sourcePath) {
|
|
523
533
|
const seen = new Set();
|
|
524
534
|
for (const cells of rows) {
|
|
@@ -535,9 +545,9 @@ function checkCloseoutSsot() {
|
|
|
535
545
|
if (!exists(closeoutPath)) return;
|
|
536
546
|
|
|
537
547
|
const closeoutContent = read(closeoutPath);
|
|
538
|
-
for (const
|
|
539
|
-
if (!closeoutContent
|
|
540
|
-
fail(`${closeoutPath} missing required closeout column or section: ${
|
|
548
|
+
for (const terms of [["Walkthrough"], ["Lessons Check", "Lessons 检查"], ["Closeout Status", "收口状态"]]) {
|
|
549
|
+
if (!contentIncludesAny(closeoutContent, terms)) {
|
|
550
|
+
fail(`${closeoutPath} missing required closeout column or section: ${terms[0]}`);
|
|
541
551
|
}
|
|
542
552
|
}
|
|
543
553
|
checkNoGenericPlaceholders(closeoutPath);
|
|
@@ -545,7 +555,7 @@ function checkCloseoutSsot() {
|
|
|
545
555
|
const closeoutTable = markdownTable(closeoutContent);
|
|
546
556
|
const closeoutHeaderIndex = findHeaderIndex(closeoutTable, /^Harness ID$/i);
|
|
547
557
|
const closeoutHeader = closeoutHeaderIndex >= 0 ? closeoutTable[closeoutHeaderIndex] : [];
|
|
548
|
-
const lessonsColumn =
|
|
558
|
+
const lessonsColumn = columnIndexAny(closeoutHeader, [/^Lessons Check$/i, /^Lessons 检查$/i, /^Lessons 检查\s*\/\s*Lessons Check$/i]);
|
|
549
559
|
if (lessonsColumn < 0) {
|
|
550
560
|
fail(`${closeoutPath} missing Lessons Check column`);
|
|
551
561
|
}
|
|
@@ -553,10 +563,11 @@ function checkCloseoutSsot() {
|
|
|
553
563
|
if (!exists("docs/Harness-Ledger.md")) return;
|
|
554
564
|
const ledgerContent = read("docs/Harness-Ledger.md");
|
|
555
565
|
const lessonIds = collectLessonIds();
|
|
566
|
+
const lessonCandidateIds = collectLessonCandidateIds();
|
|
556
567
|
const ledgerTable = markdownTable(ledgerContent);
|
|
557
568
|
const ledgerHeaderIndex = findHeaderIndex(ledgerTable, /^ID$/i);
|
|
558
569
|
const ledgerHeader = ledgerHeaderIndex >= 0 ? ledgerTable[ledgerHeaderIndex] : [];
|
|
559
|
-
const ledgerLessonsColumn =
|
|
570
|
+
const ledgerLessonsColumn = columnIndexAny(ledgerHeader, [/^Lessons Check$/i, /^Lessons 检查$/i, /^Lessons 检查\s*\/\s*Lessons Check$/i]);
|
|
560
571
|
if (ledgerLessonsColumn < 0) {
|
|
561
572
|
fail("docs/Harness-Ledger.md missing Lessons Check column");
|
|
562
573
|
}
|
|
@@ -587,20 +598,26 @@ function checkCloseoutSsot() {
|
|
|
587
598
|
if (lessonsColumn >= 0) {
|
|
588
599
|
const lessonsCheck = closeout[lessonsColumn] || "";
|
|
589
600
|
const createdMatch = lessonsCheck.match(lessonsCreatedPattern);
|
|
590
|
-
|
|
591
|
-
|
|
601
|
+
const candidateMatch = lessonsCheck.match(lessonsCandidatePattern) || lessonsCheck.match(lessonsQueuedPromotionPattern);
|
|
602
|
+
if (!createdMatch && !candidateMatch && !lessonsNonePattern.test(lessonsCheck)) {
|
|
603
|
+
fail(`${closeoutPath} row ${id} needs Lessons Check value: checked-created:<lesson-id>, checked-candidate:<candidate-id>, queued-promotion:<candidate-id>, or checked-none:<reason>`);
|
|
592
604
|
} else if (createdMatch && !lessonIds.has(createdMatch[1])) {
|
|
593
605
|
fail(`${closeoutPath} row ${id} references missing Lessons SSoT id: ${createdMatch[1]}`);
|
|
606
|
+
} else if (candidateMatch && !lessonCandidateIds.has(candidateMatch[1])) {
|
|
607
|
+
fail(`${closeoutPath} row ${id} references missing lesson candidate id: ${candidateMatch[1]}`);
|
|
594
608
|
}
|
|
595
609
|
}
|
|
596
610
|
|
|
597
611
|
if (ledgerLessonsColumn >= 0) {
|
|
598
612
|
const ledgerLessonsCheck = cells[ledgerLessonsColumn] || "";
|
|
599
613
|
const ledgerCreatedMatch = ledgerLessonsCheck.match(lessonsCreatedPattern);
|
|
600
|
-
|
|
601
|
-
|
|
614
|
+
const ledgerCandidateMatch = ledgerLessonsCheck.match(lessonsCandidatePattern) || ledgerLessonsCheck.match(lessonsQueuedPromotionPattern);
|
|
615
|
+
if (!ledgerCreatedMatch && !ledgerCandidateMatch && !lessonsNonePattern.test(ledgerLessonsCheck)) {
|
|
616
|
+
fail(`docs/Harness-Ledger.md row ${id} needs Lessons Check value: checked-created:<lesson-id>, checked-candidate:<candidate-id>, queued-promotion:<candidate-id>, or checked-none:<reason>`);
|
|
602
617
|
} else if (ledgerCreatedMatch && !lessonIds.has(ledgerCreatedMatch[1])) {
|
|
603
618
|
fail(`docs/Harness-Ledger.md row ${id} references missing Lessons SSoT id: ${ledgerCreatedMatch[1]}`);
|
|
619
|
+
} else if (ledgerCandidateMatch && !lessonCandidateIds.has(ledgerCandidateMatch[1])) {
|
|
620
|
+
fail(`docs/Harness-Ledger.md row ${id} references missing lesson candidate id: ${ledgerCandidateMatch[1]}`);
|
|
604
621
|
}
|
|
605
622
|
}
|
|
606
623
|
}
|
|
@@ -621,21 +638,45 @@ function collectLessonIds() {
|
|
|
621
638
|
);
|
|
622
639
|
}
|
|
623
640
|
|
|
641
|
+
function collectLessonCandidateIds() {
|
|
642
|
+
const root = filePath("docs/09-PLANNING");
|
|
643
|
+
const ids = new Set();
|
|
644
|
+
if (!fs.existsSync(root)) return ids;
|
|
645
|
+
function visit(dir) {
|
|
646
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
647
|
+
const full = path.join(dir, entry);
|
|
648
|
+
const stat = fs.statSync(full);
|
|
649
|
+
if (stat.isDirectory()) {
|
|
650
|
+
if (entry === "_archive") continue;
|
|
651
|
+
visit(full);
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (entry !== "lesson_candidates.md") continue;
|
|
655
|
+
const content = fs.readFileSync(full, "utf8");
|
|
656
|
+
for (const match of content.matchAll(/\|\s*(LC-[A-Za-z0-9-]+)\s*\|/g)) {
|
|
657
|
+
ids.add(match[1]);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
visit(root);
|
|
662
|
+
return ids;
|
|
663
|
+
}
|
|
664
|
+
|
|
624
665
|
function checkLessonsSsot() {
|
|
625
666
|
const lessonsPath = "docs/01-GOVERNANCE/Lessons-SSoT.md";
|
|
626
667
|
if (!exists(lessonsPath)) return;
|
|
627
668
|
|
|
628
669
|
const content = read(lessonsPath);
|
|
629
|
-
if (
|
|
670
|
+
if (!contentIncludesAny(content, [/Detail Doc/i, "详情文档"])) {
|
|
630
671
|
fail(`${lessonsPath} missing Detail Doc column`);
|
|
631
672
|
}
|
|
632
673
|
|
|
633
674
|
const table = markdownTable(content);
|
|
634
675
|
const headerIndex = findHeaderIndex(table, /^ID$/i);
|
|
635
676
|
const header = headerIndex >= 0 ? table[headerIndex] : [];
|
|
636
|
-
const detailColumn =
|
|
677
|
+
const detailColumn = columnIndexAny(header, [/^(Detail Doc|Detail)$/i, /^详情文档$/i, /^详情文档\s*\/\s*Detail Doc$/i]);
|
|
637
678
|
const idColumn = columnIndex(header, /^ID$/i);
|
|
638
|
-
const statusColumn =
|
|
679
|
+
const statusColumn = columnIndexAny(header, [/^Status$/i, /^状态$/i, /^状态\s*\/\s*Status$/i]);
|
|
639
680
|
if (idColumn < 0) fail(`${lessonsPath} missing ID column`);
|
|
640
681
|
if (detailColumn < 0) fail(`${lessonsPath} missing Detail Doc column`);
|
|
641
682
|
if (statusColumn < 0) fail(`${lessonsPath} missing Status column`);
|
|
@@ -675,7 +716,7 @@ function checkWalkthroughTemplate() {
|
|
|
675
716
|
const walkthroughTemplate = "docs/10-WALKTHROUGH/_walkthrough-template.md";
|
|
676
717
|
if (!exists(walkthroughTemplate)) return;
|
|
677
718
|
const content = read(walkthroughTemplate);
|
|
678
|
-
if (!content
|
|
719
|
+
if (!contentIncludesAny(content, ["Lessons Reflection", "Lessons 回看"])) {
|
|
679
720
|
fail(`${walkthroughTemplate} missing Lessons Reflection section`);
|
|
680
721
|
}
|
|
681
722
|
}
|