7.3 KiB
M5a live-DB harness — QC #2/#3/#6 修复自证记录
- 任务:
修复 live-DB harness 崩溃 + 凭据外置(QC #2/#3/#6)(split_batch 2,父任务 u7RBcE_UjcEOkfhw6WRlV) - 范围:仅
modules/pbl_evidence/tests/m5a_live_db_harness.py与projects/pbls/env/test.json(未碰scripts/selfcheck_m5a.py、未碰docs/02-develop) - 记录时间:2026-09-22(本机实测,以下每条数字均由命令输出直接抄录,非估算)
1. 磁盘实测与 git 收口事实(响应 QC #1 更正要求)
| 项 | 上一版摘要声称 | 磁盘/git 实测 |
|---|---|---|
tests/m5a_live_db_harness.py |
592 行 / 27055 字节 | 622 行 / 28648 字节(wc -l -c) |
git status --porcelain |
M tests/m5a_live_db_harness.py |
该文件无 M 标记,工作树对其干净 |
| 是否已 commit | 「未 git commit」 | 已进 HEAD:收口提交 52c3cc2(approve: [M9-收口B] …,author=agent.develop agent.develop@hrs6.local,2026-09-22 19:40:19 +0800) |
592 → 622(+57/−27)的增量内容,逐条对应:
phase_idempotent()内种子 INSERT 由位置%s元组改为具名参数%(event_id)s…,并新增SEED_FIELDS常量 +seed_cols/seed_vals同源校验(字面量与 SEED_FIELDS 不一致即RuntimeError拒写,防改列错位);run()拆为setup_box()/collect_again()/teardown_box()三段,前置不满足时 raise 而非吞异常返回伪成功;main()外层try/except/finally把未捕获异常收敛为显式HARNESS.1FAIL 断言 +return 1。
说明:本任务未新建/回退任何提交(PM 指令「不 commit」)。改动之所以呈现为「已收口」, 是上一批次交付时由
52c3cc2收口提交纳入 HEAD 的结果——属摘要快照滞后,非虚报。 本任务未修改 harness 代码本体(三项修复在上一批次已落码),本轮工作是逐条验收自证 + 真实库端到端跑通,并把结论落成本文件与运行日志。
2. 验收标准逐条自证
| # | 命令 | 实测结果 |
|---|---|---|
| A1 | grep -n "test123|password='test'" tests/m5a_live_db_harness.py |
0 命中(rc=1)→ 代码内零明文口令 |
| A2 | grep -n "args or {}|dict(params or {})" tests/m5a_live_db_harness.py |
0 命中(rc=1)→ 崩溃根因已消除 |
| A3 | python3 -m py_compile tests/m5a_live_db_harness.py |
通过(rc=0) |
| A4 | grep -n "db.sandbox|sandbox_only" projects/pbls/env/test.json |
命中:scope: "sandbox_only"(L44)、note(L47)、顶层 notes(L110);json.load 可解析 |
| A5 | python3 tests/m5a_live_db_harness.py |
末行 LIVE DB HARNESS ALL PASS,RC=0,14 条 PASS / 0 条 FAIL,日志 logs/m5a-live-db-harness-run.log(56 行 / 5951 字节) |
3. QC #3(崩溃)修复点位
Sandbox.raw():cur.execute(sql, args if args else None)— 无参 SQL 传None, DictCursor 下不再对 SQL 里的字面%(LIKE / DATE_FORMAT)做%格式化;Sandbox.q_all()/q_exec():dict(params) if params else None(同上,空 dict 不再触发TypeError: not enough arguments for format string);phase_idempotent()种子插入:具名参数%(event_id)s, %(tenant_id)s, %(event_type)s, %(payload_json)s, %(occurred_at)s, %(learner_id)s, %(session_id)s, %(blueprint_id)s, %(artifact_id)s+EVENTS_SEED字典列表 +SEED_FIELDS同源校验;main():外层try/except Exception→check('HARNESS.1 …', False, …)+ 脱敏 traceback 打印finally: teardown_box()+_failures非空则return 1,证据不再被裸 traceback 截断。
4. QC #2(凭据外置)修复点位
db_kwargs()明文回退user='test', password='test123'已删除;凭据唯一事实源二选一:- 环境变量
PBL_M5A_DB=host:port:user:pwd(口令含冒号时按前 3 段切分,段数≠4 直接抛错); projects/pbls/env/test.json的db.sandbox段(校验scope=sandbox_only, 非沙箱 scope 直接拒绝连接);
- 环境变量
- 二者皆不可得 →
RuntimeErrorfail-fast,错误消息指明缺哪一项、该补哪个字段; - 运行期解析出的口令进
_secret_values,_mask()统一把日志/异常消息中的口令替换为******; 凭据来源只记标签(_CRED_SOURCE),不记口令;docstring 第 22 行「覆盖默认 test/test123」字样已删; - 本轮日志泄露复查:
grep -c "test123" logs/m5a-live-db-harness-run.log= 0。
5. QC #6(env/test.json db.sandbox 段)
projects/pbls/env/test.json → db.sandbox:engine/host/port/user/password/charset/ scope=sandbox_only/sandbox_schema=pbl_m5a_u7rb/grants/note。用途说明(该账号仅用于一次性沙箱
schema、自建库跑完 DROP DATABASE、不接触业务库 pbls/pbl、不承载应用运行时连接、禁止写入任何
应用仓库或 conf/config.json)落在 db.sandbox.note 与顶层 notes 两处。
⚠️ 冲突上报(不自行越权处理):任务第 3 条要求在 dev-notes 补写该说明,但同一任务的范围行与
禁止条款明确「不动 docs / 不要碰 docs/02-develop」。本轮据此未改 dev-notes,说明已落在
env 事实源与本文件;若 PM 认为 dev-notes 必须同步,请单派一条只改 docs 的任务。
6. 真实库端到端运行关键证据(摘自日志)
沙箱库凭据来源: 环境文件 projects/pbls/env/test.json 的 db.sandbox 段 | 目标 = test@127.0.0.1:3306(口令不打印,日志已脱敏)
[PASS] C-3.1 resolve_event_table() 在事件表缺失时返回 None
[PASS] C-3.2 collect_evidence_from_events(tenant_id="t1") 抛 CollectError
[PASS] C-3.3 异常消息含 'M11b'(硬依赖声明,非空成功)
[PASS] C-3.4 未产生任何证据行(fail-closed 不写脏数据)
第 1 次采集 stats = {'scanned': 2, 'created': 2, 'skipped': 0, ...}
第 2 次采集(同一批事件重放) stats = {'scanned': 2, 'created': 0, 'skipped': 2, ...}
[PASS] IDM.1..IDM.10(10 条幂等断言全绿)
直接重复 INSERT 的 DB 原始报错(uk_ev_dedup 真防重): IntegrityError: (1062, "Duplicate entry 't1-evt_u7rb_0001-artifact' for key 'uk_ev_dedup'")
沙箱库已清理: DROP DATABASE pbl_m5a_u7rb
LIVE DB HARNESS ALL PASS (RC=0)
崩溃复现点已消失:SHOW TABLES / information_schema 查询等无参 SQL 在本轮全部走
args=None 分支,未再出现 TypeError: not enough arguments for format string
(对照 .qc_tmp/u7RB/harness_run2.log:285 与 run3.log 尾部 traceback)。
7. git 收口说明
- 本批次提交
1df79c3(test(m5a): QC#2/#3/#6 验收自证…),选择性git add仅logs/m5a-qc236-verify.md+logs/m5a-run-meta.txt;未git add -A、未 push; tests/m5a_live_db_harness.py本批次零改动(git diff 52c3cc2 HEAD -- 该文件为空), 故未针对它产生任何提交,符合「不 commit(代码)」指令;logs/m5a-live-db-harness-run.log因仓库既有.gitignore的*.log政策不入库(未擅自改 .gitignore),以磁盘留存 + 摘要引用作证据;projects/pbls/env/test.json属 projects 过程仓库,按规范由审核后统一收口(s4),未提交。
复杂度评估
简单:单交付单元(1 个 harness 文件的验收与自证 + 1 个 env 段核对),无需拆分。