feat: 环境信息唯一事实源 + 应用脚手架 QC 硬门禁 + 基础模块 load 反模式
1) project-directory-spec 新增第八章「部署环境信息(env/)」:
- 唯一事实源 projects/{项目名}/env/{test,prod}.json;禁止 apps/ 下放部署凭据
(人事项目7 实测三份 env 矛盾:项目 9187 / 应用 9288+postgresql / 实际 mariadb)
- 固定字段 schema;db.engine 必须与 DDL 方言一致
- 铁律:环境信息由人提供,agent 不得编造;禁「待明确」占位当交付;缺字段冒泡 need_info
- PM 在 need_info 未答结时不得 review_rollback(回退上游解决不了外部输入缺口)
2) qc/review-develop 新增第六章「应用脚手架硬门禁」(原技能只有模块检查,
应用脚手架零检查项,Flask 因此两次过审):
- 6.1 入口必须 ahserver,grep 命中 Flask/FastAPI/Django/jsonify 直接 reject
- 6.2 基础模块 appbase/rbac 必须真正调 load_XXX(),只 import 标 loaded 属反模式
- 6.3 端口三处一致 6.4 DDL 方言与 engine 一致 6.5 依赖完整性
3) web-application-spec 补「基础模块只 import 不调 load_XXX()」反模式警示
This commit is contained in:
parent
520a6d4f89
commit
ff667c58cd
@ -117,6 +117,29 @@ if __name__ == '__main__':
|
||||
>
|
||||
> 不要给每个模块单独建 `app.py`、单独占端口、单独起服务——模块不是独立部署单元,应用才是。以上 8 步是应用一键部署正确执行的完整清单,缺一不可。
|
||||
|
||||
> **🔴 反模式:基础模块只 import 不调 load_XXX()**
|
||||
>
|
||||
> `appbase` 和 `rbac` **同样有 `load_XXX()`**(`appbase/init.py: load_appbase()`、`rbac/init.py: load_rbac()`),必须像业务模块一样显式调用。只 `import` 包**不等于**已挂载。
|
||||
>
|
||||
> ```python
|
||||
> # ❌ 错误:只 import 就当成 loaded(rbac 权限/登录、appbase params 全没注册到 ServerEnv)
|
||||
> for name in ["apppublic","sqlor","ahserver","appbase","rbac"]:
|
||||
> pkg = importlib.import_module(name)
|
||||
> status = "loaded" # ← 误报成功,掩盖问题
|
||||
>
|
||||
> # ✅ 正确:import 后取 loader 并调用
|
||||
> from appbase.init import load_appbase
|
||||
> from rbac.init import load_rbac
|
||||
> env = ServerEnv() # ← 必须在 load_rbac() 之前
|
||||
> load_appbase(); load_rbac(); load_pybricks()
|
||||
> ```
|
||||
>
|
||||
> 症状:应用能起、`/healthz` 也可能 200,但登录必失败(rbac 未注册)、读 params 报错(appbase 未注册),日志却显示基础模块「loaded」。
|
||||
>
|
||||
> 加载顺序固定:`ServerEnv()` → 基础模块(appbase/rbac/pybricks)→ 业务模块。基础模块晚于业务模块 load,业务模块拿不到权限/配置。
|
||||
>
|
||||
> (2026-08-25 人事项目7 hrs7 实测:`load_base_modules()` 对 5 个基础模块只 `importlib.import_module` 就标 `status="loaded"`,而同文件的 `load_business_modules()` 却正确地 `getattr(pkg, loader)` + 调用——两套逻辑不一致,基础能力全部缺失。)
|
||||
|
||||
### conf/config.json (Configuration)
|
||||
Must include the following sections:
|
||||
- `password_key`: System encryption key
|
||||
|
||||
@ -77,7 +77,7 @@ projects/{项目名}/
|
||||
| 角色 | 产出 | 落点 |
|
||||
|------|------|------|
|
||||
| requirement | 需求规格说明书 | `projects/{项目名}/docs/00-requirement/requirement-spec.md` |
|
||||
| requirement | 部署环境信息 | `projects/{项目名}/env/test.json` + `prod.json` |
|
||||
| requirement | 部署环境信息(**引用+校验,不得编造**,见第八章) | `projects/{项目名}/env/test.json` + `prod.json` |
|
||||
| design | 系统架构 / UI 设计 | `projects/{项目名}/docs/01-design/architecture.md`、`ui-design.md` |
|
||||
| design | 模块级设计 | `projects/{项目名}/docs/01-design/modules/{模块名}.md` |
|
||||
| design | app spec.json | `projects/{项目名}/{应用名}_spec.json`(每个 app 一个) |
|
||||
@ -106,3 +106,51 @@ projects/{项目名}/
|
||||
## 七、部署前设置远程仓库
|
||||
|
||||
应用部署测试前,机构 `apps/` 和 `modules/` 下应用使用到的仓库都要设置远程仓库(`git remote add origin <远程地址>`),否则部署时无法 git pull 拉取最新代码。
|
||||
|
||||
## 八、部署环境信息(env/)——唯一事实源与禁止编造
|
||||
|
||||
### 8.1 唯一存放位置(铁律)
|
||||
|
||||
部署环境信息**只存放在项目目录** `projects/{项目名}/env/{test,prod}.json`,这是唯一事实源。
|
||||
|
||||
| 位置 | 允许内容 | 说明 |
|
||||
|------|---------|------|
|
||||
| `projects/{项目名}/env/{test,prod}.json` | **部署环境信息**:ssh / deploy / db / domain / port | ✅ 唯一事实源,deploy_test / deploy_prod 只读这里 |
|
||||
| `apps/{应用名}/conf/config.json` | 应用**运行配置**:监听地址、日志级别、模块库名映射 | ✅ 应用自身配置 |
|
||||
| `apps/{应用名}/env/` | —— | ❌ **禁止**。应用仓库不得存放部署环境信息,尤其禁止 ssh/db 凭据 |
|
||||
|
||||
**禁止理由**:应用仓库会被多环境/多项目复用并推到远程,放部署凭据既泄密又造成多份互相矛盾的环境信息(2026-08-25 人事项目7 实测:`projects/hrs7/env/test.json` 全是「待明确」,而 `apps/hrs7/env/test.json` 自行写了 port 9288 + driver postgresql,与项目 env 的 9187 和测试机实际的 MariaDB 3306 三方矛盾,deploy_test 无法判断该信任哪份)。
|
||||
|
||||
### 8.2 字段 schema(固定,deploy 脚本按此读取)
|
||||
|
||||
```json
|
||||
{
|
||||
"app": "hrs7",
|
||||
"env": "test",
|
||||
"port": 9187,
|
||||
"ssh": { "host": "...", "port": 22, "user": "...", "password": null, "key_file": null },
|
||||
"deploy": { "path": "~/hrs7_app", "repo_url": "...", "branch": "main" },
|
||||
"db": { "engine": "mariadb", "host": "...", "port": 3306, "user": "...", "password": "...", "dbname": "hrs7" },
|
||||
"domain": "..."
|
||||
}
|
||||
```
|
||||
|
||||
- `db.engine` 必须与应用 DDL 方言一致(mariadb → `BIGINT AUTO_INCREMENT`;postgresql → `BIGSERIAL`)。**engine 与 DDL 方言不符 = 部署必失败**,develop 阶段就要对齐。
|
||||
- 免密部署时 `ssh.password` 留 null,由部署角色注入机构密钥 `~/.ssh/org_keys/{org_id}/id_ed25519`。
|
||||
|
||||
### 8.3 环境信息由人提供,agent 不得编造(铁律)
|
||||
|
||||
**环境信息(host / user / 凭据 / 部署路径 / 域名 / 端口)是外部事实,任何 agent 都无法自行推导。**
|
||||
|
||||
- requirement 角色的职责是**引用与校验**,不是发明:把人/运维提供的环境信息落到 `env/{test,prod}.json`,并校验字段完整。
|
||||
- **禁止用「待明确 / 待确认 / TBD / placeholder」占位后当作已完成交付提交**。这类占位会一路流到 deploy_test 才暴露,浪费整条链。
|
||||
- 任一必填字段缺失 → **立即冒泡 need_info 问人**(不是 report_bug 报缺陷,也不是自己编一个),任务挂起等人回答,回答后再继续。
|
||||
- QC 检查 requirement 交付时:`env/{test,prod}.json` 存在占位词或 `pending` 数组非空 → 该项不算完成。
|
||||
|
||||
**必填字段清单**(缺任一即冒泡):`ssh.host`、`ssh.user`、`deploy.path`、`db.host`、`db.user`、`db.password`、`db.dbname`、`port`。
|
||||
|
||||
### 8.4 PM 不得在 need_info 未答结时回退上游
|
||||
|
||||
环境信息缺失属于**外部输入缺口**,回退到 requirement 重做**解决不了**——requirement 同样拿不到信息,只会再编一次占位,再被 QC 以「越权/占位」驳回,形成死循环(2026-08-25 人事项目7 实测:deploy_test 诚实冒泡 → 求助被驳 → PM 回退 requirement → requirement 再编 → QC 再驳)。
|
||||
|
||||
正确处理:存在未答结的 need_info 冒泡时,PM 只能**等待/催办**,不得 `review_rollback`。
|
||||
|
||||
@ -8,6 +8,11 @@ capability: task_capability
|
||||
|
||||
被查对象:agent.develop。审查其产出时逐项机械检查,任一项不合格即 review_reject 并列出问题。
|
||||
|
||||
**先判交付类型,再选检查章节**:
|
||||
- 交付**业务模块**(Python 包,机构 `modules/{模块名}/`)→ 查第一~五章
|
||||
- 交付**应用脚手架**(机构 `apps/{应用名}/`,有 `app/{应用名}.py` 入口)→ 查**第六章**(硬门禁)+ 第四、五章
|
||||
- 两者都交 → 两套都查
|
||||
|
||||
## 一、模块目录结构(对照 module-development-spec)
|
||||
|
||||
- 包目录 = 模块名(`{模块名}/{模块名}/`),不是 src/
|
||||
@ -40,3 +45,64 @@ capability: task_capability
|
||||
- 用 list_files / read_file 验证模块仓库目录结构真实存在
|
||||
- 用 git_status 验证模块仓库有本地 git 提交(QC 核验「实际产出」的硬证据)
|
||||
- 用 run_shell 跑 py_compile / dspy 审计脚本验证语法
|
||||
|
||||
## 六、应用脚手架硬门禁(对照 web-application-spec)——任一不过即 reject
|
||||
|
||||
交付 `apps/{应用名}/` 时逐条 grep 核验,**不看交付说明怎么写,只看代码实际内容**。
|
||||
|
||||
### 6.1 入口框架(最高优先级)
|
||||
|
||||
```bash
|
||||
grep -n 'from ahserver.webapp import webapp\|webapp(init)' apps/{应用名}/app/{应用名}.py # 必须命中
|
||||
grep -niE 'flask|fastapi|django|http\.server|jsonify|@app\.route' apps/{应用名}/app/*.py # 必须零命中
|
||||
grep -niE '^flask|^fastapi|^django' apps/{应用名}/requirements.txt # 必须零命中
|
||||
```
|
||||
|
||||
- 入口**必须** `from ahserver.webapp import webapp` + 末尾 `webapp(init)`
|
||||
- **出现 Flask / FastAPI / Django / http.server / jsonify / @app.route 任一 → 直接 reject**,理由:bricks `.ui` 只有 ahserver 的 BricksUIProcessor 能渲染,用其它框架会导致模块界面全废、根路径只剩 JSON
|
||||
- 已重复踩坑两次(2026-08-24 hrs6、2026-08-25 hrs7 均为 develop 用 Flask),这是复发项,务必先查
|
||||
|
||||
### 6.2 基础模块必须真正 load,不能只 import
|
||||
|
||||
```bash
|
||||
grep -n 'load_appbase\|load_rbac\|load_pybricks' apps/{应用名}/app/{应用名}.py # 必须都命中且是调用
|
||||
```
|
||||
|
||||
- 基础模块 **appbase / rbac** 也有 `load_XXX()`(`appbase/init.py: load_appbase()`、`rbac/init.py: load_rbac()`),**必须显式调用**:
|
||||
|
||||
```python
|
||||
from appbase.init import load_appbase
|
||||
from rbac.init import load_rbac
|
||||
env = ServerEnv() # ← 必须在 load_rbac() 之前
|
||||
load_appbase()
|
||||
load_rbac()
|
||||
load_pybricks()
|
||||
# 再逐个 load 业务模块
|
||||
```
|
||||
|
||||
- **反模式(必 reject)**:只 `importlib.import_module(name)` 就把状态标成 `loaded`,没有 `getattr(pkg, "load_"+name)` 调用。后果:rbac 权限/登录、appbase params 全没注册到 ServerEnv,登录链路必崩,却误报挂载成功(2026-08-25 hrs7 实测:`load_base_modules()` 只 import,业务模块却正确调了 loader,两套逻辑不一致)
|
||||
- 加载顺序:`ServerEnv()` → 基础模块 → 业务模块。基础模块晚于业务模块 load 会导致业务模块拿不到权限/配置
|
||||
|
||||
### 6.3 端口与环境信息一致性
|
||||
|
||||
- 应用端口**必须**取自 `projects/{项目名}/env/{test,prod}.json` 的 `port`,**不得**在应用仓库另定一个(应用 `env/` 目录本身就该不存在,见 project-directory-spec 第八章)
|
||||
- 端口在项目 env、应用 conf、交付说明三处必须同值;出现两个及以上不同值 → reject
|
||||
|
||||
### 6.4 DDL 方言与 db.engine 一致
|
||||
|
||||
```bash
|
||||
grep -niE 'BIGSERIAL|SERIAL PRIMARY|nextval' apps/{应用名}/scripts/ddl/*.sql # engine=mariadb 时必须零命中
|
||||
```
|
||||
|
||||
- `env.db.engine=mariadb` → DDL 必须 `BIGINT AUTO_INCREMENT`,**禁 PostgreSQL 方言**(`BIGSERIAL`/`SERIAL`/`nextval`)
|
||||
- `env.db.engine=postgresql` → 先确认目标机真有 PostgreSQL 在listen,否则 reject
|
||||
- 2026-08-25 hrs7 实测:DDL 写 `BIGSERIAL`、env 写 `driver: postgresql:5432`,而测试机只有 MariaDB 3306(无 psql),部署必失败
|
||||
|
||||
### 6.5 依赖完整性
|
||||
|
||||
```bash
|
||||
cat apps/{应用名}/requirements.txt # 必须含平台基础依赖
|
||||
```
|
||||
|
||||
- 必须包含应用实际用到的平台基础模块与 DB 驱动;只有 Web 框架而无 DB 驱动 → reject(连不上库)
|
||||
- 2026-08-25 hrs7 实测:requirements.txt 只有 `Flask/Jinja2/Werkzeug`,既无 ahserver/sqlor/appbase/rbac,也无任何 DB 驱动
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user