[M5a-DISC.2-A] 交付件卫生清理 + build.sh 7b 实测证据补齐

- git rm scripts/patch_build_7b.py(一次性构建期补丁脚本,移出应用仓;证据附件保留在
  projects/pbls/docs/02-develop/patches/m5a-disc2-patch_build_7b.py)
- README §期望结果:场景 1 / 场景 2 分别对应各自实测日志,不再以场景 2 日志代证场景 1,
  并如实记录场景 1 的受控截取执行方式与两处既有问题(内网源不可达、DDL 方言门禁命中注释)
This commit is contained in:
agent.develop 2026-09-22 22:17:30 +08:00
parent 37961262b4
commit 1ce57f3716
2 changed files with 45 additions and 61 deletions

View File

@ -47,10 +47,51 @@ bash modules/pbl_evidence/scripts/setup_test_env.sh
bash modules/pbl_evidence/scripts/activate_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`:`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`。 - 带 `PBL_EVIDENCE_TEST_DB`(用法见 `modules/pbl_evidence/README.md` §Running tests):`9 passed`。
- 实测日志:`projects/pbls/docs/02-develop/m5a-disc2-pytest-run.log`。
- 禁止为凑通过修改测试断言逻辑。 - 禁止为凑通过修改测试断言逻辑。
| 场景 | 解释器 | 实测日志 | 状态 |
|---|---|---|---|
| **场景 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://10.20.30.41: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` 第 0~6 步门禁本次**未实测**(静态核验 + 首轮部分实跑:第 0~3 步与 6.1/6.2
真实通过,第 4 步因上述注释冲突 die),第 7b 步**已实测**。

View File

@ -1,57 +0,0 @@
#!/usr/bin/env python3
"""一次性补丁脚本:在 apps/pbls/build.sh 第 7 步后插入「7b. 测试前置依赖(DISC.2)」。
为什么用脚本而不是 sed:build.sh 里含 `${...}` 与引号,shell 内嵌补丁容易吃掉转义。
本脚本幂等——已存在 7b 标记时直接退出,不重复插入。
"""
import io
import os
import sys
BUILD = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "build.sh")
ANCHOR = '# ---- 8. 本地安装 15 个 pbl_* 模块 + 复用模块(可编辑模式)----'
MARK = '# ---- 7b. 测试前置依赖(DISC.2)----'
BLOCK = '''# ---- 7b. 测试前置依赖(DISC.2)----
# 运行时依赖(requirements.txt)刻意不含 pytest;测试依赖单列 requirements-test.txt,
# 由本步装进同一个 venv,使
# source venv/bin/activate && python3 -m pytest tests/test_m5a_idempotency.py -v
# 在**不手工注入 PYTHONPATH** 的前提下可直接执行(此前靠 PYTHONPATH=<ws>/.pylibs
# 临时注入跑通,换机器/换角色即失效,test 角色会误判为环境不可用)。
# 只要运行时依赖的场景(如生产镜像)用 PBL_SKIP_TEST_DEPS=1 显式跳过。
REQ_TEST="${APP_DIR}/requirements-test.txt"
if [ "${PBL_SKIP_TEST_DEPS:-0}" = "1" ]; then
log "PBL_SKIP_TEST_DEPS=1:跳过测试前置依赖(venv 内将没有 pytest,测试角色需自行引导)"
elif [ ! -f "${REQ_TEST}" ]; then
die "缺测试依赖清单 ${REQ_TEST}(DISC.2 要求显式声明;确要跳过请设 PBL_SKIP_TEST_DEPS=1)"
else
log "安装测试前置依赖: ${REQ_TEST}"
"${PY}" -m pip install -r "${REQ_TEST}"
# 自证:装完必须真能 import + 跑 --version,否则本步等于没做(不让注释与事实矛盾)
"${PY}" -c 'import pytest' >/dev/null 2>&1 \\
|| die "安装后 venv 内仍无法 import pytest(${PY})"
log "7b 自证通过: $("${PY}" -m pytest --version 2>&1 | head -1) @ ${PY}"
fi
'''
def main():
build = os.path.abspath(BUILD)
with io.open(build, "r", encoding="utf-8") as f:
text = f.read()
if MARK in text:
print("SKIP: 7b 已存在,未重复插入")
return 0
if ANCHOR not in text:
print("FAIL: 找不到第 8 步锚点,拒绝盲目修改")
return 1
patched = text.replace(ANCHOR, BLOCK + ANCHOR, 1)
with io.open(build, "w", encoding="utf-8") as f:
f.write(patched)
print("OK: 已在 %s 第 8 步前插入 7b(+%d 字符)" % (build, len(patched) - len(text)))
return 0
if __name__ == "__main__":
sys.exit(main())