feat(selector): 增加离线候选遍历与严格回放验证 Demo

- 新增 selector_candidate_demo,移除 provenance intent 后枚举候选 selector
- 对候选分支执行有界重建与严格 STEP 比较
- 仅在候选遍历完整且唯一 strict 通过时生成 selector 映射记录
- 增加 selector 候选搜索、预算限制和记录生成的测试
- 保持生产 selector resolver 不受 Demo 逻辑影响
- 更新 CADFS 能力台账,记录 IMPRINT 派生 profile 的 lineage selector 缺口
This commit is contained in:
2026-09-10 15:12:57 +08:00
parent d8fc2a9207
commit 994d06aaea
36 changed files with 9268 additions and 753 deletions
+22 -1
View File
@@ -31,6 +31,23 @@ def _execute_hole(node: FeaturePlanNode, session: "ExecutionSession", *, wizard:
# 1. 校验:孔是切除操作,必须先有主体。
if session.body is None:
raise ValueError("hole feature has no body")
scope_feature_id = node.params.get("scope_feature_id")
if scope_feature_id is not None:
if not isinstance(scope_feature_id, str) or not scope_feature_id:
raise ValueError("hole scope_feature_id is invalid")
if len(session.body_members) != 1:
raise ValueError("hole scope body is no longer the sole active member")
scoped_body = session.body_members.get(scope_feature_id)
if scoped_body is None:
raise ValueError("hole scope body is no longer an independently selectable member")
scoped_solids = session.adapter.body_solids(scoped_body)
active_solids = session.adapter.body_solids(session.body)
if (
len(scoped_solids) != 1
or len(active_solids) != 1
or not scoped_solids[0].is_same(active_solids[0])
):
raise ValueError("hole scope body does not match the active body")
# 2. 确定宿主面 host_face:
host_selector = node.params.get("host_face")
if isinstance(host_selector, dict) and isinstance(host_selector.get("frame"), dict):
@@ -74,5 +91,9 @@ def _execute_hole(node: FeaturePlanNode, session: "ExecutionSession", *, wizard:
message="Thread decoration is not modeled; the hole falls back to a plain cylindrical bore",
feature_id=node.feature_id,
))
session.register_body(node.feature_id, session.adapter.cut(session.body, tool), replay_node=node)
result_body = session.adapter.cut(session.body, tool)
members = {scope_feature_id: result_body} if scope_feature_id is not None else None
session.register_body(
node.feature_id, result_body, replay_node=node, body_members=members,
)
return session.result(node, diagnostics=diagnostics)