migrate-staging-database 的 deploy_sha 挡的是「迁移必须钉在真正过了门禁的 修订上」:格式校验、查该 SHA 有没有成功的 backend-quality-gate 运行、与 staging head 比对后把纯文档前进的判定交给背书过的 controller。这三条不能丢。 但产品手填的那个值,恰恰就是「最新一个过了门禁的 staging 提交」——机器能 自己算,而且需要的 API 查询在同一步里已经写好了。改成:留空即自动解析, 填了就完全走原路径(回滚与迁移到更早修订的唯一手段)。解析出来后仍然照常 跑一遍全部校验,两条路径共用同一套门。 范围比看上去小:Deploy Staging 在门禁通过后由 backend-quality-gate 自动 dispatch,正常根本不用点;真正每次都要手填的只有 Migrate Staging Database 一个按钮。 生产两个按钮保持手填。它们额外要 allow_rollback / recovery_reference / restore_verified,设计意图就是逼人说清楚要发什么;在生产省掉这步不是便利, 是拆护栏。 AGENTS.md §2.7 禁止代理改 workflow,产品本次明确授权,已写进决策记录, 否则执行方会拒改;授权范围仅限本单点名的文件与改动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
8.9 KiB
TASK · Migrate Staging Database 不再要求手填 SHA
- 日期:2026-09-15
- 基线 commit:
origin/staging@ebd6175b - 执行分支:
codex/staging-dispatch-autofill-sha-20260915 - 影响面:
.gitea/workflows/migrate-staging-database.yml(以及可选的deploy-staging.yml手动表单)
1. 产品诉求(原话)
我不想手填 sha 了,反人类,能不能改一下。
2. 先说清楚这个 SHA 在挡什么(不能直接删)
.gitea/workflows/migrate-staging-database.yml 的第一步 Validate current staging revision and successful gate 用 inputs.deploy_sha 做三件事:
- 格式校验:必须是 40 位小写十六进制。
- 查这个 SHA 上有没有跑成功过
backend-quality-gate(event=push、branch=staging、conclusion=success)。查不到就no successful exact-SHA staging quality gate run found并退出。 - 读当前
staginghead。若输入 ≠ head,标记head_check=deferred——因为纯文档推送不触发门禁,staging 合法地会领先于最后一个被门禁验过的 SHA;是不是「纯文档前进」留给后面那份门禁背书过的 controller bundle 里的deploy/is-docs-only-range.sh判定。
它的作用是:把迁移钉在一个真正过了门禁的修订上。 这个属性一条都不能丢。
但——产品手填的那个值,恰恰就是「最新一个过了门禁的 staging SHA」。这是一个机器可以自己算出来的量,而且算它需要的 API 查询这一步里已经写好了。让人肉去查、去复制、去粘贴 40 位十六进制,纯粹是把机器的活交给了人。
3. 范围比看上去小
| workflow | 现在要不要手填 | 本单是否处理 |
|---|---|---|
Migrate Staging Database |
要,且没有任何自动触发 —— 这就是痛点 | 是 |
Deploy Staging |
表单里要,但正常情况下不用点:backend-quality-gate.yml 在门禁通过后会自己 dispatch 它(并同时传 deploy_sha 与 gate_run_id) |
可选,见任务 2 |
Deploy Production / Migrate Production Database |
要 | 否,见 §4.2 |
所以真正每次都要手填的,只有一个按钮。
4. 决策记录
4.1 产品明确授权修改 workflow
AGENTS.md §2.7 写着「不改 .gitea/workflows/**……这三件事只由产品负责人触发」。产品负责人在 2026-09-15 主动要求改这一条,本单据此授权执行方修改 .gitea/workflows/migrate-staging-database.yml。
执行方不得以 §2.7 为由拒改,但授权范围仅限本单点名的文件与改动:把 deploy_sha 变成可选并在留空时自动解析。其余 workflow、其余步骤一律不动。
4.2 生产两个按钮保持手填,这是故意的
Deploy Production 与 Migrate Production Database 除了 SHA 还要求 allow_rollback、recovery_reference、recovery_created_at、restore_verified —— 这些输入的设计意图就是逼你把「我要发什么」说出来。AGENTS.md §1.4 也把生产部署定为手动流程。
在生产上省掉这步打字不是便利,是拆掉护栏。 本单不碰它们。若之后产品仍觉得生产也烦,另开一单单独评估。
4.3 自动解析的定义
留空时,workflow 自己解析出的 SHA = staging 分支上、最新一个有成功 backend-quality-gate 运行的提交。
这与产品手工查找的对象逐字相同,因此三条安全属性全部原样保留:仍然要求存在成功的精确 SHA 门禁运行(现在是"由这个条件选出来的");仍然做 head 比对与 head_check=deferred;仍然把纯文档前进的判定交给背书过的 controller。
5. 硬红线
- 只改
workflow_dispatch.inputs与第一步Validate current staging revision and successful gate的解析逻辑。 该步骤输出的三个值(sha/gate_run_id/head_check)语义与格式不得改变;后面所有步骤一行都不许动。 - 不得放宽任何校验:40 位格式校验保留;"必须存在成功的精确 SHA 门禁运行"保留;
head_check=deferred的分支与注释保留;is-docs-only-range.sh的下游判定保留。 - 不得改
deploy-production.yml/migrate-production-database.yml(§4.2)。 - 不得改
backend-quality-gate.yml,包括它自动 dispatchdeploy-staging的那一段。 - 手填仍然必须可用:填了值就走原路径(这是回滚和"迁移到某个更早修订"的唯一手段)。留空才自动解析。
- 自动解析失败(查不到任何成功门禁运行、API 报错)时必须硬失败并给出人话原因,不得回退成"用 staging head"——head 可能根本没过门禁。
concurrency.group: staging-mutation不动。
6. 任务分解
任务 1 · migrate-staging-database.yml:SHA 变可选
1.1 输入改为:
deploy_sha:
description: 留空=自动用最新一个通过门禁的 staging 提交;填写=迁移到指定的 40 位 SHA(回滚用)
required: false
type: string
1.2 第一步开头加解析分支:
DEPLOY_SHA非空 → 完全走现在的逻辑,一行不改。DEPLOY_SHA为空 → 查actions/runs?branch=staging&event=push&status=success,按现有那段jq的同一套过滤条件(.path | split("@")[0] | endswith("backend-quality-gate.yml")、head_branch == "staging"、event == "push"、conclusion == "success")取id最大的一条,其head_sha即为解析结果;随后继续走原有的全部校验(格式、gate 查找、head 比对)。
注意:解析出来之后不要跳过第 2 步的门禁查找。让它照常再查一遍——多一次 API 调用,换"两条路径走同一套校验",值得。
1.3 在日志里显式打印一行,例如:resolved deploy_sha=<sha> (latest gated staging commit)。产品需要在日志里看到自己到底迁移了哪个修订。
1.4 解析不到时的失败信息要是人话,例如:staging 上还没有任何通过门禁的提交,先等门禁跑完再迁移。
验收标准
- 留空运行:日志里有
resolved deploy_sha=…,后续步骤与手填同一 SHA 时的行为逐步一致。 - 手填运行:行为与改动前完全一致。
- 手填一个没过门禁的 SHA:仍然被拒。
- staging 上不存在成功门禁运行时留空运行:硬失败,信息可读。
任务 2 · deploy-staging.yml(可选,产品可要可不要)
同样把 deploy_sha 改成可选 + 自动解析。收益较低——门禁通过后它会被自动 dispatch,手动表单只在重跑或回滚时用;而回滚场景本来就要手填。
allow_rollback 保持 required:自动解析出的永远是最新修订,不构成回滚;真要回滚就得手填 SHA 并显式勾选。
做不做由执行方看改动成本决定,结论写进 PROGRESS。
任务 3 · 文档
deploy/README.md:把 staging 迁移那一节改成「直接点 Run,SHA 留空即可;只有回滚到更早修订才需要填」,并写明生产两个按钮仍然必须手填及其理由。docs/tasks/PROGRESS-staging-dispatch-autofill-sha-20260915.md:改了哪些行、两条路径各自的验证记录。- 不新增 BUG 编号(这是运维易用性改动,不是缺陷)。当前最大 BUG-717。
- 不动
CHANGELOG.md(用户可见行为无变化)。
7. 让步顺序
- 若 Gitea 的
workflow_dispatch在这个版本上不支持required: false的空字符串(部分版本会传空串而非缺省),改用"填latest三个字母表示自动" 而不是留空。目的一样:不用打 40 位。哪种可行写进 PROGRESS。 - 任务 2 做不了就不做,不阻塞任务 1。
- 绝不让步:不得放宽门禁校验;不得改生产两个 workflow;不得改
backend-quality-gate.yml;手填路径必须保留可用。
8. 开工前置命令
cd /workspace/Jyotisha
git status -sb | head -1
git fetch origin --prune
git worktree add -b codex/staging-dispatch-autofill-sha-20260915 \
.worktrees/staging-dispatch-autofill-sha-20260915 origin/staging
cd .worktrees/staging-dispatch-autofill-sha-20260915
sed -n '36,90p' .gitea/workflows/migrate-staging-database.yml # 要改的那一步
⚠️ 这一单改的是部署管线本身。 改完必须确认 YAML 能被 Gitea 正确解析——一个语法错误会让按钮直接消失。推之前本地跑一次 python3 -c "import yaml,sys; yaml.safe_load(open('.gitea/workflows/migrate-staging-database.yml'))" 之类的校验。
交付:git push origin HEAD:staging,推完核对远端 SHA,并确认 Gitea 上这个 workflow 仍然出现在列表里、表单能打开。
9. 产品侧验证(改完之后)
- Gitea →
Migrate Staging Database→ SHA 留空 → Run。 - 在日志第一步看
resolved deploy_sha=…,确认它就是你以为的那个提交。 - 后面照常。