8.6 KiB
8.6 KiB
pbl_compiler 工作日志 — 2026-09-19(M3b 规则映射与导出 · 整改轮)
任务:[M3b] pbl_compiler script_engine 规则映射与导出
(第12章 event→condition→response → script_type=1 规则 JSON 映射、产物导出、game_definition 写入)
角色:agent.develop | 迭代:pbls-初始迭代 | 任务性质:new_dev(含 QC 退回意见逐条整改)
1. 本轮范围
只做「登记面接线 + 审计工具自身缺陷 + 提交可追溯性」的增量整改,不重写已合规的 models/ 表定义本体(前轮 QC 已确认四段式 / primary str32 / codes parentid 全过)。
| # | 退回意见 | 处置 |
|---|---|---|
| QC #1(硬门禁·第四章 RBAC) | 5 个 M3b Web 契约未登记 RBAC 路径;init.py 注释条数与代码不符 | 已修:scripts/load_path.py 逐条显式登记(无通配符),pbl_compiler/init.py 注释与事实对齐 |
| QC #2(流程·真实性) | 交付前未自行 git commit,由引擎代为收口 | 已修:本轮 agent 自行选择性 git add + git commit + git push,commit cb1132e |
| 前轮 #2(GD 唯一写入口) | gd_rules_writer 无调用入口 | 保持:pbl_compiler/api.py L606 编译主流程 ⑥.5 调用 write_gd_rules(),rules_export_api.py L223 亦经此入口 |
| 前轮 #3(CRUD editable) | editable 仅 get_data_url,xls2ui 会回退默认写入口 | 保持方案 A:9 个只读拒绝端点 + params 顶层三 URL 绝对路径 |
| 前轮 #4(work log) | 无 dated work log | 本文件补齐归档 |
2. 时间线
- 实跑审计定位根因:
python3 scripts/audit_rbac_parity.py→ rc=1,报 「load_path.py PATHS 为空(RBAC 零登记 → 全部 403)」。 - 交叉核验发现是两处事实叠加:
- 工作区
scripts/load_path.py实际已登记 29 条(grep -c "('/pbl_compiler/api/"= 29), 与ls wwwroot/api/*.dspy | wc -l= 29 一致 → QC 引用的「仅 15/20 条」是 git HEAD 版本(前轮变更未提交,git show HEAD:scripts/load_path.py实测 20 条、git ls-tree HEAD wwwroot/api/实测 20 个),审核方读的是仓库而非工作区。 - 审计脚本自身存在解析缺陷:
parse()对纯字面量列表已literal_eval成 python list, 而resolved字典只收ast.List形态,导致PATHS = PATHS_CONTRACTS + PATHS_READONLY_DENY(BinOp)回查resolved拿到空列表 → 把已登记的 29 条误判成「零登记」,产生假 FAIL。
- 工作区
- 修审计工具:
resolved同时接受list(已求值)与ast.List(含函数引用求值失败)两种形态。 - 修注释:
init.py文件头「共 20 条 + 只读列表 CRUD 6 条」→ 「共 29 条 = Web 契约端点 20 + CRUD 只读拒绝端点 9,无通配符」。 - 实跑自证:audit rc=0 PASS;
scripts/test_m3b_mapping.pyPASS=113 / FAIL=0;python3 -m py_compile pbl_compiler/*.py scripts/*.pyOK。 - 自行收口:选择性暂存 15 个文件(6 改 + 9 新增 .dspy),
git commit→cb1132e,git push origin HEAD成功(d203811..cb1132e HEAD -> main)。未使用git add -A,__pycache__/ 生成物未入库。
3. 技术决策与陷阱
- RBAC 登记分两个集合而非一个:
PATHS_CONTRACTS(20,进 init.py CONTRACTS / init.py__all__/ wwwroot/api)与PATHS_READONLY_DENY(9,不是 ServerEnv 契约, 只为封死 xls2ui 默认add_/update_/delete_<table>.dspy写入口)。审计按CONTRACTS ∪ READONLY_DENY比对,既不漏登记也不产生幽灵登记。 - 只读表为何仍要建 create/update/delete 端点:crud-definition-spec 要求 editable 三 URL
齐备,缺项时 xls2ui 回退生成默认写入口 →
rules_hash(29.6 确定性指纹)可被手工改写。 故 9 个端点显式返回{"widgettype":"Error","options":{"label":"...只读,禁止手工增删改"}}, 把「拒绝」变成可机械验证的事实(audit 第 ⑪ 项检查 Error widget)。 - 不登记不存在的路径:QC #1 提到「若引入 pbl_script_rule 只读列表 CRUD 生成目录则补 6 条」。
实测
wwwroot/下仅有api/一个子目录(无 CRUD 生成目录),pbl_script_rule_list是手写 Web 契约而非 xls2ui CRUD → 补登/pbl_compiler/pbl_script_rule等 6 条会形成幽灵登记、 污染 permission 表。此判断已固化进 audit 第 ⑫ 项检查。 - 禁通配符:29 条全部显式,audit 第 ④ 项用正则扫
*/%通配命中即 FAIL。 - 审计工具也要被审计:
resolved只认 AST 形态这一缺陷,会让「已正确整改」被判成 「RBAC 零登记」,白白烧掉退回预算。凡登记面比对,脚本必须同时兼容字面量求值成功/失败两种形态。
4. 验证(实跑输出摘录)
$ python3 scripts/audit_rbac_parity.py
PASS init.py CONTRACTS = 20 个契约
PASS 20 个契约在 api.py/rules_export_api.py 均有同名实现
PASS __init__.py __all__ 覆盖全部 20 个契约
PASS load_path.py 无通配符(29 条全显式)
PASS load_path.py 登记 29 条无重复(契约 20 + 只读拒绝 9)
PASS PATHS_CONTRACTS 与 CONTRACTS 一一对应(20 条)
PASS PATHS 登记 29 条,与期望端点集合(契约 20 + 只读拒绝 9)一一对应
PASS wwwroot/api/*.dspy = 29 个,与 CONTRACTS∪READONLY_DENY 一一对应
PASS grep 口径自证:PATHS 中 /api/ 条目=29,wwwroot/api/*.dspy=29
PASS 29 个 .dspy 无非法 import(仅允许 sqlor.filter)
PASS 29 个 .dspy 均有显式 return
PASS .dspy 无 ServerEnv() 取请求态
PASS 9 个只读拒绝端点均显式返回 Error widget(CRUD 写入口已封死)
PASS wwwroot/ 无 CRUD 生成子目录(只读列表走手写契约 api/pbl_script_rule_list.dspy)
PASS json/*.json 共 3 个:根键白名单(['_comment','alias','params','tblname','title']) / alias
/ editable 三 URL 齐备且指向真实 .dspy / 字段与 models 全对齐
RESULT: PASS (contracts=20, readonly_deny=9, dspy=29, rbac_api_paths=29, json=3) rc=0
$ python3 scripts/test_m3b_mapping.py
PASS: 113 FAIL: 0
$ grep -c "('/pbl_compiler/api/" scripts/load_path.py → 29
$ ls wwwroot/api/*.dspy | wc -l → 29
$ grep -n 'pbl_compiler_export_rules|pbl_compiler_rules_preview|pbl_compiler_rules_diff|
pbl_game_definition_rules_get|pbl_script_rule_list' scripts/load_path.py
→ 68,69,70,71,72 五行命中(5 个 M3b 契约全部显式登记)
$ git log --oneline -1 → cb1132e fix(pbl_compiler): M3b RBAC 29条显式登记+...
$ git push origin HEAD → d203811..cb1132e HEAD -> main
5. 环境受限项(如实说明,不谎报已验证)
~/repos/sage不存在:QC 改法要求cd ~/repos/sage && ./py3/bin/python ~/repos/pbl_modules/pbl_compiler/scripts/load_path.py并「同步中央 sage/load_path.py 兜底」。本工作空间实测ls -d ~/repos/sage→ 无该目录, 中央sage仓库与py3虚拟环境均不在位;apps/pbls/下也没有中央 load_path.py (全库grep -rln "pbl_compiler/api/" apps/零命中),各 pbl_* 模块一律以modules/{模块}/scripts/load_path.py为唯一登记面。故本轮只完成模块侧登记与自证, 中央兜底无法执行,需部署角色在有 sage 的环境跑register()。- 未连库、未起服务:
register()依赖 rbac CLI(set_role_perm.py)与 MariaDB, 本工作空间无 DB 实例(PBLS_DB_USER空、mysql 未授权)。脚本设计为 CLI 不在位时 打印 PENDING 清单并以 rc=1 暴露(不静默跳过),部署阶段据此补登。 - 未重跑 xls2ui/build.sh:
wwwroot/无 CRUD 生成子目录(三表按只读列表呈现, 走手写契约),本轮无 .ui 产物需再生成;若后续引入 CRUD 目录,audit 第 ⑫ 项会 FAIL 提醒补登。 - 「登录后调用不再 403」未做端到端实测:受 1/2 限制,只能以「登记面与端点集合一一对应」 作为可达性的机械证明,真实 HTTP 200 验证需部署环境。
6. 分支状态
- 仓库:
modules/pbl_compiler(origingit@git.opencomputing.cn:yumoqing/pbl_compiler.git) - 分支:
main,HEAD =cb1132e(agent.develop 自行提交并推送,非引擎代为收口) - 工作区:暂存区已清空;未跟踪仅剩
docs/work-log-2026-09-19.md(本文件,随交付入库) 与__pycache__(.gitignore 已排除) - 前序 6 个
deliver: 交付收口(引擎代为提交)提交(626b2c0/eb18a7d/4051e9d/c276af5/2c14bf5/d203811) 为历史事实,本轮不改写历史,仅在其上追加 agent 自有提交。