diff --git a/docs/work-log-2026-09-22-m11b2d-fixture-contract.md b/docs/work-log-2026-09-22-m11b2d-fixture-contract.md index 4327db2..7970e99 100644 --- a/docs/work-log-2026-09-22-m11b2d-fixture-contract.md +++ b/docs/work-log-2026-09-22-m11b2d-fixture-contract.md @@ -7,6 +7,12 @@ QC #14(§8 证据索引「跑的是什么」列与各证据文件首行 `# CMD:` 逐字对齐)、 QC #17(A1c 损害取证,实测见 §7.1)、QC #20(同类一次性脚本 `scripts/m11b2c_patch_fixture_ddl.py` 清理,登记见 §8 规则 8 执行记录) +- **A3a-1 轮追加(2026-09-23,任务 [M11b-2d-A3a-1])**: 只做文档文本口径修正(不碰测试文件/ + 业务代码/git):§6 计数与守卫用例表口径统一为「四组 / 17 项」并清除历史计数残留表述; + §8 证据索引「跑的是什么」列改为**逐字照抄各证据文件首行 `# CMD:`**(旧行曾把 A3 轮归档的 + 路径笔误顺手改对,仍属「引用与文件内容不一致」);并按任务书指定命令在当前 HEAD 重跑 + `tests/test_m11b2_single_tx.py`,另存新证据 + `tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt`(不覆盖旧归档),§7 移交结论以新文件为准。 - **文档定位**: **索引式登记**。夹具层实现说明的权威正文在 `tests/_m11b2_compat.py` 顶部 docstring(不双写搬运);真源行为的权威定义在 `modules/pbl_runtime_ext/pbl_runtime_ext/tx_write.py` 源码本身。本文档只做**符号清单 + 逐参数签名 + 返回键语义 + 错误码含义 + 废弃清单 + 引用规约**, @@ -221,8 +227,7 @@ SELECT 列 `entity_id, state_json, state_version, checksum, updated_by, updated_ `modules/world_sync/tests/test_m11b2d_fixture_contract.py`(本任务交付物,由一次性探针 `.m11b2d_probe.py` 升级而来,探针已由 `git rm` 移除,删除提交 `81fdb86`)。 守卫共**四组**用例(`FixtureSurfaceCase` / `ReturnKeysCase` / `GateErrorCase` / -`RegistrationDocCase`),合计 **17 项**(A3 轮为前三组 15 项,A3 轮末响应 QC #2 追加 -`RegistrationDocCase` 2 项): +`RegistrationDocCase`),合计 **17 项**(其中 `RegistrationDocCase` 2 项为 A3 轮末响应 QC #2 追加,用于守卫本登记文档的存在性与 §1.1 符号清单同源): | 组 | 用例 | 守卫内容 | |---|---|---| @@ -245,6 +250,8 @@ SELECT 列 `entity_id, state_json, state_version, checksum, updated_by, updated_ `tests/evidence/m11b2d_a3_fixture_contract_collect_only.txt`(**17 tests collected**, collection error = 0)。A3a 轮本地复跑复核一致(`./.venv/bin/python -m pytest tests/test_m11b2d_fixture_contract.py -q --tb=no` → `17 passed`)。 +**计数口径**:本节用例数(17)与上表逐行用例数、两份证据文件的 collected/passed 数三者 +一一对齐;证据文件首行 `# CMD:` 原文见 §8 证据索引(本表「组」列即四组,无第五组)。 --- @@ -266,7 +273,9 @@ git diff 81fdb86 -- tests/test_m11b2_single_tx.py # 仅 A1 的 3 处外观修 (证据 `tests/evidence/m11b2d_a3a_single_tx_after_revert_corrected.txt`——A3a 轮按正确 CMD 重跑并留证;A3 轮旧文件 `m11b2d_a3_single_tx_after_revert.txt` 首行 `# CMD:` 把路径误写成 `tests/test_m11b2d_single_tx.py`(该文件不存在),已原样保留并在 §8 证据索引登记该笔误,不覆盖 -旧归档)。失败根因是该文件仍按**旧类式夹具口径** +旧归档;A3a-1 轮再按任务书指定命令在当前 HEAD 重跑一次,另存新证据 +`tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt`(首行 `# CMD:` 与本节结论逐字对齐, +结果同为 8 failed, 32 passed, 8 xfailed,RC=1)——本处移交结论以该新文件为引用锚点)。失败根因是该文件仍按**旧类式夹具口径** 写断言,与真源不符,需两处修正(本任务无权改,移交该文件独占方 / 另开任务): 1. `TxCase.apply`:`"state_updates": su() if states is None else states` → 真源要求数组, @@ -545,12 +554,19 @@ RC=0 **口径规则**:「跑的是什么」列一律**照抄各证据文件首行 `# CMD:` 原文**(含 `cd` 前缀与解释器路径), 再附该文件正文的实际结果摘要与 `# RC=`。不再用「`xxx.py -v`」这类简写,避免与文件内容对不上。 +**A3a-1 轮修正**:上一版把 `m11b2d_a3_single_tx_after_revert.txt` 行里首行 `# CMD:` 的路径笔误 +**顺手改对**后引用(写成 `test_m11b2_single_tx.py`),这本身就又是一处「引用与文件内容不一致」; +本轮改为**原样照抄**(笔误保留在引号内并显式标注),同时新增按任务书命令在当前 HEAD 重跑的证据文件行, +需要「CMD 与所跑内容严格一致」的结论一律引用新文件。 | 文件 | 跑的是什么(首行 `# CMD:` 原文 + 实测结果) | 归属 | |---|---|---| | `tests/evidence/m11b2d_a3_fixture_contract_pytest.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2d_fixture_contract.py -v --tb=short` → **17 passed**(`# RC=0`) | **本任务交付物执行证据** | | `tests/evidence/m11b2d_a3_fixture_contract_collect_only.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2d_fixture_contract.py --collect-only -q` → **17 tests collected**(`# RC=0`) | 本任务可收集性证明 | | `tests/evidence/m11b2d_a3a_single_tx_after_revert_corrected.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2_single_tx.py -q --tb=no` → **8 failed, 32 passed, 8 xfailed**(`# RC=1`) | **A3a 轮修正版证据**:§7 移交依据(文件名与 CMD 逐字一致) | -| `tests/evidence/m11b2d_a3_single_tx_after_revert.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2d_single_tx.py -q --tb=no`(**首行路径笔误**:`test_m11b2d_single_tx.py` 不存在;正文 FAILED 行为 `tests/test_m11b2_single_tx.py`,8 failed, 32 passed, 8 xfailed) | A3 轮归档,原样保留不覆盖,笔误在此登记 | +| `tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2_single_tx.py -q --tb=no` → **8 failed, 32 passed, 8 xfailed in 0.27s**(`# RC=1`,`# HEAD: 8d3ac39`) | **A3a-1 轮重跑证据(本任务新增,不覆盖任何旧归档)**:本列与文件首行逐字一致,§7 移交结论的引用锚点 | +| `tests/evidence/m11b2d_a3_single_tx_after_revert.txt` | `# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2d_single_tx.py -q --tb=no`(**首行原文逐字照抄**:其中路径 `test_m11b2d_single_tx.py` 系 A3 轮笔误,该文件不存在;正文 8 条 FAILED 行均为 `tests/test_m11b2_single_tx.py`,末行 `8 failed, 32 passed, 8 xfailed in 0.26s`,该归档无 `# RC=` 行) | A3 轮归档,原样保留不覆盖;笔误在此登记,「CMD 与所跑内容严格一致」的版本见上一行 | | `tests/evidence/m11b2d_a1_pytest.txt` | `# CMD: cd modules/world_sync && /d/pipeline/workspaces/0/sdlc_general/modules/world_sync/.venv/bin/python -m pytest tests/test_m11b2_single_tx.py -v --tb=short` → 48 items collected,**40 passed, 8 xfailed** | **并行任务 M11b-2d-A1/A1c 的产物证据**,非本任务交付物;本任务未改名(改名会二次触碰 A1 归档),在此登记归属。注意该结果对应提交 `18dc298` 时点,已被 §7.1 所述回退打回 | | `tests/evidence/m11b2d_a1_collect_only.txt` | `# CMD: cd modules/world_sync && /d/pipeline/workspaces/0/sdlc_general/modules/world_sync/.venv/bin/python -m pytest tests/test_m11b2_single_tx.py --collect-only -q` → **48 tests collected** | 同上(A1 线归档) | +| `tests/evidence/m11b2d_a3a_a1c_damage_forensics.txt` | 首行原文为 `# FILE: tests/evidence/m11b2d_a3a_a1c_damage_forensics.txt`(**取证转录件,非单命令输出**:正文以 `$ (a) …` 逐条列出实跑命令与原样输出含 RC,命令清单见 §7.1) | A3a 轮取证归档(响应 QC #8/#17) | +| `tests/evidence/m11b2d_a3a_script_cleanup_grep.txt` | `# CMD: cd modules/world_sync && grep -r 'm11b2c_patch_fixture_ddl' scripts/ pyproject.toml build.sh tests/ world_sync/ ; echo RC=$?` → 4 段检索原样输出(`build.sh: No such file or directory`;命中仅本文档自身,代码/配置零引用) | A3a 轮一次性脚本清理取证(§8 规则 8 执行记录) | diff --git a/scripts/m11b2c_patch_fixture_ddl.py b/scripts/m11b2c_patch_fixture_ddl.py deleted file mode 100644 index bd1821f..0000000 --- a/scripts/m11b2c_patch_fixture_ddl.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -"""M11b-2c: 测试夹具 DDL 与列契约对齐补丁(只改 tests/,不动业务代码与表定义 JSON)。 - -根因(实测):tests/test_m11b2_single_tx.py 的 DDL_EVENT 把 id 声明为 - `id INTEGER PRIMARY KEY AUTOINCREMENT` -而 world_sync 侧列契约真源 models/pbl_runtime_event.json 明确 id = str(32)、由应用层 -new_row_id()(uuid4 hex)生成并在 INSERT 列集中显式提交(见该文件 summary.comment -「id 生成方 · 单一口径,QC #4」)。写路径插入 32 位十六进制字符串到 INTEGER 主键列 -=> sqlite3.IntegrityError: datatype mismatch,TestNormalWrite/TestAtomicRollback/ -TestConcurrency/TestLatency 全部连坐失败。属夹具建表与契约不一致,修夹具即可。 - -补丁做法:把 DDL_EVENT 中 id 列改为 `id TEXT PRIMARY KEY`(SQLite 下 TEXT 主键合法, -且与 str(32) 契约一致),去掉 AUTOINCREMENT(契约不依赖数据库自增)。 -""" -import io -import os -import sys - -TARGET = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), - "tests", "test_m11b2_single_tx.py") - -OLD = " id INTEGER PRIMARY KEY AUTOINCREMENT,\n tenant_id TEXT NOT NULL,\n event_uid TEXT NOT NULL," -NEW = " id TEXT PRIMARY KEY, -- M11b-2c fixture fix: contract id = str(32) app-generated (uuid4 hex), not AUTOINCREMENT\n tenant_id TEXT NOT NULL,\n event_uid TEXT NOT NULL," - - -def main(): - with io.open(TARGET, "r", encoding="utf-8") as f: - src = f.read() - n = src.count(OLD) - if n == 0: - if NEW.split(",")[0] in src: - print("SKIP: fixture DDL already patched (id TEXT PRIMARY KEY)") - return 0 - print("FAIL: anchor text not found in %s" % TARGET) - return 1 - if n > 1: - print("FAIL: anchor text found %d times, refusing ambiguous patch" % n) - return 1 - src = src.replace(OLD, NEW) - with io.open(TARGET, "w", encoding="utf-8") as f: - f.write(src) - print("OK: patched %s (1 occurrence) -> id TEXT PRIMARY KEY" % TARGET) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt b/tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt new file mode 100644 index 0000000..f5a65fe --- /dev/null +++ b/tests/evidence/m11b2d_a3a_single_tx_after_revert_rerun.txt @@ -0,0 +1,19 @@ +# CMD: cd modules/world_sync && ./.venv/bin/python -m pytest tests/test_m11b2_single_tx.py -q --tb=no +# DATE: 2026-09-23T00:41:21+08:00 +# HEAD: 8d3ac39 +# INTERPRETER: ./.venv/bin/python (Python 3.10.12, pytest 9.1.1) +# TASK: M11b-2d-A3a-1 §8 证据口径修正——按任务书指定命令重跑 test_m11b2_single_tx.py 生成新证据(不覆盖 A3 轮旧归档 m11b2d_a3_single_tx_after_revert.txt) +# NOTE: 本文件首行 # CMD 与 §8 证据索引表「跑的是什么」列逐字一致;下方为 pytest 完整原样输出 + +FF..F.FFF.F........F....................xxxxxxxx [100%] +=========================== short test summary info ============================ +FAILED tests/test_m11b2_single_tx.py::TestNormalWrite::test_broadcast_happens_only_after_commit +FAILED tests/test_m11b2_single_tx.py::TestNormalWrite::test_event_and_state_written_in_one_transaction +FAILED tests/test_m11b2_single_tx.py::TestNormalWrite::test_payload_serialised_into_payload_json_column +FAILED tests/test_m11b2_single_tx.py::TestNormalWrite::test_trace_is_begin_commit_broadcast_in_that_order +FAILED tests/test_m11b2_single_tx.py::TestNormalWrite::test_update_path_bumps_version_server_side +FAILED tests/test_m11b2_single_tx.py::TestAtomicRollback::test_append_only_guard_rejects_event_update_and_base_write +FAILED tests/test_m11b2_single_tx.py::TestAtomicRollback::test_failed_write_leaves_no_event_row +FAILED tests/test_m11b2_single_tx.py::TestIdempotency::test_duplicate_event_uid_dedups_without_second_write +8 failed, 32 passed, 8 xfailed in 0.27s +# RC=1