From 05b2bf8579a5e5dc2a97df7573d413b20902ee7e Mon Sep 17 00:00:00 2001 From: yml2213 Date: Wed, 7 Oct 2026 13:20:33 +0800 Subject: [PATCH] =?UTF-8?q?docs(agents):=20=E4=BF=AE=E6=AD=A3=E5=88=86?= =?UTF-8?q?=E6=94=AF=E7=BA=A6=E5=AE=9A=EF=BC=8C=E8=A1=A5=E4=B8=8A=E8=BF=99?= =?UTF-8?q?=E8=BD=AE=E5=AE=9E=E8=B7=B5=E4=B9=B0=E7=9A=84=E6=95=99=E8=AE=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - **删掉已作废的约定**「推完 main 再 `dev merge --ff-only main`」: dev 现在与 main 已分叉(上面有未上线的账号自动分配功能),ff-only 必然失败。 改为:`main` = 已发布,新功能从 main 开 `feat/*`;要同步 dev 只能真合并且需显式确认。 - 新增一批实证教训:提交/推送的钩子要求(`pre-commit` 查的是 `ruff format`, 只跑 `ruff check` 会被拦)、测试库 `create_all` 不会 ALTER 已有表(症状 `Unknown column`)、`dev.sh` 会自动应用迁移导致切分支后应用起不来、 生产部署的完整流程与三项前置检查。 - 坑速查 4 → 8 条:新增 `pgrep -f` 自匹配白等、`set -e` + 管道过滤半途静默中止 (曾让镜像库变空)、`ruff check` ≠ 能提交;并补上 REPEATABLE READ 的具体应对。 - 据实补全本地库清单:先 grep 全仓库确认无引用,再查内容,确认 `douyu_login_prodclone` / `douyu_login_rehearsal` 是 S1–S7 演练留下的快照。 - 原有教训一条未删,整体按「干活顺序」重排(60 → 116 行)。 --- AGENTS.md | 142 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 43 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 76afc5b..eb578f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,60 +1,116 @@ # 协作约定(给 AI 助手 / 协作者) -> 这些是用户明确表达过的偏好。**每次在这个仓库里干活前先读一遍。** +> 用户明确表达过的偏好,加上**已经用事故买来的教训**。每次在这个仓库里干活前先读一遍。 +> 每条都对应一个真实踩过的坑 —— 删之前先确认那个坑不会再犯。 -## 提交与推送 +## 1. 分支与提交 -- **不要改一点就提交、推送。** - 小改动先攒着,**攒够一批**再提交;只有用户明确说「提交 / 推送」, - 或者到了一个自然的里程碑(一个完整功能做完、一轮反馈全部改完)才 commit / push。 -- 一次提交要**整合**相关改动,不要拆成一堆碎提交。 -- 推送时 `main` 与 `dev` 一起同步(`dev` 是工作分支): - `git push gitea main` → `git checkout dev && git merge --ff-only main && git push gitea dev`。 +- `main` = **已发布**(生产跑的就是它)。功能开发**从 main 开分支**: + `git checkout -b feat/<功能名> main`,做完合回 `main`。 +- `dev` 是**历史工作分支,已与 main 分叉**(dev 上有未上线的账号自动分配功能)。 + ⚠️ 旧的「推完 main 再 `dev merge --ff-only main`」约定**已作废** —— + 分叉后这么做会失败;以后要同步 dev 只能真合并,并且必须显式确认。 +- **不要改一点就提交、推送。** 小改动先攒着、攒够一批再提交;只有用户明确说 + 「提交 / 推送」,或到了一个自然的里程碑(一个完整功能做完、一轮反馈全部改完) + 才 commit / push。一次提交要**整合**相关改动,别拆成一堆碎提交。 +- 远端名不统一:本地是 `gitea`,生产服务器上的同一个仓库叫 `origin`(URL 相同)。 -## 功能改动 +## 2. 功能改动 -- **新功能是「增加」,不是「替换」。** 旧路径要完整保留(例:账号检测保留了 - 手动粘贴,新增「按账号选择」;旧的手动输入逻辑一行未动)。 +- **新功能是「增加」,不是「替换」。** 旧路径要完整保留(例:账号检测保留了手动粘贴, + 新增「按账号选择」;旧的手动输入逻辑一行未动)。做新功能时先想清楚**旧路径会不会被影响**, + 需要扩展的地方用**可选参数 / 并集**,不要改默认行为。 - 改动要**务实、克制**:不做没人要的重构,不加用不上的抽象。 -- **不要重复展示同一份数据。** 数据库里已有的字段(如 `accounts.points` / - `gold_balance` / `elite_opened`)就让已有界面显示,查询去**刷新**它们, - 不要另开一份副本 —— 同一屏出现两份会让人分不清哪份是准的。 -- **单项外部调用失败不要让整个流程失败**,但要**如实暴露**(错误写进 `errors` +- **不要重复展示同一份数据。** 数据库里已有的字段(如 `accounts.points` / `gold_balance` / + `elite_opened`)就让已有界面显示,查询去**刷新**它们,不要另开一份副本 —— + 同一屏两份会让人分不清哪份是准的。 +- **单项外部调用失败不要让整个流程失败**,但要**如实暴露**(错误写进 `errors` / 返回值 并在 UI 展示),别让「没查到」被读成「没有」。 +- 旁路动作(写事件、写审计、释放资源)**绝不能带崩主流程**:单独 try/except + 记 warning, + 但要留兜底(如定时作业)把漏掉的补上。 -## 报表 / 汇报 +## 3. 验证要求(怎么证明你做对了) -- **如实报告,包括自己的错误、误判和局限。** 不确定就说不确定,别猜。 -- **结论要有验证**:能实测就实测(本仓库有生产镜像库可用), - 能反向验证(把 bug 注入回去看用例是否变红)就反向验证。 +- **结论要有验证**:能实测就实测(有生产镜像库 `douyu_login_prod` 可只读查), + 关键是**反向验证** —— 把 bug 注入回去,确认用例真的会变红,再还原。 + 「跑了一下没报错」不算验证。 +- **提交/推送会跑钩子**,所以本地必须按同样标准自查: + - `pre-commit`:`ruff format --check`(**只跑 `ruff check` 不够**,格式不对会直接拦下提交) + + 前端 `tsc -b`; + - `pre-push`:上面这些 + **全量 pytest**。 +- **断言要看 `model_dump()`(序列化结果)**,只看属性会假绿(原因见坑 #2)。 +- **别信「测试通过」** —— 用例可能是假绿的(原因见坑 #3)。 + +## 4. 数据库与迁移 + +- 迁移编号**按落地顺序取,不预留**;**已应用的迁移不能改名**。 +- 加列/加表后,**测试库不会自己长出新结构** —— `tests/support/db.py` 用的是 + `Base.metadata.create_all`,它**只建缺失的表,不会 ALTER 已有表**。 + 症状是 `Unknown column`,处理办法:重建测试库(DROP/CREATE `douyu_login_test`)。 +- **本地 `dev.sh` 在跑时,改迁移文件会被它自动应用到你正在用的库**。 + 所以切分支前先确认「库的迁移版本 == 目标分支的 head」,否则应用会因为 + alembic 找不到 revision **直接起不来**(`run_migrations` 没有兜底,会带崩 lifespan)。 +- 本地库:`douyu_login`(dev)、`douyu_login_test`(测试,**不要**拿别的库跑测试套件)、 + `douyu_login_prod`(生产镜像)。 + 另有 `douyu_login_prodclone`(停在 `20261003_0040`)与 `douyu_login_rehearsal` + (停在 `20261004_0049`):是 S1–S7 上线演练留下的**生产克隆快照**(各 15,182 账号), + 代码里没有任何引用 —— 只读参考,别当测试库用。 + +## 5. 部署与生产 + +生产:SSH 别名 `order+douyu_huya`,目录 `/root/live-hub-py`,跑的就是 `main`。 +**完整清单见 `docs/上线清单-S1-S7部署.md`**,核心步骤: + +```bash +# ① 部署前(缺一不可):备份 + 采基线 +docker exec live-hub-py-mysql-1 sh -c 'mysqldump ... douyu_login' | gzip > /root/backup_$(date +%m%d_%H%M).sql.gz +gzip -t /root/backup_*.sql.gz +# 采 CK 基线:样本解密长度 + 持有 CK 账号数(部署后要一字不差地对比) +# 查在途任务:正在跑的批次会被重启打断,先看能不能等 + +# ② 执行:先停 → 再迁移 → 再起 +docker compose stop douyu-login +docker compose run --rm -T douyu-login alembic upgrade head