agent.develop 84207b4d5d fix(build): 接入基座 DDL 建表链(Bug 4SxqQAulkH9eAzEys_h-e 根因闭环 / QC 未过项 #1)
问题:build.sh 建表段只覆盖 scripts/ddl/pbls_tables.sql(32 张 pbl_* 手写表)
与 modules/pbl_*/models(6 张治理/模板域表,第 10a 步),已交付的
scripts/gen_base_ddl.py 与 scripts/ddl/base_tables.sql(12 张基座表含 users)
在 build.sh 中零引用 → 重新部署 users 表仍缺失 → POST /main/rbac/user/up_login.dspy
ERROR 1146 Table 'pbl.users' doesn't exist → ahserver 兜底 500,会话 cookie 不下发。

改动(仅 build.sh,83 行纯新增,0 删除):
1) 变量声明段新增 BASE_GEN / BASE_DDL_FILE / BASE_ALIAS_MAP / BASE_PKGS_ROOT
   (= /pkgs,WS_DIR 由既有三段式探测解析,
   不硬编码路径;不存在时回退 gen_base_ddl.py 自带三段式探测并逐条回显候选)。
2) 新增第 10a-base 步(位于 10a 模块链之后、10b 运行目录之前):
   - python3 scripts/gen_base_ddl.py --out/--alias-map 从 models 单一真源
     重新生成 base_tables.sql + base_table_alias_map.json(脚本自带
     「表数<8 或 users 缺失即 die」门禁,不改其生成逻辑);
   - 产物存在性 + grep 复核表数>=8 与 users 在场;
   - mysql --protocol=TCP < base_tables.sql,连接参数全部取既有
     ////(env 事实源派生,
     零硬编码);
   - information_schema 逐张点名核验 12 张(appbase 4 + rbac 8),不达标 die
     并枚举缺失表名;users 单独点名 + 登录链 4 列
     (username/login_fail_count/last_login_fail/last_login)终态核验;
   - 打印 SELF_CHECK base_tables: PASS tables=N/12 users=present login_cols=4/4。
3) 幂等:base_tables.sql 全部 CREATE TABLE IF NOT EXISTS,重复执行零副作用。
4) 口径边界:未改动第 10 步 32 张手写表门禁、第 10a 步 6 张模块链门禁、
   第 733 行 38 关键表终态门禁;未改 gen_base_ddl.py 与 pkgs/ 下基座包。

本地实测(真实回显,非模拟):
  [gen_base_ddl] resolved BASE_PKGS_ROOT=/d/pipeline/pipeline-app/pkgs
  [gen_base_ddl] SELF_CHECK base_ddl: PASS tables=12 users=present
  [10a-base] 生成校验通过: base_tables.sql 含 12 张表,users=present
  [10a-base] 基座表点名核验: 12/12(appbase 4 + rbac 8)
  [10a-base] SELF_CHECK base_tables: PASS tables=12/12 users=present login_cols=4/4
  幂等复跑第二次同结果,退出码 0;bash -n build.sh 通过。
2026-09-30 19:49:23 +08:00

pbls

PBL Agent OS 验证原型应用(唯一入口 app/pbls.py,端口以 projects/pbls/env/test.json 为唯一事实源)。业务模块见机构 modules/pbl_*。

测试依赖(DISC.2)

结论:pytest 已显式声明,不再依赖临时注入 PYTHONPATH。 宿主 python3 上没有 pytest (python3 -m pytest → No module named pytest),且本机宿主 user site 是只读文件系统 (pip install --user 报 [Errno 30] Read-only file system),所以测试依赖的落点是 venv。

新增/相关文件清单

路径 层级 职责
apps/pbls/requirements-test.txt 应用级 测试前置依赖清单(pytest>=7.0,<10),由 build.sh 第 7b 步装进应用 venv
apps/pbls/build.sh 第 7b 步 应用级 pip install -r requirements-test.txt + import pytest 自证;PBL_SKIP_TEST_DEPS=1 可跳过
modules/pbl_evidence/requirements-dev.txt 模块级 同一版本区间的模块侧清单(不装本包也能跑离线单测的最短路径)
modules/pbl_evidence/scripts/setup_test_env.sh 模块级 建 .venv-test 并安装 requirements-dev.txt(含仓库卫生门禁)
modules/pbl_evidence/scripts/activate_test_env.sh 模块级 打印激活/直接调用测试 venv 解释器的方式
modules/pbl_evidence/scripts/run_tests.sh 模块级 一条命令跑测试:无 pytest 时自动引导,再执行 pytest
modules/pbl_evidence/README.md §Running tests 文档 排障入口 + PBL_EVIDENCE_TEST_DB 开关用法

为什么是两份清单(应用级 vs 模块级)

  • requirements-test.txt(应用级)服务整应用的测试环境:跑 build.sh 后 venv 内即有 pytest, 任何 modules/pbl_*/tests/ 都能用同一个解释器执行。
  • requirements-dev.txt(模块级)服务只测本模块的 CI/离线场景:不安装 pbls 应用、不装本包 (pip install -e .)也能一条命令装好依赖。
  • 两份版本区间同源(>=7.0,<10),避免"应用装了 9.x、模块 CI 装了 7.x"导致用例语义漂移。
  • 两者都刻意与运行时清单 requirements.txt 分离:pytest 不进生产镜像,也不进 build.sh 第 5 步的运行时依赖核验(该步只核验 ahserver/sqlor/apppublic/appbase/rbac/PyMySQL)。

