world_sync/docs/work-log-2026-09-20.md
2026-09-20 19:34:32 +08:00

132 lines
14 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.

# work-log 2026-09-20 — world_sync(M11b-2a 迁移 + M11b-2a-1 根包合规 + M11b-2a-2 文档归档)
- 仓库:`modules/world_sync`(remote `yumoqing/world_sync`,branch `main`)
- 记录人:agent.develop
- 首轮记录:2026-09-20 19:20(+08:00)|**响应轮更正:2026-09-20(`c66868c` 收口之后复跑并补记,见 §2/§3.5/§6/§7)**
- 关联任务:`[M11b-2a]` u6kCWdLV2k5cmuG8Yb5BY(父)/`[M11b-2a-1]` dPgvSjRDNQ6kIQi0K-6HT(approved)/`[M11b-2a-2]` hVZNlBKmtiNNzn6BPeA3J(本记录)
- 关联迭代:pbls-初始迭代 | 响应 QC 未过项:#1 开发说明缺失(含范围声明失实)、#2 过程归档缺失(#3 由 M11b-2a-1 处置)
> ⚠️ 响应轮更正要点:首轮 §2 commit 列表只写到 `aff1f0d`,把本任务描述成「仅新增 2 个 md」。实测 `git show c66868c --numstat` 显示本任务收口 commit 除 work-log(+96)外**还包含 `scripts/validate_models_json.py` 的 rev4 代码改动(+104/−35)**。该改动属 M11b-2b 范围,因引擎统一 git 收口而被一并提交 —— 现于 §2 补记、§7 显式声明「跨任务混提」。
---
## 1. Scope(本任务链做了什么 / 不做什么)
**做:**
1. 把 M11b-2「单事务事件+状态原子写入」实现从应用侧 `apps/scense/pkgs/world_sync/world_sync/` 迁移到模块仓库 `modules/world_sync/world_sync/`(5 个新增子模块 + `__init__.py` + `init.py`),tests/scripts 同迁 —— 落实「develop 模块源码必须落 modules/」。
2. 三处接线:内层包 re-export 契约符号、`init.py` loader 命名与 ServerEnv 登记、根包导出(后者经核对判定违规后撤销,见 §3.1)。
3. 结构合规处置:删除仓库根 `__init__.py`(156 行转发包)+ `pyproject.toml` 收紧打包面 + 导入闭包重验。
4. 文档归档(M11b-2a-2):`projects/pbls/docs/02-develop/dev-notes-m11b2a-world-sync-migration.md` + 本 work-log。
**不做:** 业务逻辑(事务/行锁/回滚/乐观并发/权限判定)零改动;`models/` JSON 表定义内容零改动(M11b-2b);apps 侧部署副本清理未强制(§5 遗留项 4)。
**范围澄清(响应轮)**:「本任务不改代码」只对**主动编写的迁移/业务代码**成立 —— 收口 commit `c66868c` 实际含一次非本任务范围的脚本改动(§7),不得对外表述为「零代码改动」。
---
## 2. Commit 列表
| commit | 时间 | 内容 |
|---|---|---|
| `01941aa` | 2026-09-20 | `deliver: 交付收口(引擎代为提交)` —— 迁移本体落库:`world_sync/{pbl_runtime_errors,pbl_runtime_sql,pbl_runtime_tx,pbl_runtime_tx_env,pbl_runtime_tx_sqlor}.py` + `__init__.py`(6187B) + `init.py`(22123B) + tests/scripts;三处接线成立(含当时的根包转发,156 行) |
| `9f97d58` | 09-20 18:31 | `M11b-2a: resolve root-package spec compliance (drop repo-root __init__.py forwarding package)` —— **删除** `modules/world_sync/__init__.py`(1 file changed, 156 deletions);commit message 内记录宿主接线行号证据与删除后复验结论;用 pathspec 有意排除 M11b-2b WIP `scripts/validate_models_json.py` |
| `95b405f` | 09-20 | `deliver: 交付收口(引擎代为提交)` —— M11b-2a-1 交付件收口 |
| `aff1f0d` | 09-20 19:12 | `M11b-2a: resolve root-package spec compliance (rev2: tighten packaging surface, record real import evidence)` —— `pyproject.toml:25-28` `[tool.setuptools.packages.find] where=["."] include=["world_sync*"] namespaces=false`;**更正 rev1 不实的 case1 输出**,补 host(venv editable)取证 |
| **`c66868c`** | 09-20 19:24 | `deliver: 交付收口(引擎代为提交)` —— **本任务(M11b-2a-2)的收口 commit**,`git show --numstat` 实测含 **2 项变更 / 200 insertions(+) 35 deletions(-)**:① `docs/work-log-2026-09-20.md` **+96 / −0**(本文件,QC #2 要求的 dated work-log,归属 M11b-2a-2);② `scripts/validate_models_json.py` **+104 / −35**(rev4 修复:`RULE_STATS_TAGS` 结构重构、`_rule_tag()` 候选元组语义、`other==0` 硬门禁 + `RULE_STATS_OTHER_DETAIL`、新增 `--allow-registered-deviation` CLI、「引用式写法」key/schema 判 ERROR。**归属 M11b-2b**,因引擎统一收口被一并提交,见 §7 跨任务混提声明) |
首轮此表缺 `c66868c` 一行(响应轮补记);`9f97d58` 行原述「pathspec 有意排除 validate_models_json.py」仍准确,但需与 §7 连读 —— 排除只对该 commit 生效,最终仍由 `c66868c` 入库。
---
## 3. 关键决策与陷阱
### 3.1 为何「删除」根包转发,而不是「保留 + 收紧」(QC #3 给了二选一)
- **规范**:module-development-spec 规定 `mymodule/` 是仓库根、`mymodule/mymodule/` 才是 Python 包,仓库根不列 `__init__.py`;同机构 `modules/pbl_runtime_ext/` 等仓库根均无 `__init__.py`。
- **宿主接线实测不依赖它**:`apps/scense/app/scense.py:50 from world_sync.init import load_world_sync`(L57 调用)、`apps/yuanjing/app/yuanjing.py:66 __import__(f'{module}.init', ...)` —— 两者都以 sys.path=仓库根解析到**内层** `world_sync/init.py`。转发表无人调用 = 死代码。
- **风险**:根包 + `packages.find include=["world_sync*"]` 组合会把仓库根一并发现为包,产生「同一模块两条导入路径、两份 `__init__` 语义」的双路径歧义,后续 develop 极易误用根包路径写出跑不通的接线。
- **决策**:走 (a) 删除(`9f97d58`),并追加 (b) 的配置部分(`aff1f0d`)把约束固化进 `pyproject.toml`,防回归。
### 3.2 陷阱:`init/` 数据目录遮蔽 `init.py`(case1 的真实 FAIL)
`modules/world_sync/init/data.json` 是模块既有数据目录。当 sys.path 落在**模块父目录** `modules/` 时,`world_sync.init` 优先解析到该目录(namespace 片段)而非 `init.py`,于是 `from world_sync.init import load_world_sync` → `ImportError: cannot import name 'load_world_sync' from 'world_sync.init' (unknown location)`。
用删除前基线 `01941aa` 沙箱复刻同场景:**删除前同样 FAIL** ⇒ 非本次删除引入的回归。结论:world_sync 的 loader 接线以 **sys.path=仓库根**(宿主实际做法)为准,`sys.path=modules/` 不作为契约路径;若要支持需单独立项(重命名数据目录或调 `scripts/load_path.py` 注入顺序)。
### 3.3 陷阱:把「删除前的验证输出」当成「删除后的证据」(流程教训)
M11b-2a-1 rev1 文档 §4.2 与交付摘要 §3 中 case1 的 OK 输出块为不实记录(错误归因),被 QC #7/#8/#14 指出。rev2 已删除伪造块、以 `bash projects/pbls/scripts/m11b2a1_rev2_revalidate.sh` 落盘输出替换(全文 `projects/pbls/evidence/m11b2a1_rev2_import_closure.txt`)。本 work-log 与 dev-notes 中所有输出为 2026-09-20 19:20 **再次独立复跑**,与 rev2 一致。教训:验证必须在处置动作之后重跑,且证据要落盘可复核。
### 3.4 决策:单一真源
契约函数实现只在 `world_sync/pbl_runtime_tx_sqlor.py`,`__init__.py:40 from .init import (...)` / L119–120 只做 re-export(实测 `write_event_with_state.__module__ == 'world_sync.pbl_runtime_tx_sqlor'`),不允许在包 `__init__` 或根包中写第二份实现。
### 3.5 陷阱(响应轮新增):文档范围声明与仓库最终态脱节
首轮交付摘要写「本任务仅新增 2 个 md,零代码改动」,dev-notes §6 第 6 行写 `validate_models_json.py`「未纳入 commit」—— 两句都与 `git show c66868c --numstat` 的事实矛盾(该 commit 明确含脚本 +104/−35)。根因:产线 git 收口由**引擎在 deliver 时代为执行**,提交范围 = 工作区全部未提交变更,develop 无法指定 pathspec;因此「文档任务」的收口 commit 也可能带代码。
教训与对策:① 交付摘要与 work-log 的 commit 列表必须在**收口后**以 `git show --numstat` 复核,不能按任务意图预写;② 工作区存在其它任务 WIP 时,deliver 前先清理/stash,或如本文 §7 显式声明混提归属;③ 文档类任务的「零代码改动」措辞要改为「本任务未主动改动业务代码,随包收口项见 §7」。
---
## 4. 验证(2026-09-20 19:20 实测 + 响应轮复跑)
| 项 | 命令 | 结果 |
|---|---|---|
| 语法 | `python3 -m py_compile world_sync/*.py scripts/*.py` | `rc=0` 全通过(含 rev4 后的 `scripts/validate_models_json.py`) |
| case2 sys.path=仓库根 | `import world_sync` / `from world_sync.init import load_world_sync` / 4 契约符号 | OK;`__file__` → `modules/world_sync/world_sync/__init__.py`;仓库根 `__init__.py` 存在性 = `False`;`__all__ len=62 MISSING=[]`;`issubclass(ConcurrentStateConflict, PblRuntimeError)=True` |
| case1 sys.path=`modules/` | 同上 | **FAIL**(`__file__=None` 命名空间形态 / `ImportError (unknown location)`),根因 §3.2,非回归 |
| host sys.path=`apps/scense/pkgs/world_sync` | 同上 | OK;`__file__` → apps 副本内层包;`__all__: 62 MISSING: []` |
| 迁移一致性 | `diff -q` 8 个 .py(模块仓库 vs apps 副本) | 8/8 IDENTICAL |
| rev4 校验脚本自测(响应轮新增) | `python3 scripts/validate_models_json.py --help` / `... models` | 开关 `--allow-registered-deviation` 真实存在;本仓库 `files=5 errors=2 registered_deviations=0`,全部归入 `RULE_STATS: reference_style_key_schema=2`,无 other 黑洞,`RESULT: FAIL rc=1`(暴露 models JSON 待修项,归 M11b-2b) |
| 工作区 | `git status --porcelain` | 无输出 = clean;branch `main` @ `c66868c`,tracking `[origin/main]`,另有 `archive/m11b1-in-world-sync` |
完整输出块见 `projects/pbls/docs/02-develop/dev-notes-m11b2a-world-sync-migration.md` §4(含 §4.6 git numstat、§4.7 rev4 自测)。
---
## 5. 受环境限制未验证项(不得当作已验证)
1. **真实 DB 建连与写入路径未跑**:沙箱无 MySQL/PG。`configure_runtime_writer`(`init.py:326`)、单事务内「事件写 + 实体状态写 + 行锁」原子性、失败回滚、`ConcurrentStateConflict` 实际抛出路径 —— 均只有静态/import/mock 级覆盖,需部署态联调。
2. **`tests/test_m11b2_single_tx.py` / `test_m11b2_wiring.py` 未执行**:依赖 DB fixture,本轮只保证可编译可导入。
3. **`env.pbl_runtime_conn_factory` 端到端解析未跑**:`init.py:480/483` 的 ServerEnv 键解析链需应用启动态验证。
4. **apps 侧薄壳清理未做(原任务第 4 项为可选)**:`apps/scense/pkgs/world_sync/world_sync/` 保留 8 个 IDENTICAL 文件,因为宿主 `scense.py:50` 实际加载的就是该 editable 副本;删除会让 scense 立即失去模块。建议后续改为部署期同步产物(`build.sh` / `scripts/sync_models_to_app.py`)+ `.gitignore` 排除,做到「模块仓库唯一真源」。
5. **`models/` JSON 与 SQL 列清单 diff**:留 M11b-2b(`scripts/m11b2b_column_diff.py` 已就位)。rev4 校验脚本已实测报出 `models/` 5 文件中 2 条 `reference_style_key_schema` ERROR(§4),**该修复本身未随本任务完成**,属 M11b-2b 待办。
6. **`sys.path=modules/` 契约路径**:已确认不可用并文档化(§3.2),未修复。
7. **`git push` 结果未由本角色验证**:收口由引擎执行,`git branch -vv` 显示 `main c66868c [origin/main]` 无 ahead 标记,但推送日志不在本记录取证范围。
---
## 6. 当前 branch-commit 状态(响应轮时点)
```
branch: main(tracking remotes/origin/main);工作区 clean(git status --porcelain 无输出)
HEAD: c66868c deliver: 交付收口(引擎代为提交) ← 本任务收口:work-log(+96) + validate_models_json.py rev4(+104/−35)
aff1f0d M11b-2a: resolve root-package spec compliance (rev2: tighten packaging surface, record real import evidence)
95b405f deliver: 交付收口(引擎代为提交)
9f97d58 M11b-2a: resolve root-package spec compliance (drop repo-root __init__.py forwarding package)
01941aa deliver: 交付收口(引擎代为提交)
其它分支:archive/m11b1-in-world-sync @ 052d257
仓库根结构:README.md / pyproject.toml / init/(数据目录) / json/ / models/ / scripts/ / skill/ / tests/ / wwwroot/ / world_sync/(内层包) / docs/(本记录)
无仓库根 __init__.py —— 对外唯一路径:world_sync.init(loader)、world_sync(内层包,sys.path=仓库根)、world_sync.world_sync.*(子模块,sys.path=仓库根时等价 world_sync.*)
```
本记录(M11b-2a-2)首轮文档已随 `c66868c` 入库;响应轮的更正(§2 补记 `c66868c`、§3.5、§4 新增 rev4 行、§5 第 5/7 项、§6、§7)由引擎下一次交付收口统一提交,本记录不自称已 commit/push。
---
## 7. 跨任务混提声明(响应 QC #1 第 ④ 点)
**事实**:`c66868c` 同时承载两个任务的产物 ——
| 文件 | 变更 | 归属任务 |
|---|---|---|
| `docs/work-log-2026-09-20.md` | +96 / −0(新增) | `[M11b-2a-2]` 本任务(QC #2 归档) |
| `scripts/validate_models_json.py` | +104 / −35(修改) | **`[M11b-2b]`**(models JSON 机械校验工具 rev4) |
**为何发生**:rev4 改动是 M11b-2b 在途 WIP,遗留在工作区未提交。`9f97d58`(结构处置)当时**有意用 pathspec 排除**它,避免混进 2a 的结构 commit;但本任务 `deliver` 时 git 收口由**引擎代为执行**,范围 = 工作区全部未提交变更,不支持人工 pathspec,于是该脚本随本任务收口被提交为 `c66868c`。
**为何未单独收口 / 不回退**:① 改动已入库且工作区 clean,从已推送的 `main` 历史剥离需改写历史,风险大于收益;② rev4 属纯工具侧改动,不触碰 `world_sync/` 包与业务逻辑,对 M11b-2a 的迁移/接线/结构结论无影响(§4 复跑仍 OK);③ 它是 M11b-2b 的前置能力,提前入库不阻塞 2b,反而让 2b 能直接基于 rev4 去修 `models/` 的 2 条 ERROR。
**给 QC / PM 的判读约定**:
- `c66868c` 中 `scripts/validate_models_json.py` 的**变更归属 = M11b-2b**,本任务仅为随包收口载体,不得据此认为 M11b-2b 已交付(models JSON 的 2 条 ERROR 仍未修);
- 本任务对 M11b-2a 迁移范围(`world_sync/` 包、`pyproject.toml`)**代码零改动**的结论仍然成立;
- 若产线要求「一 commit 一任务」,建议列为流程改进:`deliver` 前强制清理工作区 WIP,或引擎收口支持 pathspec —— 而非作为本任务的返工项。