# Changelog 贡献规则

## 二期文件名

`/v3/admin/*` 接口写入 `changelogs-v2/`：

项目例外：`/admin/fleet/*` 虽无 `/v3` 前缀，但由二期车管管理后台消费，同样写入 `changelogs-v2/`。

```text
changelogs-v2/YYYY-MM/DD_issue_业务标题-{新增接口|修改接口|删除接口}-管理后台.md
```

`/v3/mp/*` 接口写入 `changelogs-v2-mp/`：

```text
changelogs-v2-mp/YYYY-MM/DD_issue_业务标题-{新增接口|修改接口|删除接口}-小程序端.md
```

其中：

- `YYYY-MM` 和 `DD` 必须是校验运行时 `Asia/Shanghai` 的真实年月日，且均须补齐两位。跨越上海零点后仍未合并的 PR，需要把新文件重命名为当天日期。
- `issue` 必须是不带 `#` 的十进制正整数，不允许 `0`、负数或前缀符号。
- 业务标题不能为空。
- 变更类型只能是 `新增接口`、`修改接口` 或 `删除接口`。
- 端类型由目录唯一决定：`changelogs-v2/` 固定为 `管理后台`，`changelogs-v2-mp/` 固定为 `小程序端`。
- 同一改动同时影响 `/v3/admin/*` 和 `/v3/mp/*` 时，应按目录拆成两份。

一期 `changelogs/` 沿用现行格式，不套用上述强制模板。

## 校验范围

检测器读取 `git diff --name-status -z --find-renames` 的结果，只校验本次 diff 新出现的目标路径：

- `A`（新增）、`C`（复制）和 `R`（重命名）的目标路径必须通过规则。
- `M`（修改历史文件）豁免，不会因存量错误命名阻断。
- 已发布文件的 `D`（删除）和 `R`（重命名）默认以 `E_PATH_STABILITY` 阻断。确需迁移时，必须在
  `changelog-path-aliases.json` 登记旧路径到 canonical 的精确关系，并保留可读取的兼容入口。
- 重命名到受控目录时，新目标路径必须使用校验当天的上海日期。

本地校验：

```bash
npm test
npm run check:filenames -- --base origin/main --head HEAD
npm run check:path-aliases
```

生产 CLI 故意不提供 `--date` 或日期环境变量；测试只通过导出的纯函数注入 `Date`。规则失败返回退出码 `1`，Git/事件/参数等基础设施错误返回 `2`。

## 前端消费状态

新增二期 changelog 必须使用 `hl-changelog/v2` YAML Front Matter。状态只写在元数据中，不写入文件名：

```yaml
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
updated_at: "2026-07-24"
```

前端状态正常流转为：

```text
pending → claimed → implemented → released → verified
```

不需要前端修改时使用 `not_required`。字段一致性、必填证据和新增文档 frontmatter 由 `check:frontmatter` 校验。

完整职责和命令见：

- `FRONTEND_CONSUMPTION_STATUS_GUIDE.md`
- `BACKEND_CHANGELOG_DELIVERY_GUIDE.md`

已下发路径是消费契约的一部分，不通过重命名表达状态。历史路径已发生迁移时：

- `changelog-path-aliases.json` 是机器可识别的唯一映射源；
- alias 文件必须保留完整 `hl-changelog/v2` frontmatter，并用 `canonical_path` 指向 canonical；
- 前端状态更新使用 `npm run changelog:transition -- <path> <status> ... --write`，命令会同时更新
  canonical 与全部 alias；对同一状态和证据重复执行不会产生文件变更。

本地校验：

```bash
npm test
npm run check:filenames -- --base origin/main --head HEAD
npm run check:frontmatter -- --base origin/main --head HEAD
npm run check:path-aliases
```

## CI 与服务端阻断边界

Gitea Actions 会在指向 `main` 的 PR 和 `main` 的 push 上运行回归测试与文件名检测。该 workflow 是检测器：

- 在 `main` 未开启分支保护和 required status 时，失败状态不能硬性阻止合并。
- `push` 事件发生在写入之后，只能检测/报警，不能撤销直推。
- 只有管理员另行保护 `main`、关闭直推，并在 workflow 首次成功运行后，从 Gitea 最近上报的 status context 列表中选择实际值作为 required status，才能宣称服务端 hard gate 已激活。激活记录必须保存首次运行链接和 status API/分支保护回读证据；不得预设 job id/name `validate` 就是 Gitea 实际上报的 context。

因此，本仓库文件交付的准确表述是：**detector 已安装；在 `main` 未保护时，服务端 hard gate 尚未激活。**