推荐调用顺序

# 场景 1:完整应用环境(部署/联调机)
bash apps/pbls/build.sh                       # 第 7 步 venv → 7b 测试依赖 → 8 装模块
source apps/pbls/venv/bin/activate
python3 -m pytest modules/pbl_evidence/tests/test_m5a_idempotency.py -v

# 场景 2:只跑 pbl_evidence 单测(测试机/CI,最短路径)
bash modules/pbl_evidence/scripts/run_tests.sh          # 无 pytest 时自动引导 .venv-test

# 场景 3:只要环境不要跑(手工用 venv 解释器)
bash modules/pbl_evidence/scripts/setup_test_env.sh
bash modules/pbl_evidence/scripts/activate_test_env.sh

期望结果与实测证据(两个场景各对应一份日志,不互相代证)

期望输出(两场景相同):

  • 不带 PBL_EVIDENCE_TEST_DB:8 passed, 1 skipped,RC=0 (test_double_collect_is_idempotent_with_db 需真实 MariaDB,未设开关时按设计 SKIPPED,属预期)。
  • 带 PBL_EVIDENCE_TEST_DB(用法见 modules/pbl_evidence/README.md §Running tests):9 passed。
  • 禁止为凑通过修改测试断言逻辑。
场景 解释器 实测日志 状态
场景 1(build.sh 第 7b 步 → 应用 venv 内 pytest 可用) apps/pbls/venv/bin/python projects/pbls/docs/02-develop/m5a-disc2-build7b-run.log 已实测
场景 2(模块级引导 run_tests.sh / .venv-test) modules/pbl_evidence/.venv-test/bin/python projects/pbls/docs/02-develop/m5a-disc2-pytest-run.log 已实测

场景 1 日志中的关键真实输出行(由 shell tee 捕获,非手写):

[build.sh][...] 7b 自证通过: pytest 9.1.1 @ /d/pipeline/workspaces/0/sdlc_general/apps/pbls/venv/bin/python
[verify] PYTHONPATH = [<unset>]
========================= 8 passed, 1 skipped in 0.04s =========================
# pytest RC=0

即:7b 段把 pytest 装进应用 venv 后,source apps/pbls/venv/bin/activate 且 PYTHONPATH 未设置 的情况下直接跑 pytest 得到 8 passed, 1 skipped + RC=0 —— 证明 DISC.2 的原始痛点(靠临时注入 PYTHONPATH=<ws>/.pylibs 才跑得通)已被消除。

场景 1 的执行方式(受控截取,未强跑全流程)与已知限制

build.sh 第 8~14 步需要 MariaDB 建表、种子注入并启动应用,为验证 7b 而强跑全流程会污染测试库, 因此场景 1 的日志是用 projects/pbls/docs/02-develop/patches/m5a-disc2-build7b-runner.sh 按标记行从 build.sh 原样截取「头部(set -euo pipefail + 变量 + log()/die())+ 第 7 步 venv 创建与 pip 升级 + 完整 7b 段」后 bash 执行、tee 捕获得到,build.sh 本体一个字节未改 (日志末尾附该文件 md5 以供核对)。日志中同时打印了实际执行的截取脚本(cat -n)供逐行复核。

两处如实说明(均属本任务范围外的既有问题,已作为发现项上报 PM,未在本任务内改动):

  1. 截取时跳过了第 7 步的 pip install -r requirements.txt:该步指向机构内网 PyPI 源 http://DEAD-INTERNAL-PYPI-REMOVED:8081,本工作空间不可达(curl rc=124),会先于 7b 失败退出。 因此场景 1 日志证明的是「7b 段自身可执行并让 pytest 在应用 venv 内可用」, 不代表运行时依赖(ahserver/sqlor/…)在本机已装齐,也不代表 build.sh 全流程在本机跑通。
  2. 首轮曾按「截取第 1 行起的全部前缀」执行,build.sh 第 4 步 DDL 方言门禁 die: grep -Eiq '...|REFERENCES|ENUM\(|TIMESTAMP' 命中了 scripts/ddl/pbls_tables.sql 里的 说明性注释文字(第 6 行「禁止 FOREIGN KEY / 禁止 ENUM / 禁止原生 TIMESTAMP(用 DATETIME)」、 第 891 行同类声明),而非真实建表语句。该门禁与 DDL 注释的冲突是既有问题(与 DISC.2 无关), 修它需要改第 4 步 grep 或改 DDL 注释,超出本任务范围,故本次截取范围从第 7 步起。 结论:build.sh 第 06 步门禁本次未实测(静态核验 + 首轮部分实跑:第 03 步与 6.1/6.2 真实通过,第 4 步因上述注释冲突 die),第 7b 步已实测。
Description
No description provided
Readme 25 KiB