Files
eng-standards-main/03-待配置事项.md
姚章浩 5b65ed9579 docs: 正本与 Runbook/接入文档口径同步(测试语义、CI-CD 分离、门禁唯一入口、必需检查清单)
按草案逐条落到正本,并把三处已知错误的口径改回:

① 测试语义:删掉"单测跑的是构建产物,不是源码"这条被过度推广的说法。
   只有"跑产物"的套件(端到端 / 契约 / 产物自检)才必须排在构建之后;
   go test 自己编译测试程序、pytest 直读源码、vitest 默认也跑源码。
   写错这条的代价是给每个套件加假依赖、拖慢门禁并制造假故障。T8 同步改。
② CI 与 CD 分离:触发表删掉"推默认分支 → 自动部署测试环境",作业划分表删掉 deploy:test 行,
   §4.6 标注为"项目自己的 CD、不属于通用 CI",速查表同步。
③ 门禁入口:统一为 make verify(名字可不同,但 AGENTS/Runbook/CI 必须指同一个),
   §3.1、§8 清单、§9 速查表一致。
④ 新增 §4.8「必需检查清单与结果口径」:10 项必需检查的判据表 + 三条结果口径
   (失败即停但汇总照做、not_run/skipped 不算过、汇总故障不能报绿),
   以及预览/通知作为旁路的规则。
⑤ 接入文档:修掉"直推也拦得住"这句错口径,并写明接入器不再自动合并、
   --merge-pr 会先核对状态;试点记录里那一步标注为"当时的自动合并行为已改"。
⑥ 03/04/05 里的同源表述一并同步(生成物 jobs 与假成功占位的判据)。

验证:本批 18 处精确替换在脚本里逐处断言"恰好命中 1 次"(DRY-RUN 先过一遍再应用);
替换后全仓 grep 复查,旧口径只在"说明它已被改掉"的上下文里出现。
2026-10-12 00:12:06 +08:00

