pbl_blueprint — 蓝图聚合根(T04,★高风险件)
11 表 + 7 类子对象泛化契约 + 版本/change_delta + fork + 模板实例化 + 编辑锁。
11 表
pbl_blueprint · pbl_blueprint_version · pbl_change_delta · pbl_subobject ·
pbl_subobject_field · pbl_subobject_rel · pbl_blueprint_lock ·
pbl_blueprint_fork · pbl_blueprint_ref · pbl_blueprint_status_log ·
pbl_blueprint_template
7 类子对象(泛化单表,非 7 张分表)
| obj_type | 语义 | payload 必填字段 |
|---|---|---|
learning_goal |
学习目标 | statement |
task |
任务/关卡 | objective |
role |
角色 | — |
artifact |
产出物 | kind(枚举 pbl_evidence_kind) |
rubric |
评价量规 | criteria |
resource |
资源 | uri |
rule |
规则 | condition, action |
泛化机制:pbl_subobject 单表 + obj_type 判别 + payload(longtext JSON) 承载差异字段;
pbl_subobject_field 存字段元数据(tenant_id='' 为平台内置),驱动 payload 校验与前端表单;
DB 无元数据时回落 subobject.BUILTIN_SCHEMA(离线兜底)。
统一契约(7 类共用,禁止每类单开 API):
list_subobjects(tenant_id, blueprint_id, obj_type=None, parent_id=None)
get_subobject(tenant_id, subobject_id)
upsert_subobject(tenant_id, blueprint_id, obj_type, name, payload=..., subobject_id=None)
delete_subobject(tenant_id, subobject_id, cascade=True)
reorder_subobject(tenant_id, blueprint_id, obj_type, ordered_ids)
get_tree(tenant_id, blueprint_id) # 供 T05 校验 / T06 编译消费
validate_payload(tenant_id, obj_type, payload, strict=True)
add_rel / list_rels / delete_rel # 跨类型连线(aligns_to/produces/assesses...)
版本与 change_delta
commit_version() → 确定性序列化(sort_keys=True + 紧凑分隔符,不含时间戳)→ sha256 →
写 pbl_blueprint_version 快照 → 与上一版比对生成 pbl_change_delta(added/modified/removed)。
确定性序列化是 T06 pbl_compiler 幂等编译的前提。
rollback_version() 不改历史:软删现有子对象 → 按快照重建 → 提交为新版本。
fork
fork_blueprint(mode='deep') 深拷贝聚合根 + 全部子对象(按 parent 拓扑序重建 idmap)+ 关系 + 外部引用,
写 pbl_blueprint_fork 溯源;get_fork_lineage() 双向溯源。
C4 写保护
add_ref() 只把 world/scene/entity/kdb/script 的 ID + 快照 存进 pbl_blueprint_ref,
模块内不存在任何对写保护域基表的 C/U/D 调用。快照保证外部变更不影响蓝图。
状态机
draft ⇄ in_review → approved → published → archived
└──────────────────────────────────────────┘(archived 可回 draft)
非法流转 → PBL-CONFLICT-0001。质量级 5 级严格递进,禁止跳级上升(PBL-VALID-0002)。
并发
acquire_lock/release_lock + 子对象 version_no 乐观锁;
upsert_subobject 更新时带 extra_where=[('version_no','=',旧值)],不匹配即冲突。