cc-devflow 4.5.1 → 4.5.3
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/.claude/skills/cc-act/CHANGELOG.md +27 -0
- package/.claude/skills/cc-act/PLAYBOOK.md +32 -1
- package/.claude/skills/cc-act/SKILL.md +53 -7
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +35 -1
- package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +10 -1
- package/.claude/skills/cc-act/references/closure-contract.md +11 -0
- package/.claude/skills/cc-act/scripts/cc-act-common.sh +32 -1
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +130 -0
- package/.claude/skills/cc-act/scripts/verify-act-gate.sh +23 -1
- package/.claude/skills/cc-check/CHANGELOG.md +26 -0
- package/.claude/skills/cc-check/PLAYBOOK.md +128 -1
- package/.claude/skills/cc-check/SKILL.md +147 -7
- package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +164 -1
- package/.claude/skills/cc-check/references/gate-contract.md +11 -0
- package/.claude/skills/cc-check/references/review-contract.md +104 -0
- package/.claude/skills/cc-check/scripts/render-report-card.js +209 -5
- package/.claude/skills/cc-check/scripts/verify-gate.sh +28 -0
- package/.claude/skills/cc-do/CHANGELOG.md +12 -0
- package/.claude/skills/cc-do/PLAYBOOK.md +14 -9
- package/.claude/skills/cc-do/SKILL.md +24 -13
- package/.claude/skills/cc-do/references/execution-recovery.md +16 -5
- package/.claude/skills/cc-do/scripts/verify-task-gates.sh +19 -6
- package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +14 -2
- package/.claude/skills/cc-investigate/CHANGELOG.md +31 -0
- package/.claude/skills/cc-investigate/PLAYBOOK.md +124 -8
- package/.claude/skills/cc-investigate/SKILL.md +252 -17
- package/.claude/skills/cc-investigate/assets/ANALYSIS_TEMPLATE.md +112 -3
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +17 -5
- package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +141 -1
- package/.claude/skills/cc-investigate/references/investigation-contract.md +192 -0
- package/.claude/skills/cc-plan/CHANGELOG.md +26 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +18 -6
- package/.claude/skills/cc-plan/SKILL.md +72 -34
- package/.claude/skills/cc-plan/assets/DESIGN_TEMPLATE.md +30 -3
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +28 -0
- package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +46 -1
- package/.claude/skills/cc-plan/assets/TINY_DESIGN_TEMPLATE.md +24 -0
- package/.claude/skills/cc-plan/references/planning-contract.md +18 -4
- package/.claude/skills/cc-roadmap/CHANGELOG.md +14 -0
- package/.claude/skills/cc-roadmap/PLAYBOOK.md +10 -7
- package/.claude/skills/cc-roadmap/SKILL.md +43 -23
- package/.claude/skills/cc-roadmap/assets/BACKLOG_TEMPLATE.md +10 -0
- package/.claude/skills/cc-roadmap/assets/ROADMAP_TEMPLATE.md +15 -0
- package/.claude/skills/cc-roadmap/assets/TRACKING_TEMPLATE.json +1 -1
- package/.claude/skills/cc-roadmap/references/roadmap-dialogue.md +11 -7
- package/.claude/skills/cc-simplify/CHANGELOG.md +21 -0
- package/.claude/skills/cc-simplify/SKILL.md +264 -35
- package/.claude/skills/cc-spec-init/CHANGELOG.md +6 -0
- package/.claude/skills/cc-spec-init/SKILL.md +14 -1
- package/CHANGELOG.md +37 -0
- package/README.md +10 -2
- package/README.zh-CN.md +10 -2
- package/docs/examples/example-bindings.json +7 -7
- package/docs/examples/full-design-blocked/BACKLOG.md +1 -1
- package/docs/examples/full-design-blocked/README.md +1 -1
- package/docs/examples/full-design-blocked/ROADMAP.md +1 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +1 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/tasks.md +1 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +140 -3
- package/docs/examples/full-design-blocked/roadmap-tracking.json +1 -1
- package/docs/examples/local-handoff/BACKLOG.md +1 -1
- package/docs/examples/local-handoff/README.md +1 -1
- package/docs/examples/local-handoff/ROADMAP.md +1 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +1 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/tasks.md +1 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +92 -0
- package/docs/examples/local-handoff/roadmap-tracking.json +1 -1
- package/docs/examples/pdca-loop/BACKLOG.md +1 -1
- package/docs/examples/pdca-loop/README.md +1 -1
- package/docs/examples/pdca-loop/ROADMAP.md +1 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +20 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +1 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +2 -2
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/tasks.md +1 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +92 -0
- package/docs/examples/pdca-loop/roadmap-tracking.json +1 -1
- package/docs/skill-strategy-audit.md +48 -0
- package/lib/skill-runtime/__tests__/runtime.integration.test.js +19 -1
- package/lib/skill-runtime/review.js +64 -1
- package/lib/skill-runtime/schemas.js +161 -4
- package/package.json +1 -1
package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"sourceRoadmap": {
|
|
10
10
|
"itemId": "RM-001",
|
|
11
11
|
"roadmapVersion": "roadmap.v1",
|
|
12
|
-
"roadmapSkillVersion": "4.
|
|
12
|
+
"roadmapSkillVersion": "4.4.1",
|
|
13
13
|
"sourceStage": "Stage 1",
|
|
14
14
|
"successSignal": "Users can copy the invite link with one click",
|
|
15
15
|
"killSignal": "The patch requires backend or permission changes",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
]
|
|
23
23
|
},
|
|
24
24
|
"planningMeta": {
|
|
25
|
-
"reqPlanSkillVersion": "3.
|
|
25
|
+
"reqPlanSkillVersion": "3.7.0",
|
|
26
26
|
"designVersion": "design.v1",
|
|
27
27
|
"approvedAt": "2026-04-15T10:05:00.000Z",
|
|
28
28
|
"approvedBy": "user",
|
|
@@ -3,6 +3,65 @@
|
|
|
3
3
|
"verdict": "pass",
|
|
4
4
|
"overall": "pass",
|
|
5
5
|
"summary": "verdict=pass quick=2/2 strict=0/0 review=pass",
|
|
6
|
+
"specAlignment": "pass",
|
|
7
|
+
"specDeltaVerified": true,
|
|
8
|
+
"specSyncReady": true,
|
|
9
|
+
"runtime": {
|
|
10
|
+
"status": "pass",
|
|
11
|
+
"failureOwnership": []
|
|
12
|
+
},
|
|
13
|
+
"claimEvidence": [
|
|
14
|
+
{
|
|
15
|
+
"claim": "tests-pass",
|
|
16
|
+
"requiredProof": "fresh targeted test command with exit 0",
|
|
17
|
+
"commandOrArtifact": "npm test -- src/features/share/ShareDialog.test.tsx",
|
|
18
|
+
"exitStatus": 0,
|
|
19
|
+
"keyObservation": "share dialog targeted tests passed",
|
|
20
|
+
"status": "pass"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"claim": "requirements-met",
|
|
24
|
+
"requiredProof": "line-by-line planning/tasks.md and task-manifest.json checklist",
|
|
25
|
+
"commandOrArtifact": "planning/tasks.md + planning/task-manifest.json",
|
|
26
|
+
"exitStatus": null,
|
|
27
|
+
"keyObservation": "T001-T003 complete with spec/code review proof",
|
|
28
|
+
"status": "pass"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"qa": {
|
|
32
|
+
"status": "pass",
|
|
33
|
+
"regressionProof": [],
|
|
34
|
+
"testQuality": [
|
|
35
|
+
{
|
|
36
|
+
"area": "share-dialog",
|
|
37
|
+
"checksRealBehavior": true,
|
|
38
|
+
"mockBoundary": "none",
|
|
39
|
+
"testOnlyProductionApi": false,
|
|
40
|
+
"status": "pass"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"coverageAudit": {
|
|
44
|
+
"status": "pass",
|
|
45
|
+
"coveragePct": 80,
|
|
46
|
+
"pathMap": ["copy invite link success path", "clipboard fallback error path"],
|
|
47
|
+
"gaps": [],
|
|
48
|
+
"testsAdded": ["src/features/share/ShareDialog.test.tsx"],
|
|
49
|
+
"e2eRequired": false,
|
|
50
|
+
"evalRequired": false,
|
|
51
|
+
"qualityStars": "★★"
|
|
52
|
+
},
|
|
53
|
+
"browserEvidence": {
|
|
54
|
+
"status": "skipped",
|
|
55
|
+
"mode": "not-applicable",
|
|
56
|
+
"affectedRoutes": [],
|
|
57
|
+
"screenshots": [],
|
|
58
|
+
"consoleErrors": [],
|
|
59
|
+
"healthScore": null,
|
|
60
|
+
"issues": [],
|
|
61
|
+
"skipReason": "example fixture uses targeted component evidence instead of a live browser"
|
|
62
|
+
},
|
|
63
|
+
"tddException": null
|
|
64
|
+
},
|
|
6
65
|
"quickGates": [
|
|
7
66
|
{
|
|
8
67
|
"name": "targeted-tests",
|
|
@@ -22,10 +81,35 @@
|
|
|
22
81
|
"status": "pass",
|
|
23
82
|
"summary": "Task review proof and requirement-level diff review both passed",
|
|
24
83
|
"details": "T001-T003 have matching spec/code review proof and the diff stays inside the approved tiny-design boundary.",
|
|
84
|
+
"freshness": {
|
|
85
|
+
"status": "fresh",
|
|
86
|
+
"reviewedCommit": "example-head",
|
|
87
|
+
"currentCommit": "example-head",
|
|
88
|
+
"commitsSinceReview": 0,
|
|
89
|
+
"staleReason": ""
|
|
90
|
+
},
|
|
91
|
+
"qualityScore": 9,
|
|
92
|
+
"specialistReviews": [
|
|
93
|
+
{
|
|
94
|
+
"name": "testing",
|
|
95
|
+
"status": "pass",
|
|
96
|
+
"required": true,
|
|
97
|
+
"summary": "targeted tests cover the share dialog behavior for this example",
|
|
98
|
+
"skipReason": "",
|
|
99
|
+
"findings": []
|
|
100
|
+
}
|
|
101
|
+
],
|
|
25
102
|
"taskReviews": {
|
|
26
103
|
"status": "pass",
|
|
27
104
|
"required": true,
|
|
28
105
|
"summary": "All completed tasks carry spec/code proof",
|
|
106
|
+
"reviewPacket": {
|
|
107
|
+
"baseSha": "example-base",
|
|
108
|
+
"headSha": "example-head",
|
|
109
|
+
"requirements": "planning/tasks.md#T001-T003",
|
|
110
|
+
"implemented": "copy invite link workflow",
|
|
111
|
+
"reviewerContext": "task manifest plus changed share dialog files"
|
|
112
|
+
},
|
|
29
113
|
"reviewers": [],
|
|
30
114
|
"findings": []
|
|
31
115
|
},
|
|
@@ -33,12 +117,20 @@
|
|
|
33
117
|
"status": "pass",
|
|
34
118
|
"required": false,
|
|
35
119
|
"summary": "No blocking requirement-level findings",
|
|
120
|
+
"reviewPacket": {
|
|
121
|
+
"baseSha": "example-base",
|
|
122
|
+
"headSha": "example-head",
|
|
123
|
+
"requirements": "planning/design.md",
|
|
124
|
+
"implemented": "copy invite link workflow",
|
|
125
|
+
"reviewerContext": "requirement diff, plan completion, scope drift, docs staleness"
|
|
126
|
+
},
|
|
36
127
|
"reviewers": [],
|
|
37
128
|
"findings": []
|
|
38
129
|
},
|
|
39
130
|
"findings": []
|
|
40
131
|
},
|
|
41
132
|
"blockingFindings": [],
|
|
133
|
+
"gaps": [],
|
|
42
134
|
"reroute": "none",
|
|
43
135
|
"timestamp": "2026-04-15T11:20:00.000Z"
|
|
44
136
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# External Skill Strategy Audit
|
|
2
|
+
|
|
3
|
+
本审计覆盖 `/Users/dimon/001Area/80-CodeWorld/003-project/skills` 下的 22 个
|
|
4
|
+
`SKILL.md`。目标不是复制外部 skill,而是抽取能让 cc-devflow 原生 workflow
|
|
5
|
+
更稳的策略,并把不适合迁移的部分明确跳过。
|
|
6
|
+
|
|
7
|
+
## Migration Summary
|
|
8
|
+
|
|
9
|
+
| Source skill | Good strategy | cc-devflow target | Decision |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `deprecated/design-an-interface` | "design it twice",用不同接口形态比较 depth、易用错点和隐藏复杂度 | `cc-plan` | 迁移为接口备选比较 gate,不迁移 parallel subagent 强制要求 |
|
|
12
|
+
| `deprecated/qa` | 用户视角 issue、轻量澄清、按可独立验证行为拆分 | `cc-act` / `cc-plan` | 迁移为 follow-up / issue handoff 的行为化规则 |
|
|
13
|
+
| `deprecated/request-refactor-plan` | 重构计划拆成 tiny commits,每步保持可运行 | `cc-plan` / `cc-act` | 迁移为 refactor slicing 和 bisectable commit 规则 |
|
|
14
|
+
| `deprecated/triage-issue` | 先查根因,再写 TDD fix plan,issue 不绑定易腐烂文件行号 | `cc-investigate` / `cc-plan` | 迁移为 repair contract 和 durable issue brief 规则 |
|
|
15
|
+
| `deprecated/ubiquitous-language` | canonical terms、aliases to avoid、ambiguity flag | `cc-spec-init` / `cc-plan` | 迁移为 capability/domain language glossary gate |
|
|
16
|
+
| `engineering/diagnose` | 反馈回路优先级、提高 flaky 复现率、假设必须可证伪、debug tag cleanup | `cc-investigate` | 已有大部分;补强 loop sharpening 和 postmortem handoff |
|
|
17
|
+
| `engineering/github-triage` | label state machine、needs-info 保留已确认事实、resume triage notes | `cc-act` | 迁移为远端 issue/PR closeout 的状态一致性规则 |
|
|
18
|
+
| `engineering/grill-with-docs` | 术语冲突立即叫停、具体场景压测、ADR 只记难逆/意外/真实取舍 | `cc-plan` | 已有大部分;补强 glossary update 和 ADR sparsity |
|
|
19
|
+
| `engineering/improve-codebase-architecture` | deep module、deletion test、one adapter vs two adapters、locality/leverage | `cc-simplify` / `cc-plan` | 迁移为架构坏味道确认清单 |
|
|
20
|
+
| `engineering/tdd` | 禁止水平切片,使用 tracer bullet 垂直 Red/Green 循环 | `cc-do` / `cc-plan` | 已有 planning 规则;补强执行阶段逐条 task 的 tracer bullet guard |
|
|
21
|
+
| `engineering/to-issues` | 独立可领的 vertical slices,HITL/AFK 标注,依赖顺序创建 | `cc-plan` / `cc-act` | 迁移为 task / follow-up 切片规则 |
|
|
22
|
+
| `engineering/to-prd` | 从现有上下文合成 PRD,测试决策只写行为和模块,不写短期文件路径 | `cc-plan` | 迁移为 design durable output 规则,不迁移 GitHub issue 自动创建 |
|
|
23
|
+
| `engineering/zoom-out` | 不熟悉区域时先上升一层,画模块和调用方地图 | `cc-roadmap` / `cc-plan` | 已被 context sweep 覆盖;仅作为审计备注 |
|
|
24
|
+
| `misc/git-guardrails-claude-code` | 阻断危险 git 动作,保留用户确认边界 | `cc-act` | 迁移为 destructive / publish action guard,不迁移 Claude hook 实现 |
|
|
25
|
+
| `misc/migrate-to-shoehorn` | 测试里的 partial fixture 要显式表达,不用不透明 cast 掩盖类型事实 | `cc-do` / `cc-check` | 迁移为通用 test fixture discipline,不绑定 shoehorn 依赖 |
|
|
26
|
+
| `misc/scaffold-exercises` | 生成目录后必须跑专用 lint,移动用 `git mv` 保留历史 | `cc-act` | 仅迁移验证/移动原则;课程目录规则不迁移 |
|
|
27
|
+
| `misc/setup-pre-commit` | 根据实际包管理器和已有 scripts 装配 hook,最后用真实 hook smoke | `cc-act` | 仅作为工具链变更验证参考,不迁移 Husky 方案 |
|
|
28
|
+
| `personal/edit-article` | 文档结构按依赖顺序组织,段落短、信息先后可追踪 | `docs-sync` | 迁移为 docs-sync 叙事顺序规则 |
|
|
29
|
+
| `personal/obsidian-vault` | index note、wikilink、反向查找的知识图谱维护 | none | 个人知识库规则,不迁移到 cc-devflow |
|
|
30
|
+
| `productivity/caveman` | 压缩沟通但保留精确技术事实,复杂步骤暂时恢复完整表达 | `cc-act` / output style | 作为输出风格参考,不写进 workflow 合约 |
|
|
31
|
+
| `productivity/grill-me` | 一次一个问题;能查代码就别问用户 | `cc-plan` | 已有规则;审计确认不重复迁移 |
|
|
32
|
+
| `productivity/write-a-skill` | description 是触发真相源;SKILL.md 要短,复杂内容下沉到 references/scripts | `docs-sync` | 迁移为 skill contract quality gate |
|
|
33
|
+
|
|
34
|
+
## Implementation Order
|
|
35
|
+
|
|
36
|
+
1. `cc-plan`: 吸收接口备选、领域语言、垂直切片和 durable design 输出规则。
|
|
37
|
+
2. `cc-investigate`: 补强 feedback loop sharpening、flaky rate、postmortem handoff。
|
|
38
|
+
3. `cc-do`: 补强 tracer bullet 执行和 test fixture discipline。
|
|
39
|
+
4. `cc-simplify`: 增加 deep module / deletion test / adapter reality 检查。
|
|
40
|
+
5. `cc-act`: 增加 issue/PR 状态、危险 git 动作、工具链验证和 durable follow-up 规则。
|
|
41
|
+
6. `docs-sync`: 增加 skill 合约质量 gate 和文档依赖顺序检查。
|
|
42
|
+
|
|
43
|
+
## Skip Rules
|
|
44
|
+
|
|
45
|
+
- 不迁移个人路径、个人 vault、课程目录命名、具体第三方测试依赖。
|
|
46
|
+
- 不把 deprecated skill 的 GitHub issue 自动创建行为搬进主流程;cc-devflow 仍以
|
|
47
|
+
durable local artifact 和可选 remote handoff 为主。
|
|
48
|
+
- 不新增一套平行 skill;所有迁移必须落回现有 `cc-*` workflow 语义。
|
|
@@ -204,7 +204,22 @@ describe('Skill runtime', () => {
|
|
|
204
204
|
'--status',
|
|
205
205
|
'passed',
|
|
206
206
|
'--summary',
|
|
207
|
-
'task finished'
|
|
207
|
+
'task finished',
|
|
208
|
+
'--tdd-json',
|
|
209
|
+
JSON.stringify({
|
|
210
|
+
red: {
|
|
211
|
+
testSeam: 'public helper command',
|
|
212
|
+
behaviorAsserted: 'checkpoint is written under execution/tasks',
|
|
213
|
+
allowedMocks: [],
|
|
214
|
+
implementationDetailRisk: 'low'
|
|
215
|
+
},
|
|
216
|
+
testQuality: {
|
|
217
|
+
usesPublicInterface: true,
|
|
218
|
+
describesBehavior: true,
|
|
219
|
+
survivesInternalRefactor: true,
|
|
220
|
+
mocksOnlySystemBoundaries: true
|
|
221
|
+
}
|
|
222
|
+
})
|
|
208
223
|
], { encoding: 'utf8' });
|
|
209
224
|
expect(checkpoint.status).toBe(0);
|
|
210
225
|
|
|
@@ -245,6 +260,9 @@ describe('Skill runtime', () => {
|
|
|
245
260
|
expect(verify.status).toBe(0);
|
|
246
261
|
|
|
247
262
|
expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'checkpoint.json'))).toBe(true);
|
|
263
|
+
const checkpointJson = JSON.parse(fs.readFileSync(path.join(change.tasksDir, 'T001', 'checkpoint.json'), 'utf8'));
|
|
264
|
+
expect(checkpointJson.tdd.red.testSeam).toBe('public helper command');
|
|
265
|
+
expect(checkpointJson.tdd.testQuality.usesPublicInterface).toBe(true);
|
|
248
266
|
expect(fs.existsSync(path.join(repoRoot, '.harness', 'runtime', changeId))).toBe(false);
|
|
249
267
|
expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'checkpoint.md'))).toBe(false);
|
|
250
268
|
expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'review-spec.md'))).toBe(false);
|
|
@@ -79,6 +79,7 @@ function makeFinding({
|
|
|
79
79
|
status = 'open',
|
|
80
80
|
fingerprint
|
|
81
81
|
}) {
|
|
82
|
+
const confidenceScore = severityRank(severity) >= severityRank('important') ? 8 : 6;
|
|
82
83
|
return {
|
|
83
84
|
id,
|
|
84
85
|
source,
|
|
@@ -91,7 +92,12 @@ function makeFinding({
|
|
|
91
92
|
...(typeof line === 'number' ? { line } : {}),
|
|
92
93
|
action,
|
|
93
94
|
status,
|
|
94
|
-
|
|
95
|
+
confidenceScore,
|
|
96
|
+
fingerprint: fingerprint || `${source}:${category}:${id}`,
|
|
97
|
+
displayTier: status === 'informational'
|
|
98
|
+
? 'info'
|
|
99
|
+
: (severityRank(severity) >= severityRank('important') ? 'blocking' : 'warning'),
|
|
100
|
+
suppressionReason: null
|
|
95
101
|
};
|
|
96
102
|
}
|
|
97
103
|
|
|
@@ -231,6 +237,14 @@ async function detectBaseRef(repoRoot) {
|
|
|
231
237
|
return 'HEAD~1';
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
async function detectCurrentCommit(repoRoot) {
|
|
241
|
+
const result = await runCommand('git rev-parse --short HEAD', { cwd: repoRoot });
|
|
242
|
+
if (result.code === 0 && result.stdout.trim()) {
|
|
243
|
+
return result.stdout.trim();
|
|
244
|
+
}
|
|
245
|
+
return 'working-tree';
|
|
246
|
+
}
|
|
247
|
+
|
|
234
248
|
async function runCodexStructuredReview({ repoRoot, baseRef }) {
|
|
235
249
|
const command = [
|
|
236
250
|
'codex review',
|
|
@@ -530,6 +544,7 @@ async function runReviewSuite({ repoRoot, changeId, manifest, strict, skipReview
|
|
|
530
544
|
const diffReview = await runDiffReviewSection({ repoRoot, strict, skipReview });
|
|
531
545
|
const findings = flattenFindings(taskReviews, diffReview);
|
|
532
546
|
const status = deriveReviewStatus(taskReviews, diffReview);
|
|
547
|
+
const currentCommit = await detectCurrentCommit(repoRoot);
|
|
533
548
|
const details = [
|
|
534
549
|
taskReviews.summary,
|
|
535
550
|
diffReview.summary
|
|
@@ -539,6 +554,54 @@ async function runReviewSuite({ repoRoot, changeId, manifest, strict, skipReview
|
|
|
539
554
|
status,
|
|
540
555
|
summary: `Task review: ${taskReviews.status}. Diff review: ${diffReview.status}.`,
|
|
541
556
|
details,
|
|
557
|
+
freshness: {
|
|
558
|
+
status: 'fresh',
|
|
559
|
+
reviewedCommit: currentCommit,
|
|
560
|
+
currentCommit,
|
|
561
|
+
commitsSinceReview: 0,
|
|
562
|
+
staleReason: ''
|
|
563
|
+
},
|
|
564
|
+
qualityScore: status === 'pass' ? 9 : (status === 'blocked' ? 5 : 3),
|
|
565
|
+
specialistReviews: [
|
|
566
|
+
{
|
|
567
|
+
name: 'testing',
|
|
568
|
+
status: taskReviews.status,
|
|
569
|
+
required: true,
|
|
570
|
+
summary: taskReviews.summary,
|
|
571
|
+
skipReason: '',
|
|
572
|
+
findings: []
|
|
573
|
+
}
|
|
574
|
+
],
|
|
575
|
+
runtime: {
|
|
576
|
+
status: status === 'pass' ? 'pass' : (status === 'fail' ? 'fail' : 'blocked'),
|
|
577
|
+
failureOwnership: []
|
|
578
|
+
},
|
|
579
|
+
qa: {
|
|
580
|
+
status: 'pass',
|
|
581
|
+
regressionProof: [],
|
|
582
|
+
testQuality: [],
|
|
583
|
+
coverageAudit: {
|
|
584
|
+
status: 'pass',
|
|
585
|
+
coveragePct: null,
|
|
586
|
+
pathMap: [],
|
|
587
|
+
gaps: [],
|
|
588
|
+
testsAdded: [],
|
|
589
|
+
e2eRequired: false,
|
|
590
|
+
evalRequired: false,
|
|
591
|
+
qualityStars: ''
|
|
592
|
+
},
|
|
593
|
+
browserEvidence: {
|
|
594
|
+
status: 'skipped',
|
|
595
|
+
mode: 'not-applicable',
|
|
596
|
+
affectedRoutes: [],
|
|
597
|
+
screenshots: [],
|
|
598
|
+
consoleErrors: [],
|
|
599
|
+
healthScore: null,
|
|
600
|
+
issues: [],
|
|
601
|
+
skipReason: 'runtime verify did not identify a UI browser QA target'
|
|
602
|
+
},
|
|
603
|
+
tddException: null
|
|
604
|
+
},
|
|
542
605
|
taskReviews,
|
|
543
606
|
diffReview,
|
|
544
607
|
findings
|
|
@@ -247,6 +247,14 @@ const ManifestSchema = z.object({
|
|
|
247
247
|
}
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
+
const TddCheckpointEvidenceSchema = z.object({
|
|
251
|
+
red: z.record(z.any()).optional(),
|
|
252
|
+
green: z.record(z.any()).optional(),
|
|
253
|
+
refactor: z.record(z.any()).optional(),
|
|
254
|
+
feedbackLoop: z.record(z.any()).optional(),
|
|
255
|
+
testQuality: z.record(z.any()).optional()
|
|
256
|
+
}).passthrough();
|
|
257
|
+
|
|
250
258
|
const CheckpointSchema = z.object({
|
|
251
259
|
changeId: ChangeIdSchema,
|
|
252
260
|
taskId: z.string().regex(TASK_ID_PATTERN),
|
|
@@ -257,7 +265,9 @@ const CheckpointSchema = z.object({
|
|
|
257
265
|
error: z.string().default(''),
|
|
258
266
|
outputExcerpt: z.string().default(''),
|
|
259
267
|
timestamp: z.string().datetime(),
|
|
260
|
-
attempt: z.number().int().min(0).default(0)
|
|
268
|
+
attempt: z.number().int().min(0).default(0),
|
|
269
|
+
tdd: TddCheckpointEvidenceSchema.optional(),
|
|
270
|
+
tddException: z.record(z.any()).optional()
|
|
261
271
|
});
|
|
262
272
|
|
|
263
273
|
const GateResultSchema = z.object({
|
|
@@ -269,8 +279,26 @@ const GateResultSchema = z.object({
|
|
|
269
279
|
});
|
|
270
280
|
|
|
271
281
|
const ReviewSeveritySchema = z.enum(['critical', 'important', 'minor', 'info']);
|
|
272
|
-
const ReviewActionSchema = z.enum([
|
|
273
|
-
|
|
282
|
+
const ReviewActionSchema = z.enum([
|
|
283
|
+
'fix_now',
|
|
284
|
+
'follow_up',
|
|
285
|
+
'cc-investigate',
|
|
286
|
+
'reroute-cc-do',
|
|
287
|
+
'reroute-cc-plan',
|
|
288
|
+
'reroute-cc-investigate',
|
|
289
|
+
'document-follow-up',
|
|
290
|
+
'none'
|
|
291
|
+
]);
|
|
292
|
+
const ReviewFindingStatusSchema = z.enum([
|
|
293
|
+
'open',
|
|
294
|
+
'resolved',
|
|
295
|
+
'accepted',
|
|
296
|
+
'informational',
|
|
297
|
+
'accepted-fixed',
|
|
298
|
+
'rejected-with-evidence',
|
|
299
|
+
'deferred-minor',
|
|
300
|
+
'clarification-needed'
|
|
301
|
+
]);
|
|
274
302
|
|
|
275
303
|
const ReviewEvidenceSchema = z.object({
|
|
276
304
|
kind: z.enum(['command', 'file', 'note']),
|
|
@@ -291,7 +319,11 @@ const ReviewFindingSchema = z.object({
|
|
|
291
319
|
line: z.number().int().min(1).optional(),
|
|
292
320
|
action: ReviewActionSchema.default('none'),
|
|
293
321
|
status: ReviewFindingStatusSchema.default('open'),
|
|
294
|
-
fingerprint: z.string().optional()
|
|
322
|
+
fingerprint: z.string().optional(),
|
|
323
|
+
confidence: z.enum(['high', 'medium', 'low']).optional(),
|
|
324
|
+
confidenceScore: z.number().min(1).max(10).optional(),
|
|
325
|
+
displayTier: z.enum(['blocking', 'warning', 'info', 'suppressed']).optional(),
|
|
326
|
+
suppressionReason: z.string().nullable().optional()
|
|
295
327
|
});
|
|
296
328
|
|
|
297
329
|
const ReviewerResultSchema = z.object({
|
|
@@ -317,6 +349,28 @@ const ReportReviewSchema = z.object({
|
|
|
317
349
|
status: ReviewDecisionStatusSchema.default('skipped'),
|
|
318
350
|
summary: z.string().default(''),
|
|
319
351
|
details: z.string().default(''),
|
|
352
|
+
freshness: z.object({
|
|
353
|
+
status: z.enum(['fresh', 'stale', 'unknown', 'not-applicable']).default('unknown'),
|
|
354
|
+
reviewedCommit: z.string().default(''),
|
|
355
|
+
currentCommit: z.string().default(''),
|
|
356
|
+
commitsSinceReview: z.number().int().min(0).nullable().default(null),
|
|
357
|
+
staleReason: z.string().default('')
|
|
358
|
+
}).default({
|
|
359
|
+
status: 'unknown',
|
|
360
|
+
reviewedCommit: '',
|
|
361
|
+
currentCommit: '',
|
|
362
|
+
commitsSinceReview: null,
|
|
363
|
+
staleReason: ''
|
|
364
|
+
}),
|
|
365
|
+
qualityScore: z.number().min(0).max(10).nullable().default(null),
|
|
366
|
+
specialistReviews: z.array(z.object({
|
|
367
|
+
name: z.string().min(1),
|
|
368
|
+
status: ReviewDecisionStatusSchema,
|
|
369
|
+
required: z.boolean().default(false),
|
|
370
|
+
summary: z.string().default(''),
|
|
371
|
+
skipReason: z.string().default(''),
|
|
372
|
+
findings: z.array(ReviewFindingSchema).default([])
|
|
373
|
+
})).default([]),
|
|
320
374
|
taskReviews: ReviewSectionSchema.default({
|
|
321
375
|
status: 'skipped',
|
|
322
376
|
required: false,
|
|
@@ -334,15 +388,118 @@ const ReportReviewSchema = z.object({
|
|
|
334
388
|
findings: z.array(ReviewFindingSchema).default([])
|
|
335
389
|
});
|
|
336
390
|
|
|
391
|
+
const ClaimEvidenceSchema = z.object({
|
|
392
|
+
claim: z.string().min(1),
|
|
393
|
+
requiredProof: z.string().min(1),
|
|
394
|
+
commandOrArtifact: z.string().min(1),
|
|
395
|
+
exitStatus: z.number().int().nullable().optional(),
|
|
396
|
+
keyObservation: z.string().default(''),
|
|
397
|
+
status: ReviewDecisionStatusSchema
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const RuntimeFailureOwnershipSchema = z.object({
|
|
401
|
+
failure: z.string().min(1),
|
|
402
|
+
classification: z.enum(['in-branch', 'pre-existing', 'environment', 'ambiguous']),
|
|
403
|
+
touchedByDiff: z.boolean().optional(),
|
|
404
|
+
evidence: z.string().default(''),
|
|
405
|
+
action: z.string().default(''),
|
|
406
|
+
status: z.string().default('open')
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const ReportRuntimeSchema = z.object({
|
|
410
|
+
status: ReviewDecisionStatusSchema.default('skipped'),
|
|
411
|
+
failureOwnership: z.array(RuntimeFailureOwnershipSchema).default([])
|
|
412
|
+
}).default({
|
|
413
|
+
status: 'skipped',
|
|
414
|
+
failureOwnership: []
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const QaSchema = z.object({
|
|
418
|
+
status: ReviewDecisionStatusSchema.default('skipped'),
|
|
419
|
+
regressionProof: z.array(z.record(z.any())).default([]),
|
|
420
|
+
testQuality: z.array(z.record(z.any())).default([]),
|
|
421
|
+
coverageAudit: z.object({
|
|
422
|
+
status: ReviewDecisionStatusSchema.default('skipped'),
|
|
423
|
+
coveragePct: z.number().nullable().default(null),
|
|
424
|
+
pathMap: z.array(z.string()).default([]),
|
|
425
|
+
gaps: z.array(z.string()).default([]),
|
|
426
|
+
testsAdded: z.array(z.string()).default([]),
|
|
427
|
+
e2eRequired: z.boolean().default(false),
|
|
428
|
+
evalRequired: z.boolean().default(false),
|
|
429
|
+
qualityStars: z.string().default('')
|
|
430
|
+
}).default({
|
|
431
|
+
status: 'skipped',
|
|
432
|
+
coveragePct: null,
|
|
433
|
+
pathMap: [],
|
|
434
|
+
gaps: [],
|
|
435
|
+
testsAdded: [],
|
|
436
|
+
e2eRequired: false,
|
|
437
|
+
evalRequired: false,
|
|
438
|
+
qualityStars: ''
|
|
439
|
+
}),
|
|
440
|
+
browserEvidence: z.object({
|
|
441
|
+
status: ReviewDecisionStatusSchema.default('skipped'),
|
|
442
|
+
mode: z.string().default('not-applicable'),
|
|
443
|
+
affectedRoutes: z.array(z.string()).default([]),
|
|
444
|
+
screenshots: z.array(z.string()).default([]),
|
|
445
|
+
consoleErrors: z.array(z.string()).default([]),
|
|
446
|
+
healthScore: z.number().nullable().default(null),
|
|
447
|
+
issues: z.array(z.record(z.any())).default([]),
|
|
448
|
+
skipReason: z.string().default('')
|
|
449
|
+
}).default({
|
|
450
|
+
status: 'skipped',
|
|
451
|
+
mode: 'not-applicable',
|
|
452
|
+
affectedRoutes: [],
|
|
453
|
+
screenshots: [],
|
|
454
|
+
consoleErrors: [],
|
|
455
|
+
healthScore: null,
|
|
456
|
+
issues: [],
|
|
457
|
+
skipReason: ''
|
|
458
|
+
}),
|
|
459
|
+
tddException: z.string().nullable().default(null)
|
|
460
|
+
}).default({
|
|
461
|
+
status: 'skipped',
|
|
462
|
+
regressionProof: [],
|
|
463
|
+
testQuality: [],
|
|
464
|
+
coverageAudit: {
|
|
465
|
+
status: 'skipped',
|
|
466
|
+
coveragePct: null,
|
|
467
|
+
pathMap: [],
|
|
468
|
+
gaps: [],
|
|
469
|
+
testsAdded: [],
|
|
470
|
+
e2eRequired: false,
|
|
471
|
+
evalRequired: false,
|
|
472
|
+
qualityStars: ''
|
|
473
|
+
},
|
|
474
|
+
browserEvidence: {
|
|
475
|
+
status: 'skipped',
|
|
476
|
+
mode: 'not-applicable',
|
|
477
|
+
affectedRoutes: [],
|
|
478
|
+
screenshots: [],
|
|
479
|
+
consoleErrors: [],
|
|
480
|
+
healthScore: null,
|
|
481
|
+
issues: [],
|
|
482
|
+
skipReason: ''
|
|
483
|
+
},
|
|
484
|
+
tddException: null
|
|
485
|
+
});
|
|
486
|
+
|
|
337
487
|
const ReportCardSchema = z.object({
|
|
338
488
|
changeId: ChangeIdSchema,
|
|
339
489
|
verdict: z.enum(['pass', 'fail', 'blocked']).optional(),
|
|
340
490
|
overall: z.enum(['pass', 'fail']),
|
|
341
491
|
summary: z.string().default(''),
|
|
492
|
+
specAlignment: z.enum(['pass', 'fail', 'blocked']).default('blocked'),
|
|
493
|
+
specDeltaVerified: z.boolean().default(false),
|
|
494
|
+
specSyncReady: z.boolean().default(false),
|
|
495
|
+
runtime: ReportRuntimeSchema,
|
|
496
|
+
claimEvidence: z.array(ClaimEvidenceSchema).default([]),
|
|
497
|
+
qa: QaSchema,
|
|
342
498
|
quickGates: z.array(GateResultSchema),
|
|
343
499
|
strictGates: z.array(GateResultSchema),
|
|
344
500
|
review: ReportReviewSchema,
|
|
345
501
|
blockingFindings: z.array(z.string()),
|
|
502
|
+
gaps: z.array(z.string()).default([]),
|
|
346
503
|
reroute: z.enum(['none', 'cc-do', 'cc-investigate', 'cc-plan']).default('none'),
|
|
347
504
|
timestamp: z.string().datetime()
|
|
348
505
|
});
|