pbl_evidence/logs/m5a-qc236-verify.md
2026-09-22 20:03:50 +08:00

106 lines
7.3 KiB
Markdown
Raw 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.

# 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)的增量内容,逐条对应:
1. `phase_idempotent()` 内种子 INSERT 由位置 `%s` 元组改为**具名参数** `%(event_id)s…`,并新增
`SEED_FIELDS` 常量 + `seed_cols/seed_vals` **同源校验**(字面量与 SEED_FIELDS 不一致即
`RuntimeError` 拒写,防改列错位);
2. `run()` 拆为 `setup_box()` / `collect_again()` / `teardown_box()` 三段,前置不满足时 raise
而非吞异常返回伪成功;
3. `main()` 外层 `try/except/finally` 把未捕获异常收敛为显式 `HARNESS.1` FAIL 断言 + `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'` 已删除;凭据唯一事实源二选一:
1. 环境变量 `PBL_M5A_DB=host:port:user:pwd`(口令含冒号时按前 3 段切分,段数≠4 直接抛错);
2. `projects/pbls/env/test.json` 的 `db.sandbox` 段(校验 `scope=sandbox_only`,
非沙箱 scope 直接拒绝连接);
- 二者皆不可得 → `RuntimeError` fail-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 段核对),无需拆分。