remove

                        part = _cap_delta_if_needed(w, part)
                        w.data[:half, :].add_(part)
                        applied.append((w, d_cpu[:half, :].detach().to("cpu"), "slice", (0, half)))
                    else:
                        part = d[-half:, :] if d.shape[0] == w.shape[0] else d
                        part = _cap_delta_if_needed(w, part)
                        w.data[half:, :].add_(part)
                        applied.append((w, d_cpu[-half:, :].detach().to("cpu"), "slice", (half, w.shape[0])))
                else:
                    w.data.add_(d)
                    applied.append((w, d_cpu.detach().to("cpu"), "full", (0, 0)))
            except Exception:
                continue
        del deltas_cpu

    class _Applied:
        def __init__(self, records: List[Tuple[torch.nn.Parameter, torch.Tensor, str, Tuple[int, int]]]):
            self._records = records
            self._removed = False

        def remove(self) -> None:
            if self._removed:
                return
            for w, d_cpu, mode, extra in self._records:
                try:
                    if mode == "full":
                        d_dev = d_cpu.to(device=w.device, dtype=w.dtype)
                        w.data.sub_(d_dev)
                    elif mode == "slice":
                        start, end = extra
                        d_dev = d_cpu.to(device=w.device, dtype=w.dtype)
                        w.data[start:end, :].sub_(d_dev)
                except Exception:
                    pass
            self._removed = True

    return [_Applied(applied)]


modules.telemetry

# telemetry meta assembly and write (from run_repo_adapter.py)


from __future__ import annotations

from dataclasses import dataclass, asdict
from typing import Any, Dict, List, Tuple, Optional
import json
import hashlib
import os
import time

@dataclass
class ProgramState:
    root: str
    candidates_modules: List[str]
    candidates_files: List[str]
    citations: List[Tuple[str, int, int]]
    vec: Optional[List[float]] = None
    vec_weight: float = 1.0
    H: float = 0.0
    behavior_log: List[Dict[str, Any]] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        if self.behavior_log is None:
            self.behavior_log = []

    def checksum(self) -> str:
        try:
            payload = {
                "root": self.root,
                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))

def join_program_states(a: ProgramState, b: ProgramState) -> ProgramState:
    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec
    vw = float(max(0.0, (a.vec_weight if a.vec else 0.0) + (b.vec_weight if b.vec else 0.0)))
    H = float(max(0.0, a.H + b.H))
    beh = list(a.behavior_log or []) + list(b.behavior_log or [])
    return ProgramState(
        root=(b.root or a.root),
        candidates_modules=mods,
        candidates_files=files,
        citations=cites,
        vec=vec,
        vec_weight=(vw if vw > 0 else 1.0),
        H=H,
        behavior_log=beh,
    )

def new_state_from_run(
    root: str,
    *,
    modules: List[str],
    files: List[str],
    citations: List[Tuple[str, int, int]],
    z_vec: Any = None,
    beh_event: Dict[str, Any] | None = None,
    H_increment: float = 0.0,
) -> ProgramState:
    return ProgramState(
        root=str(root),
        candidates_modules=list(modules or []),
        candidates_files=list(files or []),
        citations=list(citations or []),
        vec=(list(z_vec) if isinstance(z_vec, list) else (z_vec.tolist() if hasattr(z_vec, "tolist") else None)),
        vec_weight=1.0,
        H=float(max(0.0, H_increment or 0.0)),
        behavior_log=[(beh_event or {})],
    )

def changed_bits(a: ProgramState, b: ProgramState) -> bool:
    try:
        return a.checksum() != b.checksum()
    except Exception:
        return True


ProgramState

from __future__ import annotations

from dataclasses import dataclass, asdict
from typing import Any, Dict, List, Tuple, Optional
import json
import hashlib
import os
import time

@dataclass
class ProgramState:
    root: str
    candidates_modules: List[str]
    candidates_files: List[str]
    citations: List[Tuple[str, int, int]]
    vec: Optional[List[float]] = None
    vec_weight: float = 1.0
    H: float = 0.0
    behavior_log: List[Dict[str, Any]] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        if self.behavior_log is None:
            self.behavior_log = []

    def checksum(self) -> str:
        try:
            payload = {
                "root": self.root,
                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:


        if self.behavior_log is None:
            self.behavior_log = []

    def checksum(self) -> str:
        try:
            payload = {
                "root": self.root,
                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:


                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),


            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj


        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))


    try:
        with open(path, "w", encoding="utf-8") as fh:
            fh.write(json.dumps(obj, indent=2))
    except Exception:
        pass

def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))

def join_program_states(a: ProgramState, b: ProgramState) -> ProgramState:
    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec


def _from_dict(d: Dict[str, Any]) -> ProgramState:
    return ProgramState(
        root=str(d.get("root") or d.get("program_root") or ""),
        candidates_modules=list(d.get("candidates_modules") or []),
        candidates_files=list(d.get("candidates_files") or []),
        citations=[(str(p), int(a), int(b)) for (p, a, b) in (d.get("citations") or [])],
        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))

def join_program_states(a: ProgramState, b: ProgramState) -> ProgramState:
    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec
    vw = float(max(0.0, (a.vec_weight if a.vec else 0.0) + (b.vec_weight if b.vec else 0.0)))
    H = float(max(0.0, a.H + b.H))
    beh = list(a.behavior_log or []) + list(b.behavior_log or [])
    return ProgramState(
        root=(b.root or a.root),
        candidates_modules=mods,


        vec=(list(d.get("vec")) if isinstance(d.get("vec"), list) else None),
        vec_weight=float(d.get("vec_weight") or 1.0),
        H=float(d.get("H") or 0.0),
        behavior_log=list(d.get("behavior_log") or []),
    )

def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))

