2026-09-17 23:45:03 +08:00

144 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/<name>.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 # 打印路径与契约清单
```