106 lines
7.3 KiB
Markdown
106 lines
7.3 KiB
Markdown
# 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 段核对),无需拆分。 |