def join_program_states(a: ProgramState, b: ProgramState) -> ProgramState:
    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec
    vw = float(max(0.0, (a.vec_weight if a.vec else 0.0) + (b.vec_weight if b.vec else 0.0)))
    H = float(max(0.0, a.H + b.H))
    beh = list(a.behavior_log or []) + list(b.behavior_log or [])
    return ProgramState(
        root=(b.root or a.root),
        candidates_modules=mods,
        candidates_files=files,
        citations=cites,
        vec=vec,
        vec_weight=(vw if vw > 0 else 1.0),
        H=H,
        behavior_log=beh,


def _to_dict(s: ProgramState) -> Dict[str, Any]:
    obj = asdict(s)
    obj["schema_version"] = 1
    obj["updated_at"] = time.time()
    return obj

def load_program_state(root: str, *, path: str | None = None) -> ProgramState:
    if not path or not os.path.exists(path):
        return ProgramState(root=str(root), candidates_modules=[], candidates_files=[], citations=[], vec=None, vec_weight=1.0, H=0.0, behavior_log=[])
    return _from_dict(_load_json(path))

def save_program_state(state: ProgramState, *, path: str | None = None) -> None:
    if not path:
        return
    _save_json(path, _to_dict(state))

def join_program_states(a: ProgramState, b: ProgramState) -> ProgramState:
    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec
    vw = float(max(0.0, (a.vec_weight if a.vec else 0.0) + (b.vec_weight if b.vec else 0.0)))
    H = float(max(0.0, a.H + b.H))
    beh = list(a.behavior_log or []) + list(b.behavior_log or [])
    return ProgramState(
        root=(b.root or a.root),
        candidates_modules=mods,
        candidates_files=files,
        citations=cites,
        vec=vec,
        vec_weight=(vw if vw > 0 else 1.0),
        H=H,
        behavior_log=beh,
    )

def new_state_from_run(
    root: str,
    *,
    modules: List[str],
    files: List[str],
    citations: List[Tuple[str, int, int]],
    z_vec: Any = None,
    beh_event: Dict[str, Any] | None = None,
    H_increment: float = 0.0,
) -> ProgramState:
    return ProgramState(
        root=str(root),
        candidates_modules=list(modules or []),
        candidates_files=list(files or []),
        citations=list(citations or []),
        vec=(list(z_vec) if isinstance(z_vec, list) else (z_vec.tolist() if hasattr(z_vec, "tolist") else None)),
        vec_weight=1.0,
        H=float(max(0.0, H_increment or 0.0)),


    mods = sorted(list(set(a.candidates_modules) | set(b.candidates_modules)))
    files = sorted(list(set(a.candidates_files) | set(b.candidates_files)))
    cites = sorted(list(set(a.citations) | set(b.citations)))
    # Prefer newer vec if provided; blend weight heuristically
    vec = b.vec if (b.vec and len(b.vec) > 0) else a.vec
    vw = float(max(0.0, (a.vec_weight if a.vec else 0.0) + (b.vec_weight if b.vec else 0.0)))
    H = float(max(0.0, a.H + b.H))
    beh = list(a.behavior_log or []) + list(b.behavior_log or [])
    return ProgramState(
        root=(b.root or a.root),
        candidates_modules=mods,
        candidates_files=files,
        citations=cites,
        vec=vec,
        vec_weight=(vw if vw > 0 else 1.0),
        H=H,
        behavior_log=beh,
    )

def new_state_from_run(
    root: str,
    *,
    modules: List[str],
    files: List[str],
    citations: List[Tuple[str, int, int]],
    z_vec: Any = None,
    beh_event: Dict[str, Any] | None = None,
    H_increment: float = 0.0,
) -> ProgramState:
    return ProgramState(
        root=str(root),
        candidates_modules=list(modules or []),
        candidates_files=list(files or []),
        citations=list(citations or []),
        vec=(list(z_vec) if isinstance(z_vec, list) else (z_vec.tolist() if hasattr(z_vec, "tolist") else None)),
        vec_weight=1.0,
        H=float(max(0.0, H_increment or 0.0)),
        behavior_log=[(beh_event or {})],
    )

def changed_bits(a: ProgramState, b: ProgramState) -> bool:
    try:
        return a.checksum() != b.checksum()
    except Exception:
        return True


    *,
    modules: List[str],
    files: List[str],
    citations: List[Tuple[str, int, int]],
    z_vec: Any = None,
    beh_event: Dict[str, Any] | None = None,
    H_increment: float = 0.0,
) -> ProgramState:
    return ProgramState(
        root=str(root),
        candidates_modules=list(modules or []),
        candidates_files=list(files or []),
        citations=list(citations or []),
        vec=(list(z_vec) if isinstance(z_vec, list) else (z_vec.tolist() if hasattr(z_vec, "tolist") else None)),
        vec_weight=1.0,
        H=float(max(0.0, H_increment or 0.0)),
        behavior_log=[(beh_event or {})],
    )

def changed_bits(a: ProgramState, b: ProgramState) -> bool:
    try:
        return a.checksum() != b.checksum()
    except Exception:
        return True


from dataclasses import dataclass, asdict
from typing import Any, Dict, List, Tuple, Optional
import json
import hashlib
import os
import time

@dataclass
class ProgramState:
    root: str
    candidates_modules: List[str]
    candidates_files: List[str]
    citations: List[Tuple[str, int, int]]
    vec: Optional[List[float]] = None
    vec_weight: float = 1.0
    H: float = 0.0
    behavior_log: List[Dict[str, Any]] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        if self.behavior_log is None:
            self.behavior_log = []

    def checksum(self) -> str:
        try:
            payload = {
                "root": self.root,
                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:


checksum

import hashlib
import os
import time

@dataclass
class ProgramState:
    root: str
    candidates_modules: List[str]
    candidates_files: List[str]
    citations: List[Tuple[str, int, int]]
    vec: Optional[List[float]] = None
    vec_weight: float = 1.0
    H: float = 0.0
    behavior_log: List[Dict[str, Any]] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        if self.behavior_log is None:
            self.behavior_log = []

    def checksum(self) -> str:
        try:
            payload = {
                "root": self.root,
                "mods": sorted(list(self.candidates_modules)),
                "files": sorted(list(self.candidates_files)),
                "cites": sorted([(p, int(a), int(b)) for (p, a, b) in self.citations]),
                "H": float(self.H),
                "vec_w": float(self.vec_weight),
                "vec_n": int(len(self.vec) if isinstance(self.vec, list) else 0),
            }
            raw = json.dumps(payload, sort_keys=True).encode("utf-8", errors="ignore")
            return hashlib.sha256(raw).hexdigest()
        except Exception:
            return ""

def _ensure_dir(p: str) -> None:
    try:
        os.makedirs(os.path.dirname(p), exist_ok=True)
    except Exception:
        pass

def _load_json(path: str) -> Dict[str, Any]:
    try:
        with open(path, "r", encoding="utf-8") as fh:
            return json.loads(fh.read())
    except Exception:
        return {}

def _save_json(path: str, obj: Dict[str, Any]) -> None:
    _ensure_dir(path)
    try:


from __future__ import annotations

from typing import Dict, List, Any, Tuple

from .program_graph import ProgramGraph, Entity
from .retrieval_policy import RetrievalPolicy
from .citations import CitationManager, CitationPolicy

def select_region(query: str, pg: ProgramGraph, policy: RetrievalPolicy, top_k: int = 16) -> List[str]:
    scores = policy.score_entities(query, pg)
    ids = sorted(scores.keys(), key=lambda k: scores.get(k, 0.0), reverse=True)[:max(1, int(top_k))]
    return ids

def prepare_citations(units: List[Dict[str, Any]], region_entity_ids: List[str], pg: ProgramGraph, citations_policy: Dict[str, Any], manifest: Dict[str, Any]) -> List[Dict[str, Any]]:
    cm = CitationManager(
        policy=CitationPolicy(
            enforce=bool(citations_policy.get("enforce", True)),
            per_paragraph=bool(citations_policy.get("per_paragraph", False)),
            repair=bool(citations_policy.get("repair", True)),
        ),
        pg=pg,
        manifest=manifest or {},
    )
    # Collect baseline evidence for the region and stamp
    baseline = cm.collect(region_entity_ids, contexts=[])
    out: List[Dict[str, Any]] = []
    for u in units:
        unit = dict(u)
        unit.setdefault("evidence", baseline[:4])
        unit = cm.enforce([unit])[0]
        unit = cm.stamp_provenance(unit)
        out.append(unit)
    return out


from __future__ import annotations

from typing import Dict, List, Any, Tuple

from .program_graph import ProgramGraph, Entity
from .retrieval_policy import RetrievalPolicy
from .citations import CitationManager, CitationPolicy

def select_region(query: str, pg: ProgramGraph, policy: RetrievalPolicy, top_k: int = 16) -> List[str]:
    scores = policy.score_entities(query, pg)
    ids = sorted(scores.keys(), key=lambda k: scores.get(k, 0.0), reverse=True)[:max(1, int(top_k))]
    return ids

def prepare_citations(units: List[Dict[str, Any]], region_entity_ids: List[str], pg: ProgramGraph, citations_policy: Dict[str, Any], manifest: Dict[str, Any]) -> List[Dict[str, Any]]:
    cm = CitationManager(
        policy=CitationPolicy(
            enforce=bool(citations_policy.get("enforce", True)),
            per_paragraph=bool(citations_policy.get("per_paragraph", False)),
            repair=bool(citations_policy.get("repair", True)),
        ),
        pg=pg,
        manifest=manifest or {},
    )
    # Collect baseline evidence for the region and stamp
    baseline = cm.collect(region_entity_ids, contexts=[])
    out: List[Dict[str, Any]] = []
    for u in units:
        unit = dict(u)
        unit.setdefault("evidence", baseline[:4])
        unit = cm.enforce([unit])[0]
        unit = cm.stamp_provenance(unit)


modules.interpret

# ActivationTracer hooks, capture pipeline, write JSON (lift from run_repo_adapter.py)

from typing import Dict, Tuple
import torch

def is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def block_out_hook(_key: str, _m: torch.nn.Module, _inputs: Tuple[torch.Tensor, ...], output: torch.Tensor) -> torch.Tensor | None:
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def truncate_batch(xx: Dict[str, torch.Tensor], max_tokens: int = 512) -> Dict[str, torch.Tensor]:
    max_t = max(8, int(max_tokens))
    out: Dict[str, torch.Tensor] = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:
            out[k] = v[:, -max_t:]
        else:
            out[k] = v
    return out

def get_W(m: torch.nn.Module) -> torch.Tensor:
    if hasattr(m, "lm_head") and hasattr(m.lm_head, "weight"):
        return m.lm_head.weight
    if hasattr(m, "get_output_embeddings"):
        we = m.get_output_embeddings()
        if we is not None and hasattr(we, "weight"):
            return we.weight
    raise AttributeError("No output projection found (lm_head or embeddings)")

"""
def _is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def _block_out_hook(_key, _m, _inputs, output):
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def _truncate_batch(xx):
    max_t = max(8, int(args.interpret_tokens))
    out = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:
            out[k] = v[:, -max_t:]
        else:
            out[k] = v
    return out

"""


# ActivationTracer hooks, capture pipeline, write JSON (lift from run_repo_adapter.py)

from typing import Dict, Tuple
import torch

def is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def block_out_hook(_key: str, _m: torch.nn.Module, _inputs: Tuple[torch.Tensor, ...], output: torch.Tensor) -> torch.Tensor | None:
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def truncate_batch(xx: Dict[str, torch.Tensor], max_tokens: int = 512) -> Dict[str, torch.Tensor]:
    max_t = max(8, int(max_tokens))
    out: Dict[str, torch.Tensor] = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:


# ActivationTracer hooks, capture pipeline, write JSON (lift from run_repo_adapter.py)

from typing import Dict, Tuple
import torch

def is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def block_out_hook(_key: str, _m: torch.nn.Module, _inputs: Tuple[torch.Tensor, ...], output: torch.Tensor) -> torch.Tensor | None:
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def truncate_batch(xx: Dict[str, torch.Tensor], max_tokens: int = 512) -> Dict[str, torch.Tensor]:
    max_t = max(8, int(max_tokens))
    out: Dict[str, torch.Tensor] = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:
            out[k] = v[:, -max_t:]
        else:
            out[k] = v
    return out

def get_W(m: torch.nn.Module) -> torch.Tensor:
    if hasattr(m, "lm_head") and hasattr(m.lm_head, "weight"):
        return m.lm_head.weight
    if hasattr(m, "get_output_embeddings"):
        we = m.get_output_embeddings()
        if we is not None and hasattr(we, "weight"):
            return we.weight


def is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def block_out_hook(_key: str, _m: torch.nn.Module, _inputs: Tuple[torch.Tensor, ...], output: torch.Tensor) -> torch.Tensor | None:
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def truncate_batch(xx: Dict[str, torch.Tensor], max_tokens: int = 512) -> Dict[str, torch.Tensor]:
    max_t = max(8, int(max_tokens))
    out: Dict[str, torch.Tensor] = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:
            out[k] = v[:, -max_t:]
        else:
            out[k] = v
    return out

def get_W(m: torch.nn.Module) -> torch.Tensor:
    if hasattr(m, "lm_head") and hasattr(m.lm_head, "weight"):
        return m.lm_head.weight
    if hasattr(m, "get_output_embeddings"):
        we = m.get_output_embeddings()
        if we is not None and hasattr(we, "weight"):
            return we.weight
    raise AttributeError("No output projection found (lm_head or embeddings)")

"""
def _is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def _block_out_hook(_key, _m, _inputs, output):


        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None

def truncate_batch(xx: Dict[str, torch.Tensor], max_tokens: int = 512) -> Dict[str, torch.Tensor]:
    max_t = max(8, int(max_tokens))
    out: Dict[str, torch.Tensor] = {}
    for k, v in xx.items():
        if isinstance(v, torch.Tensor) and v.dim() >= 2 and v.size(1) > max_t:
            out[k] = v[:, -max_t:]
        else:
            out[k] = v
    return out

def get_W(m: torch.nn.Module) -> torch.Tensor:
    if hasattr(m, "lm_head") and hasattr(m.lm_head, "weight"):
        return m.lm_head.weight
    if hasattr(m, "get_output_embeddings"):
        we = m.get_output_embeddings()
        if we is not None and hasattr(we, "weight"):
            return we.weight
    raise AttributeError("No output projection found (lm_head or embeddings)")

"""
def _is_block(name: str, _m: torch.nn.Module) -> bool:
    if not name.startswith("model.layers."):
        return False
    rest = name[len("model.layers."):]
    return rest.isdigit() and "." not in rest

def _block_out_hook(_key, _m, _inputs, output):
    try:
        if isinstance(output, torch.Tensor):
            return output
        if isinstance(output, (tuple, list)) and output:
            v = output[0]
            return v if isinstance(v, torch.Tensor) else None
        v = getattr(output, "hidden_states", None) or getattr(output, "last_hidden_state", None)
        return v if isinstance(v, torch.Tensor) else None
    except Exception:
        return None


modules.peft

from typing import Dict, Any, List, Optional
import os
import re
from model.inspect import detect_target_names_from_model_full

def infer_target_names(model_id: str) -> Dict[str, str]:
    names = detect_target_names_from_model_full(model_id, target_regex=None) or {}
    # names maps short -> path within the first layer subtree
    # Example: {"q_proj": "self_attn.q_proj", "o_proj": "self_attn.o_proj", ...}
    return names

def save_peft_like(out_dir: str, adapters: Dict[str, Any], *, r: int, alpha: int, target_modules: List[str], bias: str = "none", int8: bool = False, target_paths: Optional[Dict[str, str]] = None) -> None:
    """Write a minimal PEFT LoRA config + tensors for quick benchmarking.

    Note: This is a best-effort exporter; users may still need to map names depending on the model arch.
    """
    try:
        import json as _json
        cfg = {
            "peft_type": "LORA",
            "r": int(r),
            "lora_alpha": int(alpha),
            "target_modules": target_modules,
            "lora_dropout": 0.0,
            "bias": str(bias),
            "task_type": "CAUSAL_LM",
        }
        open(os.path.join(out_dir, "adapter_config.json"), "w", encoding="utf-8").write(_json.dumps(cfg, indent=2))
        # Save tensors in a stable torch format if available
        try:
            import torch as _torch  # type: ignore

            state: Dict[str, Any] = {}
            def _map_path(i: int, name: str) -> str:
                # Map target name to likely module path; best-effort for LLaMA-like arch
                if target_paths and name in target_paths:
                    return f"base_model.model.{target_paths[name]}"
                if name in ("q_proj", "k_proj", "v_proj", "o_proj"):
                    return f"base_model.model.model.layers.{i}.self_attn.{name}"
                elif name in ("up_proj", "down_proj", "gate_proj"):
                    return f"base_model.model.model.layers.{i}.mlp.{name}"
                else:
                    return f"base_model.model.model.layers.{i}.{name}"
            for i, layer in enumerate(adapters["layers"]):
                for name, tensors in layer.items():
                    base = _map_path(i, name)
                    A = _torch.from_numpy(tensors["A"]).contiguous()
                    B = _torch.from_numpy(tensors["B"]).contiguous()
                    if int8:
                        try:
                            # Per-tensor affine quantization
                            scale_A = float(A.abs().max().item() / 127.0) if A.numel() > 0 else 1.0
                            A = _torch.quantize_per_tensor(A, scale=max(scale_A, 1e-8), zero_point=0, dtype=_torch.qint8)
                            scale_B = float(B.abs().max().item() / 127.0) if B.numel() > 0 else 1.0
                            B = _torch.quantize_per_tensor(B, scale=max(scale_B, 1e-8), zero_point=0, dtype=_torch.qint8)
                        except Exception:
                            pass
                    state[f"{base}.lora_A.weight"] = A
                    state[f"{base}.lora_B.weight"] = B
            _torch.save(state, os.path.join(out_dir, "adapter_model.bin"))
        except Exception:
            pass
    except Exception:
        pass


from typing import Dict, Any, List, Optional
import os
import re
from model.inspect import detect_target_names_from_model_full

def infer_target_names(model_id: str) -> Dict[str, str]:
    names = detect_target_names_from_model_full(model_id, target_regex=None) or {}
    # names maps short -> path within the first layer subtree
    # Example: {"q_proj": "self_attn.q_proj", "o_proj": "self_attn.o_proj", ...}
    return names

def save_peft_like(out_dir: str, adapters: Dict[str, Any], *, r: int, alpha: int, target_modules: List[str], bias: str = "none", int8: bool = False, target_paths: Optional[Dict[str, str]] = None) -> None:
    """Write a minimal PEFT LoRA config + tensors for quick benchmarking.

    Note: This is a best-effort exporter; users may still need to map names depending on the model arch.
    """
    try:
        import json as _json
        cfg = {
            "peft_type": "LORA",
            "r": int(r),
            "lora_alpha": int(alpha),
            "target_modules": target_modules,
            "lora_dropout": 0.0,
            "bias": str(bias),
            "task_type": "CAUSAL_LM",
        }
        open(os.path.join(out_dir, "adapter_config.json"), "w", encoding="utf-8").write(_json.dumps(cfg, indent=2))
        # Save tensors in a stable torch format if available
        try:


    Note: This is a best-effort exporter; users may still need to map names depending on the model arch.
    """
    try:
        import json as _json
        cfg = {
            "peft_type": "LORA",
            "r": int(r),
            "lora_alpha": int(alpha),
            "target_modules": target_modules,
            "lora_dropout": 0.0,
            "bias": str(bias),
            "task_type": "CAUSAL_LM",
        }
        open(os.path.join(out_dir, "adapter_config.json"), "w", encoding="utf-8").write(_json.dumps(cfg, indent=2))
        # Save tensors in a stable torch format if available
        try:
            import torch as _torch  # type: ignore

            state: Dict[str, Any] = {}
            def _map_path(i: int, name: str) -> str:
                # Map target name to likely module path; best-effort for LLaMA-like arch
                if target_paths and name in target_paths:
                    return f"base_model.model.{target_paths[name]}"
                if name in ("q_proj", "k_proj", "v_proj", "o_proj"):
                    return f"base_model.model.model.layers.{i}.self_attn.{name}"
                elif name in ("up_proj", "down_proj", "gate_proj"):
                    return f"base_model.model.model.layers.{i}.mlp.{name}"
                else:
                    return f"base_model.model.model.layers.{i}.{name}"
            for i, layer in enumerate(adapters["layers"]):
                for name, tensors in layer.items():
                    base = _map_path(i, name)
                    A = _torch.from_numpy(tensors["A"]).contiguous()
                    B = _torch.from_numpy(tensors["B"]).contiguous()
                    if int8:
                        try:
                            # Per-tensor affine quantization
                            scale_A = float(A.abs().max().item() / 127.0) if A.numel() > 0 else 1.0
                            A = _torch.quantize_per_tensor(A, scale=max(scale_A, 1e-8), zero_point=0, dtype=_torch.qint8)
                            scale_B = float(B.abs().max().item() / 127.0) if B.numel() > 0 else 1.0
                            B = _torch.quantize_per_tensor(B, scale=max(scale_B, 1e-8), zero_point=0, dtype=_torch.qint8)
                        except Exception:
                            pass
                    state[f"{base}.lora_A.weight"] = A
                    state[f"{base}.lora_B.weight"] = B
            _torch.save(state, os.path.join(out_dir, "adapter_model.bin"))
        except Exception:
            pass
    except Exception:


modules.runner

from __future__ import annotations

import os
import json
import time
from typing import Optional, Tuple, List, Dict, Any, Set

import numpy as np
import torch
from data.tokenizer import LocalLlamaTokenizer

from modules.adapter import (
    load_adapters_npz,
    generate_lora_from_embedding,
)
from model.llama_bootstrap import build_local_llama_from_snapshot
from model.hf_snapshot import ensure_snapshot
from blocks.targets import targets_map
from blocks.inspect import infer_target_shapes
from model.inspect import detect_target_names_from_model_full
from modules.mixing import (
    register_hook_mixed_adapters,
)
from modules.caches import load_manifest, load_windows_index, pick_files_from_windows
from modules.citations import CitationManager, CitationPolicy
from modules.interpret import (
    is_block,
    block_out_hook,
    truncate_batch,
    get_W,
)
from modules.program_state import (
    load_program_state,
    save_program_state,
    join_program_states,
    new_state_from_run,
    changed_bits,
)

def _normalize_citations_regex():
    try:
        import re
        return re.compile(r"(?:path:\s*)?([A-Za-z0-9_./\\\-]+?\.\w+):(\d+)(?:-(\d+))?")
    except Exception:
        return None

def normalize_citations(text: str) -> List[tuple[str, int, int]]:
    rx = _normalize_citations_regex()
    if rx is None:
        return []
    out: List[tuple[str, int, int]] = []
    try:
        import os as _os
        for m in rx.finditer(text or ""):
            p = m.group(1)
            try:
                a = int(m.group(2) or "0")
            except Exception:
                a = 0
            try:
                b = int(m.group(3) or a)
            except Exception:
                b = a
            out.append((p.replace("\\\\", "/"), min(a, b), max(a, b)))
        return out
    except Exception:
        return []

def has_citations(s: str, per_para: bool) -> bool:
    try:
        import re as _re
        rx = _re.compile(r"(?:path:\s*)?[A-Za-z0-9_./\\-]+?\.\w+:\d+(?:-\d+)?")
        if not rx.search(s or ""):
            return False
        if per_para:
            paras = [p.strip() for p in (s or "").split("\n\n") if p.strip()]
            return all(rx.search(p) for p in paras)
        return True
    except Exception:
        return False

def generate_answer(
    model_id: str,
    adapters_npz: str,
    prompt: str,
    *,
    program_root: Optional[str] = None,
    delta_cap: float = 0.05,
    cache_dir: Optional[str] = None,
    device: str = "cuda" if torch.cuda.is_available() else "cpu",
    device_map: str = "none",
    gpu_ids: Optional[str] = None,
    # selection
    of_sources: str = "question",
    zoom_symbol: Optional[str] = None,
    zoom_radius: int = 0,
    ignore: Optional[List[str]] = None,
    # context
    pack_context: bool = False,
    pack_mode: str = "heads",
    context_tokens: int = 2000,
    function_first: bool = False,
    ff_max_candidates: int = 24,
    ff_window_lines: int = 80,
    ff_threshold: float = 0.55,
    ff_noise_penalty: float = 0.30,
    # capacity/mixing
    alpha: float = 16.0,
    rank: int = 12,
    gsub: float = 0.75,
    beta: float = 0.1,
    entropy_aware: bool = False,
    rank_min: int = 8,
    rank_max: int = 32,
    gsub_min: float = 0.6,
    gsub_max: float = 0.9,
    entropy_weights: str = "program=0.4,subgraph=0.4,question=0.2",
    target_weights: Optional[str] = None,
    layer_schedule: bool = False,
    q_aware_weights: bool = False,
    mixture_m: int = 0,
    adapters_bank: Optional[str] = None,
    per_target_rank_schedule: bool = False,
    rank_budget: int = 0,
    ablate_attn: bool = False,
    ablate_mlp: bool = False,
    alpha_warmup: bool = False,
    adapter_aware_decoding: bool = False,
    layer_rank_tiers: bool = False,
    # cones/rounding
    # cones/rounding
    cone_rank: int = 2,
    cone_weight: float = 0.5,
    round_lora: bool = False,
    round_threshold: float = 0.5,
    # citations
    require_citations: bool = False,
    citations_per_paragraph: bool = False,
    # retrieval/rerank
    rerank: bool = True,
    self_queries_path: Optional[str] = None,
    # generation
    do_sample: bool = False,
    temperature: float = 0.7,
    top_p: float = 0.9,
    repetition_penalty: float = 1.1,
    min_new_tokens: int = 64,
    max_new_tokens: int = 256,
    kv_window: int = 0,
    head_device: str = "same",  # "cpu" | "auto" | "same"
    # misc
    seed: int = 0,
    verbose: bool = False,
    # provenance footer
    commit_footer: bool = False,
    # monotone selection for non-structured path
    monotone_selection: bool = False,
) -> str:
    # Program root (path or URI) for reading artifacts/windows
    root = str(program_root) if (program_root is not None and str(program_root).strip()) else ""
    if gpu_ids and str(gpu_ids).strip():
        os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_ids).strip()
    os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")

    # Seed
    try:
        import random
        random.seed(int(seed))
        np.random.seed(int(seed))
        torch.manual_seed(int(seed))
    except Exception:
        pass

    # Prefer explicit cache_dir; else env; else project root (/..../checkpoints)
    if not cache_dir:
        env_cache = os.environ.get("TRANSFORMER_CACHE_DIR") or os.environ.get("HF_HOME")
        if env_cache:
            cache_dir = env_cache
        else:
            mod_dir = os.path.dirname(__file__)
            proj_root = os.path.abspath(os.path.join(mod_dir, "..", "..", ".."))
            cache_dir = os.path.join(proj_root, "checkpoints")
    try:
        os.makedirs(cache_dir, exist_ok=True)
    except Exception:
        pass

    # Local tokenizer (no transformers)
    snap_dir = ensure_snapshot(model_id, cache_dir)
    tok_local = LocalLlamaTokenizer(snap_dir)
    class _TokAdapter:
        def __init__(self, base):
            self._b = base
        class _Ret:
            def __init__(self, ids):
                self.input_ids = ids
        def __call__(self, text: str, add_special_tokens: bool = False, return_tensors: str | None = None):
            ids = self._b.encode(text)
            if return_tensors == "pt":
                return {"input_ids": torch.tensor([ids], dtype=torch.long)}
            return _TokAdapter._Ret(ids)
    tok = _TokAdapter(tok_local)
    def _tok_encode(text: str) -> List[int]:
        return tok_local.encode(text)
    def _tok_len(text: str) -> int:
        try:
            return len(tok_local.encode(text))
        except Exception:
            return 0
    def _tok_decode(ids: torch.Tensor | List[int]) -> str:
        if isinstance(ids, torch.Tensor):
            try:
                ids_l = ids.to("cpu").tolist()
            except Exception:
                ids_l = []
        else:
            ids_l = list(ids)
        try:
            return tok_local.decode(ids_l, skip_special_tokens=True)
        except Exception:
            return tok_local.decode(ids_l)
    torch_dtype = torch.bfloat16 if str(device).startswith("cuda") else torch.float32

    model, _cfg = build_local_llama_from_snapshot(snap_dir, device, torch_dtype, device_map=device_map, gpu_ids=gpu_ids)

    # Load base adapters
    base_layers = load_adapters_npz(adapters_npz)["layers"]

    # Selection via caches (program-agnostic): prefer windows with prompt overlap
    files: List[str] = []
    try:
        adapters_dir = os.path.dirname(adapters_npz)
        windows = load_windows_index(adapters_dir)
        files = pick_files_from_windows(root, windows, prompt, k=max(8, int(ff_max_candidates)))
    except Exception:
        files = []
    modules: List[str] = []

    # Subgraph embedding
    # Program-agnostic: skip subgraph embedding if no backend embedder; use base only
    sub = {"layers": []}

    # Shapes and targets
    tmap = targets_map("local")
    t_shapes = infer_target_shapes(model)
    num_layers = len(getattr(model, "blocks", []))
    d_model_local = int(t_shapes.get("q_proj", (0, 0))[0]) or int(getattr(getattr(model, "cfg", None), "d_model", 0) or 0)

    # Entropy-aware capacity
    scaled_rank = int(rank)
    scaled_gsub = float(gsub)
    entropy_diag: Optional[Dict[str, float]] = None

    # No subgraph z available -> keep sub empty (base-only mixing)
    sub = {"layers": []}

    # Function-first cones: build and merge
    cr = max(0, int(cone_rank))
    # Skip function-first cones in program-agnostic core (requires backend embedder)

    # Optional mixture bank: mix top-m module adapters from bank by concatenation (Σ π_i Δθ_i)
    if adapters_bank and int(mixture_m) > 0:
        try:
            import glob
            bank_root = os.path.abspath(os.path.expanduser(os.path.expandvars(adapters_bank)))
            sel_mods = [m for m in (modules or []) if m]
            picked = 0
            for mod in sel_mods:
                if picked >= int(mixture_m):
                    break
                mod_dir1 = os.path.join(bank_root, "sub_adapters", mod.replace("/", "_"))
                mod_dir2 = os.path.join(bank_root, mod.replace("/", "_"))
                cand = None
                for d in (mod_dir1, mod_dir2):
                    fp = os.path.join(d, "adapters.npz")
                    if os.path.isfile(fp):
                        cand = fp
                        break
                if not cand:
                    continue
                try:
                    bank_ad = load_adapters_npz(cand)
                except Exception:
                    continue
                # uniform π for now
                w = 1.0 / float(min(len(sel_mods), int(mixture_m)))
                sw = float(max(0.0, min(1.0, w))) ** 0.5
                # per-layer concat
                merged_layers = []
                for i in range(num_layers):
                    baseL = sub["layers"][i]
                    bL = bank_ad["layers"][i] if i < len(bank_ad.get("layers", [])) else {}
                    dst: Dict[str, Dict[str, np.ndarray]] = {}
                    for name in tmap.keys():
                        if (name in baseL) and (name in bL):
                            A1 = baseL[name]["A"]; B1 = baseL[name]["B"]
                            A2 = (sw * bL[name]["A"]).astype(np.float32); B2 = (sw * bL[name]["B"]).astype(np.float32)
                            A = np.concatenate([A1, A2], axis=1)
                            B = np.concatenate([B1, B2], axis=0)
                            dst[name] = {"A": A, "B": B, "gate": baseL[name].get("gate", np.array([0.0], dtype=np.float32))}
                        elif name in baseL:
                            dst[name] = baseL[name]
                        elif name in bL:
                            A = (sw * bL[name]["A"]).astype(np.float32)
                            dst[name] = {"A": A, "B": bL[name]["B"], "gate": bL[name].get("gate", np.array([0.0], dtype=np.float32))}
                    merged_layers.append(dst)
                sub = {"layers": merged_layers}
                # try infer rank increment from a present target
                try:
                    for i in range(num_layers):
                        any_name = next((n for n in tmap.keys() if n in bank_ad["layers"][i]), None)
                        if any_name:
                            inc = int(bank_ad["layers"][i][any_name]["B"].shape[0])
                            scaled_rank = int(scaled_rank + inc)
                            break
                except Exception:
                    pass
                picked += 1
        except Exception:
            pass

    # Optional rounding of LoRA factors
    if bool(round_lora):
        try:
            thr = float(max(0.0, round_threshold))
            for i in range(len(sub.get("layers", []))):
                for name, tensors in sub["layers"][i].items():
                    for key in ("A", "B"):
                        arr = tensors.get(key)
                        if not isinstance(arr, np.ndarray):
                            continue
                        q = float(np.median(np.abs(arr))) if arr.size > 0 else 0.0
                        if q <= 0:
                            continue
                        out = np.where(np.abs(arr) < (thr * q), 0.0, np.sign(arr) * q).astype(np.float32)
                        tensors[key] = out
        except Exception:
            pass

    # Final prompt with optional context
    final_prompt = prompt
    if bool(pack_context) and files:
        adapters_dir = os.path.dirname(adapters_npz)
        mf = load_manifest(adapters_dir)
        # Simple windows-based packing: use windows_index ranges, read from program root
        try:
            windows = load_windows_index(adapters_dir)
        except Exception:
            windows = []
        lines_out: List[str] = ["Program windows:"]
        used = 0
        budget = int(context_tokens)
        # Choose up to one top window per selected file
        for rel in files:
            rel_n = rel.replace("\\", "/")
            cand = [w for w in windows if (w.get("path") or "").replace("\\", "/") == rel_n]
            if not cand:
                continue
            w = cand[0]
            a = int(w.get("start_line", 1))
            b = int(w.get("end_line", max(a, a + 60)))
            abs_fp = rel if os.path.isabs(rel) else os.path.abspath(os.path.join(root, rel))
            try:
                src_lines = open(abs_fp, "r", encoding="utf-8", errors="ignore").read().splitlines()
            except Exception:
                continue
            a = max(1, min(a, len(src_lines)))
            b = max(a, min(b, len(src_lines)))
            block = [f"[ctx] path: {rel}:{a}-{b}"] + src_lines[a - 1 : b] + [""]
            text_block = "\n".join(block) + "\n"
            t = _tok_len(text_block)
            if used + t > budget:
                continue
            lines_out.extend(block)
            used += t
            if used >= budget:
                break
        packed = "\n".join(lines_out) if len(lines_out) > 1 else ""
        if packed:
            final_prompt = packed + "\n\n" + final_prompt
    if require_citations:
        # Tailor the example path to the first selected file for better compliance
        try:
            example_rel = files[0] if files else None
            example_path = example_rel if example_rel else "file.py"
        except Exception:
            example_path = "file.py"
        final_prompt = (
            final_prompt
            + f"\n\nInstruction: For EVERY claim, append a citation of the form {example_path}:START-END.\n"
              "Use only files shown in [ctx] above. Provide at least 3 citations overall.\n"
        )

    # Adapter-aware decoding: pointer-first nudge when citations are required
    if bool(adapter_aware_decoding) and bool(require_citations):
        try:
            example_rel = files[0] if files else None
            example_path = example_rel if example_rel else "file.py"
        except Exception:
            example_path = "file.py"
        final_prompt = (
            f"[pointer-first] Start with a citation like [{example_path}:A-B], then explain.\n\n"
            + final_prompt
        )
    ids = torch.tensor([_tok_encode(final_prompt)], dtype=torch.long, device=device)
    x = {"input_ids": ids}

    # Apply mixed adapters
    hooks = []
    def _parse_target_weights(spec: Optional[str]) -> Optional[Dict[str, float]]:
        if not spec:
            return None
        out: Dict[str, float] = {}
        try:
            for part in str(spec).split(","):
                part = part.strip()
                if not part:
                    continue
                if "=" in part:
                    k, v = part.split("=", 1)
                    k = k.strip()
                    try:
                        out[k] = float(v)
                    except Exception:
                        continue
                else:
                    out[part] = 1.0
            return out or None
        except Exception:
            return None
    tw = _parse_target_weights(target_weights) or {}
    # Optional question-aware reweighting
    if bool(q_aware_weights):
        try:
            ql = str(prompt).lower()
            mul: Dict[str, float] = {}
            if any(k in ql for k in ["signature", "param", "argument", "type", "prototype"]):
                mul.update({"o_proj": 1.10, "v_proj": 1.08})
            if any(k in ql for k in ["why", "fail", "error", "behavior", "incorrect", "bug"]):
                mul.update({"up_proj": 1.06, "down_proj": 1.05, "gate_proj": 1.04})
            if any(k in ql for k in ["where", "defined", "definition", "locate", "find"]):
                mul.update({"q_proj": 1.03})
            for k, m in mul.items():
                tw[k] = float(tw.get(k, 1.0)) * float(m)
        except Exception:
            pass
    # Optional ablations
    if bool(ablate_attn):
        for k in ("q_proj", "k_proj", "v_proj", "o_proj"):
            tw[k] = 0.0
    if bool(ablate_mlp):
        for k in ("up_proj", "down_proj", "gate_proj"):
            tw[k] = 0.0
    # Optional per-layer schedule (gentle rise toward top third)
    layer_multipliers: Optional[List[float]] = None
    if bool(layer_schedule):
        try:
            L_layers = len(base_layers or [])
            if L_layers > 0:
                layer_multipliers = []
                for i in range(L_layers):
                    frac = float(i) / float(max(1, L_layers - 1))
                    if frac < (1.0 / 3.0):
                        lm = 0.95 + 0.15 * (frac / (1.0 / 3.0))
                    elif frac < (2.0 / 3.0):
                        lm = 1.05 + 0.05 * ((frac - (1.0 / 3.0)) / (1.0 / 3.0))
                    else:
                        lm = 1.10 + 0.05 * ((frac - (2.0 / 3.0)) / (1.0 / 3.0))
                    layer_multipliers.append(float(lm))
        except Exception:
            layer_multipliers = None
    # Optional per-target rank trimming (global per target; optional budget)
    per_target_keep: Optional[Dict[str, int]] = None
    if bool(per_target_rank_schedule):
        try:
            # Heuristic fractions by target group
            base_frac: Dict[str, float] = {
                "o_proj": 1.00, "up_proj": 1.00, "down_proj": 0.90, "gate_proj": 0.80,
                "q_proj": 0.70, "k_proj": 0.65, "v_proj": 0.60,
            }
            per_target_keep = {}
            for t, frac in base_frac.items():
                keep = int(max(1, min(int(scaled_rank), round(int(scaled_rank) * float(frac)))))
                per_target_keep[t] = keep
            # Apply global per-layer rank budget if requested
            try:
                budget = int(max(0, int(rank_budget)))
            except Exception:
                budget = 0
            if budget > 0 and per_target_keep:
                total = int(sum(int(v) for v in per_target_keep.values()))
                if total > budget:
                    scale = float(budget) / float(max(1, total))
                    for t in list(per_target_keep.keys()):
                        per_target_keep[t] = int(max(1, round(int(per_target_keep[t]) * scale)))
        except Exception:
            per_target_keep = None
    alpha_used = float(alpha * (0.5 if bool(alpha_warmup) else 1.0))
    # Optional layer-tiered per-target keeps
    per_target_keep_layers: Optional[List[Dict[str, int]]] = None
    if bool(layer_rank_tiers):
        try:
            L_layers = len(base_layers or [])
            if L_layers > 0:
                per_target_keep_layers = []
                def tier_for(frac: float) -> str:
                    if frac < (1.0/3.0): return "low"
                    if frac < (2.0/3.0): return "mid"
                    return "top"
                for i in range(L_layers):
                    frac = float(i) / float(max(1, L_layers - 1))
                    tier = tier_for(frac)
                    # desired keeps by group
                    if tier == "low":
# ... truncated ...


from model.inspect import detect_target_names_from_model_full
from modules.mixing import (
    register_hook_mixed_adapters,
)
from modules.caches import load_manifest, load_windows_index, pick_files_from_windows
from modules.citations import CitationManager, CitationPolicy
from modules.interpret import (
    is_block,
    block_out_hook,
    truncate_batch,
    get_W,
)
from modules.program_state import (
    load_program_state,
    save_program_state,
    join_program_states,
    new_state_from_run,
    changed_bits,
)

def _normalize_citations_regex():
    try:
        import re
        return re.compile(r"(?:path:\s*)?([A-Za-z0-9_./\\\-]+?\.\w+):(\d+)(?:-(\d+))?")
    except Exception:
        return None

def normalize_citations(text: str) -> List[tuple[str, int, int]]:
    rx = _normalize_citations_regex()
    if rx is None:
        return []
    out: List[tuple[str, int, int]] = []
    try:
        import os as _os
        for m in rx.finditer(text or ""):
            p = m.group(1)
            try:
                a = int(m.group(2) or "0")
            except Exception:
                a = 0
            try:
                b = int(m.group(3) or a)
            except Exception:
                b = a
            out.append((p.replace("\\\\", "/"), min(a, b), max(a, b)))
        return out


    is_block,
    block_out_hook,
    truncate_batch,
    get_W,
)
from modules.program_state import (
    load_program_state,
    save_program_state,
    join_program_states,
    new_state_from_run,
    changed_bits,
)

def _normalize_citations_regex():
    try:
        import re
        return re.compile(r"(?:path:\s*)?([A-Za-z0-9_./\\\-]+?\.\w+):(\d+)(?:-(\d+))?")
    except Exception:
        return None

def normalize_citations(text: str) -> List[tuple[str, int, int]]:
    rx = _normalize_citations_regex()
    if rx is None:
        return []
    out: List[tuple[str, int, int]] = []
    try:
        import os as _os
        for m in rx.finditer(text or ""):
            p = m.group(1)
            try:
                a = int(m.group(2) or "0")
            except Exception:
                a = 0
            try:
                b = int(m.group(3) or a)
            except Exception:
                b = a
            out.append((p.replace("\\\\", "/"), min(a, b), max(a, b)))
        return out
    except Exception:
        return []

def has_citations(s: str, per_para: bool) -> bool:
    try:
        import re as _re
        rx = _re.compile(r"(?:path:\s*)?[A-Za-z0-9_./\\-]+?\.\w+:\d+(?:-\d+)?")
        if not rx.search(s or ""):
            return False
        if per_para:
            paras = [p.strip() for p in (s or "").split("\n\n") if p.strip()]
            return all(rx.search(p) for p in paras)
        return True
    except Exception:
        return False

def generate_answer(
    model_id: str,
    adapters_npz: str,
    prompt: str,
    *,
    program_root: Optional[str] = None,


    if rx is None:
        return []
    out: List[tuple[str, int, int]] = []
    try:
        import os as _os
        for m in rx.finditer(text or ""):
            p = m.group(1)
            try:
                a = int(m.group(2) or "0")
            except Exception:
                a = 0
            try:
                b = int(m.group(3) or a)
            except Exception:
                b = a
            out.append((p.replace("\\\\", "/"), min(a, b), max(a, b)))
        return out
    except Exception:
        return []

def has_citations(s: str, per_para: bool) -> bool:
    try:
        import re as _re
        rx = _re.compile(r"(?:path:\s*)?[A-Za-z0-9_./\\-]+?\.\w+:\d+(?:-\d+)?")
        if not rx.search(s or ""):
            return False
        if per_para:
            paras = [p.strip() for p in (s or "").split("\n\n") if p.strip()]
            return all(rx.search(p) for p in paras)
        return True
    except Exception:
        return False

def generate_answer(
    model_id: str,
    adapters_npz: str,
    prompt: str,
    *,
    program_root: Optional[str] = None,
    delta_cap: float = 0.05,
    cache_dir: Optional[str] = None,
    device: str = "cuda" if torch.cuda.is_available() else "cpu",
    device_map: str = "none",
    gpu_ids: Optional[str] = None,
    # selection
    of_sources: str = "question",
    zoom_symbol: Optional[str] = None,
    zoom_radius: int = 0,
    ignore: Optional[List[str]] = None,
    # context
    pack_context: bool = False,
    pack_mode: str = "heads",


            except Exception:
                b = a
            out.append((p.replace("\\\\", "/"), min(a, b), max(a, b)))
        return out
    except Exception:
        return []

def has_citations(s: str, per_para: bool) -> bool:
    try:
        import re as _re
        rx = _re.compile(r"(?:path:\s*)?[A-Za-z0-9_./\\-]+?\.\w+:\d+(?:-\d+)?")
        if not rx.search(s or ""):
            return False
        if per_para:
            paras = [p.strip() for p in (s or "").split("\n\n") if p.strip()]
            return all(rx.search(p) for p in paras)
        return True
    except Exception:
        return False

def generate_answer(
    model_id: str,
    adapters_npz: str,
    prompt: str,
    *,
    program_root: Optional[str] = None,
    delta_cap: float = 0.05,
    cache_dir: Optional[str] = None,
    device: str = "cuda" if torch.cuda.is_available() else "cpu",
    device_map: str = "none",
    gpu_ids: Optional[str] = None,
    # selection
    of_sources: str = "question",
    zoom_symbol: Optional[str] = None,
    zoom_radius: int = 0,
    ignore: Optional[List[str]] = None,
    # context
    pack_context: bool = False,
    pack_mode: str = "heads",
    context_tokens: int = 2000,
    function_first: bool = False,
    ff_max_candidates: int = 24,
    ff_window_lines: int = 80,
    ff_threshold: float = 0.55,
    ff_noise_penalty: float = 0.30,
    # capacity/mixing
    alpha: float = 16.0,
    rank: int = 12,
    gsub: float = 0.75,
    beta: float = 0.1,
    entropy_aware: bool = False,
    rank_min: int = 8,
    rank_max: int = 32,
    gsub_min: float = 0.6,
    gsub_max: float = 0.9,
    entropy_weights: str = "program=0.4,subgraph=0.4,question=0.2",
    target_weights: Optional[str] = None,
    layer_schedule: bool = False,
    q_aware_weights: bool = False,
    mixture_m: int = 0,
    adapters_bank: Optional[str] = None,
    per_target_rank_schedule: bool = False,
    rank_budget: int = 0,
    ablate_attn: bool = False,
    ablate_mlp: bool = False,
    alpha_warmup: bool = False,
    adapter_aware_decoding: bool = False,
    layer_rank_tiers: bool = False,
    # cones/rounding
    # cones/rounding
    cone_rank: int = 2,
    cone_weight: float = 0.5,
    round_lora: bool = False,
    round_threshold: float = 0.5,
    # citations
    require_citations: bool = False,
    citations_per_paragraph: bool = False,
    # retrieval/rerank
    rerank: bool = True,
    self_queries_path: Optional[str] = None,
    # generation
    do_sample: bool = False,
    temperature: float = 0.7,
    top_p: float = 0.9,
    repetition_penalty: float = 1.1,
    min_new_tokens: int = 64,
    max_new_tokens: int = 256,
    kv_window: int = 0,
    head_device: str = "same",  # "cpu" | "auto" | "same"
    # misc
    seed: int = 0,
    verbose: bool = False,
    # provenance footer
    commit_footer: bool = False,
    # monotone selection for non-structured path
    monotone_selection: bool = False,
) -> str:
    # Program root (path or URI) for reading artifacts/windows
    root = str(program_root) if (program_root is not None and str(program_root).strip()) else ""
    if gpu_ids and str(gpu_ids).strip():
        os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_ids).strip()
    os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")

    # Seed
    try:
        import random
        random.seed(int(seed))
        np.random.seed(int(seed))
        torch.manual_seed(int(seed))
    except Exception:
        pass

    # Prefer explicit cache_dir; else env; else project root (/..../checkpoints)
    if not cache_dir:
        env_cache = os.environ.get("TRANSFORMER_CACHE_DIR") or os.environ.get("HF_HOME")
        if env_cache:
            cache_dir = env_cache
        else:
            mod_dir = os.path.dirname(__file__)
            proj_root = os.path.abspath(os.path.join(mod_dir, "..", "..", ".."))
            cache_dir = os.path.join(proj_root, "checkpoints")
    try:
        os.makedirs(cache_dir, exist_ok=True)
    except Exception:
        pass

    # Local tokenizer (no transformers)
    snap_dir = ensure_snapshot(model_id, cache_dir)
    tok_local = LocalLlamaTokenizer(snap_dir)
    class _TokAdapter:
        def __init__(self, base):
            self._b = base
        class _Ret:
            def __init__(self, ids):
                self.input_ids = ids
        def __call__(self, text: str, add_special_tokens: bool = False, return_tensors: str | None = None):
            ids = self._b.encode(text)
            if return_tensors == "pt":
                return {"input_ids": torch.tensor([ids], dtype=torch.long)}
            return _TokAdapter._Ret(ids)
    tok = _TokAdapter(tok_local)
    def _tok_encode(text: str) -> List[int]:
        return tok_local.encode(text)
    def _tok_len(text: str) -> int:
        try:
            return len(tok_local.encode(text))
        except Exception:
            return 0
    def _tok_decode(ids: torch.Tensor | List[int]) -> str:
        if isinstance(ids, torch.Tensor):
            try:
                ids_l = ids.to("cpu").tolist()
            except Exception:
                ids_l = []
        else:
            ids_l = list(ids)
        try:
            return tok_local.decode(ids_l, skip_special_tokens=True)
        except Exception:
            return tok_local.decode(ids_l)
    torch_dtype = torch.bfloat16 if str(device).startswith("cuda") else torch.float32

    model, _cfg = build_local_llama_from_snapshot(snap_dir, device, torch_dtype, device_map=device_map, gpu_ids=gpu_ids)

    # Load base adapters
    base_layers = load_adapters_npz(adapters_npz)["layers"]

    # Selection via caches (program-agnostic): prefer windows with prompt overlap
    files: List[str] = []
    try:
        adapters_dir = os.path.dirname(adapters_npz)
        windows = load_windows_index(adapters_dir)
        files = pick_files_from_windows(root, windows, prompt, k=max(8, int(ff_max_candidates)))
    except Exception:
        files = []
    modules: List[str] = []

    # Subgraph embedding
    # Program-agnostic: skip subgraph embedding if no backend embedder; use base only
    sub = {"layers": []}

    # Shapes and targets
    tmap = targets_map("local")
    t_shapes = infer_target_shapes(model)
    num_layers = len(getattr(model, "blocks", []))
    d_model_local = int(t_shapes.get("q_proj", (0, 0))[0]) or int(getattr(getattr(model, "cfg", None), "d_model", 0) or 0)

    # Entropy-aware capacity
    scaled_rank = int(rank)
    scaled_gsub = float(gsub)
    entropy_diag: Optional[Dict[str, float]] = None

    # No subgraph z available -> keep sub empty (base-only mixing)
    sub = {"layers": []}

    # Function-first cones: build and merge
    cr = max(0, int(cone_rank))
    # Skip function-first cones in program-agnostic core (requires backend embedder)

    # Optional mixture bank: mix top-m module adapters from bank by concatenation (Σ π_i Δθ_i)
    if adapters_bank and int(mixture_m) > 0:
        try:
            import glob
            bank_root = os.path.abspath(os.path.expanduser(os.path.expandvars(adapters_bank)))
            sel_mods = [m for m in (modules or []) if m]
            picked = 0
            for mod in sel_mods:
                if picked >= int(mixture_m):
                    break
                mod_dir1 = os.path.join(bank_root, "sub_adapters", mod.replace("/", "_"))
                mod_dir2 = os.path.join(bank_root, mod.replace("/", "_"))
                cand = None
                for d in (mod_dir1, mod_dir2):
                    fp = os.path.join(d, "adapters.npz")
                    if os.path.isfile(fp):
                        cand = fp
                        break
                if not cand:
                    continue
                try:
                    bank_ad = load_adapters_npz(cand)
                except Exception:
                    continue
                # uniform π for now
                w = 1.0 / float(min(len(sel_mods), int(mixture_m)))
                sw = float(max(0.0, min(1.0, w))) ** 0.5
                # per-layer concat
                merged_layers = []
                for i in range(num_layers):
                    baseL = sub["layers"][i]
                    bL = bank_ad["layers"][i] if i < len(bank_ad.get("layers", [])) else {}
                    dst: Dict[str, Dict[str, np.ndarray]] = {}
                    for name in tmap.keys():
                        if (name in baseL) and (name in bL):
                            A1 = baseL[name]["A"]; B1 = baseL[name]["B"]
                            A2 = (sw * bL[name]["A"]).astype(np.float32); B2 = (sw * bL[name]["B"]).astype(np.float32)
                            A = np.concatenate([A1, A2], axis=1)
                            B = np.concatenate([B1, B2], axis=0)
                            dst[name] = {"A": A, "B": B, "gate": baseL[name].get("gate", np.array([0.0], dtype=np.float32))}
                        elif name in baseL:
                            dst[name] = baseL[name]
                        elif name in bL:
                            A = (sw * bL[name]["A"]).astype(np.float32)
                            dst[name] = {"A": A, "B": bL[name]["B"], "gate": bL[name].get("gate", np.array([0.0], dtype=np.float32))}
                    merged_layers.append(dst)
                sub = {"layers": merged_layers}
                # try infer rank increment from a present target
                try:
                    for i in range(num_layers):
                        any_name = next((n for n in tmap.keys() if n in bank_ad["layers"][i]), None)
                        if any_name:
                            inc = int(bank_ad["layers"][i][any_name]["B"].shape[0])
                            scaled_rank = int(scaled_rank + inc)
                            break
                except Exception:
                    pass
                picked += 1
        except Exception:
            pass

    # Optional rounding of LoRA factors
    if bool(round_lora):
        try:
            thr = float(max(0.0, round_threshold))
            for i in range(len(sub.get("layers", []))):
                for name, tensors in sub["layers"][i].items():
                    for key in ("A", "B"):
                        arr = tensors.get(key)
                        if not isinstance(arr, np.ndarray):
                            continue
                        q = float(np.median(np.abs(arr))) if arr.size > 0 else 0.0
                        if q <= 0:
                            continue
                        out = np.where(np.abs(arr) < (thr * q), 0.0, np.sign(arr) * q).astype(np.float32)
                        tensors[key] = out
        except Exception:
            pass

    # Final prompt with optional context
    final_prompt = prompt
    if bool(pack_context) and files:
        adapters_dir = os.path.dirname(adapters_npz)
        mf = load_manifest(adapters_dir)
        # Simple windows-based packing: use windows_index ranges, read from program root
        try:
            windows = load_windows_index(adapters_dir)
        except Exception:
            windows = []
        lines_out: List[str] = ["Program windows:"]
        used = 0
        budget = int(context_tokens)
        # Choose up to one top window per selected file
        for rel in files:
            rel_n = rel.replace("\\", "/")
            cand = [w for w in windows if (w.get("path") or "").replace("\\", "/") == rel_n]
            if not cand:
                continue
            w = cand[0]
            a = int(w.get("start_line", 1))
            b = int(w.get("end_line", max(a, a + 60)))
            abs_fp = rel if os.path.isabs(rel) else os.path.abspath(os.path.join(root, rel))
            try:
                src_lines = open(abs_fp, "r", encoding="utf-8", errors="ignore").read().splitlines()
            except Exception:
                continue
            a = max(1, min(a, len(src_lines)))
            b = max(a, min(b, len(src_lines)))
            block = [f"[ctx] path: {rel}:{a}-{b}"] + src_lines[a - 1 : b] + [""]
            text_block = "\n".join(block) + "\n"
            t = _tok_len(text_block)
            if used + t > budget:
                continue
            lines_out.extend(block)
            used += t
            if used >= budget:
                break
        packed = "\n".join(lines_out) if len(lines_out) > 1 else ""
        if packed:
            final_prompt = packed + "\n\n" + final_prompt
    if require_citations:
        # Tailor the example path to the first selected file for better compliance
        try:
            example_rel = files[0] if files else None
            example_path = example_rel if example_rel else "file.py"
        except Exception:
            example_path = "file.py"
        final_prompt = (
            final_prompt
            + f"\n\nInstruction: For EVERY claim, append a citation of the form {example_path}:START-END.\n"
              "Use only files shown in [ctx] above. Provide at least 3 citations overall.\n"
        )

    # Adapter-aware decoding: pointer-first nudge when citations are required
    if bool(adapter_aware_decoding) and bool(require_citations):
        try:
            example_rel = files[0] if files else None
            example_path = example_rel if example_rel else "file.py"
        except Exception:
            example_path = "file.py"
        final_prompt = (
            f"[pointer-first] Start with a citation like [{example_path}:A-B], then explain.\n\n"
            + final_prompt
        )
    ids = torch.tensor([_tok_encode(final_prompt)], dtype=torch.long, device=device)
    x = {"input_ids": ids}

    # Apply mixed adapters
    hooks = []
    def _parse_target_weights(spec: Optional[str]) -> Optional[Dict[str, float]]:
        if not spec:
            return None
        out: Dict[str, float] = {}
        try:
            for part in str(spec).split(","):
                part = part.strip()
                if not part:
                    continue
                if "=" in part:
                    k, v = part.split("=", 1)
                    k = k.strip()
                    try:
                        out[k] = float(v)
                    except Exception:
                        continue
                else:
                    out[part] = 1.0
            return out or None
        except Exception:
            return None
    tw = _parse_target_weights(target_weights) or {}
    # Optional question-aware reweighting
    if bool(q_aware_weights):
        try:
            ql = str(prompt).lower()
            mul: Dict[str, float] = {}
            if any(k in ql for k in ["signature", "param", "argument", "type", "prototype"]):
                mul.update({"o_proj": 1.10, "v_proj": 1.08})
            if any(k in ql for k in ["why", "fail", "error", "behavior", "incorrect", "bug"]):
                mul.update({"up_proj": 1.06, "down_proj": 1.05, "gate_proj": 1.04})
            if any(k in ql for k in ["where", "defined", "definition", "locate", "find"]):
                mul.update({"q_proj": 1.03})
            for k, m in mul.items():
                tw[k] = float(tw.get(k, 1.0)) * float(m)
        except Exception:
            pass
    # Optional ablations
    if bool(ablate_attn):
        for k in ("q_proj", "k_proj", "v_proj", "o_proj"):
            tw[k] = 0.0
    if bool(ablate_mlp):
        for k in ("up_proj", "down_proj", "gate_proj"):
            tw[k] = 0.0
    # Optional per-layer schedule (gentle rise toward top third)
    layer_multipliers: Optional[List[float]] = None
    if bool(layer_schedule):
        try:
            L_layers = len(base_layers or [])
            if L_layers > 0:
                layer_multipliers = []
                for i in range(L_layers):
                    frac = float(i) / float(max(1, L_layers - 1))
                    if frac < (1.0 / 3.0):
                        lm = 0.95 + 0.15 * (frac / (1.0 / 3.0))
                    elif frac < (2.0 / 3.0):
                        lm = 1.05 + 0.05 * ((frac - (1.0 / 3.0)) / (1.0 / 3.0))
                    else:
                        lm = 1.10 + 0.05 * ((frac - (2.0 / 3.0)) / (1.0 / 3.0))
                    layer_multipliers.append(float(lm))
        except Exception:
            layer_multipliers = None
    # Optional per-target rank trimming (global per target; optional budget)
    per_target_keep: Optional[Dict[str, int]] = None
    if bool(per_target_rank_schedule):
        try:
            # Heuristic fractions by target group
            base_frac: Dict[str, float] = {
                "o_proj": 1.00, "up_proj": 1.00, "down_proj": 0.90, "gate_proj": 0.80,
                "q_proj": 0.70, "k_proj": 0.65, "v_proj": 0.60,
            }
            per_target_keep = {}
            for t, frac in base_frac.items():
                keep = int(max(1, min(int(scaled_rank), round(int(scaled_rank) * float(frac)))))
                per_target_keep[t] = keep
            # Apply global per-layer rank budget if requested
            try:
                budget = int(max(0, int(rank_budget)))
            except Exception:
                budget = 0
            if budget > 0 and per_target_keep:
                total = int(sum(int(v) for v in per_target_keep.values()))
                if total > budget:
                    scale = float(budget) / float(max(1, total))
                    for t in list(per_target_keep.keys()):
                        per_target_keep[t] = int(max(1, round(int(per_target_keep[t]) * scale)))
        except Exception:
            per_target_keep = None
    alpha_used = float(alpha * (0.5 if bool(alpha_warmup) else 1.0))
    # Optional layer-tiered per-target keeps
    per_target_keep_layers: Optional[List[Dict[str, int]]] = None
    if bool(layer_rank_tiers):
        try:
            L_layers = len(base_layers or [])
            if L_layers > 0:
                per_target_keep_layers = []
                def tier_for(frac: float) -> str:
                    if frac < (1.0/3.0): return "low"
                    if frac < (2.0/3.0): return "mid"
                    return "top"
                for i in range(L_layers):
                    frac = float(i) / float(max(1, L_layers - 1))
                    tier = tier_for(frac)
                    # desired keeps by group
                    if tier == "low":
                        vals = {"q_proj": 2, "k_proj": 2, "v_proj": 8, "o_proj": 8, "up_proj": 12, "down_proj": 12}
                        vals["gate_proj"] = min(8, int(0.5 * vals["up_proj"]))  # 6
                    elif tier == "mid":
                        vals = {"q_proj": 3, "k_proj": 3, "v_proj": 12, "o_proj": 12, "up_proj": 16, "down_proj": 16}
                        vals["gate_proj"] = min(8, int(0.5 * vals["up_proj"]))  # 8
                    else:
                        vals = {"q_proj": 4, "k_proj": 4, "v_proj": 16, "o_proj": 16, "up_proj": 24, "down_proj": 24}
                        vals["gate_proj"] = min(8, int(0.5 * vals["up_proj"]))  # 8
                    # cap by scaled_rank and >=1
                    for k in list(vals.keys()):
                        vals[k] = int(max(1, min(int(scaled_rank), int(vals[k]))))
                    per_target_keep_layers.append(vals)
        except Exception:
            per_target_keep_layers = None
    hooks = register_hook_mixed_adapters(
        model,
        base_layers,
        sub.get("layers"),
        alpha_star=float(alpha_used),
        g_sub=float(scaled_gsub),
        rank=int(scaled_rank),
        beta=float(beta),
        target_weights=tw,
        backend="local",
        layer_multipliers=layer_multipliers,
        per_target_keep=per_target_keep,
        per_target_keep_layers=per_target_keep_layers,
        delta_cap=float(max(0.0, delta_cap)),
    )

    # Generation (always use model.generate for stability)
    if verbose:
        print("[debug] generating...")
    try:
        gen_kwargs = {
            "max_new_tokens": int(max_new_tokens),
            "do_sample
# ... truncated ...