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:
@@ -0,0 +1,173 @@
|
||||
"""Verified FeatureScript query semantics available to the selector resolver.
|
||||
|
||||
This is intentionally a small, explicit allow-list. A numeric source version
|
||||
only identifies a FeatureScript release; it does not establish that this
|
||||
runtime has verified a query family's source semantics for that release.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SelectorQueryCapability:
|
||||
query_family: str
|
||||
featurescript_version: str
|
||||
standard_library: str
|
||||
standard_library_version: str
|
||||
source: str
|
||||
contract: str
|
||||
|
||||
|
||||
# These entries correspond to the direct builder contracts exercised by the
|
||||
# CADFS 1511 corpus. New versions and query families must be registered with
|
||||
# their source/API evidence before the runtime accepts them.
|
||||
_CAPABILITIES = {
|
||||
("CAP_FACE", "1511"): SelectorQueryCapability(
|
||||
"CAP_FACE",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history",
|
||||
"direct extrude cap operation role",
|
||||
),
|
||||
("CAP_EDGE", "1511"): SelectorQueryCapability(
|
||||
"CAP_EDGE",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history",
|
||||
"direct prism source edge to qualified start/end cap edge kernel lineage",
|
||||
),
|
||||
("OFFSET_FACE", "1511"): SelectorQueryCapability(
|
||||
"OFFSET_FACE",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history",
|
||||
"shell offset-face operation role with true dependency qualification",
|
||||
),
|
||||
# These entries authorize the deliberately narrow direct-prism lineage
|
||||
# path. The capability matrix keeps the broader query families explicitly
|
||||
# partial; all other generator and lifecycle combinations remain rejected.
|
||||
("SWEPT_FACE", "1511"): SelectorQueryCapability(
|
||||
"SWEPT_FACE",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history",
|
||||
"kernel-lineage resolver contract only",
|
||||
),
|
||||
("SWEPT_EDGE", "1511"): SelectorQueryCapability(
|
||||
"SWEPT_EDGE",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history",
|
||||
"kernel-lineage resolver contract only",
|
||||
),
|
||||
("SWEPT_BODY", "1511"): SelectorQueryCapability(
|
||||
"SWEPT_BODY",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history; one-item qUnion identity",
|
||||
"active direct-new-body member selected by its producing operation",
|
||||
),
|
||||
("INTERSECT", "1511"): SelectorQueryCapability(
|
||||
"INTERSECT",
|
||||
"1511",
|
||||
"onshape/std/geometry.fs",
|
||||
"1511.0",
|
||||
"CADFS FeatureScript 1511 exported query history; BRepAlgoAPI boolean Generated(face) and SectionEdges() exact handles",
|
||||
"two source-qualified boolean input faces to one final section edge kernel lineage",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def selector_query_capability(intent: dict[str, Any]) -> SelectorQueryCapability | None:
|
||||
"""Return an explicitly verified query capability for ``intent`` only."""
|
||||
source_query = intent.get("source_query")
|
||||
if not isinstance(source_query, dict):
|
||||
return None
|
||||
family = intent.get("query_family")
|
||||
version = source_query.get("featurescript_version")
|
||||
if not isinstance(family, str) or not isinstance(version, str):
|
||||
return None
|
||||
capability = _CAPABILITIES.get((family, version))
|
||||
if capability is None:
|
||||
return None
|
||||
if (
|
||||
source_query.get("standard_library") != capability.standard_library
|
||||
or source_query.get("standard_library_version") != capability.standard_library_version
|
||||
):
|
||||
return None
|
||||
return capability
|
||||
|
||||
|
||||
def known_selector_query_versions(query_family: str) -> tuple[str, ...]:
|
||||
"""Expose registered versions for deterministic unsupported diagnostics."""
|
||||
return tuple(sorted(version for family, version in _CAPABILITIES if family == query_family))
|
||||
|
||||
|
||||
def known_selector_query_standard_library_versions(query_family: str) -> tuple[tuple[str, str], ...]:
|
||||
"""Expose exact direct imports that back a registered query contract."""
|
||||
return tuple(sorted({
|
||||
(capability.standard_library, capability.standard_library_version)
|
||||
for (family, _version), capability in _CAPABILITIES.items()
|
||||
if family == query_family
|
||||
}))
|
||||
|
||||
|
||||
def is_direct_blind_extrude_cap_output_role(
|
||||
selector: dict[str, Any],
|
||||
producer: dict[str, Any] | None,
|
||||
sketches: dict[str, dict[str, Any]],
|
||||
) -> bool:
|
||||
"""Whether a selector names one cap from the direct prism contract.
|
||||
|
||||
This is the consumer-side mirror of the lowerer's CAP_FACE constructor.
|
||||
It deliberately describes a narrow builder contract, rather than treating
|
||||
an output-role string as general permission to select arbitrary topology.
|
||||
The runtime still has to prove the exact role in its active snapshot.
|
||||
"""
|
||||
if not isinstance(selector, dict) or not isinstance(producer, dict):
|
||||
return False
|
||||
intent = selector.get("selector_intent")
|
||||
if (
|
||||
selector.get("kind") != "face"
|
||||
or selector.get("output_role") not in {"extrude.start", "extrude.end"}
|
||||
or selector.get("source") != "runtime_snapshot"
|
||||
or selector.get("output_role_source") is not None
|
||||
or any(selector.get(key) is not None for key in ("stable_id", "snapshot_id", "geometry", "binding_feature_id"))
|
||||
or not isinstance(intent, dict)
|
||||
or intent.get("query_family") != "CAP_FACE"
|
||||
or intent.get("evidence") != "operation_role"
|
||||
or intent.get("output_role") != selector.get("output_role")
|
||||
):
|
||||
return False
|
||||
policy = intent.get("derivation_policy")
|
||||
if not isinstance(policy, dict) or policy.get("multiplicity") != "one" or set(policy.get("allowed") or ()) != {"boundary", "continuation"}:
|
||||
return False
|
||||
params = producer.get("params") or {}
|
||||
if (
|
||||
producer.get("atomic_id") != "extrude_add_blind"
|
||||
or params.get("result_mode") != "new_body"
|
||||
or (params.get("end_condition") or {}).get("type") != "blind"
|
||||
):
|
||||
return False
|
||||
if params.get("draft") is None:
|
||||
return True
|
||||
sketch = sketches.get(str(producer.get("sketch_id") or "")) or {}
|
||||
profile = sketch.get("profile") or {}
|
||||
if profile.get("type") == "circle":
|
||||
return True
|
||||
contours = profile.get("contours")
|
||||
return (
|
||||
profile.get("type") == "analytic_contours"
|
||||
and isinstance(contours, list)
|
||||
and len(contours) == 1
|
||||
and bool((contours[0] or {}).get("closed"))
|
||||
)
|
||||
Reference in New Issue
Block a user