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:
@@ -138,27 +138,45 @@ class SelectorBindingTests(unittest.TestCase):
|
||||
self.assertEqual(len(binding["resolved"]), 1)
|
||||
self.assertEqual(binding["resolved"][0]["output_roles"], ["extrude.end"])
|
||||
|
||||
def test_shell_offset_face_role_binds_only_its_true_dependency_source(self) -> None:
|
||||
def test_rebuild_candidate_uses_one_incremental_replay(self) -> None:
|
||||
root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test"
|
||||
feature = root / "featurescript_rp/0001/00016195.txt"
|
||||
if not feature.exists(): self.skipTest("CADFS sample is not installed")
|
||||
candidate = lower_model(parse_featurescript(feature.read_text(), "00016195"), {})
|
||||
|
||||
# The production path must bind and export from one live session. If
|
||||
# it called the old compatibility binder, this patched entry point
|
||||
# would fail while rebuilding selector-bearing prefixes.
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
with patch(
|
||||
"engine.cdsl_engine.runtime.rebuild_cdsl",
|
||||
side_effect=AssertionError("production rebuild invoked legacy prefix replay"),
|
||||
):
|
||||
outcome = rebuild_candidate(candidate.cdsl, Path(directory) / "00016195.step")
|
||||
|
||||
self.assertEqual(outcome["status"], "rebuilt")
|
||||
self.assertEqual(
|
||||
[item["feature_id"] for item in outcome["result"]["feature_results"]],
|
||||
[item["id"] for item in candidate.cdsl["features"]],
|
||||
)
|
||||
self.assertTrue(outcome["selector_binding"])
|
||||
|
||||
def test_shell_offset_face_preserves_true_dependency_but_rejects_unproven_cap_selector(self) -> None:
|
||||
root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test"
|
||||
feature = root / "featurescript_rp/0010/00107631.txt"
|
||||
if not feature.exists(): self.skipTest("CADFS sample is not installed")
|
||||
candidate = lower_model(parse_featurescript(feature.read_text(), "00107631"), {})
|
||||
self.assertEqual(candidate.status, "converted_complete")
|
||||
|
||||
# F2 retains F1's end-cap provenance, but F3 also selects the distinct
|
||||
# start-cap plane. Its direct owner has no geometry-qualified active
|
||||
# candidate, so binding must consider the unique active F2 face without
|
||||
# weakening the exact qualified OFFSET_FACE role.
|
||||
# F2 consumes its immediate direct CAP_FACE output role. F3 retains
|
||||
# its exact OFFSET_FACE true-dependency intent, but its separate
|
||||
# start-cap removal selector is deferred and must not rebind
|
||||
# geometrically.
|
||||
prefix = deepcopy(candidate.cdsl)
|
||||
prefix["features"] = prefix["features"][:3]
|
||||
bound, evidence = bind_candidate_selectors(prefix)
|
||||
|
||||
first, offset = bound["features"][-1]["selectors"]
|
||||
self.assertEqual(first["owner_feature_id"], "f_F2")
|
||||
self.assertEqual(first["stable_id"], "body:f_F2:face:1")
|
||||
self.assertEqual(first["snapshot_id"], "body:f_F2:face:1")
|
||||
self.assertEqual(first["source"], "runtime_snapshot")
|
||||
self.assertEqual(first["confidence"], 1.0)
|
||||
first, offset = prefix["features"][-1]["selectors"]
|
||||
self.assertEqual(first["selector_intent"]["query_family"], "CAP_FACE")
|
||||
self.assertEqual(first["selector_intent"]["derivation_policy"]["multiplicity"], "none")
|
||||
self.assertEqual({key: offset[key] for key in (
|
||||
"kind", "owner_feature_id", "output_role", "output_role_source", "source", "confidence",
|
||||
)}, {
|
||||
@@ -168,33 +186,25 @@ class SelectorBindingTests(unittest.TestCase):
|
||||
})
|
||||
self.assertEqual(offset["selector_intent"]["query_family"], "OFFSET_FACE")
|
||||
self.assertEqual(offset["selector_intent"]["disambiguation"]["type"], "true_dependency")
|
||||
binding = next(item for item in evidence if item["feature_id"] == "f_F3")
|
||||
self.assertEqual(binding["resolved"][0]["snapshot_id"], "body:f_F2:face:1")
|
||||
self.assertEqual(binding["resolved"][1]["record_id"], "body:f_F2:face:5")
|
||||
with self.assertRaisesRegex(ValueError, "f_F3: selector_query_unsupported after prefix rebuild"):
|
||||
bind_candidate_selectors(prefix)
|
||||
|
||||
# Binding must not hide the OCC feasibility boundary. The requested
|
||||
# second shell currently produces an invalid shape, so preserve the
|
||||
# F2 prefix instead of changing thickness or removal faces.
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
outcome = rebuild_candidate(candidate.cdsl, Path(directory) / "00107631.step")
|
||||
self.assertEqual(outcome["status"], "rebuild_failed")
|
||||
self.assertEqual(outcome["error"]["type"], "RuntimeExecutionError")
|
||||
self.assertEqual(outcome["error"]["message"], "OCC shell operation produced an invalid shape")
|
||||
self.assertEqual(outcome["error"]["message"], "f_F3: selector_query_unsupported during incremental replay")
|
||||
self.assertEqual(outcome["last_executable_prefix"]["failed_feature_id"], "f_F3")
|
||||
self.assertEqual(outcome["last_executable_prefix"]["last_feature_id"], "f_F2")
|
||||
|
||||
def test_intersection_vertex_binds_a_pattern_copy_with_exact_instance_owner_evidence(self) -> None:
|
||||
def test_intersection_vertex_preserves_outer_copy_provenance_without_geometry_binding(self) -> None:
|
||||
root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test"
|
||||
feature = root / "featurescript_rp/0042/00423838.txt"
|
||||
if not feature.exists(): self.skipTest("CADFS sample is not installed")
|
||||
candidate = lower_model(parse_featurescript(feature.read_text(), "00423838"), {})
|
||||
reference = next(item for item in candidate.cdsl["features"] if item["id"] == "f_F7")["params"]["end_condition"]["reference"]
|
||||
self.assertTrue(all(item["owner_match_required"] for item in reference["intersection_of"][:2]))
|
||||
|
||||
bound, evidence = bind_candidate_selectors(candidate.cdsl)
|
||||
reference = next(item for item in bound["features"] if item["id"] == "f_F7")["params"]["end_condition"]["reference"]
|
||||
self.assertEqual(reference["selector_intent"]["query_family"], "INTERSECT")
|
||||
copy_components = reference["intersection_of"][:2]
|
||||
self.assertTrue(all(item["owner_feature_id"] == "f_F4.c4.f_F1" for item in copy_components))
|
||||
self.assertTrue(all(item.get("snapshot_id") for item in copy_components))
|
||||
binding = next(item for item in evidence if item["feature_id"] == "f_F7")
|
||||
self.assertGreaterEqual(len(binding["resolved"]), 2)
|
||||
self.assertEqual([item["selector_intent"]["query_family"] for item in copy_components], ["COPY", "COPY"])
|
||||
with self.assertRaisesRegex(ValueError, "f_F7: selector_query_unsupported after prefix rebuild"):
|
||||
bind_candidate_selectors(candidate.cdsl)
|
||||
|
||||
Reference in New Issue
Block a user