# pbl_validation 模块技能(M2 校验引擎) ## 定位 PBL 蓝图校验引擎:**14 维校验 + 5 级质量状态(quality_state)**,阈值全部配置化常量, 输出固定契约的校验报告,供 pbl_compiler(发布门禁)、pbl_assessment(量规联动)、 前端蓝图编辑器(问题定位)消费。 ## 挂载 ```python # app/pbls.py init() from pbl_validation.init import load_pbl_validation load_pbl_validation() # 建表 + 注册 5 个契约 + 内置 14 维规则种子(幂等) ``` 库名唯一来源:`ServerEnv().get_module_dbname('pbl_validation')`,**禁止硬编码 DBNAME**。 ## 数据表(2 张) | 表 | 用途 | 关键字段 | |---|---|---| | `pbl_validation_rule` | 校验规则(14 维,`script_type=1` 规则 JSON 形态) | tenant_id / rule_id / dim / weight / severity / enabled / rule_json(含 thresholds) | | `pbl_validation_result` | 校验结果(14 维得分 + 5 级质量状态) | tenant_id / result_id / blueprint_id / quality_state / total_score / dim_scores / dim_detail / report_json / fingerprint | DDL:`sql/pbl_validation.sql`(幂等,含 14 条内置规则种子)。 ## 契约接口(5 个,`/pbl_validation/api/.dspy`) | 接口 | 说明 | 必填入参 | |---|---|---| | `pbl_validation_run` | 执行 14 维校验并落库,返回报告契约 | `blueprint`(dict 或 JSON 串);`tenant_id` 缺省取上下文 | | `pbl_validation_get` | 按 `result_id` 或 `blueprint_id`(最新一次)取报告 | 二者之一 | | `pbl_validation_list` | 分页列出结果,可按 `blueprint_id`/`quality_state`/`keyword` 过滤 | — | | `pbl_validation_rule_list` | 列出规则 + 14 维元信息 + 生效阈值/默认阈值 | — | | `pbl_validation_rule_save` | 新增/更新规则(阈值配置化落库,脏阈值直接拒绝) | `dim`(D01~D14) | `pbl_validation_run` 可选入参:`blueprint_id` / `version` / `dims`(只跑指定维度)/ `thresholds`(阈值覆盖)/ `persist`(0=dry-run 不落库)/ `operator`。 ## 14 维清单 | 维度 | code | 名称 | 权重 | 核心 | |---|---|---|---|---| | D01 | structure_completeness | 结构完整性(7 类子对象齐备) | 1.2 | ★ | | D02 | naming_quality | 命名规范 | 0.8 | | | D03 | objective_alignment | 学习目标对齐 | 1.2 | ★ | | D04 | driving_question | 驱动问题质量 | 1.0 | | | D05 | role_design | 角色设计 | 1.0 | | | D06 | scene_design | 场景设计 | 0.9 | | | D07 | entity_model | 实体模型 | 0.9 | | | D08 | task_chain | 任务链完整性 + **多路径覆盖率 mcRatio** | 1.3 | ★ | | D09 | rule_integrity | 规则引用完整性 | 1.1 | | | D10 | assessment_rubric | 评估量规(权重和=1) | 1.2 | ★ | | D11 | evidence_binding | 产出物/证据绑定 | 1.0 | | | D12 | difficulty_balance | 难度平衡 | 0.7 | | | D13 | duration_balance | 时长平衡 | 0.7 | | | D14 | safety_compliance | 安全合规扫描 | 1.0 | ★ | ★ = 核心维度,任一 fail 直接把质量状态压到 Q1。 ## 阈值配置化常量(`constants.DEFAULT_THRESHOLDS`) **Q-OPEN-8:`mcRatio = 0.7`**(多路径覆盖率阈值)。其余关键项: `qualityBasicScore=0.40` / `qualityGoodScore=0.70` / `qualityExcellentScore=0.90`、 `minSubObjectKinds=7`、`objectiveCoverageRatio=0.8`、`roleTaskCoverageRatio=0.8`、 `taskEvidenceCoverageRatio=0.8`、`ruleRefIntegrityRatio=1.0`、`rubricWeightSum=1.0` (容差 0.01)、`maxSafetyHits=0`。 覆盖优先级(低→高):默认常量 → 规则记录 `rule_json.thresholds` → 接口入参 `thresholds` (引擎内 `rule_json` 由接口层用「规则库阈值 + 入参阈值」合成,故入参最终生效)。 非法覆盖(未知 key / 类型不符 / 负数 / 比例 >1)被忽略并记入 `threshold_ignored`; `rule_save` 侧则**直接拒绝**(fail-closed,不落脏配置)。 ## 5 级质量状态规则(`engine.decide_quality_state`,自上而下短路) | 规则 | 条件 | 结果 | |---|---|---| | R1 | 无维度结果 / 全部 skip | `Q0_DRAFT` | | R2 | 存在 blocker 级问题 | `Q1_INCOMPLETE` | | R3 | 核心维度(D01/D03/D08/D10/D14)有 fail | `Q1_INCOMPLETE` | | R4 | 加权总分 < 0.40 | `Q1_INCOMPLETE` | | R5 | 总分 ≥ 0.90 且无 warn/fail | `Q4_EXCELLENT` | | R6 | 总分 ≥ 0.70 且核心维度全 pass | `Q3_GOOD` | | R7 | 总分 ≥ 0.40 | `Q2_BASIC` | | R8 | 兜底 | `Q1_INCOMPLETE` | 总分 = Σ(维度得分×权重) / Σ权重(skip 维度不计入分母)。维度得分:pass=1.0、warn=0.6、 fail/skip=0,D08/D10 等按覆盖率/权重和连续取值。 **发布门禁**:`is_publishable()` 要求 `quality_state ∈ {Q3_GOOD, Q4_EXCELLENT}`。 ## 校验报告契约 `pbl.validation.report/1.0` ```jsonc { "contract": "pbl.validation.report/1.0", "engine_version": "1.0.0", "report_id": "vr_xxxx", "tenant_id": "t1", "blueprint_id": "BP1", "version": "v1", "ruleset": "builtin-14d", "created_at": 1730000000000, "elapsed_ms": 3, "fingerprint": "sha256前32位(载荷+阈值,幂等复用)", "quality_state": "Q4_EXCELLENT", "quality_label": "优秀", "quality_order": 4, "quality_reasons": ["R5: 加权总分 0.9700 >= Q4 线 0.90 且无 warn/fail"], "total_score": 0.97, "weighted_sum": 13.58, "weight_sum": 14.0, "dim_count": 14, "dim_total": 14, "state_summary": {"pass": 14, "warn": 0, "fail": 0, "skip": 0}, "severity_summary": {"blocker": 0, "major": 0, "minor": 0, "info": 0}, "issue_count": 0, "passed": true, "dimensions": [{"dim":"D08","name":"任务链完整性","state":"pass","score":1.0, "weight":1.3,"weighted_score":1.3, "metrics":{"mcRatio":1.0,"mcRatio_threshold":0.7,"path_count":2, "branch_exits_total":2,"branch_exits_covered":2, "dangling":[],"cyclic_paths":0}, "issues":[]}], "issues": [{"dim":"D08","code":"V-TASK-004","severity":"major", "message":"多路径覆盖率 mcRatio=0.50 低于阈值 0.70(Q-OPEN-8)", "path":"tasks.mcRatio","expected":0.7,"actual":0.5}], "thresholds": {"mcRatio": 0.7, "...": "..."}, "threshold_ignored": [], "engine_errors": [], "dimensions_meta": [{"dim":"D01","code":"structure_completeness","name":"结构完整性", "weight":1.2,"desc":"..."}] } ``` ### 问题码索引 `V-TENANT-001` 租户缺失 · `V-INPUT-001~004` 载荷非法 · `V-DB-001/002` 库名或 sqlor 不可用 · `V-STRUCT-001/002` 结构 · `V-NAME-001~004` 命名 · `V-OBJ-001~003` 目标 · `V-DQ-001~004` 驱动问题 · `V-ROLE-001~003` 角色 · `V-SCENE-001~003` 场景 · `V-ENT-001~003` 实体 · `V-TASK-001~005` 任务链(004=mcRatio,005=环) · `V-RULE-001/002` 规则引用 · `V-RUB-001~004` 量规(004=权重和≠1) · `V-EV-001~003` 产出物 · `V-DIFF-001~004` 难度 · `V-DUR-001~003` 时长 · `V-SEC-001~005` 安全(破坏性 SQL / 危险命令 / 硬编码凭据 / 动态执行 / 不适宜内容) · `V-ENGINE-001~003` 引擎(禁用 / 返回类型 / 维度异常兜底 fail)。 ## 陷阱 - 库名一律 `ServerEnv().get_module_dbname('pbl_validation')`,禁止硬编码 DBNAME。 - sqlor 只有 `C/U/D/R/I/sqlExe`;查询走 `pbl_common.api` 的 `q_all/q_one`(已适配), 本模块 `api.q_all/q_one` 做了「优先 pbl_common、回落 sqlor.sqlExe」双通道。 - 所有读写强制带 `tenant_id`(`pbl_common.api.tenant_id()`),缺失即 fail-closed 报错。 - 新增契约需同步四处:`api.py` 定义 + `API_REGISTRY` + `__init__.py` 导出 + `init.py` env 注册 + `scripts/load_path.py` 的 `API_PATHS`。 - 引擎是**纯函数**(无 DB/网络/随机),同载荷同阈值必得同报告;落库只在 api 层做。 - 单维度 checker 抛异常不会中断整体:引擎兜底记 `fail` + `V-ENGINE-003`(fail-closed)。 - 蓝图载荷支持 4 种形态:`{objects:[{kind:...}]}` / `{kinds:{task:[...]}}` / 顶层复数键(`tasks`/`roles`/...) / `{blueprint:{...}}` 包装。 ## 自测 ```bash cd modules/pbl_validation && python3 tests/test_validation_engine.py # 111 项断言全绿 python3 scripts/load_path.py # 打印路径与契约清单 ```