refactor(cdsl_engine): sink atomic runtime capability flags into schema contracts
Phase 4 of the decoupling refactor (behavior-preserving):
- profile_schema.json: every operation contract now carries
runtime_capability {body_mutating, requires_active_body,
replayable, requires_selector, open_profile_ok} (single source of truth)
- operation_contracts.py: validates and forwards the flags
- capabilities.py: the five data-classification frozensets are now
derived from the schema at import time; dispatch-logic sets
(_HOLE_ATOMICS, _PATTERN_ATOMICS, extent constants) stay in code
- test_profile_schema.py: completeness + structural invariants test
Equivalence proven by flag counts (27/13/25/6/2) matching the previous
hand-written sets and by the unchanged test-baseline failure set.
This commit is contained in:
@@ -19,31 +19,8 @@ from .runtime_types import (
|
||||
from .operation_contracts import materialized_feature_contracts
|
||||
|
||||
|
||||
_SELECTOR_REQUIRED = frozenset({"extrude_add_blind_with_hole", "extrude_from_face", "loft_add_with_cap_face", "fillet", "chamfer", "shell"})
|
||||
_SKETCH_ATOM_PREFIXES = ("extrude_", "revolve_", "sweep_")
|
||||
# 开放轮廓(closed=false / role=open)只有"刀具截面补槽口边闭合后作切除"的
|
||||
# 物理意义:仅 extrude 直切类原子支持;add/回转对开放轮廓会造出无意义的封块。
|
||||
_OPEN_PROFILE_ATOMICS = frozenset({"extrude_cut_blind", "extrude_cut_through"})
|
||||
_PRIMARY_ATOMICS = frozenset({
|
||||
"extrude_add_blind", "extrude_add_blind_with_hole", "extrude_add_two_sided", "extrude_cut_blind", "extrude_cut_two_sided", "extrude_from_face", "extrude_surface",
|
||||
"extrude_cut_through",
|
||||
"revolve_add", "revolve_cut", "revolve_surface", "hole_blind", "hole_countersink",
|
||||
"hole_counterbore", "sphere_add", "box_add", "cylinder_add",
|
||||
})
|
||||
_HOLE_ATOMICS = frozenset({"hole_blind", "hole_countersink", "hole_counterbore", "hole_wizard"})
|
||||
_ACTIVE_BODY_REQUIRED = frozenset({
|
||||
"extrude_cut_blind", "extrude_cut_two_sided", "extrude_cut_through",
|
||||
"loft_add_with_cap_face", "revolve_cut", *_HOLE_ATOMICS, "fillet", "chamfer", "shell",
|
||||
# thread_cut 是 cut 型特征:必须在已有主体(宿主)上做布尔差,不能凭空
|
||||
# 造实体;无宿主时按 active_body 前置阻止而非让 executor 在 None 上崩溃。
|
||||
"thread_cut",
|
||||
})
|
||||
_BODY_MUTATING_ATOMICS = frozenset({
|
||||
"extrude_add_blind", "extrude_add_blind_with_hole", "extrude_add_two_sided", "extrude_cut_blind", "extrude_cut_two_sided", "extrude_from_face",
|
||||
"extrude_cut_through", "loft_add", "loft_add_with_cap_face", "sweep_add",
|
||||
"revolve_add", "revolve_cut", "sphere_add", "box_add", "cylinder_add",
|
||||
"thread_add", "thread_cut", "bend_add", "gear_add", "rack_add", *_HOLE_ATOMICS, "fillet", "chamfer", "shell",
|
||||
})
|
||||
# ``ExecutionSession.body_members`` only contains independently selectable
|
||||
# body outputs. A normal additive/cut/dress-up feature replaces the active
|
||||
# aggregate, while ``result_mode: new_body`` and ``keep_tools`` are the two
|
||||
@@ -51,14 +28,6 @@ _BODY_MUTATING_ATOMICS = frozenset({
|
||||
# members can additionally expose a proven COPY instance; replayed/fused
|
||||
# patterns remain ineligible because no exact instance ownership exists.
|
||||
_PATTERN_ATOMICS = frozenset({"pattern_linear", "pattern_mirror", "pattern_circular"})
|
||||
# A pattern may replay a previous pattern as well as a direct body mutation.
|
||||
# Context-only features have no geometry definition to instance. thread_add,
|
||||
# thread_cut, bend_add, gear_add and rack_add are excluded: pattern
|
||||
# translation does not yet move their parametric axis/frame, so a replayed
|
||||
# instance would silently re-run at the original location.
|
||||
_REPLAYABLE_ATOMICS = (
|
||||
_BODY_MUTATING_ATOMICS - frozenset({"thread_add", "thread_cut", "bend_add", "gear_add", "rack_add"})
|
||||
) | frozenset({"pattern_linear", "pattern_mirror", "pattern_circular"})
|
||||
_SUPPORTED_EXTENTS = frozenset({
|
||||
"blind", "mid_plane", "through_all", "through_all_both", "through_all_and_blind",
|
||||
"up_to_surface", "up_to_vertex", "offset_from_surface", "through_next", "up_to_body",
|
||||
@@ -71,6 +40,39 @@ _EXTENT_TARGET_KINDS = {
|
||||
}
|
||||
|
||||
|
||||
def _runtime_capabilities() -> dict[str, dict[str, bool]]:
|
||||
"""Return the per-atomic runtime capability flags from the schema registry.
|
||||
|
||||
``profile_schema.json.operation_contracts[*].runtime_capability`` is the
|
||||
single source of truth for these classifications. Adding an atomic
|
||||
operation updates one JSON contract instead of editing code-level sets.
|
||||
"""
|
||||
path = Path(__file__).with_name("profile_schema.json")
|
||||
contracts = materialized_feature_contracts(json.loads(path.read_text(encoding="utf-8")))
|
||||
return {atomic_id: contract["runtime_capability"] for atomic_id, contract in contracts.items()}
|
||||
|
||||
|
||||
_RUNTIME_CAPABILITIES = _runtime_capabilities()
|
||||
_SELECTOR_REQUIRED = frozenset(a for a, c in _RUNTIME_CAPABILITIES.items() if c["requires_selector"])
|
||||
# 开放轮廓(closed=false / role=open)只有"刀具截面补槽口边闭合后作切除"的
|
||||
# 物理意义:仅 extrude 直切类原子支持;add/回转对开放轮廓会造出无意义的封块。
|
||||
_OPEN_PROFILE_ATOMICS = frozenset(a for a, c in _RUNTIME_CAPABILITIES.items() if c["open_profile_ok"])
|
||||
_PRIMARY_ATOMICS = frozenset({
|
||||
"extrude_add_blind", "extrude_add_blind_with_hole", "extrude_add_two_sided", "extrude_cut_blind", "extrude_cut_two_sided", "extrude_from_face", "extrude_surface",
|
||||
"extrude_cut_through",
|
||||
"revolve_add", "revolve_cut", "revolve_surface", "hole_blind", "hole_countersink",
|
||||
"hole_counterbore", "sphere_add", "box_add", "cylinder_add",
|
||||
})
|
||||
_ACTIVE_BODY_REQUIRED = frozenset(a for a, c in _RUNTIME_CAPABILITIES.items() if c["requires_active_body"])
|
||||
_BODY_MUTATING_ATOMICS = frozenset(a for a, c in _RUNTIME_CAPABILITIES.items() if c["body_mutating"])
|
||||
# A pattern may replay a previous pattern as well as a direct body mutation.
|
||||
# Context-only features have no geometry definition to instance. thread_add,
|
||||
# thread_cut, bend_add, gear_add and rack_add are excluded: pattern
|
||||
# translation does not yet move their parametric axis/frame, so a replayed
|
||||
# instance would silently re-run at the original location.
|
||||
_REPLAYABLE_ATOMICS = frozenset(a for a, c in _RUNTIME_CAPABILITIES.items() if c["replayable"])
|
||||
|
||||
|
||||
def _mappings(value: Any):
|
||||
"""Yield nested feature mappings for capability-only contract checks."""
|
||||
if isinstance(value, dict):
|
||||
|
||||
Reference in New Issue
Block a user