@hupan56/wlkj 3.1.3 → 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/templates/qoder/commands/optional/wl-insight.md +1 -1
  3. package/templates/qoder/commands/optional/wl-report.md +2 -2
  4. package/templates/qoder/commands/optional/wl-status.md +1 -1
  5. package/templates/qoder/commands/wl-code.md +1 -1
  6. package/templates/qoder/commands/wl-design.md +2 -0
  7. package/templates/qoder/commands/wl-init.md +1 -1
  8. package/templates/qoder/commands/wl-prd.md +4 -0
  9. package/templates/qoder/commands/wl-req.md +3 -0
  10. package/templates/qoder/commands/wl-search.md +2 -0
  11. package/templates/qoder/commands/wl-task.md +1 -1
  12. package/templates/qoder/commands/wl-test.md +1 -1
  13. package/templates/qoder/contracts/CHANGELOG.md +418 -0
  14. package/templates/qoder/contracts/README.md +184 -0
  15. package/templates/qoder/contracts/code.md +81 -0
  16. package/templates/qoder/contracts/commit.md +86 -0
  17. package/templates/qoder/contracts/contract-header.md +76 -0
  18. package/templates/qoder/contracts/design.md +106 -0
  19. package/templates/qoder/contracts/fallback.md +126 -0
  20. package/templates/qoder/contracts/isolation.md +119 -0
  21. package/templates/qoder/contracts/prd.md +118 -0
  22. package/templates/qoder/contracts/schemas/design-spec.schema.json +46 -0
  23. package/templates/qoder/contracts/schemas/prd.schema.json +36 -0
  24. package/templates/qoder/contracts/schemas/test-cases.schema.json +40 -0
  25. package/templates/qoder/contracts/spec.md +81 -0
  26. package/templates/qoder/contracts/task.md +125 -0
  27. package/templates/qoder/contracts/test.md +112 -0
  28. package/templates/qoder/scripts/deployment/setup/repo_root.py +17 -4
  29. package/templates/qoder/scripts/validation/test/autotest.py +3 -0
  30. package/templates/qoder/scripts/validation/test/autotest_data.py +3 -1
  31. package/templates/qoder/skills/wl-prd-full/SKILL.md +50 -50
