diff --git a/docs/work-log-2026-09-22-m11b2c.md b/docs/work-log-2026-09-22-m11b2c.md index 42a2d51..c24262a 100644 --- a/docs/work-log-2026-09-22-m11b2c.md +++ b/docs/work-log-2026-09-22-m11b2c.md @@ -2,9 +2,19 @@ - 模块:`world_sync`(宿主镜像/消费方侧,运行时事件与实体状态单事务写入器) - 里程碑:**M11b-2**(单事务写两表);上游真源模块 `pbl_runtime_ext`(表结构与 `tx_write/tx_read` 能力权威源) -- 任务:`[M11b-2c-T2] 补 M11b-2 开发文档 dev-notes.md + code_files.md`(task_id=`kICTWazBqgIWtKNO7sz8A`,classify_task=new_dev) -- 本文按 module-development-spec「Work Logs 强制项」产出:本次改了什么、数据模型、契约接口、陷阱与裁决、验证证据。 -- 范围纪律:本任务**只补文档**,未修改任何业务代码 / `models/*.json` / `scripts/load_path.py`(后者归 T3)。 +- 本轮任务:`[M11b-2c-T2-a] 写 dev-notes.md 追加章 + work-log 正文`(task_id `XvEexvh10D4dfkvR3xkkf`,role=agent.develop,task_kind=new_dev,父任务 `[M11b-2c-T2] kICTWazBqgIWtKNO7sz8A`) +- 本文按 module-development-spec「Work Logs 强制项」产出:**改了什么 / 数据模型 / 契约接口 / 陷阱与裁决 / 验证证据**(依次对应 §0、§1、§2、§3、§4)。 +- 范围纪律:本轮**只写文档正文**,未修改任何业务代码 / `models/*.json` / `scripts/load_path.py`(RBAC 登记归 T3;本里程碑本无新 HTTP 路径,见 §2.3)。 + +## 0. 本轮(T2-a)写作范围与纪律 + +| 项 | 口径 | +|---|---| +| 本轮只做 | 写实质正文:本文(模块工作日志)+ `projects/pbls/docs/02-develop/dev-notes.md` 的 `[M11b-2c]` 章 | +| 本轮不做 | 不产出 `code_files.md`(归 `[M11b-2c-T2-b]`,task_id `EBIrHXlTuUkKYl7dPdYgo`);不落盘 `measure.log`、不执行 git、不写 fallback 交付摘要(归 `[M11b-2c-T2-c]`,task_id `UFjoRchqgo8asHC3rP5he`) | +| git 事实陈述 | **本阶段尚未提交,本模块工作区为未提交状态**。git 选择性提交由收口轮 T2-c 执行;本文不预留任何 commit hash 槽位,也不出现「本轮已提交」字样 | +| 自指竞态 | 本文**不声明自身字节数**;凡涉及 `dev-notes.md` / 本文 / `code_files.md` 三者尺寸之处,一律写「见 measure.log `[final]` 段(由收口子任务落盘)」。代码文件本轮零改动,其字节数可现场 `wc -c` 实测写死(见 §6.2) | +| 占位符 | 全文无字母尺寸槽、无 40 位 `0` 串 | ## 1. 数据模型 @@ -12,20 +22,20 @@ M11b-2 写路径涉及两张表,**结构权威源在 `pbl_runtime_ext/models/` ### 1.1 `pbl_runtime_event`(运行时事件,append-only) -- 真源:`modules/pbl_runtime_ext/models/pbl_runtime_event.json`;副本:`modules/world_sync/models/pbl_runtime_event.json`(8782B) +- 真源:`modules/pbl_runtime_ext/models/pbl_runtime_event.json`;副本:`modules/world_sync/models/pbl_runtime_event.json`(8782B,25 列) - 一致性:由 `scripts/m11b2b_column_diff.py` + `scripts/m11b2_selftest.py` 机械核对,`mirror-sha256-equal` 断言真源与 `apps/scense/pkgs/world_sync` 镜像**字节级一致**(本次重跑 PASS)。 - 语义要点: - **append-only**:写路径只做 INSERT,不 UPDATE / 不 DELETE(`TestScopeAndSqlContract::test_event_sql_is_insert_only` 守这条)。 - `event_uid` 是幂等/重试定位键(默认 uuid4 hex,可由入参指定以便测试因果链);旧口径的 `event_id` 已废弃。 - `state_version` 与状态行生效后的版本号**对齐**(同事务内第 4 步算出再写第 5 步),供 M11b-3 广播去重与 M11b-4 轮询增量拉取。 - - `seq_no` 严格单调递增(探针断言 PASS);`source` 默认 `world_sync.m11b2`;`broadcast` 标记位由 M11b-3 消费。 + - `seq_no` 严格单调递增(P99 探针断言 PASS);`source` 默认 `world_sync.m11b2`;`broadcast` 标记位由 M11b-3 消费。 - `payload` 以 JSON **文本**入库(`json.dumps` 后写 `text` 列;抽象类型归一 `json→text`、`bigint→long`,不保留物理修饰)。 ### 1.2 `pbl_entity_state`(实体状态,服务端权威版本) - 真源:`modules/pbl_runtime_ext/models/pbl_entity_state.json`;副本:`modules/world_sync/models/pbl_entity_state.json`(6099B) -- 列集(真源实测 10 列,早期「8 列」口径作废):`tenant_id / id / session_id / entity_id / state_json / state_version / checksum / updated_by / created_at / updated_at` -- 定位键 = 唯一键 `uk_es (tenant_id, session_id, entity_id)`,与 `write_event_with_state` / `read_entity_state` 的 WHERE 完全一致(**没有** `world_id` 列,`world_id` 仅作历史兼容入参被忽略)。 +- 列集(真源实测 **10 列**,早期「8 列」口径作废):`tenant_id / id / session_id / entity_id / state_json / state_version / checksum / updated_by / created_at / updated_at` +- 定位键 = 唯一索引 **`uk_es (tenant_id, session_id, entity_id)`**,与 `write_event_with_state` / `read_entity_state` 的 WHERE 完全一致(**没有** `world_id` 列,`world_id` 仅作历史兼容入参被忽略)。 - `state_version` 单调 +1,**客户端禁写**;`state_json` 存完整新状态(非 diff)。 - `id` 类型偏离:真源 `BIGINT AUTO_INCREMENT`,world_sync 副本内联为 `str/length=32`(spec 合规写法),主键由应用层生成 32 位 uuid。**写路径 INSERT 不显式提交 id**——生产 MySQL 交给真源 DDL 的 AUTO_INCREMENT,本地/测试 sqlite DDL 用应用层生成值。此偏离为有意选择(副本侧不走「登记放行 id 非 str(32)」路线,因为本任务范围禁改校验器脚本),评审勿判结构缺陷。 - 主键只在 `summary[0].primary=["id"]` 单点声明,`indexes[]` 内不出现 `PRIMARY` 条目(spec 规则 `index_name_primary`)。 @@ -48,14 +58,14 @@ def read_entity_state(conn_factory=None, tenant_id=None, session_id=None, - 成功返回:`{event_uid, state_version, action: updated|inserted|event_only, elapsed_ms, isolation_level_applied, dialect, ...}`。 - `elapsed_ms` 是 P99 统计的采样来源; - `isolation_level_applied=False` 在 sqlite 下是**正常**(无该概念),MySQL/PG 下应为 True。 -- `read_entity_state` 返回 `{"state": ..., "state_version": int, "updated_at": ...}`,查不到返回 `None`;它是**独立短事务**,不与写入事务共用(避免长事务),供上层冲突后重读版本再重试。 +- `read_entity_state` 返回 `{"state": ..., "state_version": int, "updated_at": ...}`,查不到返回 `None`;它是**独立短事务**,不与写入事务共用(避免长事务占行锁),供上层冲突后重读版本再重试。 - 复用 `conn` 时仍由本函数负责该连接的 commit/rollback,**调用方不要自行 commit**。 ### 2.2 三处同步注册(module-development-spec 铁律 4,已 grep 核验) | 环节 | 位置 | |---|---| -| ① 实现 | `world_sync/pbl_runtime_tx.py:310,351`(`__all__` 已导出) | +| ① 实现 | `world_sync/pbl_runtime_tx.py:310,351`(模块 `__all__` 已导出) | | ② 包导出 | `world_sync/__init__.py:119-120`(import)+ `:209-210`(`__all__`) | | ③ 宿主挂载 | `world_sync/init.py:513-514` → `env.write_event_with_state` / `env.read_entity_state` | @@ -74,15 +84,16 @@ M11b-2 **不新增** `.dspy` / `.ui`,因此 `scripts/load_path.py` 中**没有 1. **别在 world_sync 侧建表**。DDL 归 `pbl_runtime_ext`;`world_sync/models/*.json` 只是消费方契约视图。改真源必须同步本副本并重跑 `m11b2b_column_diff.py` + `m11b2_selftest.py`。 2. **列名不许写死**。列集由 `pbl_runtime_authority` 从真源机械导出,`_assert_contract()` 在建 SQL 之前 fail-closed(`AuthorityResolutionError`)。新增列只改真源 JSON + 同步副本,代码里出现字面量列名清单 = 双写分叉隐患。 3. **定位键是 `tenant_id + session_id + entity_id`**,不是 `world_id`(表里没这列)。传 `world_id` 只被忽略——别指望它做隔离。 -4. **`expected_version` 两级校验缺一不可**:预检给友好错误(带 expected/actual),CAS(`rowcount != 1`)防预检与写入之间的窄窗口。只留预检会丢失更新。 +4. **`expected_version` 两级校验缺一不可**:预检给友好错误(带 expected/actual),CAS(`rowcount != 1`)防预检与写入之间的窄窗口。只留预检会丢失更新;只留 CAS 则冲突时报错退化为「受影响行数 0」的无语义失败,调用方无法自助重试。 5. **状态行 INSERT 不带 `id`**(见 §1.2 偏离说明),且 UNIQUE 列空串必须归一为 `None`(`''` 会互相撞唯一键)。 -6. **写序是先状态、后事件**。反过来会让事件携带一个可能被回滚的 `state_version`。 -7. **`isolation_level_applied=False` 不等于失败**(sqlite 无该概念)。测试断言要按 dialect 分支。 +6. **写序是先状态、后事件**。反过来会让事件携带一个可能被回滚的 `state_version`,M11b-3 广播与 M11b-4 轮询都会拿到脏版本。 +7. **`isolation_level_applied=False` 不等于失败**(sqlite 无该概念)。测试断言要按 dialect 分支;MySQL/PG 下若为 False 先查账号权限/版本。 8. **`conn_factory` 三级优先级**:显式注入(可传 DB URL)→ 复用 `conn` → 宿主 `ServerEnv` 连接池(`POOL_KEYS=("sqlor_pools","db_pools","pools","sqlorPools")`,库名键 `("pbl","world_sync","default")`)。拿不到池就抛 `ConnFactoryNotConfigured`,**禁止**回落到裸连或读 `env/{test,prod}.json` 凭据(project-directory-spec §8.1)。 9. **`m11b2_selftest.py` 的 `cross-check-sql` 检查器**:M11b-2c 重构后 `EVENT_COLUMNS = columns_of(EVENT_TABLE)`(运行时派生),旧正则抓字面量元组会误报「未能解析」。已由 commit `6532d8f` 改为三级解析(A 字面量 / B1 运行时 import / B2 静态回落)。再遇到同类 FAIL 先怀疑检查器而非业务代码。 -10. **遗留测试文件是技术债不是验收依据**:`tests/test_m11b2_single_tx.py`、`tests/test_m11b2_wiring.py` 的 29 条失败源于脚手架 DDL 与真源不一致、仍用已废弃的 `event_id` 关键字、缺显式 dialect、`init.py` 相对路径等(详见 `m11b2c-tests-result.md` §4.1 逐条归因)。等价覆盖已在 `pbl_runtime_ext/tests/test_m11b2c_runtime_ext.py`(9 passed,含 2 条 P99 门禁)。重写需单列 rework 任务。 +10. **遗留测试文件是技术债,不是验收依据**:`tests/test_m11b2_single_tx.py`、`tests/test_m11b2_wiring.py` 的 29 条失败源于脚手架 DDL 与真源不一致、仍用已废弃的 `event_id` 关键字、缺显式 dialect、`init.py` 相对路径等(逐条归因见 `projects/pbls/docs/02-develop/m11b2c-tests-result.md` §4.1)。等价覆盖已在 `pbl_runtime_ext/tests/test_m11b2c_runtime_ext.py`(9 passed,含 2 条 P99 门禁与 1 条冲突回滚干净性)。重写需单列 rework 任务,本轮**未修改这两个文件**。 11. **广播/轮询不在此模块的 M11b-2 路径里**:post-commit 广播由 `init.py` 的 hook 把 `write_event_with_state` 包一层(M11b-3),3s 轮询兜底在 `pbl_runtime_polling.py`(M11b-4)。摘掉这两层不影响 M11b-2 写入正确性——排查时先确认看到的是哪一层。 12. **P99 数据是离线 sqlite/内存引擎实测**,不含网络 RTT 与真实 InnoDB 锁等待,只能作为逻辑时延下界;上线后在测试环境按 `pbl_runtime_latency.py` 口径复测。 +13. **冲突后的重试姿势**:捕获 `ConcurrentStateConflict` → `read_entity_state` 重读最新 `state_version` → 以该值为新 `expected_version` 重跑 `write_event_with_state`。**不要**盲目循环重试(版本被他人持续推进时应向上报错)。异常族行号见 §6.2。 ## 4. 验证证据(本次实跑) @@ -96,9 +107,10 @@ RESULT: PASS ``` - 全文落盘:`projects/pbls/docs/02-develop/m11b2c-t2-selftest-rerun.log`(64695B) -- 真源侧:`pbl_runtime_ext` pytest `9 passed in 0.41s`(0 失败);`m11b_selftest.py` `总计 110 项,PASS 110,FAIL 0 → RESULT: PASS` -- P99(`m11b2c_p99_probe.py`,n=60,SLA=200ms):`write_event_with_state[INSERT] P99=0.2414ms` / `read_entity_state P99=0.2241ms` / `write_event_with_state[UPDATE] P99=0.4984ms`,均 PASS;`seq_no` 严格递增、读回 `entity_id` 一致性 PASS -- 模块 HEAD:`world_sync` @ `5e3c48d`、`pbl_runtime_ext` @ `9a79e63`(`git status --porcelain` 本任务无代码改动) +- 真源侧:`pbl_runtime_ext` pytest **9 passed / 0 failed**(`m11b2c-tests-pbl-runtime-ext-raw.log`);`m11b_selftest.py` **总计 110 项,PASS 110 / FAIL 0 → RESULT: PASS**(`m11b2c-tests-selftest-raw.log`) +- P99(`m11b2c_p99_probe.py`,n=60,SLA 200ms,`m11b2c-tests-p99-probe-raw.log`):`write_event_with_state[INSERT分支] P99=0.2414ms` / `read_entity_state P99=0.2241ms` / `write_event_with_state[UPDATE分支] P99=0.4984ms`,三条均 PASS;附带 `seq_no` 严格递增 PASS、UPDATE 分支 60 次覆写后 `state_version` 单调至 61、读回 `entity_id` 一致性 PASS +- 本模块 pytest:`29 failed / 56 passed`(`m11b2c-tests-pytest-raw.log`)——**遗留测试脚手架漂移,非业务缺陷**,定性依据见 §3 陷阱 10 +- 本轮为纯文档轮,未改代码,故无新增编译/端点验证;上述数字全部来自磁盘真实留证日志,可逐条复核 ## 5. 关联文档 @@ -107,120 +119,41 @@ RESULT: PASS - RBAC 口径:`m11b2c-rbac-path-declaration.md`;实跑留证:`m11b2c-tests-result.md` 及各 `m11b2c-tests-*-raw.log` - 模块技能:`modules/world_sync/skill/SKILL.md`;上一份工作日志:`modules/world_sync/docs/work-log-2026-09-20.md` +## 6. 本轮(T2-a)补充:文档收口约定与实测锚点 -## 6. T2 重做补充(2026-09-22,响应 QC #1~#4) +### 6.1 与前几轮的差异(为什么本文不再有「第三轮刷新/收口」章节) -本轮不改任何代码,只补文档与收口。补充要点(详版见 `projects/pbls/docs/02-develop/dev-notes.md` `[M11b-2c]` 章 §7): +本模块文档此前几轮把「写作」与「测量取证 + git 提交 + 数字回填」混在同一轮做,结果反复在回填一步中断,交出的文档里留下字母尺寸槽与 hash 占位串,且出现「文档声称已提交而磁盘 `git status` 仍是未提交」的陈述与事实矛盾。本轮按 PM 拆分把两件事彻底分离: -### 6.1 伴生交付件 code_files.md(QC #1) +- **T2-a(本轮)**:只写正文(本文 + dev-notes `[M11b-2c]` 章)。凡尺寸类自指/互指信息一律改为「见 measure.log `[final]` 段」的引用约定,不写死数字、不留占位串。 +- **T2-b**:产出 `code_files.md` 文件清单(代码文件实测字节数 + `grep -n` 行号锚点)。 +- **T2-c**:重跑测量落盘 measure.log(`[final]` / `[git]` 两段)→ 两仓 git 选择性收口 → 回填**非自指**尺寸 → 写 fallback 交付摘要。 -新建 `projects/pbls/deliverables/agent.develop/kICTWazBqgIWtKNO7sz8A_code_files.md`,逐条列出 M11b-2c 涉及文件的路径 + `wc -c` 实测字节数 + `grep -n` 行号锚点,数字来源落盘 `projects/pbls/docs/02-develop/m11b2c-t2-code-files-measure.log`。dev-notes §6 的引用已改为工作空间根相对全路径。 +因此本文不再声明自身字节数,也不声明 `dev-notes.md` / `code_files.md` 的字节数;**git 收口状态如实记为「本阶段尚未提交,工作区为未提交状态」**,与 `git status --porcelain` 的磁盘事实一致。 -### 6.2 本模块文件的实测锚点(复核一致) +### 6.2 本模块文件锚点(T2-a 现场实测,代码零改动故可直接对账) -| 文件 | 字节数 | 锚点 | +| 文件 | 字节数(`wc -c` 实测) | 锚点(`grep -n` 实测) | |---|---|---| -| `world_sync/pbl_runtime_tx.py` | 23584 | `:296 _set_isolation` / `:310 read_entity_state` / `:351 write_event_with_state` / `:403-413 expected_version 校验` / `:439-444 ConcurrentStateConflict` / `:517 isolation_level_applied` | -| `world_sync/pbl_runtime_tx_sqlor.py` | 5956 | `:126 write_event_with_state` / `:154 read_entity_state` | +| `world_sync/pbl_runtime_tx.py` | 23584 | `:296 _set_isolation` / `:310 read_entity_state` / `:351 write_event_with_state` / `:517 isolation_level_applied` | | `world_sync/pbl_runtime_sql.py` | 8872 | `:136 begin_stmt` / `:148 read_committed_stmt` / `:157 for_update_clause` | | `world_sync/pbl_runtime_errors.py` | 4819 | `:35 PblRuntimeError` / `:71 TxConfigError` / `:78 ConnFactoryNotConfigured` / `:85 EventWriteError` / `:92 StateWriteError` / `:99 ConcurrentStateConflict` / `:110 TxAbortError` | +| `world_sync/pbl_runtime_tx_sqlor.py` | 5956 | `:126 write_event_with_state` / `:154 read_entity_state` | | `world_sync/__init__.py` | 9156 | `:119-120` 导入、`:209-210` `__all__` | -| `world_sync/init.py` | 25922 | `:512` M11b-2 注释、`:513 env.write_event_with_state`、`:514 env.read_entity_state`、`:587` M11b-3 广播钩子覆盖挂载 | +| `world_sync/init.py` | 25922 | `:513 env.write_event_with_state`、`:514 env.read_entity_state`、`:587` M11b-3 广播钩子二次覆盖同名挂载 | | `models/pbl_runtime_event.json` | 8782 | 25 列,四段式合规 | | `models/pbl_entity_state.json` | 6099 | 10 列,`uk_es=['tenant_id','session_id','entity_id']` | -| `scripts/m11b2_selftest.py` | 18932 | 4 路径落点、554 条断言 | +| `scripts/m11b2_selftest.py` | 18932 | 554 条断言(§4) | -真源侧 `modules/pbl_runtime_ext`:`pbl_runtime_ext/tx_write.py`(35357B, `:344 apply_runtime_event` / `:466 read_states`)、`models/pbl_runtime_event.json`(10942B)、`models/pbl_entity_state.json`(1871B)、`scripts/m11b2c_p99_probe.py`(12167B)、`scripts/m11b_selftest.py`(27591B)、`pbl_runtime_ext/latency.py`(4523B, `SLA_P99_MS=200.0`)。 +真源侧 `modules/pbl_runtime_ext`:`pbl_runtime_ext/tx_write.py`(35357B,`:344 apply_runtime_event` / `:466 read_states`)、`scripts/m11b2c_p99_probe.py`(P99 探针)、`pbl_runtime_ext/latency.py`(`SLA_P99_MS=200.0`)。 -### 6.3 陷阱补充:三处同步注册在 M11b-3 之后有「二次覆盖」 +> 行号口径统一:`read_committed_stmt` 一律记 **`:148`**(本轮 `grep -n '^def read_committed_stmt' world_sync/pbl_runtime_sql.py` 实测),dev-notes `[M11b-2c]` 章 §2.2 同口径。 -`init.py:513` 先把裸函数挂到 `env.write_event_with_state`,`init.py:587`(M11b-3)又用 `install_broadcast_hook(env)` 的包装器**覆盖同名**。改 M11b-2 写路径时若只 grep 到 `:513` 会误判挂载点——运行时实际生效的是 `:587` 的包装器(内部仍委派 `:513` 的实现)。`grep -n 'env.write_event_with_state' world_sync/init.py` 必须看全两处。 +### 6.3 遗留缺口(供 PM 编排) -### 6.4 本轮实跑验证 +1. `tests/test_m11b2_single_tx.py` / `tests/test_m11b2_wiring.py` 共 29 条漂移用例需单列 rework(等价覆盖已在真源侧全绿,不阻塞 M11b-2 验收)。 +2. 真实 MySQL/PG 下的端到端时延与 `isolation_level_applied=True` 验证需 deploy_test 连库补测(本地 sqlite 无该概念,见 §3 陷阱 7/12)。 -- `world_sync/scripts/m11b2_selftest.py`:**断言合计 554:PASS 554 / FAIL 0 → RESULT: PASS**(全文 `projects/pbls/docs/02-develop/m11b2c-t2-selftest-rerun.log`,64695B) -- `pbl_runtime_ext` pytest:**9 passed,0 失败**;`pbl_runtime_ext` selftest:**110 项 PASS 110 / FAIL 0 → RESULT: PASS** -- P99(`m11b2c_p99_probe.py`,n=60,SLA 200ms):write[INSERT] 0.2414ms / read 0.2241ms / write[UPDATE] 0.4984ms,均 PASS -- 文档一致性(第二轮时点实测):`grep -c "M11b-2\|expected_version\|READ COMMITTED\|P99\|无新 HTTP 路径" dev-notes.md` = 50 命中。本轮(第三轮)dev-notes.md 又追加了 §7.4 重写与 §8,命中行数随之增长,本轮实测的逐词/合并命中数原样记录在 `projects/pbls/docs/02-develop/m11b2c-t2-code-files-measure.log` `[final]` 段(不在本文写死,避免再次出现「自述与磁盘不一致」,见本文 §7.6 与 dev-notes §8.3) +### 6.4 复杂度评估(本轮) -### 6.5 遗留缺口 - -`tests/test_m11b2_single_tx.py`(27309B) / `tests/test_m11b2_wiring.py`(25520B) 断言口径与重构后源码契约漂移(T1 实跑 29 failed / 56 passed,根因在测试侧 fixture/旧签名),建议 PM 单列 rework。本模块本轮**未修改这两个文件**。 - -## 7. 第三轮补充(2026-09-22,响应 QC #12 / #15 / #16) - -本轮仍**不改任何业务代码 / 表定义 JSON / `scripts/load_path.py`**,只做三件事: -①刷新第二轮自述、与磁盘不一致的字节数(QC #12);②把 git 收口从「引擎代收口」改为 -「agent 自行选择性提交」并留下逐仓可核对的事实(QC #15);③更正 dev-notes.md §7.4 中 -「本任务已自行提交、commit hash 见交付摘要」的不实陈述(QC #16——当时交付摘要里没有任何 hash)。 - -### 7.1 引用数字刷新(本轮 `wc -c` 实测;旧值 = 第二轮自述) - -| 文件 | 第二轮自述 | 本轮实测 | 差异原因 | -|---|---|---|---| -| `docs/work-log-2026-09-22-m11b2c.md`(本文) | 11422 | SIZWL | 第二轮自述后又追加了 §6(T2 重做补充),本轮追加本 §7 | -| `projects/pbls/docs/02-develop/dev-notes.md` | 41881 | SIZDN | 第二轮自述后又追加 §7.1~§7.6,本轮重写 §7.4 并追加 §8 | -| `projects/pbls/deliverables/agent.develop/kICTWazBqgIWtKNO7sz8A_code_files.md` | 11723 | SIZCF | 第二轮自述后又补 §5~§7(既有证据清单 / 遗留缺口 / 复杂度评估),本轮加 §8 | - -§6.2 表内列的**代码文件**字节数(`pbl_runtime_tx.py` 23584 / `pbl_runtime_tx_sqlor.py` 5956 / -`pbl_runtime_sql.py` 8872 / `pbl_runtime_errors.py` 4819 / `__init__.py` 9156 / `init.py` 25922 / -`models/pbl_runtime_event.json` 8782 / `models/pbl_entity_state.json` 6099 / `scripts/m11b2_selftest.py` 18932) -本轮逐条 `wc -c` 复核**与磁盘一致、未漂移**(本任务零代码改动,`git status --porcelain` 除本文档外为空)。 -原始 `wc -c` / `grep -n` / `git show --stat` 输出见 -`projects/pbls/docs/02-develop/m11b2c-t2-code-files-measure.log` 的 `[final]` / `[git]` 段 -(`[final]` 段测量时间戳晚于本任务所有文件的最后修改时间)。 - -> 自指竞态处理:上表「本轮实测」值与 dev-notes §7.1/§8.1、code_files §4/§8 中的同名数字, -> 均在内容定稿后测得,之后只做**等长替换**(5 位尺寸槽 → 5 位实测值;40 位 `0` hash 占位 → 40 位真 hash), -> 因此数字与磁盘始终一致;若后续再追加内容,本节数字即失效,须以重跑的 measure.log 为准。 - -### 7.2 行号口径统一为 `:148` - -`read_committed_stmt` 的行号在第二轮分裂为两处(dev-notes §2.2 写 `:149`、code_files.md §1.3 写 `:148`)。 -本轮实测 `grep -n "^def read_committed_stmt" world_sync/pbl_runtime_sql.py` → -`148:def read_committed_stmt(dialect):`,**统一为 `:148`**(本文 §6.2 原本即 `:148`,无需改动; -dev-notes §2.2 已按实测更正,见其 §8.2)。其余锚点(`:136 begin_stmt` / `:157 for_update_clause` / -`:296 _set_isolation` / `:310 read_entity_state` / `:351 write_event_with_state` / `:99 ConcurrentStateConflict` / -`:513-514 env.*`)复核与第二轮声明一致。 - -### 7.3 git 收口事实(QC #15 / #16) - -- **第二轮遗留事实(引擎代收口,非 agent 提交)**:本文 §6(T2 重做补充)的落库由引擎代收口完成—— - commit `dc9e51b6ab4294c3f55132b854e4b0a10baa1550`,message `deliver: 交付收口(引擎代为提交)`, - `git show --stat` 显示该笔只含本文件 1 个 / +40 行。而第二轮 dev-notes §7.4 却自称「本任务自行选择性提交 - (commit hash 见交付摘要)」且摘要里没有 hash,即 QC #16 所指不实陈述。 -- **本轮 agent 自提「内容笔」**:`git add docs/work-log-2026-09-22-m11b2c.md` + - `git commit -m 'docs(M11b-2c-T2): 补 work-log §7 数字刷新与 git 收口事实'`, - hash = `WS00000000000000000000000000000000000000`(该笔提交后由 `git log -1 --format=%H` 取值回填)。 - `git show --stat` 文件清单:仅 `docs/work-log-2026-09-22-m11b2c.md`(1 file changed)。 - **未** `git add -A`、**未** add `wwwroot/`(CRUD 只读构建产物,module-development-spec 硬门禁 16)、 - **未** add `tests/test_m11b2_*.py`(不在本任务范围,见 §6.5)。 -- **本轮「回填笔」**:把上述 hash 与本文尺寸真值写进文件后,工作区再次出现本文件的未提交改动, - 故另起一笔 `git add docs/work-log-2026-09-22-m11b2c.md && git commit`。回填笔 hash 不写进文件 - (避免自指无限递归),用 `cd modules/world_sync && git log -1 --format=%H` 现场查询,交付摘要中亦给出。 -- 同一「内容笔 + 回填笔」模式应用于 `projects/pbls`(选择性 add 本任务 3 个文件: - `docs/02-develop/dev-notes.md`、`docs/02-develop/m11b2c-t2-code-files-measure.log`、 - `deliverables/agent.develop/kICTWazBqgIWtKNO7sz8A_code_files.md`;pbls 内容笔 hash = `PB00000000000000000000000000000000000000`)。 - -### 7.4 本轮验证(不改代码,故以一致性复核 + 既证实跑结论为准) - -- 代码文件字节数与 §6.2 声明逐条复核一致(见 7.1),无「文档描述与磁盘漂移」。 -- 行号锚点与 §6.2 声明一致(见 7.2),`read_committed_stmt` 两处口径已统一为 `:148`。 -- 验收关键词(dev-notes.md)`M11b-2` / `expected_version` / `READ COMMITTED` / `P99` / `无新 HTTP 路径` 全部命中。 -- 实跑结论沿用第二轮(本轮零代码改动,重跑结论不变,未重复消耗环境): - `scripts/m11b2_selftest.py` **554 断言 PASS 554 / FAIL 0 → RESULT: PASS** - (全文 `projects/pbls/docs/02-develop/m11b2c-t2-selftest-rerun.log`,64695B); - `pbl_runtime_ext` pytest **9 passed / 0 failed**;`pbl_runtime_ext` selftest **110 项 PASS 110 / FAIL 0**; - P99(`m11b2c_p99_probe.py`,n=60,SLA 200ms)write[INSERT] 0.2414ms / read 0.2241ms / - write[UPDATE] 0.4984ms,均 PASS(原文见 `m11b2c-tests-p99-probe-raw.log` 与 dev-notes §3.2)。 - -### 7.5 本轮未改动清单(范围纪律) - -未改 `world_sync/*.py`、未改 `models/*.json`、未改 `scripts/load_path.py`、未改 `tests/test_m11b2_*.py`、 -未改 `wwwroot/` 生成目录;两仓 `git status --porcelain` 除本任务文档外为空(见 measure.log `[git]` 段)。 - -### 7.6 复杂度评估(本轮) - -**复杂度评估:简单,单交付单元,无需拆分。** 本轮为文档数字/行号刷新 + 两仓 git 自行收口 + 不实陈述更正, -无新增功能面、无可并行独立子工作。遗留缺口仍是 §6.5(两个遗留测试文件需 rework)与 -C 层真实库端到端证据(需 deploy_test 连库补),均不在本任务范围。 +**简单**——单交付单元(两份文档正文写作),零代码改动、零表定义改动、无跨模块影响,**无需拆分**。父任务 `[M11b-2c-T2]` 整体为复杂(多独立交付单元 + 串行收口依赖),已由 PM 拆为 T2-a / T2-b / T2-c 三子任务并按批次派发,口径见 §6.1。