From 53b2f0008dfc3bdc46dd3c89bfc3285aed28e127 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Wed, 14 Oct 2026 15:39:22 +0800 Subject: [PATCH] docs(tasks): release path production fix brief (agent loop, issue #74, bounce 1) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3 --- docs/tasks/README.md | 1 + ...SK-release-path-production-fix-20261014.md | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/tasks/TASK-release-path-production-fix-20261014.md diff --git a/docs/tasks/README.md b/docs/tasks/README.md index c6300838..8f9921d2 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -335,6 +335,7 @@ | `TASK-beta-main-path-20261014.md` | `PROGRESS-beta-main-path-20261014.md` | **内测主路径**:BUG-1063 他人报告 worker 读档案(逐列只读授权 + test:db);对话与报告「AI 生成,仅供参考」标识与免责;BUG-1080/283 状态;状态板按事实清账;冒烟清单 `docs/testing/beta-smoke-20261014.md`。与发布单并行 | 第 1 次打回后已修,待验收 | `codex/beta-main-path-20261014` | | `TASK-beta-main-path-fix-20261014.md` | `PROGRESS-beta-main-path-20261014.md` | **#73 第 1 次打回**:`fca62fda` 内容通过;与 #63 删除的旧报告视图有代码冲突,接受删除即可 | 待验收 | `codex/beta-main-path-20261014` | | `TASK-release-path-production-20261014.md` | — | **发布通路 + 生产首发**:产品 10-14 授权改生产工作流(发布 SHA = 最近门禁成功提交 + 其后纯文档);63 个迁移清单与演练脚本、首发 runbook;生产拒绝测试验证码。Grok 不 dispatch 生产工作流 | 待执行 | — | +| `TASK-release-path-production-fix-20261014.md` | — | **#74 第 1 次打回**:发布规则成立;测试写死 Windows 路径(Linux 全红)、主机演练依赖主机 node 且会留下生产数据副本、docs-only 头时回滚被拒;另补 CHECK_RELEASE_GATE 断言与 OTP 守卫规范化 | 待领取 | `codex/release-path-production-20261014` | | `TASK-beta-safety-net-20261014.md` | — | **内测安全网**:每日备份 + 恢复演练、探活告警、本地错误汇总、日志轮转、按 requestId 查日志。**等发布通路单合入、#58 合入后开工** | 待前置 | — | | `TASK-beta-capacity-20261014.md` | — | **内测容量**:按用户限流、重计算短排队与对话重试、兑换码当邀请码、staging 10/20 并发压测。**等 #58 合入后开工,压测等 #57 合入** | 待前置 | — | | `TASK-special-lagnas-native-20261008.md` | `PROGRESS-special-lagnas-native-20261008.md` | **特殊上升点原生计算(线上缺陷)**:sync6 U6 运行时调 PyJHora,生产镜像没有 PyJHora → staging 上 Hora/Ghati/Sree/Indu/Pranapada 全 blocked;原生实现、PyJHora 只作冻结对照、快速门禁止运行时 import jhora;最先做 | 已验收(已部署 staging `795b8845`,BUG-1273) | `codex/special-lagnas-native-20261008`(未上线;部署以 `/api/health` 为准) | diff --git a/docs/tasks/TASK-release-path-production-fix-20261014.md b/docs/tasks/TASK-release-path-production-fix-20261014.md new file mode 100644 index 00000000..86fc1d4e --- /dev/null +++ b/docs/tasks/TASK-release-path-production-fix-20261014.md @@ -0,0 +1,52 @@ +# TASK · 发布通路修复单(issue #74,第 1 次打回) + +- 日期:2026-10-14 +- 原任务书:`docs/tasks/TASK-release-path-production-20261014.md`(产品负责人 2026-10-14 在 issue #74 再次确认授权修改四个生产工作流) +- 被验 SHA:`00e6efdbfa3d97b0aad764865321bc00fb1cee13`(`codex/release-path-production-20261014`) +- 执行方:Grok,同一分支续做(先 merge 最新 `origin/staging`,不改写已推历史) +- 红线不变:仍只改原任务书授权的四个工作流;不改 staging 工作流、`gated-paths.txt`、`is-docs-only-range.sh`;不点任何生产按钮 + +## 1. 验收结论:发布规则本身成立,三处阻断首发 + +已确认成立(不需要改):正向路径要求 R 有精确 SHA 的 staging push 门禁、R 或 H 有手动发布门禁、main == staging、R..H 只含文档;变更前复核用的是 R 门禁产物里的 `is-docs-only-range.sh` 与 `gated-paths.txt`;staging 工作流零改动;`AGENTS.md` 只动了授权的 §2.4、§2.5、§2.7。 + +### B1 · Python 测试在 Linux 上全红(会让发布门禁红) + +`tests/test_resolve_release_revision.py` 第 13–14 行写死 `PYTHON = ROOT/".venv"/"Scripts"/"python.exe"` 和 `D:\Program Files\Git\bin\bash.exe`。Claude 在 Linux 全量 pytest:该文件 7 条里 6 条失败(`python.exe: No such file or directory`)。`release-quality-gate.yml` 跑全树 pytest,runbook 第 3 步会红。 +- 修:用 `sys.executable`;bash 用 `shutil.which("bash")`,Windows 再回落到 Git Bash。Linux 与 Windows 都要过。 + +### B2 · 主机模式的迁移演练跑不通,且会在生产库上留下一份生产数据副本 + +`deploy/rehearse-production-migrations.sh`: +- `run_node_sql`(约 88–137 行)在**主机**上跑 `node` + `import pg`,连 `@postgres:5432`(约 253 行)——这个主机名只在 Docker 网络里有;生产主机按规矩不装 node / `node_modules`、不构建。计数步骤失败退出 1,清理步骤(约 142 行)也用同一个函数,同样失败只打警告 → `rehearse_<时间戳>` 库连同恢复出来的生产数据留在生产 PostgreSQL 上,与 runbook「演练库会删掉」矛盾。 +- 恢复用 `--no-owner --no-acl`,对象归 `POSTGRES_USER`,而迁移以 `role=schema_owner` 执行,`ALTER` 可能报 "must be owner";ACL 没恢复,第 316–325 行的权限检查看到的不是生产真实授权,「退出 4 = BUG-1063 授权缺失」不可靠。 +- 修: + 1. 主机模式下所有 SQL 都走 `docker compose exec` / `docker run` 进 postgres 或 web 容器执行(与第 271 行 `--entrypoint node` 一致),不依赖主机 node。 + 2. 清理放 `trap`,并且**清理失败要非零退出并大字提示「演练库未删除,请手动 DROP DATABASE rehearse_xxx」**,不得只打警告。 + 3. 恢复后先把对象属主改成 `schema_owner`(或以 restore 后的属主执行迁移),并说明权限检查的口径;若做不到「看到生产真实授权」,就把「退出 4」的含义在脚本头和 runbook 里改成如实描述。 + 4. 本地模式的连接串拒绝带 `?` 查询参数(`?database=` / `?host=` 能覆盖库名守卫)。 + 5. runbook 第 5 步列的通过标准(归档会话前后数、自镜像前后数、NOTICE 计数)脚本并不打印:要么脚本打印,要么 runbook 删掉,二者必须一致。 +- 验收:新增或扩展 `tests/test_rehearse_production_migrations.py`:主机模式不调用主机 `node`(用假 `docker` 记录调用);清理失败时退出码非零;带查询参数的 URL 被拒。 + +### B3 · runbook 的失败回退走不通 + +- `deploy-production.yml` 回滚分支(约 126–137 行)仍要求 main 头 H 有一次 staging push 门禁成功记录;而本单要解决的正是「H 只多了文档、没有门禁记录」的情况——此时 `first` 返回 null、`jq -e` 失败,runbook 约 107 行依赖的回滚会被拒。 +- 修:回滚分支对 controller 的门禁查找改用与正向相同的规则(`resolve-release-revision.sh` 解析出的 R),或在 H 无门禁时用 R 的门禁产物;回滚的「目标 SHA 必须在已审 main 历史里」等原有检查不放宽。加合同测试锁住。 +- runbook 约 106 行「从恢复点整库恢复」没有给出工具和步骤:写清用哪个脚本 / 命令、需要哪个文件(`recovery_reference` 结尾就是备份文件名)、恢复后怎么核对。 + +## 2. 非阻断但这轮一并改 + +1. `frontend/tests/staging-backend-workflows.test.ts`:迁移与恢复两条用例把工作流里的门禁断言换成了检查脚本文本,**没有任何断言锁住三个工作流里的 `CHECK_RELEASE_GATE=true`**——删掉它会让正向路径失去发布门禁要求而测试仍绿。补上这三处断言(三栏写明)。 +2. `frontend/src/modules/identity/config.ts` 约 101 行用原始字符串比 `AUTH_USER_ORIGIN`,`https://jyotisha.chat/`(带斜杠)会漏过「生产拒绝测试验证码」。改为与 `readOrigin` 规范化后的值比较,并加一条带斜杠的测试。 +3. `resolve-release-revision.sh` 的正向判定用的是 H 自己检出里的 `gated-paths.txt`;虽然变更前有 R 产物复核兜底,但 recovery 工作流没有复核。请在 recovery 的判定里同样用 R 产物(或在 PROGRESS 写明为何恢复点可以接受)。 + +## 3. 验收标准 + +- Linux:`python3 -m pytest tests/test_resolve_release_revision.py tests/test_rehearse_production_migrations.py -q` 全绿;Claude 全量 pytest 与 staging 基线逐条比对无新增;前端全量 `npm test` 无新增。 +- `bash -n` 全部脚本通过。 +- runbook 每一步与工作流 / 脚本输出逐条一致(Claude 逐条对照)。 +- 仍未点任何生产按钮。 + +## 4. 让步顺序 + +B1、B2、B3 都不可让;第 2 节第 1、2 条不可让,第 3 条可写理由不改。