fix(web): reject false macro coverage and record source gaps
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-09-05 18:35:18 +08:00
parent 60ac88cc86
commit 9ec6d4d28f
5 changed files with 843 additions and 19 deletions

View File

@@ -846,26 +846,17 @@ def auto_operator_macro_batch(inventory: dict) -> dict | None:
]
if not units:
return None
gates = (
("duplicate_move", "OBJECT_DUPLICATE_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-duplicate-production.spec.ts", "object-duplicate-production.json", None),
("delete", "OBJECT_DELETE_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-delete-batch-production.spec.ts", "object-delete-production.json", None),
("hide_view", "OBJECT_VISIBILITY_MACRO_BATCH", "OBJECT", "tests/files/web/generated/WBV2-P2-002-OBJECT.TRANSFORM_HIERARCHY.blend", "web/tests/e2e/wbv2-object-visibility-clear-batch-production.spec.ts", "object-visibility-clear-production.json", None),
("location_clear", "OBJECT_LOCATION_CLEAR_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-transform-clear-batch-production.spec.ts", "object-transform-clear-production.json", "LOCATION"),
("rotation_clear", "OBJECT_ROTATION_CLEAR_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-transform-clear-batch-production.spec.ts", "object-transform-clear-production.json", "ROTATION"),
("scale_clear", "OBJECT_SCALE_CLEAR_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-transform-clear-batch-production.spec.ts", "object-transform-clear-production.json", "SCALE"),
("transform_apply", "OBJECT_TRANSFORM_APPLY_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-transform-apply-batch-production.spec.ts", "object-transform-apply-production.json", None),
("move_to_collection", "OBJECT_MOVE_COLLECTION_MACRO_BATCH", "OBJECT", "tests/files/web/generated/WBV2-P24-001-OBJECT_OPERATIONS.MOVE_COLLECTION.blend", "web/tests/e2e/wbv2-object-move-batch-production.spec.ts", "object-move-production.json", None),
("parent_set", "OBJECT_PARENT_MACRO_BATCH", "OBJECT", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-object-parent-production.spec.ts", "object-parent-production.json", None),
("primitive_cube_add", "MESH_PRIMITIVE_CUBE_MACRO_BATCH", "MESH", "tests/files/web/basic_scene.blend", "web/tests/e2e/wbv2-primitive-cube-batch-production.spec.ts", "primitive-cube-production.json", None),
("extrude_", "MESH_EXTRUDE_MACRO_BATCH", "MESH", "tests/files/web/generated/WBV2-P2-003-MESH.EDIT_CORE.blend", "web/tests/e2e/wbv2-mesh-topology-production.spec.ts", "mesh-topology-production.json", "EXTRUDE"),
("loopcut", "MESH_LOOPCUT_MACRO_BATCH", "MESH", "tests/files/web/generated/WBV2-P2-003-MESH.EDIT_CORE.blend", "web/tests/e2e/wbv2-mesh-topology-production.spec.ts", "mesh-topology-production.json", "LOOP_CUT"),
("dissolve", "MESH_DISSOLVE_MACRO_BATCH", "MESH", "tests/files/web/generated/WBV2-P2-003-MESH.EDIT_CORE.blend", "web/tests/e2e/wbv2-mesh-topology-production.spec.ts", "mesh-topology-production.json", "DISSOLVE"),
("merge", "MESH_MERGE_MACRO_BATCH", "MESH", "tests/files/web/generated/WBV2-P2-003-MESH.EDIT_CORE.blend", "web/tests/e2e/wbv2-mesh-topology-production.spec.ts", "mesh-topology-production.json", "MERGE"),
)
for marker, module_id, owner, fixture, test, production_name, operation in gates:
# Names are exact on purpose. Shared words such as "delete" or
# "duplicate" do not prove that a macro from another editor invokes the
# same native command; substring matching would create false coverage.
# No unresolved macro currently has an exact native gate. Keep the table
# empty until a matching fixture and command are added; mapping a macro to
# a merely similar operation would be false coverage.
gates = ()
for exact_identifier, module_id, owner, fixture, test, production_name, operation in gates:
if not (ROOT / fixture).is_file() or not (ROOT / test).is_file():
continue
selected = next((unit for unit in units if marker in unit["identifier"].lower()), None)
selected = next((unit for unit in units if unit["identifier"] == exact_identifier), None)
if not selected:
continue
return {
@@ -901,6 +892,34 @@ def pending_summary(inventory: dict) -> dict:
return {"count": len(pending), "byKind": by_kind, "byFamily": by_family, "sample": [unit.get("id") for unit in pending[:12]]}
def write_source_gap_report(inventory: dict) -> None:
"""Persist the next bounded source gaps when no exact gate exists.
This is a planner artifact, not coverage evidence. It gives the unattended
loop a deterministic handoff for the next implementation pass without
marking an unsupported unit as verified or repeatedly rescanning the tree.
"""
pending = [unit for unit in inventory.get("units", []) if isinstance(unit, dict) and unit.get("coverageStatus") != "VERIFIED"]
report = {
"schemaVersion": 1,
"status": "awaiting_exact_native_gate",
"pendingCount": len(pending),
"next": [
{
"unitId": unit.get("id"),
"identifier": unit.get("identifier"),
"kind": unit.get("kind"),
"family": unit.get("family"),
"source": (unit.get("locations") or [{}])[0].get("path"),
"line": (unit.get("locations") or [{}])[0].get("line"),
"required": "real Blender Main/WASM command adapter plus exact Chromium fixture",
}
for unit in pending[:64]
],
}
write_json(CONTROL_ROOT / "unresolved-source-batches.json", report)
def run_node(*args: str) -> None:
result = subprocess.run(["node", *args], cwd=ROOT, text=True, capture_output=True, check=False)
output = result.stdout or result.stderr
@@ -1152,6 +1171,7 @@ def select_batch(inventory: dict) -> dict:
if macro:
return macro
summary = pending_summary(inventory)
write_source_gap_report(inventory)
write_planner_status({
"status": "waiting_for_exact_evidence",
"reason": "no_configured_unresolved_source_batch",