Files
cdsl-cad/cadfs_to_cdsl/rebuild.py
T

124 lines
4.8 KiB
Python

from __future__ import annotations
from copy import deepcopy
from pathlib import Path
import re
from typing import Any
def _last_executable_prefix(error: Exception, output: Path) -> dict[str, Any] | None:
"""Export the checkpoint already produced by the failed live replay."""
execution = getattr(error, "incremental_execution", None)
bound = getattr(error, "bound_cdsl", None)
if execution is None or not isinstance(bound, dict):
return None
session = execution.session
if not session.results or (session.body is None and not session.surface_members):
return None
from engine.cdsl_engine.runtime import finalize_cdsl_execution
try:
result = finalize_cdsl_execution(execution, output)
except Exception:
return None
last_feature_id = next(reversed(session.results))
features = list(bound.get("features") or [])
feature_count = next(
(index + 1 for index, feature in enumerate(features) if feature.get("id") == last_feature_id),
0,
)
if feature_count == 0:
return None
prefix = deepcopy(bound)
prefix["features"] = features[:feature_count]
return {
"failed_feature_id": getattr(error, "failed_feature_id", None) or _failed_feature_id(error),
"feature_count": feature_count,
"last_feature_id": last_feature_id,
"bound_cdsl": prefix,
"result": result,
}
def _failed_feature_id(error: Exception) -> str | None:
diagnostic = getattr(error, "diagnostic", None)
feature_id = getattr(diagnostic, "feature_id", None)
if isinstance(feature_id, str) and feature_id:
return feature_id
match = re.match(r"([^:\s]+): ", str(error))
return match.group(1) if match else None
def _last_preflight_executable_prefix(
cdsl: dict[str, Any], analysis: Any, output: Path,
) -> dict[str, Any] | None:
"""Persist the contiguous executable prefix rejected by later preflight."""
feature_results = list(getattr(analysis, "feature_results", ()) or ())
first_blocked = next(
(index for index, result in enumerate(feature_results) if not result.executable),
None,
)
if first_blocked in (None, 0):
return None
features = list(cdsl.get("features") or [])
if first_blocked > len(features):
return None
prefix = deepcopy(cdsl)
prefix["features"] = features[:first_blocked]
try:
prefix_result = rebuild_candidate(prefix, output)
except Exception:
return None
if prefix_result.get("status") != "rebuilt":
nested_prefix = prefix_result.get("last_executable_prefix")
return nested_prefix if isinstance(nested_prefix, dict) else None
result = prefix_result.get("result")
if not isinstance(result, dict):
return None
return {
"failed_feature_id": feature_results[first_blocked].feature_id,
"feature_count": first_blocked,
"last_feature_id": features[first_blocked - 1].get("id"),
"bound_cdsl": prefix_result.get("bound_cdsl", prefix),
"result": result,
}
def rebuild_candidate(cdsl: dict[str, Any], output: Path) -> dict[str, Any]:
from engine.cdsl_engine.runtime import analyze_cdsl, finalize_cdsl_execution
from .selector_binding import bind_and_execute_candidate_selectors
analysis = analyze_cdsl(cdsl)
analysis_dict = analysis.as_dict() if hasattr(analysis, "as_dict") else {"runtime_eligible": analysis.runtime_eligible}
if not analysis.runtime_eligible:
result = {"status": "runtime_ineligible", "analysis": analysis_dict}
prefix = _last_preflight_executable_prefix(cdsl, analysis, output)
if prefix is not None:
result["last_executable_prefix"] = prefix
return result
try:
replay = bind_and_execute_candidate_selectors(cdsl)
result = finalize_cdsl_execution(replay.execution, output)
return {
"status": "rebuilt",
"analysis": analysis_dict,
"selector_binding": replay.evidence,
"bound_cdsl": replay.bound_cdsl,
"result": result,
}
except Exception as exc:
detail = {"type": type(exc).__name__, "message": str(exc)}
if hasattr(exc, "selector_resolutions"):
detail["selector_resolutions"] = exc.selector_resolutions
prefix = _last_executable_prefix(exc, output)
result = {"status": "rebuild_failed", "analysis": analysis_dict, "error": detail}
bound = getattr(exc, "bound_cdsl", None)
if isinstance(bound, dict):
result["bound_cdsl"] = bound
binding = getattr(exc, "selector_binding", None)
if isinstance(binding, list):
result["selector_binding"] = binding
if prefix is not None: result["last_executable_prefix"] = prefix
return result