@@ -0,0 +1,119 @@
1
+ # 隔离与并发安全契约(ISOLATION)
2
+
3
+ > 回答团队最关心的三个问题:**我能不能改到别人的任务?同步会不会覆盖别人的工作?禅道同步会不会拉错/推错?**
4
+ > 本文件是这些保证的**单一事实源**。实现见 `task_utils.py` / `team_sync.py` / `syncgate.py`。
5
+
6
+ ---
7
+
8
+ ## TL;DR(给 PM 的 3 句话)
9
+
10
+ 1. **本地任务**:你只能改自己创建/被指派的任务,别人的任务 ACL 直接拒绝(返回 4)——改不到。
11
+ 2. **team_sync 同步**:push 只暂存白名单路径(workspace/data/docs/data/index)+ 安全扩展名,pull 用 autostash 保护你的本地改动——正常不丢不覆盖。
12
+ 3. **禅道同步**:禅道是**团队共享账号**,server 层不区分谁在操作 → **必须靠 assignedTo 归属过滤**,否则会拉到/覆盖队友任务。见下文「禅道同步」红线。
13
+
14
+ ---
15
+
16
+ ## 一、本地任务隔离(已实现,强保证)
17
+
18
+ ### 1.1 任务存储:团队共享 + 字段隔离
19
+
20
+ - 任务文件 `workspace/tasks/{MM-DD-slug}/task.json` 是**团队共享目录**,push 后全队可见。
21
+ - 隔离**不靠物理分目录**,靠 task.json 里的 `creator` / `assignee` 字段 + ACL 校验。
22
+ - 真正「个人隔离」的只有:个人草稿产出(`workspace/members/{dev}/`)、活跃任务指针(`.runtime/current-task.{dev}` 按开发者命名)、私有凭证(`.private/`)。
23
+
24
+ ### 1.2 ACL:谁能改一个任务
25
+
26
+ | 操作 | 谁能做 |
27
+ |------|--------|
28
+ | create(新建) | 任何人(新任务归属创建者,assignee 默认=创建者) |
29
+ | start / finish / archive / reassign / set-due / block / 子任务 | **仅** `creator ∪ assignee ∪ admin` |
30
+ | list / 查看所有人任务 | 任何人(产品要看全局排期);`--mine` 才过滤只看自己 |
31
+
32
+ - 实现:`task_utils.py` `assert_can_modify_task`。非归属人操作一律返回退出码 **4(权限拒绝)**。
33
+ - 所有变更命令都过此校验:`task_lifecycle.py`(create 除外)/ `task_relations.py` 全部写操作。
34
+
35
+ ### 1.3 并发读改写:每任务一把锁
36
+
37
+ - `modify_task_json` 在文件锁 `task_dir/.task.lock` 内完成 load→改→write,**原子**。
38
+ - 锁竞争超时**不降级为无锁写**——宁可失败也不丢更新。
39
+ - 写入是原子操作(temp 文件 + `os.replace`),最坏情况是「半写」,不会产生损坏的 JSON。
40
+ - **结论**:两个 PM 同时改同一个任务的不同字段(一个改 status、一个改 due)→ 不丢更新。
41
+
42
+ ### 1.4 已知边界(低风险,记录在案)
43
+
44
+ - `archive`(整目录移动)与并发写同一任务:ACL 先挡非归属人;归属人之间的极端时序靠 OS 文件系统兜底,最坏是「改完的内容随目录进了 archive」,不损坏但可能「以为没生效」。
45
+ - `list`(无 `--mine`)能看到所有人的任务——这是**有意设计**(产品看全局),不是隔离漏洞。
46
+
47
+ ---
48
+
49
+ ## 二、team_sync 同步(已实现,强保证)
50
+
51
+ ### 2.1 push:只推白名单 + 安全扩展名 + 串行锁
52
+
53
+ - **路径白名单**(`SYNC_SCOPES`):只 `workspace` / `data/docs` / `data/index` 三个 scope。
54
+ - **扩展名白名单**(`SAFE_EXTENSIONS`):仅 `.md .html .json .jsonl .yaml .yml .toml .txt .csv .svg`。`.env .zip .docx` 等一律拒绝并打印跳过警告。
55
+ - **绝不** `git add -A`;改为逐 scope + 扩展名过滤的批量 add(每批 400 个)。
56
+ - **全局串行锁** `team-sync.lock`(push 与 pull 共用),同一时刻只有一个同步在跑。
57
+ - **零信任门禁**(commit 前):身份强制 + git 作者与注册身份一致 + 秘密扫描 + REQ-ID 撞号校验 + 平台标注 + EVA 质量门禁(≥80%)。任一失败 `git reset HEAD` 撤销暂存。
58
+
59
+ > 各人产出在 `members/{自己}/` 物理隔离:A push 会把 `members/B/` 也推上去,但路径不冲突,不会覆盖 B 的内容。
60
+
61
+ ### 2.2 pull:autostash 保护本地改动 + 冲突安全回退
62
+
63
+ - `git pull --rebase --autostash`:本地未提交改动先 stash,rebase 完再 pop——**正常不丢**。
64
+ - 冲突时(`SYNC_CONFLICT` 标记 + 退出码 3):自动 `git rebase --abort` + 尝试恢复 stash + 输出 6 步 AI 指南。**绝不要求用户自己跑 git**(CRITICAL RULE #3)。
65
+ - `kg.duckdb` 二进制冲突有专门自动解决(取 `built_at` 更新的版本)。
66
+
67
+ ### 2.3 已知边界
68
+
69
+ - `--autostash` 的 stash pop 本身也可能冲突(典型:两个 PM 同日改同一份共享索引)。此情况**数据不丢**(还在 stash 里),但需 AI/人工介入 `git stash pop`。
70
+ - 没有「本地有未提交改动就先警告再 pull」的预检——直接 autostash,靠 git 兜底。
71
+
72
+ ---
73
+
74
+ ## 三、禅道同步(共享账号 — 红线区,需重点遵守)
75
+
76
+ > ⚠️ 禅道 MCP 是**团队共享账号**(`.qoder/config.yaml` 的 `zentao.user`),server 层无法区分「这次操作是哪个本地开发者发起的」。
77
+ > 这是拉错/推错风险的**唯一来源**。
78
+
79
+ ### 3.1 红线(违反 = 可能污染/覆盖队友)
80
+
81
+ | 方向 | 红线 | 正确做法 |
82
+ |------|------|---------|
83
+ | 拉取(禅道→本地) | ❌ 直接 `list_execution_tasks` 不过滤 → 拉到全队任务写进本地 | ✅ **强制** `assignedTo == 当前开发者禅道账号` 过滤 |
84
+ | 推送(本地→禅道) | ❌ 批量盲推 create/update → 覆盖同名队友任务 | ✅ **默认 `--dry-run`** + 仅推 `creator==我` 的 + 禅道同名任务 assignedTo 须一致才更新 |
85
+ | create | ❌ 用共享账号把任务派给别人 | ✅ 强制 `assignedTo = 当前开发者` |
86
+ | 幂等 | ❌ 重复 create 同一任务 | ✅ task.json 的 `zentao_id` 字段做主键,已有则跳过 |
87
+
88
+ ### 3.2 归属字段对照(实现 zentao_sync 的依据)
89
+
90
+ | 字段 | 用途 | 能否区分「我的 vs 别人的」 |
91
+ |------|------|------------------------|
92
+ | `assignedTo`(指派人) | 禅道任务核心归属字段 | ✅ **最可靠,拉取主过滤以此为准** |
93
+ | `openedBy`(创建人) | 谁建的(改派后不变) | ⚠️ 辅助,语义不同 |
94
+ | `account` | 工时记录字段(list_effort) | ❌ 不是任务归属,别用 |
95
+
96
+ ### 3.3 本地 developer ↔ 禅道 account 映射
97
+
98
+ - 本地 developer 名(如 `hupan56`)与禅道 account(如 `hupan`)**不一致**,需映射表。
99
+ - 映射存于 member 注册信息(`zentao_account` 字段)。同步前先解析当前 developer → 禅道 account,再用 account 做过滤。
100
+ - **无映射 = 拒绝同步**(宁可不同步也不猜,避免拉错)。
101
+
102
+ ---
103
+
104
+ ## 四、违反契约的症状与自检
105
+
106
+ | 症状 | 含义 | 自检/恢复 |
107
+ |------|------|----------|
108
+ | 退出码 **4** | ACL 权限拒绝 | 你不是该任务的 creator/assignee/admin,确认是否选错任务 |
109
+ | 退出码 **3(SYNC_CONFLICT)** | 同步冲突 | AI 接 `team_sync.py` 输出的 6 步指南解决,无需用户碰 git |
110
+ | 退出码 **2(SYNC_BUSY)** | 同步锁竞争 | 等 5 分钟(stale_seconds=300)或确认无其它同步在跑 |
111
+ | `task.json.corrupt.<ts>` 出现 | task.json 曾损坏 | 已自动备份,原文件清空等重建;查 stderr 告警定位原因 |
112
+
113
+ ---
114
+
115
+ ## 五、修改本契约的规则
116
+
117
+ - 本文件描述的保证**靠代码实现**(`task_utils.py` ACL/锁、`team_sync.py` 同步、`syncgate.py` 门禁、`zentao_sync.py` 归属过滤)。
118
+ - 若改了相关代码的行为,**必须同步更新本文件**,否则契约与实现脱节。
119
+ - 新增任何「多人共享数据」的操作(新命令、新脚本),都必须在本文件登记其隔离机制。
@@ -0,0 +1,118 @@
1
+ # 模块契约:prd(需求)
2
+
3
+ > 产品模块。从「一句话」到「可发布的 PRD + 原型」。
4
+ > 这是**最上游的契约源**,下游 design/spec/task/test 都靠它。
5
+
6
+ ---
7
+
8
+ ## Input(吃什么)
9
+
10
+ | 优先级 | 输入 | 怎么用 |
11
+ |--------|------|--------|
12
+ | **完整** | 业务需求描述 + 平台 | `context_pack.py <词> --platform <web\|app>` 取上下文 |
13
+ | 降级 1 | 只有业务描述,没指定平台 | **必须先问平台**(见铁律),不许跳过 |
14
+ | 降级 2 ★ | 用户一句话口语需求 | 跑 context_pack + search_index --prd 自补上下文 |
15
+ | 参考 | 现有页面 / 字段 / API | 来自 context_pack 的 7 段输出,不强依赖 |
16
+
17
+ **平台是硬约束**:Web=fywl-ui / APP=Carmg-H5 / both。没定平台不许开干。
18
+
19
+ ---
20
+
21
+ ## Output(吐什么)
22
+
23
+ ### 主产物:PRD 草稿
24
+
25
+ ```
26
+ 路径:workspace/members/{developer}/drafts/REQ-{YYYY}-{NNN}-{标题}.md
27
+ 命名:REQ-ID 由 common/reqid.py 的 allocate_req_id() 原子分配
28
+ ```
29
+
30
+ **第一行必须是契约头**(软契约,缺了只警告):
31
+
32
+ ```markdown
33
+ <!-- @contract prd v1
34
+ platform: web|app|both
35
+ req-id: REQ-2025-0042
36
+ title: 保单批改功能
37
+ mode: full|quick|reference|brainstorm|planning
38
+ # brainstorm/planning 已随探索能力迁至 /wl-insight,PRD 不再主动产出这两个模式。
39
+ # 保留枚举是为了向后兼容旧 PRD(eval_prd 仍能识别)。新 PRD 只用 quick/reference。
40
+ acceptance: [验收点1, 验收点2]
41
+ source: context_pack:保单批改,web
42
+ -->
43
+ ```
44
+
45
+ ### 副产物:原型
46
+
47
+ ```
48
+ 单端:workspace/members/{developer}/drafts/prototype-{feature}.html
49
+ 两端:...prototype-{feature}-web.html + ...prototype-{feature}-app.html
50
+ ```
51
+
52
+ ### 归档(自动)
53
+
54
+ ```
55
+ 归档副本:workspace/members/{dev}/archive/{YYYY-MM-DD}/REQ-*.md(只复制不移动)
56
+ ```
57
+
58
+ ### 发布
59
+
60
+ ```
61
+ 发布后:git_sync.py 的 collect_prds() 把草稿拷到 data/docs/prd/REQ-*.md(立刻可搜)
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 必含字段骨架
67
+
68
+ ### full 模式(完整需求)— 13 章
69
+
70
+ 版本信息 / 变更日志 / 名词解释 / 需求背景 / 需求来源 / 产品现状 /
71
+ 需求范围 / 功能清单 / 字段规格 / 操作与校验 / 非功能性需求 / 埋点 / 版本计划
72
+
73
+ > **"版本计划"章节边界**:只写**本期排期**(本需求何时上线)。
74
+ > 长期 roadmap / 多版本路线图已归 `/wl-insight plan`,不在 PRD 内展开。
75
+ > PRD 聚焦"本次做什么",不背"未来规划"的职责。
76
+
77
+ ### quick 模式(零星需求)— 6 章
78
+
79
+ 功能入口 / 需求背景 / 需求说明 / 影响范围 / 验收标准 / 不在本次范围
80
+
81
+ > quick 模式整体跳过 EVA 门禁(用于快速出稿,不背完整质量责任)。
82
+
83
+ ---
84
+
85
+ ## 校验(唯一硬门禁)
86
+
87
+ ```bash
88
+ python .qoder/scripts/orchestration/wlkj.py eval <prd.md> [原型.html]
89
+ ```
90
+
91
+ | 维度 | 权重 | 检查内容 |
92
+ |------|------|----------|
93
+ | A1 现实锚定 | 40 分 | PRD 表格内 camelCase 字段、API 路径在索引命中比例 |
94
+ | A2 风格保真 | 30 分 | 原型颜色来自真源(无原型则跳过,满分降为 70) |
95
+ | A3 模板完整 | 30 分 | 章节齐全比例 |
96
+
97
+ **阈值:≥ 80% 才 PASS**(`PASS_THRESHOLD = 80.0`)。结果追加到 `data/learning/eval-history.jsonl`。
98
+
99
+ > full 模式无原型时满分 70,实际过线需 `A1+A3 ≥ 56`。
100
+ > **这是整个工作流唯一的硬门禁**——因为 prd 是契约源头,源头不靠谱全链路歪。
101
+
102
+ ---
103
+
104
+ ## 与下游的接口
105
+
106
+ | 下游模块 | 消费 prd 的什么 |
107
+ |----------|----------------|
108
+ | design | 验收标准里的界面相关点 + 平台 |
109
+ | task | 功能清单 → 拆任务 |
110
+ | spec | 全文,尤其是字段规格 + 操作校验 |
111
+ | test | `acceptance` 列表 → 测试用例 |
112
+
113
+ ---
114
+
115
+ ## 现状提醒
116
+
117
+ - ✅ eval_prd.py 已存在,校验可跑。
118
+ - ⚠️ quick 模式跳过 EVA,可能产出质量较低的契约。下游拿到 quick PRD 时应留意。
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "qoder://contract/design-spec",
4
+ "title": "Design Spec 契约 (设计师规格)",
5
+ "description": "设计师从 Figma/Axure 录入的规格。优先级 > 代码风格 > PDF 规范。最适合 schema 化的契约 (纯 JSON 产物)。",
6
+ "type": "object",
7
+ "required": ["_contract", "design_tokens", "layout", "components"],
8
+ "properties": {
9
+ "_contract": {
10
+ "type": "object",
11
+ "required": ["type", "version", "platform", "requirement"],
12
+ "properties": {
13
+ "type": { "const": "design-spec" },
14
+ "version": { "type": "integer", "minimum": 1 },
15
+ "platform": { "type": "string", "enum": ["web", "app", "both"] },
16
+ "requirement": { "type": "string", "description": "关联的需求名/REQ-ID" },
17
+ "source": { "type": "string", "description": "figma:截图 / lanhu:链接" }
18
+ }
19
+ },
20
+ "design_tokens": {
21
+ "type": "object",
22
+ "description": "配色/尺寸/字体/圆角等设计令牌",
23
+ "properties": {
24
+ "colors": { "type": "object" },
25
+ "spacing": { "type": "object" },
26
+ "fonts": { "type": "object" },
27
+ "radius": { "type": "object" }
28
+ }
29
+ },
30
+ "layout": {
31
+ "type": "object",
32
+ "description": "页面布局结构 (栅格/区块/导航)"
33
+ },
34
+ "components": {
35
+ "type": "array",
36
+ "description": "组件清单 (类型/props/状态)",
37
+ "items": { "type": "object" }
38
+ },
39
+ "icons": {
40
+ "type": "array",
41
+ "description": "图标清单 (禁止 emoji, web=AntDesign SVG / app=Vant)",
42
+ "items": { "type": "string" }
43
+ }
44
+ },
45
+ "additionalProperties": true
46
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "qoder://contract/prd",
4
+ "title": "PRD 契约 (产品需求文档)",
5
+ "description": "PRD 是最上游的契约源。下游 design/spec/task/test 都靠它。机器可校验版。",
6
+ "type": "object",
7
+ "required": ["type", "version", "req-id", "platform", "title", "acceptance"],
8
+ "properties": {
9
+ "type": { "const": "prd", "description": "契约类型标识" },
10
+ "version": { "type": "integer", "minimum": 1, "description": "契约版本, 未来演进用 (当前 v1)" },
11
+ "req-id": {
12
+ "type": "string",
13
+ "pattern": "^REQ-\\d{4}-\\d{3,}$",
14
+ "description": "需求编号, 贯穿全链路唯一 key, 由 reqid.py 原子分配"
15
+ },
16
+ "platform": {
17
+ "type": "string",
18
+ "enum": ["web", "app", "both"],
19
+ "description": "目标平台: web=fywl-ui / app=Carmg-H5 / both=两端"
20
+ },
21
+ "title": { "type": "string", "minLength": 2, "description": "需求标题" },
22
+ "acceptance": {
23
+ "type": "array",
24
+ "items": { "type": "string" },
25
+ "minItems": 1,
26
+ "description": "验收标准列表, 下游 test 据此生成用例"
27
+ },
28
+ "mode": {
29
+ "type": "string",
30
+ "enum": ["quick", "reference", "brainstorm", "planning"],
31
+ "description": "生成模式 (quick 零星需求, reference 完整档)"
32
+ },
33
+ "source": { "type": "string", "description": "来源: context_pack:词,平台 / manual" }
34
+ },
35
+ "additionalProperties": true
36
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "qoder://contract/test-cases",
4
+ "title": "Test Cases 契约 (测试用例集)",
5
+ "description": "从 PRD acceptance 或手动生成的测试用例。autotest 强依赖其结构。",
6
+ "type": "object",
7
+ "required": ["_contract", "cases"],
8
+ "properties": {
9
+ "_contract": {
10
+ "type": "object",
11
+ "required": ["type", "version"],
12
+ "properties": {
13
+ "type": { "const": "test-cases" },
14
+ "version": { "type": "integer", "minimum": 1 },
15
+ "platform": { "type": "string", "enum": ["web", "app", "both"] },
16
+ "req-id": {
17
+ "type": "string",
18
+ "pattern": "^REQ-\\d{4}-\\d{3,}$",
19
+ "description": "关联需求 (可空, 测试用例可能跨需求)"
20
+ }
21
+ }
22
+ },
23
+ "cases": {
24
+ "type": "array",
25
+ "minItems": 1,
26
+ "items": {
27
+ "type": "object",
28
+ "required": ["name", "intent"],
29
+ "properties": {
30
+ "name": { "type": "string", "description": "用例名" },
31
+ "intent": { "type": "string", "description": "测试意图/验收点" },
32
+ "anchor": { "type": "string", "description": "页面锚点 (定位用)" },
33
+ "steps": { "type": "array", "items": { "type": "string" } },
34
+ "expected": { "type": "string" }
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "additionalProperties": true
40
+ }
@@ -0,0 +1,81 @@
1
+ # 模块契约:spec(技术规格)
2
+
3
+ > 规格模块。把 PRD 翻译成开发能照着写的**技术契约**。
4
+ > 是 code 模块的最佳输入。
5
+
6
+ ---
7
+
8
+ ## Input(吃什么)
9
+
10
+ | 优先级 | 输入 | 怎么用 |
11
+ |--------|------|--------|
12
+ | **完整** | 一份已确认的 PRD(`data/docs/prd/REQ-*.md`) | 字段规格 + 操作校验 → 接口/数据结构 |
13
+ | 降级 1 | PRD 草稿(`drafts/REQ-*.md`) | 也能写 spec,标 `source: draft` |
14
+ | 参考 | 历史 Spec | `workspace/specs/` 看同类写法 |
15
+ | 参考 | 字段命名 | `search_index.py --field <字段名>` |
16
+ | 参考 | 数据字典 | `.qoder/context/data-dictionary.md`(不存在则跳过) |
17
+
18
+ **团队技术约定(写进 spec 的默认约束)**:
19
+ - 后端 Java:MyBatis Plus + RESTful + `BigDecimal` 金额 + JSR-303 校验 + `Result<T>`
20
+ - 表名 `t_{module}_{entity}`,全栈 Entity→Mapper→Service→Controller
21
+ - 不写 PRD 未定义的功能
22
+
23
+ ---
24
+
25
+ ## Output(吐什么)
26
+
27
+ ### 主产物:Spec 文件
28
+
29
+ ```
30
+ 路径:workspace/specs/REQ-{ID}-{module}.spec.md
31
+ (或任务目录 workspace/tasks/{task-id}/spec.md)
32
+ 命名:★ 统一为 REQ-{ID}-{module}.spec.md
33
+ ```
34
+
35
+ **契约头**:
36
+
37
+ ```markdown
38
+ <!-- @contract spec v1
39
+ source-req: REQ-2025-0042
40
+ platform: web
41
+ module: policy
42
+ endpoints: [POST /api/policy/amend, GET /api/policy/amend/{id}]
43
+ -->
44
+ ```
45
+
46
+ ### 骨架
47
+
48
+ 每条 PRD 验收标准 → 映射一个 Spec 测试用例。必须包含:
49
+
50
+ - 接口定义(路径 / 方法 / 入参 / 出参 / 错误码)
51
+ - 数据结构(表 / 字段 / 类型 / 约束)
52
+ - 边界与异常处理
53
+ - 与 PRD 验收标准的映射表
54
+
55
+ ---
56
+
57
+ ## 校验
58
+
59
+ - ❌ **无独立校验脚本**(待建)。
60
+ - 软契约:缺 `source-req` 只警告。
61
+ - review 模式(带 `review` 参数)只给改进建议,不重生成。
62
+
63
+ ---
64
+
65
+ ## 与上下游的接口
66
+
67
+ | 方向 | 接口 |
68
+ |------|------|
69
+ | 上游 prd | 读 PRD 验收标准 + 字段规格 |
70
+ | 下游 code | spec 是 code 的最佳输入 |
71
+ | 下游 test | spec 的测试用例映射 → 单元测试 |
72
+
73
+ ---
74
+
75
+ ## ⚠️ 现状提醒(KNOWN GAP)
76
+
77
+ - **文件命名两处 skill 不一致**:
78
+ - `spec-generator/SKILL.md` 写 `REQ-{ID}-{module}.spec.md`
79
+ - `wl-spec/SKILL.md` 写 `spec-{REQ-ID}-{desc}.md`
80
+ - **契约统一为 `REQ-{ID}-{module}.spec.md`**(与 prd 的 REQ-ID 命名一致,便于贯穿检索)。
81
+ - 待修正 `wl-spec/SKILL.md` 的输出路径声明。
@@ -0,0 +1,125 @@
1
+ # 模块契约:task(任务)
2
+
3
+ > 任务模块。把 PRD 拆成可执行任务 + RICE 排优先级。
4
+ > task.json 是本模块的**唯一事实源**。
5
+
6
+ ---
7
+
8
+ ## Input(吃什么)
9
+
10
+ | 优先级 | 输入 | 怎么用 |
11
+ |--------|------|--------|
12
+ | **完整** | 一份 PRD(`REQ-*.md`) | 功能清单 → 拆任务 |
13
+ | 降级 1 | PRD 草稿(drafts 里的) | 也能拆,只是还没发布 |
14
+ | 降级 2 | 一句话任务描述 | 直接 `task.py create "XXX"` |
15
+ | 参考 | 已有任务 | `task.py list` 看排期,避免重复 |
16
+
17
+ 不强依赖 prd 模块执行——可以直接手动建任务。
18
+
19
+ ---
20
+
21
+ ## Output(吐什么)
22
+
23
+ ### 任务目录
24
+
25
+ ```
26
+ 路径:workspace/tasks/{MM-DD-slug}/
27
+ 内含:
28
+ task.json ← 任务元数据 + 状态 + RICE
29
+ prd.md ← 任务级需求(可空)
30
+ implement.jsonl ← 实现记录
31
+ check.jsonl ← 检查记录
32
+ ```
33
+
34
+ ### task.json 骨架(对齐 task.py 真实输出)
35
+
36
+ ```json
37
+ {
38
+ "title": "...",
39
+ "slug": "baodan-piGai",
40
+ "status": "planning", // planning → in_progress → completed(归档时再补 archived_at)
41
+ "priority": "P0|P1|P2|P3",
42
+ "assignee": "{developer}", // ← 注意是 assignee 不是 owner
43
+ "creator": "{developer}",
44
+ "created_at": "...", "updated_at": "...",
45
+ "branch": null, "base_branch": null,
46
+ "scope": null,
47
+ "parent": null, "children": [], // 父子任务
48
+ "tags": ["REQ-2026-0042"], // ← PRD 的 REQ-ID 记这里(双向追溯)
49
+ "rice": 24, // ← RICE 排序时 AI 算好后写入(数值,不是对象)
50
+ // 能力增强字段(可选,旧 task.json 不含时取默认值)
51
+ "due_date": "2026-07-01", // YYYY-MM-DD(set-due 写)
52
+ "start_date": null,
53
+ "estimate_hours": null,
54
+ "blocked_by": [], // 被哪些任务阻塞(block 写,自动维护反向 blocks)
55
+ "blocks": [], // 被哪些任务依赖(自动维护)
56
+ "stage_ts": { "created": "...", "started": null, "completed": null },
57
+ "zentao_id": null // 对应禅道任务 ID(zentao_sync 写)。幂等主键: 已有则跳过 create。
58
+ // 隔离契约见 contracts/isolation.md「禅道同步」。
59
+ }
60
+ ```
61
+
62
+ > ⚠️ 字段名以 **task.py 实际输出**为准(`assignee`/`planning`/`completed`/`rice` 为数值)。
63
+ > 上面是权威骨架,与 task.py 的 `cmd_create` 逐字段对齐。
64
+
65
+ ### 状态流转
66
+
67
+ ```
68
+ create(planning) → start → in_progress → finish → completed → archive
69
+ ```
70
+
71
+ **关键动作都会自动 stage workspace/tasks/ 到 team_sync**(push 后团队可见)。
72
+
73
+ ---
74
+
75
+ ## 操作命令
76
+
77
+ ```bash
78
+ # 基础生命周期
79
+ python .qoder/scripts/task.py create "XXX" [--slug ...] [--assignee ...] [--priority P0|P1|P2|P3]
80
+ python .qoder/scripts/task.py list [--mine] [--status in_progress] [--ready] [--blocked]
81
+ python .qoder/scripts/task.py show <task-dir>
82
+ python .qoder/scripts/task.py start <task-dir> # planning → in_progress,设为活跃任务
83
+ python .qoder/scripts/task.py current [--source] # 看当前活跃任务
84
+ python .qoder/scripts/task.py finish # 活跃任务 → completed,清活跃指针
85
+ python .qoder/scripts/task.py archive <task-dir> # 移到 .qoder/archive/{YYYY-MM}/,自动清孤儿依赖
86
+
87
+ # 子任务
88
+ python .qoder/scripts/task.py add-subtask <parent> <child>
89
+ python .qoder/scripts/task.py remove-subtask <parent> <child>
90
+
91
+ # 排期与依赖(B2 能力)
92
+ python .qoder/scripts/task.py set-due <task> <YYYY-MM-DD>
93
+ python .qoder/scripts/task.py block <task> <blocker> # 循环依赖自动检测,反向 blocks 自动维护
94
+ python .qoder/scripts/task.py unblock <task> <blocker>
95
+ python .qoder/scripts/task.py gantt [--weeks 4] # 只排有日期的任务,自动标逾期
96
+ ```
97
+
98
+ **退出码**:`0`=成功 / `1`=任务不存在/JSON 缺失/循环依赖 / `4`=权限不足(零信任 ACL,仅 creator/assignee/admin 可改)。
99
+
100
+ **RICE** = Reach × Impact × Confidence ÷ Effort(AI 层评估,算好后写入 task.json 的 `rice` 数值字段)
101
+
102
+ ---
103
+
104
+ ## 校验
105
+
106
+ - ❌ **无独立校验脚本**。当前靠 task.py 自身的状态机约束。
107
+ - 软契约:task.json 缺 `_contract` / `acceptance` 只警告不拦。
108
+
109
+ ---
110
+
111
+ ## 与上下游的接口
112
+
113
+ | 方向 | 接口 |
114
+ |------|------|
115
+ | 上游 prd | 读 PRD 的功能清单 → 拆任务 |
116
+ | 下游 spec/code | 任务目录可放 `spec.md`(spec 模块写到任务目录时) |
117
+
118
+ ---
119
+
120
+ ## 现状提醒
121
+
122
+ - ✅ task.py 功能完整:CRUD + 依赖图(block/unblock + 循环检测)+ 排期(set-due/gantt)+ 子任务 + 零信任 ACL + 归档孤儿依赖清理。
123
+ - ✅ PRD→task 衔接:create 时把 REQ-ID 记进 `tags`,PRD 验收点贴进 task 的 `prd.md`(命令层引导)。
124
+ - ✅ RICE 排序在 AI 层(task.py 只存数值,不替 AI 算分)。
125
+ - 🧩 QoderWork 增强(可选):待办双向同步。无连接器则回退,task.json 仍为准。