forked from Gitlink/gitlink-cli
170 lines
6.2 KiB
Markdown
170 lines
6.2 KiB
Markdown
# 裁决记录 — REQUEST_CHANGES(硬门禁失败 + 1 个 major)
|
||
|
||
> 模拟 `gitlink-gatekeeper` 的完整执行记录:采集 → 逐维算分 → 硬门禁 → 裁决 → 渲染评分卡 → dry-run 回写命令。
|
||
> 策略:默认 `gatekeeper.yaml`(权重 40/20/15/15/10,severity_penalty blocker=100/major=25/minor=5/nit=1,thresholds pass=85 / request_changes=60,max_changed_files=80)。
|
||
> 命令均来自 `REFERENCE.md` 第 7 节 CLI 映射,已对照真实 shortcut 核验。
|
||
|
||
**场景**:`Gitlink/forgeplus` 仓库 PR #305,重构订单结算逻辑,改动了 4 个源码文件但**未附带任何测试**,其中一处折扣计算有边界缺陷(major)。CI 通过。
|
||
|
||
---
|
||
|
||
## ① 采集上下文
|
||
|
||
```bash
|
||
gitlink-cli pr +view -i 305 --owner Gitlink --repo forgeplus --format json
|
||
gitlink-cli pr +files -i 305 --owner Gitlink --repo forgeplus --format json
|
||
gitlink-cli pr +diff -i 305 --owner Gitlink --repo forgeplus --format json
|
||
gitlink-cli api GET /Gitlink/forgeplus/pulls/305/commits --format json
|
||
gitlink-cli ci +builds --owner Gitlink --repo forgeplus --format json
|
||
```
|
||
|
||
**采集结果摘要**
|
||
|
||
| 信号 | 值 |
|
||
|------|----|
|
||
| 标题 | `refactor(billing): rework settlement pipeline` |
|
||
| 描述 | 非空,长度 88 字符(≥30),**无** `#<n>` 关联 |
|
||
| `changed_files` | 4 |
|
||
| `changed_src` | 4(`settlement.go` / `discount.go` / `invoice.go` / `tax.go`) |
|
||
| `changed_tests` | 0 |
|
||
| commits | 3 条,符合 Conventional Commits 的 2 条(1 条为 `wip: fix`)→ conforming=2 |
|
||
| CI | passing |
|
||
| AI 审查发现 | 0 blocker / 1 major / 1 minor / 2 nit |
|
||
|
||
---
|
||
|
||
## ② 逐维算分(公式代入,可复算)
|
||
|
||
**review_findings(权重 40)** — §3.1
|
||
```
|
||
penalty = 25(major) + 1×5(minor) + 2×1(nit) = 32
|
||
score = 40 × max(0, 1 − 32/40) = 40 × (1 − 0.8) = 40 × 0.2 = 8
|
||
```
|
||
|
||
**test_coverage(权重 20)** — §3.2
|
||
```
|
||
changed_src=4 > 0, changed_tests=0
|
||
→ score = 0
|
||
```
|
||
|
||
**pr_hygiene(权重 15)** — §3.3
|
||
```
|
||
描述≥30 ✓ (+1/3)
|
||
关联 Issue ✗ (0)
|
||
体量 changed_files=4 ≤ max_changed_files/2 = 40 ✓ (+1/3)
|
||
命中比例 = 2/3
|
||
score = round(15 × 2/3) = round(10.0) = 10
|
||
```
|
||
|
||
**commit_quality(权重 15)** — §3.4
|
||
```
|
||
conforming/total = 2/3
|
||
score = round(15 × 2/3) = round(10.0) = 10
|
||
```
|
||
|
||
**ci_status(权重 10)** — §3.5
|
||
```
|
||
CI passing → score = 10
|
||
```
|
||
|
||
**总分**
|
||
```
|
||
total = 8 + 0 + 10 + 10 + 10 = 38
|
||
```
|
||
|
||
---
|
||
|
||
## ③ 硬门禁判定(§4)
|
||
|
||
| 门禁 | 配置 | 命中? |
|
||
|------|------|:------:|
|
||
| `forbid_blocker_findings` | true | 否(0 blocker) |
|
||
| `require_ci_pass` | true | 否(passing) |
|
||
| `require_tests_for_src_changes` | true | **是**(changed_src=4>0 且 changed_tests=0) |
|
||
| `require_linked_issue` | false | —(未启用) |
|
||
| `max_changed_files` | 80 | 否(4 ≤ 80) |
|
||
|
||
`hard_gate_failed = true`。
|
||
|
||
---
|
||
|
||
## ④ 裁决(§5)
|
||
|
||
```
|
||
hard_gate_failed = true
|
||
→ verdict = REQUEST_CHANGES (无视总分;本例 total=38 < request_changes(60) 也指向 REQUEST_CHANGES,结论一致)
|
||
```
|
||
|
||
---
|
||
|
||
## ⑤ 渲染的评分卡
|
||
|
||
```markdown
|
||
## 🛡️ Gatekeeper Report — PR #305 refactor(billing): rework settlement pipeline
|
||
|
||
**Verdict: ❌ REQUEST_CHANGES** · Score: 38/100 · policy: gatekeeper.yaml@v1
|
||
|
||
| Dimension | Weight | Score | Notes |
|
||
|-----------|:------:|:-----:|-------|
|
||
| Review findings | 40 | 8/40 | 0 blocker / 1 major / 1 minor / 2 nit |
|
||
| Test coverage | 20 | 0/20 | 4 src / 0 test files |
|
||
| PR hygiene | 15 | 10/15 | desc ✓ / linked issue ✗ / size ✓ |
|
||
| Commit quality | 15 | 10/15 | 2/3 conventional |
|
||
| CI status | 10 | 10/10 | passing |
|
||
|
||
### ⛔ Hard gate failures (1)
|
||
- `require_tests_for_src_changes`: 改动了 4 个源码文件,但本 PR 未包含任何测试文件
|
||
|
||
### 🔴 Must fix (1)
|
||
- [major] 折扣金额未做下限保护,满减叠加时可算出负数总价 — discount.go:72
|
||
|
||
### 🟡 Should fix (1)
|
||
- [minor] `settle()` 吞掉了 tax 计算的 error,应向上传播 — settlement.go:118
|
||
|
||
### 🔵 Nits (2)
|
||
- [nit] commit `wip: fix` 不符合 Conventional Commits,建议 rebase 整理 — (commit)
|
||
- [nit] 导出结构体 `Invoice` 字段缺少注释 — invoice.go:14
|
||
|
||
### ✅ Strengths
|
||
- 改动聚焦、体量适中(4 文件),CI 全绿
|
||
|
||
### Next steps
|
||
1. **补测试**(最高优先级):为 4 个改动源码文件补单元测试,解除 `require_tests_for_src_changes` 硬门禁
|
||
2. 修复折扣下限的 major 缺陷,建议补一条针对负数总价的回归测试
|
||
3. 整理 `wip: fix` commit、补充 error 传播后,重新触发 gatekeeper
|
||
---
|
||
*Generated by gitlink-gatekeeper · policy-as-code PR gate · re-run after changes*
|
||
```
|
||
|
||
---
|
||
|
||
## ⑥ 将执行的回写命令(dry-run 展示)
|
||
|
||
> 默认 dry-run,不传 `--apply` 时仅打印。REQUEST_CHANGES 永不涉及合并。
|
||
|
||
```bash
|
||
# [dry-run] 1) 评分卡作为评论回写(与 workflow 脚本一致,走 pr +comment)
|
||
gitlink-cli pr +comment -i 305 -b "$(cat scorecard.md)" --owner Gitlink --repo forgeplus
|
||
# 裁决=REQUEST_CHANGES 不直接用平台的强语义 rejected(留给人工);裁决靠评分卡标题 + 标签表达
|
||
|
||
# [dry-run] 2) 打 needs-changes 标签(labels.request_changes = "gatekeeper:needs-changes")
|
||
gitlink-cli label +create -n "gatekeeper:needs-changes" -c "#D1242F" \
|
||
-d "Gatekeeper verdict: REQUEST_CHANGES" --owner Gitlink --repo forgeplus
|
||
# 标签挂到 PR 背后的 issue.id(非 PR 号):
|
||
ISSUE_ID=$(gitlink-cli pr +view -i 305 --owner Gitlink --repo forgeplus --format json | jq -r '.data.issue.id')
|
||
gitlink-cli api POST /Gitlink/forgeplus/issues/$ISSUE_ID --body '{
|
||
"issue_tag_ids": [<gatekeeper:needs-changes 的 tag_id>],
|
||
"done_ratio": 0,
|
||
"subject": "<PR 原标题>",
|
||
"description": "<PR 原描述>"
|
||
}'
|
||
|
||
# [dry-run] 3)(子题三善后)创建 tracking issue 汇总必修项并关联 PR #305
|
||
# 注意:用 $'...' 让 \n 成为真实换行(双引号里的字面 \n 不会换行)
|
||
gitlink-cli issue +create --owner Gitlink --repo forgeplus \
|
||
-t "[gatekeeper] PR #305 必修项跟踪" \
|
||
-b $'由 gatekeeper 裁决 REQUEST_CHANGES 触发。\n硬门禁: require_tests_for_src_changes。\nMust fix: discount.go:72 折扣下限。\n关联 PR: #305'
|
||
```
|
||
|
||
> 实际写回需追加 `--apply`,Agent 会先复述「将回写 1 条评论 + 打 gatekeeper:needs-changes 标签 + 建 1 条 tracking issue,不合并」并等待确认。
|