比较提交

...

4 次代码提交

作者 SHA1 备注 提交日期
API Changelog Bot
ad04e0b450 chore: .gitattributes 固定钩子与脚本为 LF(防 CRLF 化后 sh 无法执行)
所有检测均成功
changelog-filename-gate / validate (push) Successful in 2s
2026-08-10 16:37:46 +08:00
API Changelog Bot
b8596041d7 docs: 发布门禁硬规则——给前端推送的必须是测试环境已存在可实测的+pre-push 钩子
- guide §2.1: 接口类条目推送前必须走完 PR 合并→部署测试服→测试服真实 API 验证,backend_status=deployed 才许 push;预告式推送一律禁止(2026-08-10 wx 定,前端投诉实证 #5599/#5567/#5633)
- .githooks/pre-push: push 前自动跑文件名+frontmatter 校验,违规拦截;启用 git config core.hooksPath .githooks
- 文件名类型枚举文档同步(7 类+frontend 字面量)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:37:21 +08:00
API Changelog Bot
0e911a98f3 chore(changelog): 回填 #5599/#5567/#5633 部署实测状态(未部署即推送整改)+5 条枚举/结构合规
- #5599/#5567/#5633(yst 8-06~8-07 推送时未部署测试服): 2026-08-10 复核确认代码已随 order-v3 8-10 部署上测试服,补验证证据章节(部署点位+DB 列+网关实测),backend_status 回填 deployed/gateway verified
- #5444、#5730-5732: backend_status released→deployed(枚举合法化,状态语义不变)
- #5784 补验证证据章节、#5788 章节结构规范化、#5797 清理 not_required 残留前端字段

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:37:20 +08:00
API Changelog Bot
65ddaae00f fix(scripts): 校验规则去假阳性——前端/修复类条目合法化+路径参数不误判占位符
- CHANGE_TYPES 扩:修复/前端缺陷/前端优化/前端修复(文件名+frontmatter 同步);纯前端条目 issue 段允许 frontend 字面量、backend_status 允许 not_required(接口类仍禁)
- E_PLACEHOLDER 只拦双花括号/TODO/待补充,不再误杀 {orderId} 等 REST 路径参数
- E_SECTIONS 仅约束接口类条目,章节名宽匹配(变更接口/变更清单/接口变化/行为变化等)
- 核心门禁保持硬:接口类必须 backend_status=deployed 才允许发布(E_BACKEND_PENDING)
- 背景:规则假阳性致 CI 长期常红被忽略,真违规(未部署即推送)淹没其中;npm test 46/46 绿

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:36:48 +08:00
共有 13 个文件被更改,包括 125 次插入37 次删除

2
.gitattributes vendored 普通文件
查看文件

@ -0,0 +1,2 @@
.githooks/* text eol=lf
scripts/*.mjs text eol=lf

25
.githooks/pre-push 普通文件
查看文件

@ -0,0 +1,25 @@
#!/bin/sh
# changelog 发布门禁(推送前强制校验)
# 启用(每台机一次): git config core.hooksPath .githooks
# 拦截目标: 接口类 changelog 未部署测试服(backend_status != deployed)就推送给前端,
# 以及文件名/frontmatter 结构违规。规则实现见 scripts/validate-changelog-*.mjs。
zero=0000000000000000000000000000000000000000
status=0
while read local_ref local_sha remote_ref remote_sha; do
# 删除远端分支的推送没有本地内容可校验
[ "$local_sha" = "$zero" ] && continue
if [ "$remote_sha" = "$zero" ]; then
base=$(git rev-parse --verify origin/main 2>/dev/null) || continue
else
base=$remote_sha
fi
[ "$base" = "$local_sha" ] && continue
node scripts/validate-changelog-filenames.mjs --base "$base" --head "$local_sha" || status=1
node scripts/validate-changelog-frontmatter.mjs --base "$base" --head "$local_sha" || status=1
done
if [ "$status" -ne 0 ]; then
echo "" >&2
echo "推送被 changelog 发布门禁拦截:接口类条目必须测试服已部署+实测(backend_status=deployed)后才能推送给前端。" >&2
echo "修正文件后重试;规则详见 BACKEND_CHANGELOG_DELIVERY_GUIDE.md §2.1。" >&2
fi
exit $status

查看文件

@ -10,9 +10,11 @@
文件名:
```text
DD_issue_业务标题-{新增接口|修改接口|删除接口}-{管理后台|小程序端}.md
DD_issue_业务标题-{新增接口|修改接口|删除接口|修复|前端缺陷|前端优化|前端修复}-{管理后台|小程序端}.md
```
纯前端条目无后端工单issue 段写字面量 `frontend`,如 `10_frontend_标题-前端缺陷-管理后台.md`
例如:
```text
@ -48,6 +50,21 @@ verified_at: ""
- 不需要前端修改:`frontend_status: "not_required"`
- 后端不要代替前端填写 `implemented``released``verified`
## 2.1 发布门禁硬规则,2026-08-10 wx 定)
**给前端推送的 changelog,内容必须是测试环境已经存在、可实测到的。**
- 接口类条目(新增接口/修改接口/删除接口推送前必须走完「PR 合并 → 部署测试服 → 测试服真实 API 验证」,frontmatter 必须 `backend_status: "deployed"`,并在正文「验证证据」章节贴实测结果。
- `backend_status``merged` / `pending` / `implemented` 等未部署状态的条目**禁止 push**(校验规则 E_BACKEND_PENDING 会拦)。「先给前端契约、部署随后」的预告式推送一律禁止——前端拿到 changelog 会立刻联调,接口不在等于空耗与误判。
- 纯前端条目(前端缺陷/前端优化/前端修复):`backend_status: "not_required"`,change_type 用对应前端类型;`frontend_status: "not_required"` 时不得残留 frontend_owner / frontend_ref / target_release / verified_at。
- 背景2026-08-06~08-07 三条未部署即推送的条目(#5599/#5567/#5633导致前端在测试环境验不到字段2026-08-10 投诉属实);当时仓库 CI 因校验规则假阳性长期常红被忽略,规则已于 2026-08-10 修正(前端条目类型合法化、`{orderId}` 路径参数不再误判为占位符),此后 **CI 红 = 真违规,必须当场修复回填**
**推送校验(强制)**
- 推荐一次性启用本地钩子,之后 push 自动拦截:`git config core.hooksPath .githooks`
- 未启用钩子则每次 push 前手动跑 §3 的两条校验命令,红了不许推。
- 仓库 CIchangelog-filename-gate对每次 push 复检;push 后请回看 Gitea Actions 状态,红 X 必须当场处理。
## 2.5 写作方法论(对齐 yst 团队 changelog-conventions SKILL,2026-08-04 起执行)
**受众优先**:触达 `/admin/*` `/mp/*` `/v3/admin/*` `/v3/mp/*` 等对外前缀的改动**一律**写前端 changelog,哪怕"前端代码零改动"(前端 AI 可能有 workaround 需清理信号)。`/v3/internal/*` Feign 接口**必须拆出去**单独走后端 changelog,不许和 admin/mp 接口塞同一份(反例:# traveler 11 接口事故)。

查看文件

@ -5,7 +5,7 @@ title: "Step2 canonical full snapshot 与稳定槽位"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "released"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "Pi"

查看文件

@ -5,15 +5,15 @@ title: "历史终止订单车辆核单空态"
consumer: "admin"
change_type: "修改接口"
author: "yst(GIT)"
backend_status: "pending"
gateway_status: "pending"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@4a2dcc8e20fe23ffc2b3d35ae8f02e62661b642d"
target_release: "v2.1"
verified_at: "2026-08-06"
status_note: "PR #5570 已合并 dev-v3;运行时行为尚未验证,管理后台待适配新增阻断枚举。"
updated_at: "2026-08-06"
status_note: "PR #5570 已合并 dev-v3;2026-08-10 复核确认测试服已部署、网关链路实测连通(见文末验证证据章节)。管理后台待适配新增阻断枚举。"
updated_at: "2026-08-10"
base: "dev-v3"
---
@ -295,3 +295,11 @@ Authorization: Bearer <管理后台访问令牌>
- **后端负责人**@yst / yaosutu
- **前端消费方**:管理后台车辆核单 Tab
## 验证证据2026-08-10 复核回填,wx
> 本条 changelog 2026-08-06 推送时 backend_status=pending未部署,违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建dev-v3,晚于 PR #5570 合并点2026-08-06 08:17,本变更代码已在运行实例中。
- `GET /v3/admin/order/{orderId}/settlement/step3/vehicles` 经网关 9443 + 真 admin token 实测链路连通(普通订单返回既有业务码,行为正常)。
- 测试库当前无 `flow_status=TERMINATED` 的历史终止订单,`LEGACY_VEHICLE_FEE_SOURCE_MISSING` 安全空态场景暂无法端到端复现,该场景行为以合并代码 + 部署点位确认;如前端联调需要真实数据请联系后端造数。

查看文件

@ -5,16 +5,16 @@ title: "核单餐食餐厅下拉值独立存储"
consumer: "admin"
author: "yst"
change_type: "修改接口"
backend_status: "merged"
gateway_status: "pending"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@01bd3875046cd32e9497e2f00a9eb0f782a197dd"
verified_at: ""
target_release: ""
updated_at: "2026-08-07"
updated_at: "2026-08-10"
base: "dev-v3"
status_note: "PR #5600 已合并 dev-v3,尚未部署测试服;restaurantId 关联资源服务餐厅下拉接口 PR #5583"
status_note: "PR #5600 已合并 dev-v3;2026-08-10 复核确认测试服已部署并验证(见文末验证证据章节)。restaurantId 关联资源服务餐厅下拉接口 PR #5583"
---
# 核单餐食餐厅下拉值独立存储(不覆盖餐食名称)
@ -298,7 +298,7 @@ Content-Type: application/json
- **破坏性兼容**:无。两个字段均为可选新增;存量请求不传两字段时行为完全不变;存量数据两列为 NULL
- **前端同步上线**:不强制同步。前端未接新字段前,保存 / 回显行为与之前一致(回显多两个 null 字段,不读即可);前端接新字段需等后端部署后联调
- **后端部署状态**PR #5600 已合并 dev-v3,**尚未部署测试服**(见 Front Matter backend_status / status_note
- **后端部署状态**PR #5600 已合并 dev-v3,**测试服已部署**2026-08-10 复核确认,见文末验证证据章节
- **回滚方案**:后端回滚 = 下线两字段即可。回滚时前端需同步停止传这两字段;存量数据两列本就为 NULL 或历史快照值,无数据迁移、无回滚 SQL
## 12. 注意事项
@ -317,3 +317,12 @@ Content-Type: application/json
- Commithttps://git.1814.love:8443/wx/HL/commit/9884585a292924c1a0a7a5fec6b7dc8ab87aa59d
- 关联依赖:餐厅资源下拉接口 PR #5583(资源服务,已上线)
- 后端负责人yst腰苏图
## 验证证据2026-08-10 复核回填,wx
> 本条 changelog 2026-08-06 推送时后端尚未部署测试服(原 status_note 自述),违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建dev-v3,晚于 PR #5600 合并点2026-08-06 14:56,本变更代码已在运行实例中。
- 测试服 DB `hl_order_service_v3.order_settlement_meal` 已存在 `restaurant_id` / `restaurant_name` 两列Flyway 已执行)。
- `SettlementMealRespVO``restaurantId` / `restaurantName` 字段dev-v3 源码核对)。
- `GET /v3/admin/order/{orderId}/settlement/meals` 经网关 9443 + 真 admin token 实测返回 `code=200`空列表订单;测试库现有餐食记录的订单因核单数据权限581008 无权查看此订单)未能以 SUPER_ADMIN 直接观测到带值行,字段存在性以 DB 列 + VO 源码 + 部署点位三重证据确认。

查看文件

@ -5,15 +5,15 @@ title: "订单详情补核单状态字段"
consumer: "admin"
change_type: "修改接口"
author: "yst(GIT)"
backend_status: "implemented"
gateway_status: "pending"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "hl-admin@18f8e23b9b2c77a81fed3de87fe9a7b94ff3b201"
target_release: "v2.1"
verified_at: ""
status_note: "PR #5635 已合并 dev-v3merge commit c378061b08;管理后台待接入 reviewStatus/reviewStatusName。"
updated_at: "2026-08-07"
status_note: "PR #5635 已合并 dev-v3;2026-08-10 复核确认测试服已部署、reviewStatus/reviewStatusName 经网关实测在出参中(见文末验证证据章节)。管理后台待接入。"
updated_at: "2026-08-10"
base: "dev-v3"
---
@ -275,3 +275,10 @@ Authorization: Bearer <管理后台访问令牌>
- **PR**[#5635](https://git.1814.love:8443/wx/HL/pulls/5635)
- **Commit**[c378061b08](https://git.1814.love:8443/wx/HL/commit/c378061b08e85cc7794b23c2a49691ad4f8eb01e)
- **后端负责人**:腰苏图
## 验证证据2026-08-10 复核回填,wx
> 本条 changelog 2026-08-07 推送时 backend_status=implemented非法枚举且未部署,违反「测试服部署+实测后才通知前端」流程。2026-08-10 复核补齐部署与验证证据如下:
- 测试服 hl-order-service-v3 运行版本为 2026-08-10 15:10 构建dev-v3,晚于 PR #5635 合并点2026-08-07 14:25,本变更代码已在运行实例中。
- `GET /v3/admin/order/{orderId}` 经网关 9443 + 真 admin token 实测:`data.main` 已包含 `reviewStatus` / `reviewStatusName` 两个键(未进入核单流程的订单两键返回 JSON null,符合本文 8.2 边界示例)。

查看文件

@ -5,7 +5,7 @@ title: "后端已修复:房型 BIG_BED 全链路中文(#5730+ 派车通
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "released"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "not_required"
frontend_owner: ""
@ -22,13 +22,15 @@ generated: "2026-08-09T11:40:00+08:00"
> 两个后端修复已合并 dev-v3、部署 TEST 并验证通过。告知前端知晓/验证/配合接入。
## ① #5730 房型 BIG_BED 全链路中文展示
## 变更内容
### ① #5730 房型 BIG_BED 全链路中文展示
**修复**`room_category` 字典补充 BIG_BED→「大床房」中文 label,行程/住宿安排/配房等展示处 `roomCategoryLabel` 现在映射到中文,不再显示英文 BIG_BED。
**前端影响****无需改代码**。原先住宿安排/行程里房型显示「BIG BED1」的位置,现在应显示「大床房」。请前端**验证**房型中文展示是否已正常(如订单 26-8083 娜仁托娅的住宿安排)。
## ② #5732 派车通知预览(render-batch)日期按接续段分段
####5732 派车通知预览(render-batch)日期按接续段分段
**修复**`render`/`render-batch` 渲染的「日期」order.startDate/endDate/days 占位符)在传入 `serviceDates` 非空时按 **min~max 分段**,未传时回退订单全程;与实际 HOLD 通知快照口径一致。

查看文件

@ -57,6 +57,11 @@ base: "dev-v3"
- 保留行继续占用车辆/司机(同日期同资源不可重复派),人工取消后释放;改期后新日期不受旧占用影响。
- 换版自动化只作用于 unassigned减槽取消未派占位、增槽补新 unassigned。
## 验证证据
- 后端 PR #5785(主)+ #5787/#5789(连带)已合并 dev-v3 并部署测试服(backend_status=deployed 于 2026-08-10 回填,测试服 hl-order-service-v3 运行 2026-08-10 构建版本)。
- 详情接口新增 2 字段随该版本在测试服生效;前端实现自测 util 5/5、组件 4/4、看板关联 287/287、checkpoint 全过(见 status_note)。
## 关联 / 联系人
### 链接

查看文件

@ -28,7 +28,9 @@ base: "dev-v3"
---
## 1. 详情接口 vehicleSlots 新增 3 字段
## 变更接口
### 1. 详情接口 vehicleSlots 新增 3 字段
`GET /admin/fleet/board/orders/{orderId}``vehicleSlots[]` 每行新增:
@ -42,7 +44,7 @@ base: "dev-v3"
**前端要做**: 保留行渲染「旧数据/需求已改版」标识(区别于当前槽位),操作只留「改派 / 取消」;顶部黄条(supersededAssignments)保持现状作提醒入口。注意保留行的 `fleetItemIndex` 是旧版展开序,可能与当前需求槽位撞号,**渲染分组请以 superseded 标志区分,勿再单靠 fleetItemIndex**。
## 2. 候选查询排除校验放宽(保留行改派入口打通)
### 2. 候选查询排除校验放宽(保留行改派入口打通)
`POST /admin/fleet/assignments/candidates`:
@ -51,11 +53,11 @@ base: "dev-v3"
- 保留行自身占用会被正确排除:实测 exclude 后原车 available=true、conflicts=[](可改回原车或换车)。
- 防护不回归:非本订单/不存在的 assignmentId、普通行 fleetItemIndex 不匹配 → 仍报「参数非法」。
## 2.5 跟进(PR #5798,2026-08-10):排除未派车占位行也不校验序号
### 2.5 跟进(PR #5798,2026-08-10):排除未派车占位行也不校验序号
现版前端槽位上下文缺 `fleetItemIndex` 时回退 0(`useAssignFlow.js:294`),排除 SUV 占位行(实际序号 1)时被后端精确匹配拒绝(26-9313 复现)。后端已放宽:**排除当前需求的 unassigned 占位行时不校验 fleetItemIndex**(需求归属仍校验),座位按占位行自身 requiredSeats 快照。现版前端不改也能选车,但仍建议槽位上下文与 `vehicleSlots[].fleetItemIndex`/`assignmentId` 同源取值,消除序号错位。
## 2.6 展示布局建议(wx 2026-08-10 口径)
### 2.6 展示布局建议(wx 2026-08-10 口径)
场景:原需求商务车×2(两辆均已派),改为商务×1+SUV×1。期望车务再派车时看到:
@ -65,7 +67,7 @@ base: "dev-v3"
即"原来的两辆商务车都可见(一辆沿用在新槽、一辆标旧),新需求两个槽位齐全"。
## 3. 实测数据样例(测试服 26-9313)
## 验证证据:实测数据样例(测试服 26-9313)
```json
// vehicleSlots 尾部保留行

查看文件

@ -8,10 +8,10 @@ change_type: "修复"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "not_required"
frontend_owner: "mmg"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: "2026-08-10"
verified_at: ""
status_note: "接口契约零变化,前端无需改动即生效readByPeer 字段在车务会话首次真正有值)。附带新增:车务团队读后向定制师推点对点 im-chat-read 信令,SSE 角标实时化接线时可顺带消费实现气泡实时翻「已读」。测试服 16:00 后已用真实 API + Redis 信令抓包验证通过。"
updated_at: "2026-08-10"
base: "dev-v3"

查看文件

@ -8,7 +8,7 @@ const CONTROLLED_ROOTS = new Map([
['changelogs-v2', '管理后台'],
['changelogs-v2-mp', '小程序端'],
]);
const CHANGE_TYPES = new Set(['新增接口', '修改接口', '删除接口']);
const CHANGE_TYPES = new Set(['新增接口', '修改接口', '删除接口', '修复', '前端缺陷', '前端优化', '前端修复']);
const PATH_ALIAS_MANIFEST = 'changelog-path-aliases.json';
function ruleError(code, path, message, expected) {
@ -180,7 +180,7 @@ export function validateChangelogPath(inputPath, now = new Date()) {
'E_CHANGE_TYPE',
changelogPath,
`变更类型为 ${actualType || '(缺失)'}`,
'新增接口 / 修改接口 / 删除接口',
[...CHANGE_TYPES].join(' / '),
));
}
@ -203,8 +203,8 @@ export function validateChangelogPath(inputPath, now = new Date()) {
if (day !== expectedDate.day) {
errors.push(ruleError('E_DAY', changelogPath, `日前缀为 ${day}`, expectedDate.day));
}
if (!/^[1-9]\d*$/.test(issue)) {
errors.push(ruleError('E_ISSUE', changelogPath, `Issue 号为 ${issue || '(缺失)'}`, '不带 # 的十进制正整数'));
if (!/^[1-9]\d*[a-z]?$/.test(issue) && issue !== 'frontend') {
errors.push(ruleError('E_ISSUE', changelogPath, `Issue 号为 ${issue || '(缺失)'}`, '不带 # 的十进制正整数(可带一位小写字母后缀),或纯前端条目用 frontend'));
}
if (title.trim() === '') {
errors.push(ruleError('E_TITLE', changelogPath, '业务标题为空', '非空业务标题'));

查看文件

@ -19,10 +19,12 @@ const FRONTEND_STATUSES = new Set([
'released',
'verified',
]);
const BACKEND_STATUSES = new Set(['pending', 'tested', 'deployed']);
const BACKEND_STATUSES = new Set(['pending', 'tested', 'deployed', 'not_required']);
const GATEWAY_STATUSES = new Set(['pending', 'verified', 'not_required']);
const CONSUMERS = new Set(['admin', 'mp', 'internal', 'multiple']);
const CHANGE_TYPES = new Set(['新增接口', '修改接口', '删除接口']);
const CHANGE_TYPES = new Set(['新增接口', '修改接口', '删除接口', '修复', '前端缺陷', '前端优化', '前端修复']);
// 接口契约类条目:后端必须已部署测试服并实测(E_BACKEND_PENDING 硬门禁)才允许发布
const API_CHANGE_TYPES = new Set(['新增接口', '修改接口', '删除接口']);
const REQUIRED_KEYS = [
'schema',
'ticket',
@ -180,8 +182,11 @@ export function validateV2Document(file, text, { requireV2 = false } = {}) {
if (!GATEWAY_STATUSES.has(metadata.gateway_status)) {
errors.push(ruleError('E_GATEWAY_STATUS', file, `gateway_status 非法: ${metadata.gateway_status || '(空)'}`));
}
if (metadata.backend_status !== 'deployed') {
errors.push(ruleError('E_BACKEND_PENDING', file, '发布的 changelog 必须是 backend_status=deployed'));
if (API_CHANGE_TYPES.has(metadata.change_type) && metadata.backend_status === 'not_required') {
errors.push(ruleError('E_BACKEND_STATUS', file, '接口类 changelog 不允许 backend_status=not_required'));
}
if (!['deployed', 'not_required'].includes(metadata.backend_status)) {
errors.push(ruleError('E_BACKEND_PENDING', file, '发布的 changelog 必须是 backend_status=deployed(未部署测试服并实测前禁止推送;纯前端条目用 not_required)'));
}
if (metadata.gateway_status === 'pending') {
errors.push(ruleError('E_GATEWAY_PENDING', file, '发布的 changelog 不能保留 gateway_status=pending'));
@ -200,15 +205,21 @@ export function validateV2Document(file, text, { requireV2 = false } = {}) {
if (issue && metadata.ticket !== issue) {
errors.push(ruleError('E_TICKET_MISMATCH', file, `ticket=${metadata.ticket} 与文件名 Issue=${issue} 不一致`));
}
const filenameType = /-(新增接口|修改接口|删除接口)-(?:管理后台|小程序端)\.md$/.exec(filename)?.[1];
const filenameType = /-(新增接口|修改接口|删除接口|修复|前端缺陷|前端优化|前端修复)-(?:管理后台|小程序端)\.md$/.exec(filename)?.[1];
if (filenameType && metadata.change_type !== filenameType) {
errors.push(ruleError('E_TYPE_MISMATCH', file, `change_type=${metadata.change_type} 与文件名=${filenameType} 不一致`));
}
if (/\{[^{}\n]+\}|\bTODO\b|待补充/i.test(body)) {
// 单花括号是 REST 路径参数惯例({orderId}),只拦真正的模板残留:双花括号、TODO、待补充
if (/\{\{[^{}\n]+\}\}|\bTODO\b|待补充/i.test(body)) {
errors.push(ruleError('E_PLACEHOLDER', file, '正文仍有 TODO、待补充或模板占位符'));
}
if (!body.includes('## 变更接口') || !body.includes('## 验证证据')) {
errors.push(ruleError('E_SECTIONS', file, '正文缺少“变更接口”或“验证证据”章节'));
// 接口类条目必须有接口清单章节与验证章节;修复/前端类条目结构自由,不强制
if (API_CHANGE_TYPES.has(metadata.change_type)) {
const hasApiSection = /^##[^\n]*(变更接口|变更清单|变更内容|接口详情|变更点|接口变化|行为变化)/m.test(body);
const hasEvidenceSection = /^##[^\n]*(验证|测试|复现|证据)/m.test(body);
if (!hasApiSection || !hasEvidenceSection) {
errors.push(ruleError('E_SECTIONS', file, '接口类正文缺少接口清单(变更接口/变更清单)或验证(验证证据/测试)章节'));
}
}
return errors;
}