chore(#216): 提交信息工单号门禁(commit-msg hook + CI)+ 台账补录 #191~#197
R-P2-9 治理无号提交(不追溯历史,只管新增): 1. 判据单一来源 scripts/check-commit-issue.sh: - --message-file(本地 hook)/ --range(CI)/ --head-only(CI 回退) - 放行:信息含 #数字、显式 [skip-issue]、merge 提交;违规逐条列出后退出 1。 - 临时 git 仓正/负/区间/空区间/skip/merge/--no-verify 全部实测。 2. scripts/install-commit-msg-hook.sh:安装 .git/hooks/commit-msg 调用判据脚本 (与 gitleaks pre-commit 独立;判据随仓库更新无需重装)。 3. .gitea/workflows/test.yml 新增 commit-message-lint 轻量 job(纯 git 不依赖 docker): push 用 before..after、PR 用 base..head;两端不可达/新分支/force-push 回退仅查 HEAD, 保证不误阻断主干。 4. docs/standards/issue-workflow.md §1.5 + README 补提交规范与钩子安装说明。 5. 台账新增 §十七,据 Gitea API + git log 考据补录 #191~#197: #192/#194/#195/#197 closed 且均有关闭凭证评论;#191/#193/#196 open(附 commit/文档依据)。 R-P2-9 回填已完成。
This commit is contained in:
@@ -18,6 +18,49 @@ on:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
# #216/R-P2-9: 提交信息必须携带 #工单号(与本地 commit-msg 钩子共用 scripts/check-commit-issue.sh)。
|
||||
# 纯 git 轻量门禁, 不依赖 docker; 只校验「本次新增」提交, 不追溯历史。
|
||||
commit-message-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码 (显式 clone)
|
||||
run: |
|
||||
rm -rf /workspace/ci-repo
|
||||
git clone --quiet http://127.0.0.1:3000/tanzk/csctalon.git /workspace/ci-repo
|
||||
cd /workspace/ci-repo && git log --oneline -1
|
||||
|
||||
- name: 校验新增提交信息携带工单号 (#216)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd /workspace/ci-repo
|
||||
zero=0000000000000000000000000000000000000000
|
||||
event="${{ github.event_name }}"
|
||||
# 默认按 push 的 before..after;PR 改用 base..head。
|
||||
before="${{ github.event.before }}"
|
||||
after="${{ github.event.after }}"
|
||||
[ -z "$after" ] && after="${{ github.sha }}"
|
||||
if [ "$event" = "pull_request" ]; then
|
||||
before="${{ github.event.pull_request.base.sha }}"
|
||||
after="${{ github.event.pull_request.head.sha }}"
|
||||
fi
|
||||
echo "event=$event before=${before:-<empty>} after=$after"
|
||||
|
||||
# 两端提交都本地可达且 before 非全零(非新分支首推)→ 精确校验新增区间;
|
||||
# 新分支首推 / force-push 旧基不可达 / fork PR 等无法确定可靠区间时,
|
||||
# 回退为仅校验 HEAD(保守: 不追溯、不误阻断; 主干最新提交本就要求带号)。
|
||||
if [ -n "${before:-}" ] && [ "$before" != "$zero" ] \
|
||||
&& git cat-file -e "${before}^{commit}" 2>/dev/null \
|
||||
&& git cat-file -e "${after}^{commit}" 2>/dev/null; then
|
||||
range="$before..$after"
|
||||
echo "== 校验新增提交区间 $range =="
|
||||
git log --oneline "$range" || true
|
||||
bash scripts/check-commit-issue.sh --range "$range"
|
||||
else
|
||||
echo "== 无法确定可靠区间(新分支/force-push/fork),回退仅校验 HEAD =="
|
||||
git log --oneline -1
|
||||
bash scripts/check-commit-issue.sh --head-only
|
||||
fi
|
||||
|
||||
backend-lint-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -161,7 +161,10 @@ csctalon/
|
||||
| 规范 | `docs/standards/` | 错误码 / 审查清单 / 任务派工单模板 / 工单驱动工作流 |
|
||||
| 文档组织 | `docs/README.md` | docs 目录职责 / 文件命名规范 / 运维手册分发 |
|
||||
| 测试 | `backend/tests/` | pytest 基建, 独立 `csctalon_test` 库, 隔离开发/生产 |
|
||||
| CI | `.gitea/workflows/` | gitleaks 凭证扫描 + backend-test(ruff `app/`+`tests/` · **空库 alembic upgrade head** · pytest,强制) |
|
||||
| CI | `.gitea/workflows/` | gitleaks 凭证扫描 + backend-test(**提交信息工单号校验** · ruff `app/`+`tests/` · **空库 alembic upgrade head** · pytest,强制) |
|
||||
|
||||
> **提交钩子(建议安装)**:`bash scripts/install-gitleaks-hook.sh`(pre-commit 扫凭证)+
|
||||
> `bash scripts/install-commit-msg-hook.sh`(commit-msg 强制提交信息带 `#工单号`,#216)。
|
||||
|
||||
**协作流程**: 需求/事件 → **建 Gitea 工单**(见 [docs/standards/issue-workflow.md](docs/standards/issue-workflow.md),事故拆单:incident + governance)→ 架构师出设计 → 人工锁定(`docs/arch/` + git tag) → 开发者实现(提交/PR 关联 `#issue号`)→ 审查员审查 → 人工终审合并。测试与 lint 由 CI 机器验证, 不依赖 AI 口头声称。
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
3. **一单一目标**。事故类必须拆成「止损工单」与「治理工单」两条,禁止混单。
|
||||
4. **工单必须写「关闭条件」**。没有关闭条件的工单视为无效工单。
|
||||
5. **代码变更必须关联工单**。提交信息、PR 描述须携带 `#issue号`,否则审查不通过。
|
||||
本地 `commit-msg` 钩子与 CI(`commit-message-lint`)双重校验(#216):安装钩子执行
|
||||
`bash scripts/install-commit-msg-hook.sh`(与 gitleaks 的 pre-commit 相互独立);
|
||||
判据脚本 `scripts/check-commit-issue.sh` 两处同源。merge 提交自动放行;确无工单的纯维护/
|
||||
版本号提交须在信息中显式写 `[skip-issue]`;紧急可用 `git commit --no-verify`(会同时绕过
|
||||
gitleaks,慎用)。CI 只校验**本次新增**提交,不追溯历史。
|
||||
6. **禁止无凭证关闭**。关闭工单前必须先追加 `## 关闭凭证核验` 评论,逐条对应关闭
|
||||
条件并给出可复现的核验方式(测试名 / commit sha / 实测命令);批量关闭时每张
|
||||
工单各写一条。详见 §四点一。
|
||||
|
||||
@@ -390,7 +390,7 @@ sudo rm -f /opt/csctalon/backups/pre-org-20260914.dump # 108M (09
|
||||
| R-P2-6 | P2 | L-3(2031 乱年份 3 行 ¥203)决策悬置 | ✅ 脚本已落地(#209 `7a7bc25`;前置缺陷 #220 `ad7ddf5`),生产随发布打标 | 报告 §4.4;#207 已拍板选项③(只打标、不改 register_time/口径):scripts/mark_manual_future_year_209.py 经 bootstrap+db_guard,默认 dry-run、行数安全门(--expected 3 不符拒绝)、写 dup_residual+note、幂等;5 单测 + test 库端到端(3 行¥203 打标/拒绝/幂等/清理)全绿。遗留:生产 3 行随发布执行 `--mode prod --apply --allow-real-db` 后回贴 #209/#207。实施中另修 bootstrap 导入时序致切库失效的缺陷(#220,影响所有非默认模式脚本,新增 2 子进程回归测试) |
|
||||
| R-P2-7 | P2 | LLM 审计无 token/成本字段;无问答级缓存 | 待处理 | 报告 §3.2 INFO |
|
||||
| R-P2-8 | P2 | API 文档端点数 ~374 vs 实际 520(+39%) | ✅ 已完成(#215,2026-10-07) | 报告 §3.6 W3;以 `app.openapi()` 实盘(较台账清点时已再增长):**449 个路径 / 547 个 method 操作**(448 个 `/api/v1` 业务路径 + `/health`);API 文档升 v1.2、README §6.3 同步校正,均附可复算命令;REF 明细以代码为准、不逐条重列(避免再失真) |
|
||||
| R-P2-9 | P2 | 无号提交 ~50%;台账行与 #191~#197 登记缺失 | 待处理 | 报告 §3.6 W4/INFO;治理(hook/CI)+ 补录 |
|
||||
| R-P2-9 | P2 | 无号提交 ~50%;台账行与 #191~#197 登记缺失 | ✅ 已完成(#216,2026-10-07) | 报告 §3.6 W4/INFO;① 判据单一脚本 `scripts/check-commit-issue.sh`(带号 / `[skip-issue]` / merge 放行),本地 commit-msg hook 安装器 `scripts/install-commit-msg-hook.sh`(与 gitleaks pre-commit 独立,临时仓正/负/跳过/--no-verify 全测);② CI test.yml 新增 `commit-message-lint` 轻量 job,校验本次新增提交(before..after / PR base..head,区间不可得回退仅查 HEAD,不误阻断、不追溯历史);③ 台账新增 §十七据 Gitea API+git log 考据补录 #191~#197(4 关闭均有凭证评论、3 open);④ issue-workflow.md §1.5 + README 补提交信息规范与钩子安装。守不做项:未改写历史提交 |
|
||||
| R-P2-10 | P2 | `scripts/_bootstrap.py` 路径与实际不符;顶层 `scripts/` 0 处 bootstrap | 待处理 | 报告 §3.6 W2;涉 AGENTS 改动须人工审核 |
|
||||
| R-P2-11 | P2 | 备份异地未配置、恢复演练未做 | 待处理 | 报告 §3.5 W7;配置异地存储 + 排期演练 |
|
||||
| R-P2-12 | P2 | web 无 healthcheck;四服务无资源限额;nginx 宿主日志未见轮转 | 待处理 | 报告 §3.5 W8;逐项加固 |
|
||||
@@ -441,3 +441,18 @@ sudo rm -f /opt/csctalon/backups/pre-org-20260914.dump # 108M (09
|
||||
| S-P2-4 | P2 | 3 个 .ts 零类型(checkJs:false);api 层零覆盖 | 待处理 | 报告 §4.4 |
|
||||
| S-P2-5 | P2 | 运营策略硬编码(sync_task_manager:386 等 4 处)须发版 | 待处理 | 报告 §4.1 |
|
||||
| S-P2-6 | P2 | 发票/微信注册数据源未入待办 | 待处理 | 报告 §4.2 |
|
||||
|
||||
## 十七、工单补录:#191~#197(#216,R-P2-9)
|
||||
|
||||
> 2026-10-07 据 Gitea API + `git log` 考据补记(R 报告 §4.x「台账 header 失真、#191~#197 无登记行」)。
|
||||
> 状态为 **Gitea 实查**(非转述报告——报告评审时无 API 凭证,曾注「#195~#197 关闭凭证无法线上核验」;本次持 token 核实:4 张已关闭工单**均有「关闭凭证核验」评论**)。仅补登记,不改工单状态、不追溯历史提交。
|
||||
|
||||
| 工单 | 标题(摘要) | Gitea 状态(2026-10-07 实查) | 考据依据(commit / 文档 / 凭证) |
|
||||
|---|---|---|---|
|
||||
| #191 | E 路定时采集恒 0 行:0 行当成功 + 无时效监控 + 低频档窗口写死昨天 | 🔵 open(4 评论,**含凭证评论**) | E 路时效闭环已落地:`5bf4325`/`6c369a7`(档位按源可配小时/窗口 + 0 行/时效告警 + AI T+1)、`f42fcb1`(低频回填看自身记录)、`1cd8f19`(基准日随采集小时消误报);只读核验脚本 `4e0a31a`。open 疑为持续观测/生产确认未闭环 |
|
||||
| #192 | 命中链路把「缺维度空壳快照」当有效命中(74~88 字"暂无"回答) | ✅ closed 2026-09-24(1 评论,**有凭证**) | `a579138`(空壳快照门槛)、`d1f1162`(命中门槛收紧为"问什么必须有什么"+ 占比/字数双判据) |
|
||||
| #193 | AI 报告刷新频率与命中量错配(日预生成 100+ vs 命中 2~10) | 🔵 open(5 评论,**无关闭凭证**) | 联动 **R-P0-3 / #204**:P1+P2 已实施处于 dry_run 影子期(`3630c30`),方案 `docs/design/20260924-#193-AI报告刷新策略-无新事件跳过-实现方案.md`;生产验收数据待补,**不重开、不静默关**(见 R-P0-3 行) |
|
||||
| #194 | 本地遗留同名库 csctalon 处置:备份 + 根 .env 对齐 dev + 改名 | ✅ closed 2026-09-24(1 评论,**有凭证**) | 运维处置类(备份/改名/环境对齐),无代码 commit 属正常;凭证见工单评论 |
|
||||
| #195 | 315 共享文档解析治理:脏值清洗增强 + 自由文本投诉日期补救 | ✅ closed 2026-09-25(1 评论,**有凭证**) | `90b48c1`(确定性恢复 + 批次传播 + 提示词沉淀);样本号码 PII 净化另见 #211 凭证遗留项 |
|
||||
| #196 | 退款数据治理:采集偏差检测 + 数据异常修复 | 🔵 open(0 评论,**无凭证**) | 审计服务 `63498ef`(采集对账+日期跳跃+负数检测)、修复 `5f5a67a`(YY/MMDD 解析 + 空日期邻近填充);报告 `docs/reports/20260926-退款日期缺陷治理.md`;《仓库入库规范》§五 checklist 尚有未勾项(结论报告落档)——open 与该收尾未完成一致 |
|
||||
| #197 | gen_system v2.1:派生字段系统侧注入 + 122b 降级修正 | ✅ closed 2026-09-27(2 评论,**有凭证**) | `a67bb76`(v2.1 落地)、`e175646`/`354c18f`(ruff/CI 兼容修复)、`99841af`(提示词迭代 4 份报告入库) |
|
||||
|
||||
86
scripts/check-commit-issue.sh
Executable file
86
scripts/check-commit-issue.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# 提交信息工单号校验(#216 / R-P2-9)
|
||||
#
|
||||
# 本地 commit-msg 钩子与 Gitea CI 共用本脚本,保证两处判据完全一致(单一事实来源):
|
||||
# bash scripts/check-commit-issue.sh --message-file <file> # 校验单条信息(commit-msg hook)
|
||||
# bash scripts/check-commit-issue.sh --range <revspec> # 校验区间内每条提交(CI,如 before..after)
|
||||
# bash scripts/check-commit-issue.sh --head-only # 仅校验 HEAD(CI 无法确定区间时的回退)
|
||||
#
|
||||
# 判据(任一满足即放行该条提交):
|
||||
# 1) merge 提交:subject 以 "Merge " 开头(git/github/gitea 自动合并产生,天然无工单);
|
||||
# 2) 提交信息全文含显式跳过标记 [skip-issue](大小写不敏感)——仅限纯维护/版本号 bump 等
|
||||
# 确无工单的场景,留下可审计的显式声明;
|
||||
# 3) 提交信息含 "#" + 数字(#123)。
|
||||
# 其余一律判为不合规;存在任一条不合规即退出码 1(空区间视为通过)。
|
||||
set -euo pipefail
|
||||
|
||||
ISSUE_RE='#[0-9]+'
|
||||
SKIP_RE='\[skip-issue\]'
|
||||
|
||||
# check_one <标识>,提交信息从 stdin 读入;合规返回 0,不合规打印一行并返回 1。
|
||||
check_one() {
|
||||
local ident="$1" msg subject
|
||||
msg="$(cat)"
|
||||
subject="$(printf '%s\n' "$msg" | sed -n '1p')"
|
||||
|
||||
# 1) merge 提交(英文 "Merge ...";中文合并极少出现在自动提交里,一并兼容大小写)
|
||||
case "$subject" in
|
||||
"Merge "*|"merge "*) return 0 ;;
|
||||
esac
|
||||
# 2) 显式跳过标记(全文、大小写不敏感)
|
||||
if printf '%s\n' "$msg" | grep -Eiq "$SKIP_RE"; then
|
||||
return 0
|
||||
fi
|
||||
# 3) 携带工单号
|
||||
if printf '%s\n' "$msg" | grep -Eq "$ISSUE_RE"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf ' ✗ %s\n 首行: %s\n' "$ident" "$subject" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
check_sha() {
|
||||
local sha="$1" rc=0 ident
|
||||
ident="$(git log -1 --format='%h %s' "$sha")"
|
||||
if ! git log -1 --format=%B "$sha" | check_one "$ident"; then
|
||||
rc=1
|
||||
fi
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
main() {
|
||||
local mode="${1:-}" arg="${2:-}" rc=0 sha
|
||||
case "$mode" in
|
||||
--message-file)
|
||||
[ -n "$arg" ] || { echo "用法: $0 --message-file <file>" >&2; exit 2; }
|
||||
if ! check_one "commit-msg" < "$arg"; then rc=1; fi
|
||||
;;
|
||||
--range)
|
||||
[ -n "$arg" ] || { echo "用法: $0 --range <revspec>" >&2; exit 2; }
|
||||
# 逐个提交校验;收集所有违规而非遇第一条即停,便于作者一次改全。
|
||||
while IFS= read -r sha; do
|
||||
[ -z "$sha" ] && continue
|
||||
if ! check_sha "$sha"; then rc=1; fi
|
||||
done < <(git rev-list "$arg")
|
||||
;;
|
||||
--head-only)
|
||||
if ! check_sha "HEAD"; then rc=1; fi
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 --message-file <file> | --range <revspec> | --head-only" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
{
|
||||
echo ""
|
||||
echo "❌ 上述提交信息缺少工单号(规范: 信息中写 #工单号,如 'fix(#123): ...')。"
|
||||
echo " 确无工单的纯维护/合并提交,请在信息中显式加 [skip-issue];merge 提交自动放行。"
|
||||
} >&2
|
||||
fi
|
||||
exit "$rc"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
40
scripts/install-commit-msg-hook.sh
Executable file
40
scripts/install-commit-msg-hook.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# 安装 commit-msg 钩子:提交信息必须携带 #工单号(#216 / R-P2-9)
|
||||
# 用法: bash scripts/install-commit-msg-hook.sh
|
||||
#
|
||||
# 与 pre-commit(gitleaks,见 scripts/install-gitleaks-hook.sh)是两个独立钩子文件,
|
||||
# 互不影响、可分别安装;判据统一调用入库脚本 scripts/check-commit-issue.sh,
|
||||
# 因此判据更新随仓库走,无需重装钩子。
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
||||
echo "❌ 不在 git 仓库中" >&2
|
||||
exit 1
|
||||
}
|
||||
HOOK_DIR="$REPO_ROOT/.git/hooks"
|
||||
HOOK_FILE="$HOOK_DIR/commit-msg"
|
||||
CHECK_SCRIPT="$REPO_ROOT/scripts/check-commit-issue.sh"
|
||||
|
||||
if [ ! -f "$CHECK_SCRIPT" ]; then
|
||||
echo "❌ 找不到 $CHECK_SCRIPT(请在仓库根目录执行本脚本)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$HOOK_DIR"
|
||||
|
||||
# 注意用字面量 heredoc('EOF'):hook 内的 $1 / $(...) 必须在触发时而非安装时展开。
|
||||
cat > "$HOOK_FILE" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# commit-msg: 校验提交信息携带 #工单号(#216)
|
||||
# 判据见 scripts/check-commit-issue.sh(本地与 CI 同源)。
|
||||
set -euo pipefail
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
bash "$REPO_ROOT/scripts/check-commit-issue.sh" --message-file "$1"
|
||||
EOF
|
||||
|
||||
chmod +x "$HOOK_FILE"
|
||||
echo "✅ commit-msg 工单号钩子已安装: ${HOOK_FILE}"
|
||||
echo " 判据脚本: ${CHECK_SCRIPT}(随仓库更新,无需重装)"
|
||||
echo " 跳过方式: 提交信息加 [skip-issue](显式声明),或紧急时 git commit --no-verify"
|
||||
echo " (--no-verify 会同时绕过 gitleaks pre-commit,慎用)"
|
||||
Reference in New Issue
Block a user