168 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 待配置事项清单
> 每项:**现状(已核实)→ 要做什么 → 为什么 → 怎么验证 → 谁来做**。
> 优先级:**P0** = 不做则规范形同虚设;**P1** = 影响发布可靠性;**P2** = 一致性/卫生。
> 现状全部来自本次实测(命令在括注里)。
>
> ⚠️ 本清单只讲"还差什么";**"怎么让它以后默认生效"(三渠道 + 新工程 5 步)见 `05-应用机制-让规范在以后所有工程生效.md`** —— 别把两份读串。
---
## P0
### 1. 分支保护 —— **已定:默认不开**(不需要动)
- **决定**:按原稿口径,`main` **不受保护**,所有改动直接进 `main`(正本 §1.1 / §1.3)。
- **现状**:曾给 `Weknora/knowledge-governance` 开过一次(禁直推 + 强制 `build / build (push)`),
**已关掉**;7 个仓现在 `GET /repos/{r}/branch_protections` 全为 `[]`。
- **这条知识别丢**:将来真需要"谁都不能直推"时,开保护**前**必须做 `06-接入既有工程.md` §2 的体检 ——
**盲目勾"必须状态检查通过"会让 PR 永远等一个不会出现的检查**。判据仍然有效,只是默认不用它。
- **可逆**:开/关都是一次 API 调用或网页点一下,不涉及数据。
### 2. `knowledge-adapter-service` 的工作流不在 `main` 上
- **现状**:`main` 的 `.gitea/workflows/` **不存在**;`build.yml` 只在 `ci/setup` 分支(`GET .../contents/.gitea/workflows?ref=ci/setup` → 200,`ref=main` → 404)。仓库已有 `runner-weknora-ka-01`。
- **要做什么**:把 `.gitea/workflows/build.yml` + `.gitea/scripts/{ci_gate.py,ci_report.py}` 合到 `main`;关掉/删掉 `ci/setup` 分支。
- **为什么**:现在推 `main` **不触发任何校验**——这个仓库的 `main` 处于"裸奔"状态。
- **怎么验证**:`GET /repos/Weknora/knowledge-adapter-service/contents/.gitea/workflows` 在默认分支返回 `build.yml`;推一个提交,`actions/tasks` 出现新 run。
- **谁来做**:开发(走正常 PR);合并前用 `attach_repo.sh` 的模板拷贝逻辑。
### 3. 生产发布的"人工确认"落地方式二选一(需在实例上实测)
- **现状**:Gitea **没有** GitLab 的 `when: manual` + `manual_confirmation`;生产部署目前**完全不经过 CI**(DobotAI 是人工在生产机 clone + build)。
- **要做什么**:
- 方案 A:确认 Gitea 1.26.2 的 Actions 是否支持 `environment:` 及其审批;支持就在生产 workflow 上用。
- 方案 B(不依赖平台):生产 workflow 只 `on.workflow_dispatch`,必填 `sha` + `confirm=deploy-production`,最后一步"切镜像"由本人在生产机执行。
- **为什么**:规范 §5.2 的三层确认里,第二层(参数)与第三层(人)已可落地;第一层要不要平台能力必须先实测,**不能假设**。
- **怎么验证**:在**非生产**仓库建一个 `environment: test-protect` 的最小 workflow 试跑;或直接采用方案 B 并留一条演练记录。
- **谁来做**:本人确认 + 开发实现。
### 4. "同一份构建产物"的产物落地方式(本环境当前**不满足**)
- **现状**:DobotAI 的做法是**在目标机上各自 build**(测试机 build 一次、生产机再 clone 源码 build 一次)——**两份二进制并不逐字节相同**,违反 §5.1。
- **要做什么**:
1. 构建移进 CI(仓库 Runner 上 `docker build`)或至少**只在一台机器 build 一次**;
2. `docker save` 出 `dist/<repo>-<sha12>.tar` + 写 `release-<sha12>.json`(含 `image_id` / `tar_sha256`);
3. 产物放到一个**两个环境都取得到**的托管点(见第 5 项);
4. 测试与生产都 `docker load` 同一份 tar,并各自断言 `image_id` 相同。
- **为什么**:这是本次规范最核心的新增要求。"测试验收过"必须等于"生产跑的就是那份字节",否则验收结论对生产**无效**。
- **怎么验证**:测试机与生产机各跑 `docker image inspect --format '{{.Id}}'`,两个值**相同**;且都 == 清单 `image_id`。
- **谁来做**:开发(改造构建 + 部署脚本);本人验收。
---
## P1
### 5. 构建产物的托管点
- **现状**:`ci-bridge` 的 `/api/ci/publish` 是给**静态网页预览**(tar.gz 解包 + URL)用的,不适合放镜像 tar / 大文件;`/srv/aiball/ci/previews/` 下面只有 3 个目录。DobotAI 的 tar 目前不在任何统一位置。
- **要做什么**:定一个产物目录(建议 `/srv/aiball/ci/artifacts/<ns>/<repo>/<sha12>/`,与 bridge 复用同机同 token,按 sha 分目录 + 保留 N 份),或走对象存储/OSS。
- **为什么**:§5.1 要求"生产取同一个 tar",就必须有一个**两个环境都能取到、且可按 sha 寻址**的地方。
- **怎么验证**:从测试机和生产机各 `curl` 一次同一个 `tar_sha256` 地址,都能下到且 `sha256sum` 与清单一致。
- **谁来做**:本人定位置 + 开发接。
### 6. 生产/测试的部署凭据尚不存在
- **现状**:只有 3 个 Weknora 仓库配了 `CI_BRIDGE_URL`(variable) / `CI_BRIDGE_TOKEN`(secret),**没有任何部署凭据**(`GET /repos/{r}/actions/secrets`)。DobotAI 的部署靠本人在生产机手动执行。
- **要做什么**:按命名后缀建变量/密钥(Gitea 无 environment scope,见规范 §7.1):
- Variables:`DEPLOY_TEST_HOST` `DEPLOY_TEST_PORT` `DEPLOY_TEST_USER` `DEPLOY_PROD_HOST` `DEPLOY_PROD_PORT` `DEPLOY_PROD_USER` `ARTIFACT_BASE_URL`
- Secrets:`DEPLOY_TEST_SSH_KEY` `DEPLOY_PROD_SSH_KEY` `ARTIFACT_TOKEN`
- **为什么**:CI 要有能力"传产物"到目标机;同时 Gitea 无 File 类型 secret,私钥内容整体存 secret、由脚本落盘 0600。
- **怎么验证**:`GET /repos/{r}/actions/variables` 与 `/actions/secrets` 列出全部名字(值不显示);在一个 dry-run workflow 里只在**变量名 + ✓/✗** 层面校验(绝不回显值)。
- **谁来做**:本人在网页/用 `attach_repo.sh` 的接口写入;凭据环节**必须**由本人操作。
### 7. `Weknora/Enterprise-Knowledge-Base` 接入(含分支收敛)
- **现状**:7 条分支(`main` + `release/graph-guard-v0.7.1-r1`、`release/server-running-v0.7.1`、`develop/enterprise-kb`、`chore/db-pool-tuning`、`feature/dingtalk-richtext-image`、`feature/dingtalk-image-only`);**无 workflow、无 Runner**;语言 Go+Vue。
- **要做什么**:分支收敛(该合的合、该删的删)→ 跑规范 §8 的 10 步接入清单。
- **为什么**:长期分支 + `release/*` 正是规范 §1.1 的反模式;且它没有任何校验。
- **怎么验证**:`GET /repos/{r}/branches` 只剩 `main` + 短命分支;`actions/tasks` 有新 run。
- **谁来做**:开发 + 本人确认分支删除范围(删分支不可逆)。
### 8. Runner 覆盖盘点
- **现状**:Weknora 三仓**各一个**仓库级 Runner(kg/dp/ka);`aiball` 组织级 1 个(`runner-software-01`,覆盖 `protocol-docs` 与 `software-pc`);`Weknora` 组织级 **0 个**。
- **要做什么**:每个新接入仓库都要有**归属该仓库**的 Runner(否则 run 永远 `queued`)。用 `deploy_repo_runner.sh` 起。
- **为什么**:规范 §4.2 —— "run 一直 queued" 的头号原因是仓库没有自己的 Runner,而不是工作流写错。
- **怎么验证**:`GET /repos/{r}/actions/runners` 的 `runners` 非空且 `status=online`。
- **谁来做**:开发(`bash /srv/aiball/runner/deploy_repo_runner.sh <owner/repo> <name>`)。
### 9. `aiball/software-pc` 的 runner 依赖第三方 action
- **现状**:`validate.yml` 用 `actions/checkout@v4` + `actions/setup-node@v4`,在 `runner-software-01` 上 run#1 = success(**该 runner 能取 action**);但 Weknora 三仓 runner 上刻意不用。
- **要做什么**:在 `validate.yml` 顶部加注释说明"本 runner 支持取 action";并补上 `npm ci`(现在用 `npm install`,不可重现)。
- **为什么**:规范 §4.3 要求"按 Runner 配置区分"且要写明理由,否则下一个人会照抄到不支持 `uses:` 的 runner 上。
- **怎么验证**:把 `npm install` 改成 `npm ci` 后重跑 run,仍 green。
- **谁来做**:开发。
### 10. 生产迁移与回滚脚本的"幂等门"复核
- **现状**:DobotAI 已有 `ops/` 下的 `deploy_dobotai_prod.sh` / `rollback_dobotai_prod.sh` / `prod_verify.sh` / `prod_last_turn.sh`(在生产机 `/opt/dobotai/container/ops/`)。
- **要做什么**:对照规范 §5.8 / §5.5 逐条核对:产物 sha 校验、迁移列 COUNT 门、agent 配置 hash CAS、`flock` 互斥、0600 备份。
- **为什么**:规范要求"部分失败后重跑不会双重应用",这是**脚本级**保证,必须在脚本里看到。
- **怎么验证**:每个门都**故意触发**一次(喂一个已存在的列 / 错的 sha),确认脚本**拒绝执行**而不是静默继续。
- **谁来做**:开发(只读复核 + 演练);演练在测试机做。
---
## P2
### 11. `aiball/upper-tool`、`zheromiku/protocol-docs` 是空仓
- **现状**:两个仓库 `empty=true`。
- **要做什么**:要么初始化(README + `.gitignore` + 门禁骨架),要么归档。
- **为什么**:空仓出现在仓库列表里,会让人"以为这里该有东西"。
- **怎么验证**:`GET /repos/{r}` 的 `empty=false`,或仓库已归档。
- **谁来做**:本人决定去留。
### 12. `docs/提交规范.md` 缺失
- **现状**:`~/.githooks/commit-msg` 与 `.gitea/scripts/ci_gate.py` 的提示文案都写着"详见 `docs/提交规范.md`",但仓库里**没有这个文件**。
- **要做什么**:把规范 §2 的内容落成各仓的 `docs/提交规范.md`(或把提示文案改成指向本规范)。
- **为什么**:一条指不到地方的指路,比不指路更费时间(原稿 §2.2 的原话)。
- **怎么验证**:`test -f docs/提交规范.md` 通过;或 grep 提示文案确认已改为可达路径。
- **谁来做**:开发(顺手改)。
### 13. 规范自身的仓库化(已完成,只剩"各仓加指针")
- **现状**:正本已入仓 —— `zheromiku/eng-standards-main`,默认分支 `main`,2 条提交,HEAD `419396f3ce0c`;本地 `~/eng-standards/` 的 `git rev-parse HEAD` 与远端 `ls-remote` 一致。
⚠️ 仓名带了 `-main` 后缀(原计划写的是 `eng-standards`);文档内 4 处引用已按**实际仓名**改正,不留指不到的指针。
- **要做什么**:~~①建仓~~ ✅ ~~②push~~ ✅;③ 各仓 `AGENTS.md` 加一行指针:`Weknora/{dobotai-platform, knowledge-governance, knowledge-adapter-service, Enterprise-Knowledge-Base}`、`aiball/{software-pc, protocol-docs}`。
- **为什么**:规范要"不用每次重复说一遍",靠的是可被引用的单一来源(原稿 §11)。先前放在 `/srv/aiball/ci/standards/` 下是分类错误 —— 跨仓规范不该挂在单个项目(AI球)的目录里。
- **怎么验证**:`git ls-remote --heads origin main` 的 SHA == 本地 `git rev-parse HEAD`;各仓 `AGENTS.md` 里的指针路径可达。
- **谁来做**:③ 需要**改动 6 个仓库**,属独立动作 —— 等指示,不自行扩围。
### 14. `aiball` 固件(ESP32-P4)的流水线尚未定义
- **现状**:`/srv/aiball/firmware` 有固件工程,但 Gitea 上**没有对应仓库**;`aiball` 组织下只有 `protocol-docs` / `software-pc` / `upper-tool`。
- **要做什么**:固件入仓后,按同一套 §5.1 建固件流水线:`idf.py build` 一次 → 记录 `.bin` 的 sha256 → 测试机烧录测试版 → **量产/发布烧同一份 `.bin`**。
- **为什么**:固件同样适用"同一份产物"铁律;烧录"只写不回读",所以**产物哈希是唯一可信的同一性证据**(AIxProbe 经验)。
- **怎么验证**:`sha256sum` 两次产物文件一致;烧录日志里的字节数与 `OpenOCD wrote` 一致。
- **谁来做**:本人定仓库归属 + 开发建流水线。
### 15. `ci-bridge` 的公开地址与实际可达性核对
- **现状**:`config.json` 的 `public_base=http://192.168.50.134:8899`、`public_base_alt=http://100.92.49.78:8899`;本次实测 `127.0.0.1:8899/healthz` 正常(`reports:19, previews:7, notify:true`)。
- **要做什么**:核对 `192.168.50.134` 是否仍是本机当前 LAN 地址(网段变化会让所有通知里的链接失效)。
- **为什么**:报告里给的每个 URL 都必须能 200,否则通知等于没发。
- **怎么验证**:`curl -m 5 http://192.168.50.134:8899/healthz` 与 `curl -m 5 http://100.92.49.78:8899/healthz` 都返回 `ok:true`。
- **谁来做**:本人/开发。
### 16. 规范守门脚本的 Gitea 版(可选)
- **现状**:附件里的 `spec-check.mjs` 是 GitLab 口径(判据含 `glab` 占位符、`.gitlab-ci.yml`、`workflow.rules`),直接拿来自Gitea 环境跑会**假红**。
- **要做什么**:改写判据:`.gitlab-ci.yml` → `.gitea/workflows/*.yml`;`workflow.rules` → `on:` 三类入口;`glab-placeholder` → `giteactl/gitea_api.py` 等价约束;`resource_group` → `flock`。保留 `--self-test` 的反向自检。
- **为什么**:规范的"可执行"部分最好变成退出码(原稿 §11.2),但不改写就会假红,而假红和假绿一样要修。
- **怎么验证**:`--self-test` 造两个夹具(合规全绿、违规每条都红)。
- **谁来做**:开发(本次未做,见任务边界)。
---
## 不建议做的事(写下来防止被"顺手加上")
- ❌ 不要为了能 push 去改 Gitea 凭据/token scope —— 权限没配好要**问人**,自己换 remote/换账号会把"权限没配好"变成"动作做了一半"。
- ❌ 不要把测试环境部署塞回 `build.yml`(CI 流水线只管校验与编译);生产 workflow 就是生产 workflow。
占位作业在填完真实逻辑之前**必须红**,不许"打印 TODO 然后返回成功"。
- ❌ 不要给生产 workflow 设 `concurrency.cancel-in-progress: true`(会取消正在进行的部署,而取消不是回滚)。
- ❌ 不要在生产与测试**同时**跑压测(两服共用同一套 RDS,会扰动生产)。
- ❌ 不要在源码路径里用 `dist` / `data` / `secrets` 这些名字(`.gitignore` 会静默吞掉)。