994d06aaea
- 新增 selector_candidate_demo,移除 provenance intent 后枚举候选 selector - 对候选分支执行有界重建与严格 STEP 比较 - 仅在候选遍历完整且唯一 strict 通过时生成 selector 映射记录 - 增加 selector 候选搜索、预算限制和记录生成的测试 - 保持生产 selector resolver 不受 Demo 逻辑影响 - 更新 CADFS 能力台账,记录 IMPRINT 派生 profile 的 lineage selector 缺口
174 lines
6.6 KiB
Python
174 lines
6.6 KiB
Python
"""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"))
|
|
)
|