@namewta/speculo 1.0.14 → 1.0.16
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/README.md +2 -2
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/template/canonical/canonical-specdev-goal-plan.md +25 -13
- package/template/canonical/canonical-specdev-grill-with-docs.md +2 -1
- package/template/canonical/canonical-specdev-spec.md +2 -1
- package/template/canonical/canonical-specdev-tickets.md +3 -2
- package/template/commands/handoff.md +1 -1
- package/template/commands/status.md +1 -1
- package/template/skills/engineering-standards-builder/examples/README.md +6 -0
- package/template/skills/engineering-standards-builder/manifest.txt +1 -0
- package/template/skills/engineering-standards-builder/scripts/self-test.mjs +1 -0
- package/template/skills/engineering-standards-builder/scripts/sync-manifest.mjs +2 -2
- package/template/skills/engineering-standards-builder/scripts/validate-builder.mjs +7 -3
- package/template/workflows/specdev/I-init-setup/tracking-template.md +1 -1
- package/template/workflows/specdev/INDEX.md +1 -1
- package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +4 -2
- package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +2 -0
- package/template/workflows/specdev/P-goal-plan/planning-modes.md +13 -8
- package/template/workflows/specdev/P-goal-plan/references/map-control.md +1 -1
- package/template/workflows/specdev/P-goal-plan/references/single-change-plan.md +4 -2
- package/template/workflows/specdev/README.md +4 -4
- package/template/workflows/specdev/T-triage/T-triage.md +44 -10
- package/template/workflows/specdev/T-triage/capture-protocol.md +89 -0
- package/template/workflows/specdev/T-triage/capture-template.md +42 -0
- package/template/workflows/specdev/T-triage/intake-protocol.md +2 -0
- package/template/workflows/specdev/T-triage/issue-record-template.md +27 -0
- package/template/workflows/specdev/T-triage/references/classification-map.md +10 -9
- package/template/workflows/specdev/T-triage/references/public-projection.md +27 -4
- package/template/workflows/specdev/T-triage/tools/capture-status.mjs +125 -0
- package/template/workflows/specdev/common/README.md +1 -0
- package/template/workflows/specdev/common/rules/artifact-contract.md +2 -1
- package/template/workflows/specdev/common/rules/workflow-routing.md +3 -2
- package/template/workflows/specdev/common/rules/workflow-state-and-lifecycle.md +1 -0
- package/template/workflows/specdev/common/schemas/capture.schema.json +15 -0
- package/template/workflows/specdev/common/tools/README.md +14 -1
- package/template/workflows/specdev/common/tools/validate-specdev.mjs +151 -22
|
@@ -50,14 +50,14 @@ Goal Plan 只拥有单个 Ticket 无法独立决定的事情:整体 Outcome、
|
|
|
50
50
|
|
|
51
51
|
加载 `<Path>{roots.workflows}/specdev/P-goal-plan/planning-modes.md</Path>`:
|
|
52
52
|
|
|
53
|
-
1. 验证 Spec、Tickets、合同覆盖、DAG
|
|
53
|
+
1. 验证 Spec、Tickets、合同覆盖、DAG、路径所有权和待执行 Deep Ticket 完整性;未来 draft 票按规划输入门记录局部缺口;
|
|
54
54
|
2. 只读探索影响调度的代码与项目事实;
|
|
55
55
|
3. 识别 migration、high-assurance、reference-conformance、release-coordination 等适用模式;
|
|
56
56
|
4. 从 config 读取 `max_implementation_agents` 与 `max_integration_attempts`,将实际值快照到 `implementation_agent_limit` 与 `integration_attempt_limit`;本计划可以降低但不得超过 config 或平台能力,Lead 不计入;
|
|
57
57
|
5. 根据 workspace 策略记录实现 commit 与 direct-parent/candidate integration 授权事实;缺失时仍可完成 plan 文档,但 ready_for_execution 保持 false,并列为 run 的阻塞条件;
|
|
58
58
|
6. 只询问无法发现且会改变 Gate、Wave、owner、迁移、批准或验收的问题。
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
**完成标准**:计划内 Ticket、范围、覆盖、DAG 与所有权完整;未来 draft 票已记录真实缺口、生产者证据和 DoR 重审条件;Lead、授权状态、实现并发上限和父分支可判定。缺执行授权时可交付规划,但 `ready_for_execution` 保持 `false`。
|
|
61
61
|
|
|
62
62
|
### 2. 构建 Outcome、DAG、Wave 与 Gate
|
|
63
63
|
|
|
@@ -133,6 +133,8 @@ Goal Plan 不复制 Ticket 的局部施工路线、全部文件预测或逐项
|
|
|
133
133
|
## 完成标准
|
|
134
134
|
|
|
135
135
|
- Goal Plan schema v6 且 `ready_for_execution` 与状态一致;
|
|
136
|
+
- 规划完成与执行就绪分别报告;允许交付 `draft / ready_for_execution: false`,单 change 不创建父 Implementation Map/Plan;
|
|
137
|
+
- 等待上游产物的未来票保持 draft,局部缺口只阻塞依赖闭包;进入执行的票必须重新通过 DoR,上游完成不自动提升 Ready;
|
|
136
138
|
- Lead 唯一,implementation subagent 上限来自 config/平台能力,review/research agent 不受 SpecDev 数字限制;
|
|
137
139
|
- 每个实现 Ticket 都有 workspace、commit、对应 integration gate 和 Evidence 出口;
|
|
138
140
|
- current 模式不创建 source/candidate worktree,适用 E2E 由 Lead 在 current workspace 运行;required 模式保持 source/parent-candidate 边界;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 工件链与权威
|
|
10
10
|
|
|
11
|
-
大需求 → W 的 Initiative 候选图 → 每个 change 自己的 G/Grill → S/Spec → T 的计划型 Ticket 与 tickets-map → P 的 Goal → I/实现与 Evidence → Goal 集成验收 → 按需学习/远程 reconcile 或 publish
|
|
11
|
+
大需求 → W 的 Initiative 候选图 → 每个 change 自己的 G/Grill → S/Spec → T 的计划型 Ticket 与 tickets-map → P 的 Goal → I/实现与 Evidence → Goal 集成验收 → 按需学习/远程 reconcile 或 publish/归档。尚未成 Change 的记事项可先 T-triage capture 到 GitHub inbox,再逐条 intake。
|
|
12
12
|
|
|
13
13
|
已明确的小请求直接进入适用阶段;无需为了路由而创建 Triage。跨 change 实现由 P 统一管理。
|
|
14
14
|
|
|
@@ -47,7 +47,7 @@ CLI 初始化和刷新保持原 namespace、三方配置合并、schema migrator
|
|
|
47
47
|
|
|
48
48
|
## 场景路由
|
|
49
49
|
|
|
50
|
-
不清晰的大需求选 W,单 change 的高影响决定选 G,Ready Spec 拆票选 T-tickets
|
|
50
|
+
不清晰的大需求选 W,单 change 的高影响决定选 G,Ready Spec 拆票选 T-tickets,单个已拆票 change 或多个 Ready change 的 Goal 选 P-goal-plan;来源冻结/远程回写/完成后记账/尚未成 Change 的记事项才选 T-triage。精确条件与全部出口见 `<Path>{roots.workflows}/specdev/common/rules/workflow-routing.md</Path>`。
|
|
51
51
|
|
|
52
52
|
## Work 条目
|
|
53
53
|
|
|
@@ -61,12 +61,12 @@ CLI 初始化和刷新保持原 namespace、三方配置合并、schema migrator
|
|
|
61
61
|
- **I-implement** — 实现与验收:执行已授权的 Ready Ticket 或获批 Direct Spec,产生可回读实现和验收证据;不从模糊需求直接写代码。
|
|
62
62
|
- **I-init-setup** — 初始化设置:初始化 SpecDev 的语言、配置、全局状态、本地 change 追踪、领域知识布局、验证命令和并发治理。
|
|
63
63
|
- **L-learn-change** — Change 学习:在开发完成后围绕当前 SpecDev change 回答问题,并用面向零专业背景读者的 Markdown 与 ASCII 图解持续记录理解。
|
|
64
|
-
- **P-goal-plan** — Goal
|
|
64
|
+
- **P-goal-plan** — Goal 规划与执行:为单个已拆票 change 或多个 Ready change 规划、执行或恢复 Goal;只在用户要求交付编排或已有 map 需推进时使用,不代替需求探索和 Ticket 编写。
|
|
65
65
|
- **P-prototype** — UI 设计原型:检测现有项目的 UI 事实,按产品任务推荐并逐步选择设计风格,生成持久化设计系统文档、多风格 HTML 对照和可运行 HTML/CSS/JS 原型。
|
|
66
66
|
- **R-review-architecture** — 架构审查:从用户指定范围或 Git 热点扫描代码库中的结构性坏味道、代码 judo 机会和维护性风险,以中文 Markdown 记录高置信候选,并对用户选择的一个方案运行设计树访谈。
|
|
67
67
|
- **S-spec** — 编写 Spec:综合已知事实、设计决定、诊断与代码现状,产出以外部行为和验收合同为权威的 Ready Spec。
|
|
68
68
|
- **T-tickets** — 编写计划型 Tickets:将已澄清的 Spec 或等价获批计划拆为可验收的实施 Ticket,并绑定真实项目 Skill;不用于探索未知需求或执行代码。
|
|
69
|
-
- **T-triage** — 请求分诊:需要冻结外部来源、审计摄入、对 completed change 回写来源 Issue
|
|
69
|
+
- **T-triage** — 请求分诊:需要冻结外部来源、审计摄入、对 completed change 回写来源 Issue、把已完成 Ticket 投影为带分类标签的 GitHub Issue,或把尚未成 Change 的记事项写成仍 open 的 GitHub Issue 时使用;已清晰的本地需求不必为了路由而经本入口。
|
|
70
70
|
- **W-wayfinder** — 探索大需求与 Change 边界:大需求的 change 边界或实施路线尚不可见时建立探索地图,并分别澄清各 change;已有清晰 Spec 时不触发。
|
|
71
71
|
|
|
72
72
|
<!-- AUTO-INDEX-END -->
|
|
@@ -3,15 +3,15 @@ id: specdev/triage
|
|
|
3
3
|
type: workflow-entry
|
|
4
4
|
workflow: specdev
|
|
5
5
|
name: 请求分诊
|
|
6
|
-
description: 需要冻结外部来源、审计摄入、对 completed change 回写来源 Issue
|
|
7
|
-
keywords: [triage, 摄入, import, issue, reconcile, publish, close, 风险, 路由]
|
|
6
|
+
description: 需要冻结外部来源、审计摄入、对 completed change 回写来源 Issue、把已完成 Ticket 投影为带分类标签的 GitHub Issue,或把尚未成 Change 的记事项写成仍 open 的 GitHub Issue 时使用;已清晰的本地需求不必为了路由而经本入口。
|
|
7
|
+
keywords: [triage, 摄入, import, issue, reconcile, publish, capture, close, 风险, 路由]
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 请求分诊
|
|
11
11
|
|
|
12
12
|
> 激活本 Work 后,先读取 `<Path>{roots.workflows}/specdev/README.md</Path>`,再执行本入口。
|
|
13
13
|
|
|
14
|
-
Triage 是 SpecDev
|
|
14
|
+
Triage 是 SpecDev 唯一的远程摄入、关闭、发布投影与记事项捕获边界。开发期间,change 级 `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>`、`<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`、`<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>`、Spec、Ticket、Map、Goal Plan、Evidence 和状态文件是开发唯一权威;workspace 级 `<Path>{roots.state}/specdev/capture.md</Path>` 是尚未成 Change 的 inbox 计数权威(缺失合法)。远程系统只保存原始请求、经确认后的完成通知、票级发布记录,以及仍 open 的记事项。GitHub 不是 tracker,也不是开发权威。
|
|
15
15
|
|
|
16
16
|
## 读取范围
|
|
17
17
|
|
|
@@ -19,22 +19,23 @@ Triage 是 SpecDev 唯一的远程摄入、关闭与发布投影边界。开发
|
|
|
19
19
|
2. 再读取 `<Path>{roots.workflows}/specdev/common/rules/activation-and-memory.md</Path>`,按当前分支、状态和关键词定位最小相关工件。
|
|
20
20
|
3. 只在本 Work 明确要求恢复、冲突、执行安全或归档证据时扩展为全量读取;缺少匹配证据或 owner/gateway 时停止受影响分支。
|
|
21
21
|
|
|
22
|
-
普通本地请求直接进入适用 Work,不为了完成路由额外创建来源工件。用户明确要求来源审计时仍执行完整 intake;缺陷根因诊断仍交 D,不删除风险分诊与远程回写能力。完成后要记账才选 publish。
|
|
22
|
+
普通本地请求直接进入适用 Work,不为了完成路由额外创建来源工件。用户明确要求来源审计时仍执行完整 intake;缺陷根因诊断仍交 D,不删除风险分诊与远程回写能力。完成后要记账才选 publish。尚未成 Change、只想先在 GitHub 留一条仍 open 的记录时才选 capture。
|
|
23
23
|
|
|
24
24
|
## 模式
|
|
25
25
|
|
|
26
26
|
- **intake**:冻结输入、创建或恢复 change、分类并返回下一 Work。
|
|
27
27
|
- **reconcile**:本地 change 已完成后,确认远程完成摘要并关闭支持的 GitHub 来源 Issue;不重新分诊或修改开发契约。
|
|
28
28
|
- **publish**:本地 change 已完成后,把计划内 Ticket 投影为带分类标签的 GitHub Issue,用脱敏 Evidence 关闭它们,并留下 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>` 账本。标签必须包含 `specdev:published`。
|
|
29
|
+
- **capture**:尚未有 Change 时,把记事项写成仍 open 的 GitHub Issue,并留下 `<Path>{roots.state}/specdev/capture.md</Path>`。标签必须包含 `specdev:captured`。不创建 change,不写 change 级 triage 工件,`mode=capture` 不得出现在 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`。
|
|
29
30
|
|
|
30
31
|
## 共同启动
|
|
31
32
|
|
|
32
33
|
1. 解析 roots,按 `<Path>{roots.workflows}/specdev/README.md</Path>` 读取全局状态和 change 状态。
|
|
33
|
-
2. Intake 可以创建 change;reconcile 与 publish 必须选择一个已存在的 change。publish 的对象必须已 completed。
|
|
34
|
-
3.
|
|
35
|
-
4. 重读已有 `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`,不覆盖已冻结的来源。publish 在本地源缺失这些文件时可以按协议补建轻量快照,仍不得虚构 GitHub locator。
|
|
34
|
+
2. Intake 可以创建 change;reconcile 与 publish 必须选择一个已存在的 change。publish 的对象必须已 completed。capture 既不创建也不选择 change,不写 `current_work`,不加载 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`。
|
|
35
|
+
3. 仅 intake、reconcile 与 publish:若该 change 的 `current_work` 为 null,设置为 `specdev/triage`;指向其他 Work 时先恢复或完成显式 handoff。capture 跳过本步。
|
|
36
|
+
4. 重读已有 `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`,不覆盖已冻结的来源。publish 在本地源缺失这些文件时可以按协议补建轻量快照,仍不得虚构 GitHub locator。capture 不读、不写这些文件。
|
|
36
37
|
|
|
37
|
-
`external_action` 只描述源 Issue。`publish_action`
|
|
38
|
+
`external_action` 只描述源 Issue。`publish_action` 只描述票级发布投影。capture 行 state 只描述 inbox 记录。三者互不覆盖。未授权时远程写入为零。
|
|
38
39
|
|
|
39
40
|
## Intake
|
|
40
41
|
|
|
@@ -88,9 +89,28 @@ node <Path>{roots.workflows}/specdev/T-triage/tools/publish-status.mjs</Path> \
|
|
|
88
89
|
--state-root <Path>{roots.state}/specdev</Path>
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
## Capture
|
|
93
|
+
|
|
94
|
+
尚未成 Change、用户要求先把记事项写到 GitHub 时,加载:
|
|
95
|
+
|
|
96
|
+
- `<Path>{roots.workflows}/specdev/T-triage/capture-protocol.md</Path>`;
|
|
97
|
+
- `<Path>{roots.workflows}/specdev/T-triage/references/classification-map.md</Path>`;
|
|
98
|
+
- `<Path>{roots.workflows}/specdev/T-triage/references/public-projection.md</Path>`。
|
|
99
|
+
|
|
100
|
+
按协议走硬门、确认表、dry-run,再调用 github-npm-ops 的 `issue-search` / `issue-create`。不调用 `issue-comment-close`。账本写 `<Path>{roots.state}/specdev/capture.md</Path>`。Issue 正文用 `<Path>{roots.workflows}/specdev/T-triage/issue-record-template.md</Path>`。默认 1 条记录对应一次未来 intake / 一个未来 Change。攒多了再处理:批量 capture,然后逐条 intake 或先走 W;不把多条 locator 写入同一个 source。
|
|
101
|
+
|
|
102
|
+
成功留下仍 open 的 inbox Issue。intake 消费到同一 locator 时把对应行标为 `intaken`。用户放弃为 `waived`。capture 不挡 Archive,因为没有 change 可归档。
|
|
103
|
+
|
|
104
|
+
workspace inbox 计数:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
node <Path>{roots.workflows}/specdev/T-triage/tools/capture-status.mjs</Path> \
|
|
108
|
+
--state-root <Path>{roots.state}/specdev</Path>
|
|
109
|
+
```
|
|
110
|
+
|
|
91
111
|
## 状态与验证
|
|
92
112
|
|
|
93
|
-
运行:
|
|
113
|
+
intake、reconcile 或 publish 运行:
|
|
94
114
|
|
|
95
115
|
```bash
|
|
96
116
|
node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
@@ -98,7 +118,16 @@ node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
|
98
118
|
<Path>{roots.state}/specdev/changes/{change}</Path>
|
|
99
119
|
```
|
|
100
120
|
|
|
101
|
-
|
|
121
|
+
capture 在账本存在时运行:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
125
|
+
--capture <Path>{roots.state}/specdev/capture.md</Path>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
缺失 `<Path>{roots.state}/specdev/capture.md</Path>` 合法,不要为了校验去创建它。
|
|
129
|
+
|
|
130
|
+
验证通过后,intake / reconcile / publish 原子重读 source、triage、publish(若请求过)和 change 状态;成功时将 `specdev/triage` 去重加入 `works_run` 并清空 `current_work`;可恢复失败保留 `current_work` 和具体 blocker。capture 不改任何 change 状态。
|
|
102
131
|
|
|
103
132
|
## 完成标准
|
|
104
133
|
|
|
@@ -109,6 +138,7 @@ node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
|
109
138
|
- 未授权时远程写入为零;
|
|
110
139
|
- Reconcile 可从失败检查点幂等恢复;
|
|
111
140
|
- Publish 可从 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>` 失败行幂等恢复,cancelled 默认 skip,本地源计入发布数;
|
|
141
|
+
- Capture 可从 `<Path>{roots.state}/specdev/capture.md</Path>` 失败行幂等恢复,Issue 保持 open,不创建 Change;
|
|
112
142
|
- 状态、验证结果和下一 Work 完整路径已返回。
|
|
113
143
|
|
|
114
144
|
## 子文件引用
|
|
@@ -116,11 +146,15 @@ node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
|
116
146
|
- Intake:`<Path>{roots.workflows}/specdev/T-triage/intake-protocol.md</Path>`
|
|
117
147
|
- Reconcile:`<Path>{roots.workflows}/specdev/T-triage/reconcile-protocol.md</Path>`
|
|
118
148
|
- Publish:`<Path>{roots.workflows}/specdev/T-triage/publish-protocol.md</Path>`
|
|
149
|
+
- Capture:`<Path>{roots.workflows}/specdev/T-triage/capture-protocol.md</Path>`
|
|
119
150
|
- Source 模板:`<Path>{roots.workflows}/specdev/T-triage/source-template.md</Path>`
|
|
120
151
|
- Triage 模板:`<Path>{roots.workflows}/specdev/T-triage/triage-template.md</Path>`
|
|
121
152
|
- Publish 模板:`<Path>{roots.workflows}/specdev/T-triage/publish-template.md</Path>`
|
|
153
|
+
- Capture 模板:`<Path>{roots.workflows}/specdev/T-triage/capture-template.md</Path>`
|
|
122
154
|
- 分类映射:`<Path>{roots.workflows}/specdev/T-triage/references/classification-map.md</Path>`
|
|
123
155
|
- 公共投影:`<Path>{roots.workflows}/specdev/T-triage/references/public-projection.md</Path>`
|
|
124
156
|
- Issue 正文:`<Path>{roots.workflows}/specdev/T-triage/issue-body-template.md</Path>`
|
|
157
|
+
- 记事项正文:`<Path>{roots.workflows}/specdev/T-triage/issue-record-template.md</Path>`
|
|
125
158
|
- 关闭评论:`<Path>{roots.workflows}/specdev/T-triage/close-comment-template.md</Path>`
|
|
126
159
|
- 发布计数:`<Path>{roots.workflows}/specdev/T-triage/tools/publish-status.mjs</Path>`
|
|
160
|
+
- inbox 计数:`<Path>{roots.workflows}/specdev/T-triage/tools/capture-status.mjs</Path>`
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Capture Protocol
|
|
2
|
+
|
|
3
|
+
仅在 Triage `mode=capture` 时加载。目标是把尚未成 Change 的记事项写成仍 open 的 GitHub Issue,并留下 workspace 级 `<Path>{roots.state}/specdev/capture.md</Path>`。
|
|
4
|
+
|
|
5
|
+
GitHub 是 inbox 和计数器,不是 tracker,也不是开发权威。capture 不创建、不选择、不改写任何 change。票级完成后投影走 publish,源 Issue 关闭走 reconcile,外部输入冻结走 intake;四者互不覆盖。
|
|
6
|
+
|
|
7
|
+
## 1. 触发与对象
|
|
8
|
+
|
|
9
|
+
用户必须给出至少一条记事项(标题、现在时摘要、分类)。禁止扫整个 workspace 自动发。允许一次授权批量多条;默认 **1 条记录 = 1 次未来 intake / 1 个未来 Change**。v1 不写 `related_locators`,不把 N 条 locator 塞进同一个未来 source。
|
|
10
|
+
|
|
11
|
+
相关但目标不清 → 先 capture 为多条 inbox,以后走 `<Path>{roots.workflows}/specdev/W-wayfinder/W-wayfinder.md</Path>` 或逐条 intake,不在本协议合并。
|
|
12
|
+
|
|
13
|
+
可选开关:排除 id 列表。目标 repo 默认从 `git remote` 推断,必须展示确认。
|
|
14
|
+
|
|
15
|
+
capture **不得**:
|
|
16
|
+
|
|
17
|
+
- 创建 change 目录或 `<Path>{roots.state}/specdev/changes/{change}/</Path>` 下任何工件;
|
|
18
|
+
- 写 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>` / `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` / `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>`;
|
|
19
|
+
- 设置任何 change 的 `current_work`;
|
|
20
|
+
- 加载 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`;
|
|
21
|
+
- 调用 `issue-comment-close` 或关闭刚创建的 Issue;
|
|
22
|
+
- 在本地复制 inbox 正文副本;
|
|
23
|
+
- 打 `specdev:published`、`specdev:change`、`needs-triage`、`needs-info`、`ready-for-agent`、`ready-for-human`。
|
|
24
|
+
|
|
25
|
+
只写 `<Path>{roots.state}/specdev/capture.md</Path>` 和经授权的远程 inbox Issue。缺失该账本合法,首次 capture 才创建。
|
|
26
|
+
|
|
27
|
+
## 2. 硬门
|
|
28
|
+
|
|
29
|
+
失败即停,零远程写入。已有账本行保持原 state。
|
|
30
|
+
|
|
31
|
+
1. 每条纳入记录有 id(`YYYY-MM-DD-<kebab>`)、现在时摘要、且 `kind` 为 bug、feature、refactor、investigation、operations、documentation 或 review。禁止 `mixed`。
|
|
32
|
+
2. 调用 `<Path>{roots.skills}/github-npm-ops/SKILL.md</Path>` 能读目标 repo、能 dry-run `issue-create`。本协议只用 `issue-search` / `issue-create`。
|
|
33
|
+
3. 分类映射见 `<Path>{roots.workflows}/specdev/T-triage/references/classification-map.md</Path>`。缺 type 标签时 dry-run 表列出将创建的标签,授权后才 `gh label create`。
|
|
34
|
+
4. 用户看见完整 dry-run 表(id、标题、标签、正文、reason)并给出 **本次** 明确确认。
|
|
35
|
+
|
|
36
|
+
origin 固定 `local`。marker:`specdev:capture:<id>`。
|
|
37
|
+
|
|
38
|
+
## 3. 准备记录
|
|
39
|
+
|
|
40
|
+
按 `<Path>{roots.workflows}/specdev/T-triage/references/public-projection.md</Path>` 脱敏。现在时,不是完成后的过去时,也不是派工祈使句。
|
|
41
|
+
|
|
42
|
+
Issue 正文:`<Path>{roots.workflows}/specdev/T-triage/issue-record-template.md</Path>`。
|
|
43
|
+
|
|
44
|
+
用 `<Path>{roots.workflows}/specdev/T-triage/capture-template.md</Path>` 写或更新 `<Path>{roots.state}/specdev/capture.md</Path>`。先把纳入行标 `planned`,用户排除的标 `skipped:duplicate` 以外的跳过由执行期判定。
|
|
45
|
+
|
|
46
|
+
## 4. 幂等执行
|
|
47
|
+
|
|
48
|
+
对每条纳入记录:
|
|
49
|
+
|
|
50
|
+
1. `issue-search` 查 marker 或精确标题 + `specdev:captured`。
|
|
51
|
+
2. 已存在且 marker 在且仍 open → 账本 `open`,跳过创建。
|
|
52
|
+
3. 已存在且 marker 在但已 closed → 停止该行,展示冲突,不重开、不覆盖。intake 已消耗的行应为 `intaken`,由 intake 协议回写,不由本协议改 closed。
|
|
53
|
+
4. 已存在但无 marker → 停止该行,展示冲突,不覆盖别人的 Issue。
|
|
54
|
+
5. 不存在 → dry-run `issue-create` → 授权后 `--apply` → 保持 **open**。marker 写在正文 Provenance。不评论、不关闭。
|
|
55
|
+
6. 任一步失败:该行 `failed`,记录已完成步骤和下一重试动作;已成功的记录不回滚。
|
|
56
|
+
|
|
57
|
+
`--apply` 只表示调用方完成本次确认,不替代授权。远程失败不补建本地 Change。
|
|
58
|
+
|
|
59
|
+
全部纳入记录到达 `open` 或合法 `skipped:duplicate`,且无 `failed` 时结束。用户明确放弃未发出的行:`waived`。重跑是恢复,不是重发。`intaken` 只由后续 intake 写入。
|
|
60
|
+
|
|
61
|
+
## 5. 校验与计数
|
|
62
|
+
|
|
63
|
+
账本存在时:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
|
|
67
|
+
--capture <Path>{roots.state}/specdev/capture.md</Path>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
缺失该文件时不要为了校验去创建它。
|
|
71
|
+
|
|
72
|
+
workspace inbox 计数:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
node <Path>{roots.workflows}/specdev/T-triage/tools/capture-status.mjs</Path> \
|
|
76
|
+
--state-root <Path>{roots.state}/specdev</Path>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
数字只来自 `<Path>{roots.state}/specdev/capture.md</Path>`,不把 GitHub 搜索当权威,也不计入 `published_issues`。
|
|
80
|
+
|
|
81
|
+
## 完成标准
|
|
82
|
+
|
|
83
|
+
- 用户指定的记事项均有对应仍 open 的 GitHub Issue,或账本有合法 skip / waived;
|
|
84
|
+
- 每条已捕获 Issue 带且仅带一个 type 标签,以及 `specdev:captured` 与 `origin:local`;
|
|
85
|
+
- 正文是现在时 inbox 记录,不是派工单,也不是完成后投影;
|
|
86
|
+
- marker 使重跑不重复建贴;
|
|
87
|
+
- 未创建 Change,未写 `current_work`,未调用关闭;
|
|
88
|
+
- `<Path>{roots.state}/specdev/capture.md</Path>` 与远程重读一致,失败行可恢复;
|
|
89
|
+
- 未授权时远程写入为零。
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
artifact: capture-index
|
|
4
|
+
mode: capture
|
|
5
|
+
repo: owner/repo
|
|
6
|
+
updated_at: <ISO-8601>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Capture
|
|
10
|
+
|
|
11
|
+
## 捕获计划
|
|
12
|
+
|
|
13
|
+
- **目标 repo:** `owner/repo`
|
|
14
|
+
- **origin:** local
|
|
15
|
+
- **排除 id:** 无 / `<YYYY-MM-DD-slug>`
|
|
16
|
+
- **确认记录:** 无 / 本次授权时间与操作员
|
|
17
|
+
|
|
18
|
+
capture 不创建 Change,不写 `current_work`,不关闭 Issue。GitHub 是 inbox,不是开发权威。
|
|
19
|
+
|
|
20
|
+
## 账本
|
|
21
|
+
|
|
22
|
+
| id | kind | title | labels | number | url | marker | sha256 | state |
|
|
23
|
+
|---|---|---|---|---|---|---|---|---|
|
|
24
|
+
| 2026-09-17-login-timeout | bug | bug: login timeout on empty session | bug, specdev:captured, origin:local | — | — | specdev:capture:2026-09-17-login-timeout | — | planned |
|
|
25
|
+
|
|
26
|
+
`state`:`planned | open | skipped:duplicate | intaken | waived | failed`。
|
|
27
|
+
|
|
28
|
+
`sha256` 覆盖实际发出的 Issue 正文。漂移只警告,不自动重发。
|
|
29
|
+
|
|
30
|
+
## 计数
|
|
31
|
+
|
|
32
|
+
- **inbox_open:** 0
|
|
33
|
+
- **inbox_intaken:** 0
|
|
34
|
+
- **inbox_waived:** 0
|
|
35
|
+
- **skipped:** 0
|
|
36
|
+
- **failed:** 0
|
|
37
|
+
|
|
38
|
+
计数权威是本文件,不是 GitHub 搜索。`inbox_open` 不计 `published_issues`。
|
|
39
|
+
|
|
40
|
+
## 重试
|
|
41
|
+
|
|
42
|
+
无 / 失败行的已完成步骤和下一步。已成功的记录不回滚。
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
- locator 相同但 hash 不同:展示漂移,不覆盖原快照;只有用户确认后才创建新 change,并在新 source 中记录 `supersedes_source`;
|
|
17
17
|
- 没有稳定 locator:按用户指定 change 或新 change 继续。
|
|
18
18
|
|
|
19
|
+
若 `<Path>{roots.state}/specdev/capture.md</Path>` 存在,且某行 `url` 或 marker 对应当前 `canonical_locator`:将该行标为 `intaken`。不得把多条 capture 行合并进同一个 source。默认一条 capture 记录对应一次未来 intake / 一个 Change。相关但目标不清时先走 `<Path>{roots.workflows}/specdev/W-wayfinder/W-wayfinder.md</Path>`。缺失捕获账本不影响 intake。
|
|
20
|
+
|
|
19
21
|
同时只读扫描永久 ADR、archive 中已关闭的同类请求和当前 active change 标题。发现概念相似项时向用户展示路径与一句话理由,询问是否仍要继续。不自动 wontfix,不新建 `.out-of-scope/` 目录。
|
|
20
22
|
|
|
21
23
|
## 3. 冻结内容
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Captured Record 正文模板
|
|
2
|
+
|
|
3
|
+
capture 创建仍 open 的 GitHub Issue 时使用。先套 `<Path>{roots.workflows}/specdev/T-triage/references/public-projection.md</Path>` 脱敏,再填本模板。占位符不得把 state Path 带出去。现在时;不写「请去实现」。
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
> *This was generated by AI during SpecDev T-triage capture.*
|
|
7
|
+
|
|
8
|
+
## Captured Record
|
|
9
|
+
|
|
10
|
+
**Category:** <bug | feature | refactor | investigation | operations | documentation | review>
|
|
11
|
+
**Origin:** local
|
|
12
|
+
**Status:** inbox, open; not a development ticket
|
|
13
|
+
|
|
14
|
+
**Summary:** <一句话,现在要记下的事实或意图。>
|
|
15
|
+
|
|
16
|
+
**Observed / intended:**
|
|
17
|
+
<现在观察到什么、想记下什么。写「现在怎样 / 想记下什么」,不写「去改哪个文件」,不写派工祈使句。>
|
|
18
|
+
|
|
19
|
+
**Why parked:**
|
|
20
|
+
<为什么先记到 GitHub、还不进 Change。>
|
|
21
|
+
|
|
22
|
+
**Out of scope for this record:**
|
|
23
|
+
<本条不决定的事项;没有则写「无」。本条默认对应一次未来 intake / 一个未来 Change。>
|
|
24
|
+
|
|
25
|
+
**Provenance:**
|
|
26
|
+
- Marker: `specdev:capture:<YYYY-MM-DD-slug>`
|
|
27
|
+
```
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Classification Map
|
|
2
2
|
|
|
3
|
-
T-triage 本地分类与 GitHub type 标签的对照。publish 只打本表允许的标签;intake 仍把 8 值写在 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`,v1 不回写源 Issue。
|
|
3
|
+
T-triage 本地分类与 GitHub type 标签的对照。publish 与 capture 只打本表允许的标签;intake 仍把 8 值写在 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>`,v1 不回写源 Issue。
|
|
4
4
|
|
|
5
5
|
## SpecDev 分类
|
|
6
6
|
|
|
7
7
|
Change 级 `classification`:`bug | feature | refactor | investigation | operations | documentation | review | mixed`。
|
|
8
8
|
|
|
9
|
-
票级 `kind` 与上相同,去掉 `mixed`。缺省合法:publish 时继承 Change 分类;Change 为 `mixed` 时确认表必须给出每张纳入票的 `kind`。
|
|
9
|
+
票级 `kind` 与上相同,去掉 `mixed`。缺省合法:publish 时继承 Change 分类;Change 为 `mixed` 时确认表必须给出每张纳入票的 `kind`。capture 每条记录必须自带 `kind`,禁止 `mixed`。
|
|
10
10
|
|
|
11
11
|
## GitHub type 标签
|
|
12
12
|
|
|
@@ -23,13 +23,14 @@ Change 级 `classification`:`bug | feature | refactor | investigation | operat
|
|
|
23
23
|
| `review` | `enhancement` | — | `review:` |
|
|
24
24
|
| `mixed` | 禁止直接发布 | 拆到票级 `kind` | — |
|
|
25
25
|
|
|
26
|
-
每个已发布 Issue 恰好一个 type 标签(`refactor` 的额外 `refactor` 不算第二 type)。
|
|
26
|
+
每个已发布 Issue 恰好一个 type 标签(`refactor` 的额外 `refactor` 不算第二 type)。capture 的 inbox Issue 同样恰好一个 type 标签。
|
|
27
27
|
|
|
28
28
|
## 固定附加标签
|
|
29
29
|
|
|
30
|
-
- `specdev:published
|
|
31
|
-
- `
|
|
32
|
-
-
|
|
30
|
+
- `specdev:published`:publish 计数与去重。不得打到 capture 的 inbox Issue。
|
|
31
|
+
- `specdev:captured`:capture inbox 计数与去重。不得打到 publish 的票 Issue 或父索引。与 `specdev:published` 互斥。
|
|
32
|
+
- `origin:local` 或 `origin:intake`:来源。本地对话/粘贴/项目文件为 `local`;冻结自 GitHub Issue/PR 为 `intake`。capture 固定 `origin:local`。
|
|
33
|
+
- 父 Change 索引 Issue 另打 `specdev:change`。`mixed` 的父 Issue 不打 type。capture 不得打 `specdev:change`。
|
|
33
34
|
|
|
34
35
|
## 可选标签
|
|
35
36
|
|
|
@@ -38,11 +39,11 @@ Change 级 `classification`:`bug | feature | refactor | investigation | operat
|
|
|
38
39
|
|
|
39
40
|
## 禁止标签
|
|
40
41
|
|
|
41
|
-
不得打到自发布 Issue
|
|
42
|
+
不得打到自发布 Issue、父索引或 capture inbox Issue 上:
|
|
42
43
|
|
|
43
44
|
`needs-triage`、`needs-info`、`ready-for-agent`、`ready-for-human`、`wontfix`、`duplicate`、`invalid`、`stale`。
|
|
44
45
|
|
|
45
|
-
cancelled
|
|
46
|
+
cancelled 票若被纳入 publish,使用 close reason `not_planned`,不打 `wontfix`。
|
|
46
47
|
|
|
47
48
|
## 标题
|
|
48
49
|
|
|
@@ -50,4 +51,4 @@ cancelled 票若被纳入,使用 close reason `not_planned`,不打 `wontfix`
|
|
|
50
51
|
<前缀> <ticket.title>
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
不把内部 id `T-01` 写入标题。内部 id 只出现在正文 Provenance 和 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>`。
|
|
54
|
+
不把内部 id `T-01` 写入标题。内部 id 只出现在正文 Provenance 和 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>`。capture 标题同样不加内部 id;capture id 只出现在正文 Provenance 和 `<Path>{roots.state}/specdev/capture.md</Path>`。
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Public Projection
|
|
2
2
|
|
|
3
|
-
T-triage 远程正文的脱敏与耐久规则。intake 不写远程。reconcile
|
|
3
|
+
T-triage 远程正文的脱敏与耐久规则。intake 不写远程。reconcile 关闭评论、publish 的 Issue 正文 / 关闭评论、以及 capture 的 inbox Issue 正文都遵守本文件。
|
|
4
4
|
|
|
5
5
|
## Disclaimer
|
|
6
6
|
|
|
7
|
-
每条远程 Issue
|
|
7
|
+
每条远程 Issue 正文和评论必须以这一行开头。publish:
|
|
8
8
|
|
|
9
9
|
```markdown
|
|
10
10
|
> *This was generated by AI during SpecDev T-triage publish.*
|
|
@@ -16,8 +16,16 @@ reconcile 关闭评论把 `publish` 换成 `reconcile`:
|
|
|
16
16
|
> *This was generated by AI during SpecDev T-triage reconcile.*
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
capture inbox 正文把 `publish` 换成 `capture`:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
> *This was generated by AI during SpecDev T-triage capture.*
|
|
23
|
+
```
|
|
24
|
+
|
|
19
25
|
## 允许写入远程的字段
|
|
20
26
|
|
|
27
|
+
publish / reconcile(过去时):
|
|
28
|
+
|
|
21
29
|
- 已发生的行为与验收(过去时)
|
|
22
30
|
- 可公开 commit / PR URL
|
|
23
31
|
- 验证结论:定向 / 回归 / E2E 是否跑过、是否通过;未跑时一句原因
|
|
@@ -26,6 +34,13 @@ reconcile 关闭评论把 `publish` 换成 `reconcile`:
|
|
|
26
34
|
- `Part of #<n>` / `Blocked by #<n>`
|
|
27
35
|
- cancelled 原因:`cancelled-already-implemented`(指到已有公开位置)或 `cancelled-out-of-scope`(指到 ADR / 用户决定)
|
|
28
36
|
|
|
37
|
+
capture(现在时):
|
|
38
|
+
|
|
39
|
+
- 现在观察到的现象或想记下的意图(现在时)
|
|
40
|
+
- 分类、`origin:local`、capture id、marker
|
|
41
|
+
- 为什么先停在 inbox、还不进 Change
|
|
42
|
+
- 本条明确不决定的事项
|
|
43
|
+
|
|
29
44
|
项目相对路径只在描述公开模块边界时允许,并注明「当时路径,可能已变」。
|
|
30
45
|
|
|
31
46
|
## 禁止写入远程
|
|
@@ -37,11 +52,11 @@ reconcile 关闭评论把 `publish` 换成 `reconcile`:
|
|
|
37
52
|
- 「请 agent 去实现」的祈使句
|
|
38
53
|
- 文件行号
|
|
39
54
|
|
|
40
|
-
关闭评论是 Evidence 的公共投影,不是副本。不得把 Evidence 原文贴出去。
|
|
55
|
+
关闭评论是 Evidence 的公共投影,不是副本。不得把 Evidence 原文贴出去。capture 没有关闭评论。
|
|
41
56
|
|
|
42
57
|
## 最低关闭评论
|
|
43
58
|
|
|
44
|
-
|
|
59
|
+
即使脱敏后也必须保留(仅 reconcile / publish):
|
|
45
60
|
|
|
46
61
|
1. 结果一句话(通过 / 取消原因)
|
|
47
62
|
2. 公开 commit 或 PR URL;没有则写「无公开 commit/PR」
|
|
@@ -64,3 +79,11 @@ specdev:<change>:publish-index
|
|
|
64
79
|
```
|
|
65
80
|
|
|
66
81
|
reconcile 源 Issue 仍用 `specdev:<change>:completion`,与 publish marker 互不替代。
|
|
82
|
+
|
|
83
|
+
capture inbox:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
specdev:capture:<YYYY-MM-DD-slug>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
只写入 Issue 正文 Provenance。Issue 保持 open。与 `specdev:published` / `specdev:<change>:completion` 互不替代。
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aggregate inbox counts from the workspace-owned capture.md ledger.
|
|
4
|
+
* Local file is authoritative; this tool does not query GitHub.
|
|
5
|
+
* Missing capture.md is legal and counts as an empty inbox.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
|
|
11
|
+
const OPEN = "open";
|
|
12
|
+
const INTAKEN = "intaken";
|
|
13
|
+
const WAIVED = "waived";
|
|
14
|
+
const SKIPPED = new Set(["skipped:duplicate"]);
|
|
15
|
+
|
|
16
|
+
function parseFrontmatter(text) {
|
|
17
|
+
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
18
|
+
if (!match) return {};
|
|
19
|
+
const meta = {};
|
|
20
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
21
|
+
const idx = line.indexOf(":");
|
|
22
|
+
if (idx === -1) continue;
|
|
23
|
+
meta[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
24
|
+
}
|
|
25
|
+
return meta;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseLedgerStates(body) {
|
|
29
|
+
const rows = [];
|
|
30
|
+
for (const line of body.split(/\r?\n/)) {
|
|
31
|
+
if (!/^\|/.test(line) || /^\|\s*-+/.test(line) || /^\|\s*id\s*\|/i.test(line)) continue;
|
|
32
|
+
const cells = line.split("|").map((c) => c.trim()).filter((_, i, arr) => i > 0 && i < arr.length - 1);
|
|
33
|
+
if (cells.length < 9) continue;
|
|
34
|
+
rows.push({
|
|
35
|
+
id: cells[0],
|
|
36
|
+
kind: cells[1],
|
|
37
|
+
state: cells[8],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return rows;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function summarize(stateRoot) {
|
|
44
|
+
const file = join(stateRoot, "capture.md");
|
|
45
|
+
if (!existsSync(file)) {
|
|
46
|
+
return {
|
|
47
|
+
inbox_open: 0,
|
|
48
|
+
inbox_intaken: 0,
|
|
49
|
+
inbox_waived: 0,
|
|
50
|
+
inbox_skipped: 0,
|
|
51
|
+
inbox_failed: 0,
|
|
52
|
+
records: 0,
|
|
53
|
+
missing: true,
|
|
54
|
+
ledger: null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const text = readFileSync(file, "utf8");
|
|
59
|
+
const meta = parseFrontmatter(text);
|
|
60
|
+
const body = text.replace(/^---[\s\S]*?---/, "");
|
|
61
|
+
const rows = parseLedgerStates(body);
|
|
62
|
+
let inbox_open = 0;
|
|
63
|
+
let inbox_intaken = 0;
|
|
64
|
+
let inbox_waived = 0;
|
|
65
|
+
let inbox_skipped = 0;
|
|
66
|
+
let inbox_failed = 0;
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
if (row.state === OPEN) inbox_open += 1;
|
|
69
|
+
else if (row.state === INTAKEN) inbox_intaken += 1;
|
|
70
|
+
else if (row.state === WAIVED) inbox_waived += 1;
|
|
71
|
+
else if (SKIPPED.has(row.state)) inbox_skipped += 1;
|
|
72
|
+
else if (row.state === "failed") inbox_failed += 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
inbox_open,
|
|
77
|
+
inbox_intaken,
|
|
78
|
+
inbox_waived,
|
|
79
|
+
inbox_skipped,
|
|
80
|
+
inbox_failed,
|
|
81
|
+
records: rows.length,
|
|
82
|
+
missing: false,
|
|
83
|
+
ledger: file,
|
|
84
|
+
repo: meta.repo || null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function usage() {
|
|
89
|
+
console.error("Usage: node capture-status.mjs --state-root <specdev-state-root> [--json]");
|
|
90
|
+
process.exit(2);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function main(argv) {
|
|
94
|
+
let stateRoot = null;
|
|
95
|
+
let json = false;
|
|
96
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
97
|
+
if (argv[i] === "--state-root") {
|
|
98
|
+
stateRoot = argv[i + 1];
|
|
99
|
+
i += 1;
|
|
100
|
+
} else if (argv[i] === "--json") {
|
|
101
|
+
json = true;
|
|
102
|
+
} else {
|
|
103
|
+
usage();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!stateRoot) usage();
|
|
107
|
+
const summary = summarize(stateRoot);
|
|
108
|
+
if (json) {
|
|
109
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
const missing = summary.missing ? " (missing ledger, empty inbox)" : "";
|
|
113
|
+
console.log(`inbox_open: ${summary.inbox_open}${missing}`);
|
|
114
|
+
console.log(`inbox_intaken: ${summary.inbox_intaken}`);
|
|
115
|
+
console.log(`inbox_waived: ${summary.inbox_waived}`);
|
|
116
|
+
console.log(`inbox_skipped: ${summary.inbox_skipped}`);
|
|
117
|
+
console.log(`inbox_failed: ${summary.inbox_failed}`);
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
122
|
+
process.exit(main(process.argv.slice(2)));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { summarize };
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
- 来源快照:`<Path>{roots.workflows}/specdev/common/schemas/source.schema.json</Path>`
|
|
41
41
|
- 分诊:`<Path>{roots.workflows}/specdev/common/schemas/triage.schema.json</Path>`
|
|
42
42
|
- 发布账本:`<Path>{roots.workflows}/specdev/common/schemas/publish.schema.json</Path>`
|
|
43
|
+
- 捕获账本:`<Path>{roots.workflows}/specdev/common/schemas/capture.schema.json</Path>`
|
|
43
44
|
- 诊断:`<Path>{roots.workflows}/specdev/common/schemas/diagnosis.schema.json</Path>`
|
|
44
45
|
- 代码审查:`<Path>{roots.workflows}/specdev/common/schemas/code-review.schema.json</Path>`
|
|
45
46
|
- UI 设计包:`<Path>{roots.workflows}/specdev/P-prototype/design-package.schema.json</Path>`
|
|
@@ -9,6 +9,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
|
|
|
9
9
|
| 来源快照 | `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` | 原始请求、捕获时间、locator、hash 和关闭能力 | 当前产品合同或实现状态 |
|
|
10
10
|
| 分诊 | `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>` | 请求类别、影响、风险、缺失输入、下一 work、源 Issue reconcile 状态和 publish_action | 详细实现方案、开发进度或票级发布账本 |
|
|
11
11
|
| 发布账本 | `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>` | 票级 GitHub 投影的编号、标签、marker、state 和发布计数 | Ticket 契约、Evidence 原文或源 Issue 关闭 |
|
|
12
|
+
| 捕获账本 | `<Path>{roots.state}/specdev/capture.md</Path>` | 尚未成 Change 的记事项、GitHub inbox 编号、标签、marker 和 inbox 计数;缺失合法 | Change、Ticket、Evidence 或已完成票的发布投影 |
|
|
12
13
|
| 诊断 | `<Path>{roots.state}/specdev/changes/{change}/diagnosis.md</Path>` | 复现、证据、根因、修复不变量和回归契约 | 未经验证的修复实现 |
|
|
13
14
|
| 设计日志 | `<Path>{roots.state}/specdev/changes/{change}/LOG.md</Path>` | 讨论轨迹、确认、延后、替代与废弃结论 | 当前架构权威摘要 |
|
|
14
15
|
| 设计树 | `<Path>{roots.state}/specdev/changes/{change}/design-tree.json</Path>` | 决策节点、依赖、当前 frontier、轮次与共识状态 | 领域真相或架构决定正文 |
|
|
@@ -51,7 +52,7 @@ Change CONTEXT/ADR 是 active change 内的执行权威,不是 workflow 级永
|
|
|
51
52
|
|
|
52
53
|
当前 change 决定与永久知识冲突时,必须在 LOG/ADR 中显式说明替代关系;它只约束当前 change,直到 A 决定是否提升并更新永久版本。
|
|
53
54
|
|
|
54
|
-
`<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` 只对“原始输入是什么”具有权威;后续用户决定、ADR 和 Spec 可以显式演进该意图。远程来源在摄入后发生变化不会自动改写本地合同,必须重新 Triage。GitHub 上由 publish 投影出的 Issue 不是开发权威;发布计数以 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>` 为准。
|
|
55
|
+
`<Path>{roots.state}/specdev/changes/{change}/source.md</Path>` 只对“原始输入是什么”具有权威;后续用户决定、ADR 和 Spec 可以显式演进该意图。远程来源在摄入后发生变化不会自动改写本地合同,必须重新 Triage。GitHub 上由 publish 投影出的 Issue 不是开发权威;发布计数以 `<Path>{roots.state}/specdev/changes/{change}/publish.md</Path>` 为准。GitHub 上由 capture 记下的 inbox Issue 也不是开发权威;inbox 计数以 `<Path>{roots.state}/specdev/capture.md</Path>` 为准,缺失该文件视为空 inbox。
|
|
55
56
|
|
|
56
57
|
代码事实可以证明计划已过时,但不能静默改写用户目标或已接受契约。出现这种情况时,按 `<Path>{roots.workflows}/specdev/common/rules/deviation-control.md</Path>` 退回相应工件修订。
|
|
57
58
|
|