feat(v2): T06-b 方案装配与依赖预检(可定位的 E-19 文案)
T06 第二块。核对后确认 component_registry.freeze() 已实现大部分 AC-28: 按 release 指针解析依赖、原生方法文本装配时固化、循环依赖与输出冲突检查、 数据域一致性("演示与正式组件不能混用")、content_hash。因此本批**不重复实现冻结**, 只补真正的缺口。 新增 contracts:JudgmentBinding、ReviewPlan(含维度、关键核查项、专项绑定)。 新增 review_plan.check_dependencies() / assemble(): - **缺口**:未发布/已撤回的依赖原先抛裸 KeyError,被 translate() 映射成 404 "对象不存在",用户无法定位是哪一项。现改为逐个检查并**指明依赖名与原因** ("尚未发布或已撤回"/"版本状态为 X"/"发布指针指向的版本不存在") - 只用 release 指针判定可用性——草稿与已撤回天然没有指针,这正是 BR-27 "草稿或已撤回组件不得进入新运行"的机械表达 - 装配时接入 T06-a 的维度解析与呈现判定,并做不丢失断言 测试:test_review_plan.py 增至 25 项(新增 7 项装配)。其中版本换版后 content_hash 必须变化,用于证明版本确实被冻结进结果而不是每次重解析。 全量 340 项 OK(333 → 340);verify.py 10/10 PASS。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -569,3 +569,50 @@ class DimensionSpec(Contract):
|
||||
def scale_key(self) -> tuple[str, str]:
|
||||
"""跨维度可比性的唯一判据:刻度标识 + 版本。"""
|
||||
return (self.scale_id, self.scale_version)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- 评审方案(T06-b)
|
||||
class JudgmentBinding(Contract):
|
||||
"""把某个业务任务绑定到具体的专项判断配置修订(03 §9.3)。"""
|
||||
|
||||
task: str = Field(min_length=1, max_length=ID_MAX)
|
||||
profile_id: Identifier
|
||||
profile_revision: int = Field(ge=1)
|
||||
|
||||
|
||||
class ReviewPlan(Contract):
|
||||
"""评审方案:数据卡 / Skills / Rules / 经验与核查维度的版本化装配。
|
||||
|
||||
方案固定引用与维度定义,发起运行时验证依赖在当前项目/域获准并**冻结版本**
|
||||
(BR-27 / E-19 / AC-28)。草稿或已撤回组件不得进入新运行。
|
||||
"""
|
||||
|
||||
id: Identifier
|
||||
project_id: Identifier
|
||||
data_domain: DataDomain
|
||||
version: str = Field(min_length=1, max_length=70)
|
||||
revision: int = Field(ge=1)
|
||||
title: str = Field(min_length=1, max_length=200)
|
||||
status: GovernanceStatus
|
||||
data_card_refs: list[Ref] = Field(default_factory=list, max_length=64)
|
||||
skill_refs: list[Ref] = Field(default_factory=list, max_length=64)
|
||||
rule_refs: list[Ref] = Field(default_factory=list, max_length=64)
|
||||
experience_refs: list[Ref] = Field(default_factory=list, max_length=64)
|
||||
dimensions: list[DimensionSpec] = Field(default_factory=list, max_length=32)
|
||||
critical_check_ids: list[Identifier] = Field(default_factory=list, max_length=64)
|
||||
judgment_bindings: list[JudgmentBinding] = Field(default_factory=list, max_length=16)
|
||||
created_by: Identifier
|
||||
reviewer_id: Identifier | None = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _check_plan(self) -> ReviewPlan:
|
||||
# 维度同 ID 不得定义两次(真正的一致性由 review_plan.resolve_dimensions 把关)
|
||||
ids = [spec.id for spec in self.dimensions]
|
||||
if len(set(ids)) != len(ids):
|
||||
raise ValueError("同一方案内维度 ID 不得重复")
|
||||
tasks = [binding.task for binding in self.judgment_bindings]
|
||||
if len(set(tasks)) != len(tasks):
|
||||
raise ValueError("同一业务任务只能绑定一个专项判断配置")
|
||||
if self.status == GovernanceStatus.published and self.reviewer_id is None:
|
||||
raise ValueError("已发布方案必须有审核人")
|
||||
return self
|
||||
|
||||
Reference in New Issue
Block a user