deliver: 交付收口(引擎代为提交)

This commit is contained in:
agent.develop 2026-09-20 19:55:41 +08:00
parent f9c91ee724
commit fc359f8dc5
2 changed files with 79 additions and 41 deletions

View File

@ -1,23 +1,28 @@
{
"key": "schema",
"schema": {
"table": "pbl_entity_state",
"authority_module": "pbl_runtime_ext",
"authority_path": "modules/pbl_runtime_ext/models/pbl_entity_state.json",
"owner": "pbls",
"milestone": "M11b-2b",
"decision_ref": "PM 裁决(任务 u0EO4x3ajntR41acaHj5H 问答):选 B —— 以 pbl_runtime_ext 为唯一真源",
"decision_basis": [
"设计文档 docs/01-design/modules/entity.md 明确 pbl_entity_state 为 pbl_runtime_ext 侧、pbls 所有",
"world_sync 仅作为单事务写入的消费方,不拥有该表结构定义权",
"本任务不得反向修改 M11b-1 已批准产物"
],
"structure_note": "本文件不再自带 summary/fields/indexes/codes 结构体;列集、主键、索引一律以 authority_path 指向的 pbl_runtime_ext 定义为准。world_sync 侧消费方代码pbl_runtime_sql.py / pbl_runtime_tx.py::write_event_with_state / pbl_runtime_schema.py以该权威结构为准不再依赖旧的 8 列本地结构。",
"consumers": [
"modules/world_sync/world_sync/pbl_runtime_sql.py",
"modules/world_sync/world_sync/pbl_runtime_tx.py::write_event_with_state",
"modules/world_sync/world_sync/pbl_runtime_schema.py"
],
"mirror_note": "apps/scense/pkgs/world_sync/models/pbl_entity_state.json 是本文件的打包镜像,只由 modules/world_sync/scripts/sync_models_mirror.py 生成,禁止手工双写;一致性由 modules/world_sync/scripts/m11b2b_selftest.py 的 sha256 断言守护。"
"summary": [
{
"name": "pbl_entity_state",
"title": "实体状态(服务端权威)",
"primary": ["id"],
"catelog": "entity",
"comment": "【本表定位 · world_sync 侧内联副本】实体状态表服务端权威state_version 单调递增,客户端禁写;由 world_sync 单事务写入路径 write_event_with_state 与事件行同事务更新,乐观锁冲突映射为 ConcurrentStateConflict。【结构权威源 · PM 裁决】PM 裁决(任务 u0EO4x3ajntR41acaHj5H 问答):选 B —— 以 pbl_runtime_ext 为唯一真源;结构权威定义位于 modules/pbl_runtime_ext/models/pbl_entity_state.jsonM11b-1 已批准产物,本任务禁止反向修改),建表 DDL 归该模块所有本文件不复制其物理实现细节。world_sync 仅作为单事务写入的消费方不拥有该表结构定义权。【为什么是内联而不是引用】database-table-definition-spec 只承认 summary/fields/indexes/codes 四段式scripts/validate_models_json.pyM11b-2a 子任务 A 修复版)对 key=schema 引用式写法直接判 FAILQC #5故本文件按真源逐字段内联权威列集真源实为 10 列tenant_id/id/session_id/entity_id/state_json/state_version/checksum/updated_by/created_at/updated_at任务书所述「8 列」系早期口径,以真源实测为准),作为 world_sync 侧的消费方契约视图;一致性由 scripts/m11b2b_column_diff.py 与 scripts/m11b2b_selftest.py 机械核对真源变更时必须同步本副本。【抽象类型归一说明】真源使用物理类型写法id=int(20) unsigned auto_increment、session_id/state_version=bigint、state_json=json本副本按 spec 归一为抽象类型long/text不保留 unsigned/length 物理修饰bigint→long、json→text存 JSON 文本,由应用层 json.dumps/loads。【id 类型偏离处理 · 本子任务的选择与理由】真源 id 为自增 BIGINT 主键(真源侧以 auto_increment/unsigned 私有键表达该偏离);子任务 A 的最终登记表 COMPLIANCE_DEVIATIONS 为空 {}A 按 QC #5 选 (a):不放行任何历史失效项),且本任务范围明确禁止修改校验器脚本,因此 world_sync 侧不走「登记放行 id 非 str(32)」路线,而是内联为 spec 合规写法 type=str / length=32、不带 auto_increment 键,主键值由应用层生成 32 位 uuid 去横线十六进制串world_sync/pbl_runtime_tx.py::new_event_uid 同族工具函数);与真源的 id 类型差异由 world_sync 侧消费方代码适配:写路径 INSERT 不显式提交 id见 pbl_runtime_tx.py 状态行 INSERT 列集 cols 不含 id生产 MySQL 交由真源 DDL 的 AUTO_INCREMENT 生成 BIGINT本地/测试库authority 层渲染的 sqlite DDL使用应用层生成的 str(32)。此差异为有意选择、非疏漏,评审请勿据此判为结构缺陷。【主键与唯一键说明】真源 summary[0] 未声明 primary其物理主键由 indexes 中 PRIMARY(id) 表达,故本副本 primary=[\"id\"],并把真源 uk_estenant_id+session_id+entity_id 唯一键,即消费方定位键 STATE_KEY_COLUMNS内联为 idxtype=unique实体状态定位键为 tenant_id + session_id + entity_id本表无 event_uid 概念。【消费方清单】modules/world_sync/world_sync/pbl_runtime_sql.pySTATE_TABLE/STATE_COLUMNS、modules/world_sync/world_sync/pbl_runtime_tx.py::write_event_with_state_fetch_state_version/_update_state/_insert_state、modules/world_sync/world_sync/pbl_runtime_authority.py列契约解析层上述代码引用的列名必须全部出现在本文件 fields[] 中。【打包镜像说明】apps/scense/pkgs/world_sync/models/pbl_entity_state.json 是本文件的打包镜像,只由 modules/world_sync/scripts/sync_models_mirror.py 生成,禁止手工双写;一致性由 modules/world_sync/scripts/m11b2b_selftest.py 的 sha256 断言守护。【私有键剥离说明】真源使用的 spec 未定义键 summary[0].module/engine/charset/tenant_scoped、fields[].comment/null/unsigned/auto_increment、indexes[].unique/fields在本副本中一律不保留或已归一为 spec 键nullable/idxtype/idxfields本文件根键仅 summary/fields/indexes/codescodes 段本表无枚举编码列故为空数组。"
}
],
"fields": [
{"name": "tenant_id", "title": "租户ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "id", "title": "主键ID(应用层生成)", "type": "str", "length": 32, "nullable": "no"},
{"name": "session_id", "title": "会话", "type": "long", "nullable": "no"},
{"name": "entity_id", "title": "实体标识", "type": "str", "length": 32, "nullable": "no"},
{"name": "state_json", "title": "状态JSON", "type": "text", "nullable": "yes"},
{"name": "state_version", "title": "单调版本", "type": "long", "nullable": "no"},
{"name": "checksum", "title": "状态摘要", "type": "str", "length": 32, "nullable": "no"},
{"name": "updated_by", "title": "写入者", "type": "str", "length": 32, "nullable": "no"},
{"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no"},
{"name": "updated_at", "title": "更新时间", "type": "datetime", "nullable": "no"}
],
"indexes": [
{"name": "PRIMARY", "idxtype": "unique", "idxfields": ["id"]},
{"name": "uk_es", "idxtype": "unique", "idxfields": ["tenant_id", "session_id", "entity_id"]}
],
"codes": []
}

View File

@ -1,24 +1,57 @@
{
"key": "schema",
"schema": {
"table": "pbl_runtime_event",
"authority_module": "pbl_runtime_ext",
"authority_path": "modules/pbl_runtime_ext/models/pbl_runtime_event.json",
"owner": "pbls",
"milestone": "M11b-2b",
"decision_ref": "PM 裁决(任务 u0EO4x3ajntR41acaHj5H 问答):选 B —— 以 pbl_runtime_ext 为唯一真源",
"decision_basis": [
"任务书原文:在 M11b-1 产出的 pbl_runtime_event 表基础上(依赖 key=schema引用语义自任务定义起即为 B",
"设计文档 docs/01-design/modules/entity.md 明确该表为 pbl_runtime_ext 侧、pbls 所有",
"pbl_runtime_ext 侧 pbl_runtime_event 的 DDL + 3 个迁移文件 + dev-notes 均已 approved为既定权威结构",
"本任务不得反向修改 M11b-1 已批准产物"
],
"structure_note": "本文件不再自带 summary/fields/indexes/codes 结构体列集、主键、索引、分区、append-only 约束一律以 authority_path 指向的 pbl_runtime_ext 定义为准25 列 / id long 自增 + (id, created_at) 复合主键 / 按月 RANGE COLUMNS 分区 / append-only 触发器。world_sync 侧消费方代码pbl_runtime_sql.py / pbl_runtime_tx.py::write_event_with_state / pbl_runtime_schema.py以该 25 列权威结构为准,不再依赖旧的 12 列本地结构。",
"consumers": [
"modules/world_sync/world_sync/pbl_runtime_sql.py",
"modules/world_sync/world_sync/pbl_runtime_tx.py::write_event_with_state",
"modules/world_sync/world_sync/pbl_runtime_schema.py"
],
"mirror_note": "apps/scense/pkgs/world_sync/models/pbl_runtime_event.json 是本文件的打包镜像,只由 modules/world_sync/scripts/sync_models_mirror.py 生成,禁止手工双写;一致性由 modules/world_sync/scripts/m11b2b_selftest.py 的 sha256 断言守护。"
"summary": [
{
"name": "pbl_runtime_event",
"title": "运行时事件流(append-only)",
"primary": ["id", "created_at"],
"catelog": "entity",
"comment": "【本表定位 · world_sync 侧内联副本】运行时事件流append-only禁 UPDATE/DELETE由权威模块 pbl_runtime_ext 的存储过程 pbl_assert_append_only + BEFORE UPDATE/BEFORE DELETE 触发器强制;按 created_at 做按月 RANGE COLUMNS(created_at) 分区,分区保留 14 个月)。物理主键为复合主键 (id, created_at) —— MySQL/MariaDB 要求分区表的所有唯一键(含主键)必须包含分区列,否则建表报错 1503。【结构权威源 · PM 裁决】PM 裁决(任务 u0EO4x3ajntR41acaHj5H 问答):选 B —— 以 pbl_runtime_ext 为唯一真源;结构权威定义位于 modules/pbl_runtime_ext/models/pbl_runtime_event.jsonM11b-1 已批准产物本任务禁止反向修改DDL 派生源为该模块 scripts/pbl_runtime_event_ddl.py 与 scripts/migrations/*.sql建表/分区/触发器归 pbl_runtime_ext 所有本文件不复制那套逻辑。【为什么是内联而不是引用】database-table-definition-spec 只承认 summary/fields/indexes/codes 四段式scripts/validate_models_json.pyM11b-2a 子任务 A 修复版)对 key=schema 引用式写法直接判 FAILQC #5故本文件按真源逐字段内联权威列集作为 world_sync 侧的消费方契约视图;两份定义的一致性由 scripts/m11b2b_column_diff.py 与 scripts/m11b2b_selftest.py 机械核对真源列集变更时必须同步本副本。【id 类型偏离处理 · 本子任务的选择与理由】真源 id 为 type=long + auto_incrementBIGINT AUTO_INCREMENT真源侧已在其 summary[0].comment 自行登记该偏离);子任务 A 的最终登记表 COMPLIANCE_DEVIATIONS 为空 {}A 按 QC #5 选 (a):不放行任何历史失效项),且本任务范围明确禁止修改校验器脚本,因此 world_sync 侧不再走「登记放行 id=long」路线而是内联为 spec 合规写法 type=str / length=32、不带 auto_increment 键,由应用层生成 32 位 uuid 去横线十六进制串作为主键值(见 world_sync/pbl_runtime_tx.py::new_event_uid正是 uuid4().hex 32 位)。与真源的 id 类型差异由 world_sync 侧消费方代码适配:写路径 INSERT 不显式提交 id 时交由真源 DDL 的 AUTO_INCREMENT 生成BIGINT本地/测试库scripts 渲染的 sqlite DDL则使用应用层生成的 str(32);对外幂等与跨系统追溯一律使用 event_uidstr 64uk_event_uid 唯一键),不依赖 id 的物理类型。此差异为有意选择、非疏漏评审请勿据此判为结构缺陷。【消费方清单】modules/world_sync/world_sync/pbl_runtime_sql.pyEVENT_TABLE/EVENT_COLUMNS、modules/world_sync/world_sync/pbl_runtime_tx.py::write_event_with_state单事务事件+状态写入、modules/world_sync/world_sync/pbl_runtime_authority.py列契约解析层上述代码引用的列名必须全部出现在本文件 fields[] 中。【打包镜像说明】apps/scense/pkgs/world_sync/models/pbl_runtime_event.json 是本文件的打包镜像,只由 modules/world_sync/scripts/sync_models_mirror.py 生成,禁止手工双写;一致性由 modules/world_sync/scripts/m11b2b_selftest.py 的 sha256 断言守护。【私有键剥离说明】真源使用的 spec 未定义顶层扩展键 module/engine/charset/collate/tenant_scoped/append_only/write_paths/guards/partition/ddl_source以及 fields[].ddl_type/comment/auto_increment、indexes[].comment、codes[].comment在本副本中一律不保留本文件根键仅 summary/fields/indexes/codessummary[0] 仅 name/title/primary/catelog/commentfields[] 仅 name/title/type/length/dec/nullable/defaultindexes[] 仅 name/idxtype/idxfieldscodes[] 仅 field/table/valuefield/textfield/cond这些物理实现细节以真源与其 DDL 派生源为准。"
}
],
"fields": [
{"name": "id", "title": "主键ID(应用层生成)", "type": "str", "length": 32, "nullable": "no"},
{"name": "tenant_id", "title": "租户ID", "type": "str", "length": 32, "nullable": "no", "default": ""},
{"name": "event_uid", "title": "事件UID", "type": "str", "length": 64, "nullable": "no"},
{"name": "event_code", "title": "事件编码", "type": "str", "length": 64, "nullable": "no", "default": ""},
{"name": "idem_key", "title": "幂等键", "type": "str", "length": 128, "nullable": "no", "default": ""},
{"name": "world_id", "title": "世界ID", "type": "long", "nullable": "no", "default": 0},
{"name": "scene_id", "title": "场景/会话ID", "type": "long", "nullable": "no", "default": 0},
{"name": "session_id", "title": "游戏会话ID", "type": "long", "nullable": "no", "default": 0},
{"name": "entity_id", "title": "实体ID", "type": "str", "length": 64, "nullable": "no", "default": ""},
{"name": "actor_id", "title": "触发者", "type": "str", "length": 64, "nullable": "no", "default": ""},
{"name": "event_type", "title": "事件类型", "type": "str", "length": 64, "nullable": "no"},
{"name": "payload", "title": "事件负载", "type": "text", "nullable": "yes"},
{"name": "payload_json", "title": "事件负载JSON", "type": "text", "nullable": "yes"},
{"name": "causation_id", "title": "因果链", "type": "str", "length": 64, "nullable": "no", "default": ""},
{"name": "seq", "title": "会话内单调序号", "type": "long", "nullable": "no", "default": 0},
{"name": "seq_no", "title": "会话内单调序号(M11a)", "type": "long", "nullable": "no", "default": 0},
{"name": "source", "title": "来源", "type": "str", "length": 32, "nullable": "no", "default": "runtime"},
{"name": "state", "title": "事件状态", "type": "str", "length": 16, "nullable": "no", "default": "applied"},
{"name": "state_version", "title": "服务端权威版本", "type": "long", "nullable": "no", "default": 0},
{"name": "tx_group", "title": "事务组", "type": "str", "length": 64, "nullable": "no", "default": ""},
{"name": "broadcast", "title": "是否参与广播", "type": "short", "nullable": "no", "default": 1},
{"name": "created_by", "title": "创建人", "type": "long", "nullable": "no", "default": 0},
{"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no", "default": "CURRENT_TIMESTAMP"},
{"name": "updated_at", "title": "记录时间戳", "type": "datetime", "nullable": "no", "default": "CURRENT_TIMESTAMP"},
{"name": "occurred_at", "title": "兼容列(旧分区键)", "type": "datetime", "nullable": "yes"}
],
"indexes": [
{"name": "uk_event_uid", "idxtype": "unique", "idxfields": ["tenant_id", "event_uid", "created_at"]},
{"name": "uk_tenant_idem", "idxtype": "unique", "idxfields": ["tenant_id", "idem_key", "created_at"]},
{"name": "ix_scene_created", "idxtype": "index", "idxfields": ["scene_id", "created_at"]},
{"name": "ix_tenant_session_seq", "idxtype": "index", "idxfields": ["tenant_id", "session_id", "seq"]},
{"name": "ix_tenant_session_seqno", "idxtype": "index", "idxfields": ["tenant_id", "session_id", "seq_no"]},
{"name": "ix_tenant_world_type", "idxtype": "index", "idxfields": ["tenant_id", "world_id", "event_type"]},
{"name": "ix_tx_group", "idxtype": "index", "idxfields": ["tx_group"]},
{"name": "ix_created_at", "idxtype": "index", "idxfields": ["created_at"]}
],
"codes": [
{
"field": "event_type",
"table": "appcodes_kv",
"valuefield": "k",
"textfield": "v",
"cond": "parentid='pbl_event_type'"
}
]
}