6.5 KiB
| name | description |
|---|---|
| pbl_evidence | 产出物与证据幂等采集模块(M5a/M5b)——pbl_artifact/pbl_evidence 两表 CRUD、事件→证据幂等采集、证据列表/统计/水位查询。改本模块前先读完「契约接口」「陷阱」两节。 |
pbl_evidence 模块技能
定位
产出物(artifact)管理与学习证据(evidence)幂等采集。M5a 提供产出物 CRUD + 单事件/批量事件落证据; M5b(回放/增量续采)直接复用本模块的采集器与水位接口。
挂载
from pbl_evidence.init import load_pbl_evidence
load_pbl_evidence() # 宿主 apps/pbls 的 app/pbls.py init() 中按拓扑序调用
模块是 Python 包(无 app.py / 无端口 / 无独立部署单元),前端仅 wwwroot/ 下 .ui/.dspy 静态资源。
数据表(2 张)
pbl_artifact:学生产出物(版本内联version_no,唯一索引uk_art_uid(tenant_id, artifact_uid))pbl_evidence:学习证据(唯一索引uk_ev_dedup(tenant_id, source_event_id, evidence_type)防重)
表定义:models/{table}.json(四段式 summary/fields/indexes/codes);CRUD:json/evidence_*.json。
编码种子:init/data.json(Format B,3 组 appcodes,见下「编码字典」)。
契约接口(10 个,与 pbl_evidence/init.py 契约段 env 注册一一对应)
| # | 契约函数 | .dspy 路径(/pbl_evidence/api/...) |
说明 |
|---|---|---|---|
| 1 | pbl_artifact_create |
pbl_artifact_create.dspy |
新建产出物,自动补 tenant_id/artifact_uid/version_no=1/status=draft/created_at |
| 2 | pbl_artifact_read |
pbl_artifact_read.dspy |
按 id 读,强制租户过滤 |
| 3 | pbl_artifact_update |
pbl_artifact_update.dspy |
白名单列更新,禁改 tenant_id/id |
| 4 | pbl_artifact_delete |
pbl_artifact_delete.dspy |
带归属校验的删除 |
| 5 | pbl_artifact_list |
pbl_artifact_list.dspy |
分页 + 会话/蓝图/作者/类型/状态过滤 |
| 6 | pbl_evidence_collect |
pbl_evidence_collect.dspy |
单事件 → 一条证据;重复调用返回 deduped=True |
| 7 | pbl_evidence_collect_from_events |
pbl_evidence_collect_from_events.dspy |
M5a 主能力:扫 pbl_runtime_event → 映射 → 幂等落库,返回 scanned/created/skipped/updated/ignored/failed + watermark |
| 8 | pbl_evidence_list |
pbl_evidence_list.dspy |
学习者/产出物/会话/蓝图/类型/时间窗过滤 + 分页 |
| 9 | pbl_evidence_stats |
pbl_evidence_stats.dspy |
证据类型分布统计,供 M6 评估与概览页 |
| 10 | pbl_evidence_watermark |
无独立 .dspy(见下) | 返回某会话/蓝图已采集到的时间水位,供 M5b/cron 增量续采 |
watermark 的调用方式(第 10 条契约刻意不生成 .dspy):
- 内部调用:宿主/cron/M5b 通过
ServerEnv().pbl_evidence_watermark(...)直调; - 备选(若需走 HTTP):
pbl_evidence_stats.dspy返回值中扩展watermark字段(stats 内嵌), 当前实现collector.evidence_stats只返回total/by_type,尚未内嵌 —— 需要时改 stats 的 返回聚合(res['watermark'] = await _watermark(tid))即可,不必新增 .dspy; - 若将来需要前端直接轮询,再新增
wwwroot/api/pbl_evidence_watermark.dspy,并同步登记scripts/load_path.py+ 中央apps/pbls/scripts/load_path.py(双层 RBAC),否则 403。
除上述 10 个对外契约外,
init.py还注册了 4 个内部能力(供 M5b 回放 / M6 评估复用,不算对外契约、 无 .dspy):pbl_collect_evidence_from_events、pbl_resolve_event_table、pbl_evidence_types、pbl_event_to_evidence_map。核对口径:api.py契约定义 10 ==__init__.py契约导出 10 ==init.py契约 env 注册 10 ==wwwroot/api/*.dspy9(watermark 无 .dspy)。
编码字典(init/data.json,Format B)
| parentid(≤22 字符) | 含义 | 子项 |
|---|---|---|
pbl_artifact_type |
产出物类型 | document/code/model/presentation/poster/video/dataset/other(8) |
pbl_artifact_status |
产出物状态 | draft/submitted/reviewing/returned/graded/archived(6) |
pbl_evidence_type |
证据类型 | 取自 evidence_map.EVIDENCE_TYPES 8 类:artifact/assessment/peer_review/reflection/milestone/collaboration/resource/observation |
models/*.json 的 codes[].cond 一律 parentid='...'(绝不用 id=),且三组 parentid 与
models/pbl_artifact.json、models/pbl_evidence.json 中的 cond 完全一致。
陷阱
- 库名一律
get_module_dbname('pbl_evidence')(.dspy 直接调用;.py 用ServerEnv().get_module_dbname(...)), 禁止硬编码 DBNAME;取不到库名直接抛PblError(fail-closed),不退化成查错库。 - sqlor 只有
C/U/D/R/I/sqlExe;查询统一走pbl_common.api的q_all/q_one(已适配 sqlor 上下文)。sor.I只接 1 个参数(表名由上下文决定),sor.I('t', data)会 TypeError。 - 所有读写强制带
tenant_id(pbl_common.api.tenant_id()),缺失即 fail-closed 报错。 dedup_key= md5(tenant_id|source_event_id|evidence_type),32 位定长,必须与uk_ev_dedup语义对齐; 改唯一索引必须同步改evidence_map.build_dedup_key。- 时间统一格式化为
YYYY-MM-DD HH:MM:SS字符串(normalize_dt),避免 datetime/str 混用导致 sqlor 占位符绑定失败。 - 未知事件类型降级为
observation(不丢事件);IGNORED_EVENTS白名单外置在evidence_map.py, 新增噪声事件改这里,别在 SQL 里写死过滤。 - 函数注册三处同步:①
api.py定义 → ②__init__.py导出 → ③init.pyenv.<name>=<name>; 新增对外路径再加第 ④ 处scripts/load_path.py(+ 中央宿主清单,双层 RBAC,禁通配符)。 漏 ② → import 期 ImportError;漏 ③ → .dspy NameError;漏 ④ → 403。 - 批量采集依赖 M11b 的
pbl_runtime_event;该表不存在时按设计抛CollectError → PBL_E_DB_UNAVAILABLE(本地环境未联调,勿当成代码缺陷)。 wwwroot/{alias}/(xls2ui 生成物)是只读构建产物,改逻辑改json/*.json+models/*.json后重跑 build。
依赖
- 直接:
sqlor(见pyproject.toml,仅此一项) - 基础包(宿主 build.sh 安装,不写进 pyproject):
apppublic、ahserver、appbase、rbac - 兄弟模块:
pbl_common(租户上下文/错误码/时间序列化/查询封装)