"""
NexusLoRA  ⚡🛡️🧠🔮
Unified LLM Fine-Tuning Engine  —  Tam Birleşik Tek Sınıf

NexusLoRA v1.0  (Ömür Bera Işık)
  ⚡  Custom Triton kernels (RMSNorm, SwiGLU, RoPE)
  ⚡  Fused backward pass + torch.compile fullgraph
  🧠  Mixture of Experts (MoE) router + sparse activation
  🧠  Optuna hyperparameter tuning
  💾  CPU/NVMe offloading (ZeRO-Infinity style)
  💾  2-bit quantization (independent of bitsandbytes)
  🛡️  Smart OOM recovery + VRAM guard
  🛡️  All features True/False + 0.0-1.0 power control

NexusLoRA v1.0  (Ömür Bera Işık)
  💎  CrystalCore™        — Runtime kernel crystallization
  🧬  MorphicMemory™      — Markov-predicted tensor reuse + GC
  🎵  SpectraOptimizer™   — Frequency-domain adaptive optimizer
  🎼  ResonanceScheduler™ — Self-tuning LR via gradient spectrum
  🌈  ChromaticPrecision™ — Per-layer dynamic dtype assignment
  🌊  GradientHarmonics™  — Wavelet gradient processing
  🧠  NeuralProfiler™     — LSTM-based OOM/explode prediction
  🔮  CrystalPipeline™    — Dynamic grad-accum + async checkpoint
  ♻️   ZeroWaste™          — Dead-param elimination
  🌐  UniversalAdapter™   — HF/TRL/PEFT/DeepSpeed auto-patch

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Mimari:
  NexusLoRA modülleri doğrudan NexusLoRA sınıfı içine entegre
  edilmiştir. NexusEngine ara sınıfı yoktur; tek giriş noktası
  NexusLoRA'dır.

Hızlı başlangıç:
    fl = NexusLoRA("meta-llama/Llama-3.2-3B",
                  nexus_enabled=True, nexus_power=1.0)
    model, tokenizer = fl.load()
    trainer = fl.get_trainer(dataset)
    fl.train(trainer)

Sadece NexusLoRA:
    fl = NexusLoRA("meta-llama/Llama-3.2-3B", nexus_enabled=False)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"""
from __future__ import annotations

__version__ = "1.0.0"
__author__  = "Ömür Bera Işık <fastloraoffical@gmail.com>"
__all__     = ["NexusLoRA", "NexusLoRAConfig"]

import collections, gc, hashlib, json, logging, math, os, queue
import random, sys, threading, time, traceback, warnings
from dataclasses import dataclass, field
from functools import wraps
from pathlib import Path
from typing import (Any, Callable, Dict, List, Literal,
                    Optional, Set, Tuple, Union)

import torch
import torch.nn as nn
import torch.nn.functional as F

# ── Logging ───────────────────────────────────────────────────────────────────
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [NexusLoRA] %(levelname)s: %(message)s",
    datefmt="%H:%M:%S",
)
logger = logging.getLogger("NexusLoRA")
warnings.filterwarnings("ignore", category=UserWarning)
warnings.filterwarnings("ignore", category=FutureWarning)

_TORCH_VER      = tuple(int(x) for x in torch.__version__.split(".")[:2])
_HAS_COMPILE    = _TORCH_VER >= (2, 0)
_HAS_SDPA       = hasattr(F, "scaled_dot_product_attention")
_HAS_FUSED_ADAM = _TORCH_VER >= (2, 0)
_HAS_BF16       = torch.cuda.is_available() and torch.cuda.is_bf16_supported()

_MIN_VERSIONS = {
    "torch": "2.1.0", "transformers": "4.40.0", "accelerate": "0.27.0",
    "bitsandbytes": "0.43.0", "peft": "0.10.0", "trl": "0.8.0",
}


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 1 — BİRLEŞİK HATA SİSTEMİ  (NexusLoRA ErrorReport + NexusLoRA NexusError)
# ══════════════════════════════════════════════════════════════════════════════
# Her iki sistemin hata kayıtları tek havuzda toplanır.
# NexusError daha gelişmiş: thread-lock, impact seviyeleri, guard() context manager.
# ErrorReport, NexusLoRA'nın mevcut çağrı imzası korunarak NexusError üzerine köprü kurar.

class NexusError:
    """
    Birleşik hata yönetimi — hiçbir hata sistemi durduramaz.
    Her hata: KOD + NE + NEDEN + ÇÖZÜM + PERFORMANS ETKİSİ.
    """
    _registry: List[Dict] = []
    _lock = threading.Lock()

    @classmethod
    def report(cls, code: str, what: str, why: str, fix: str,
               impact: str = "minimal", exc: Exception = None, fatal: bool = False):
        with cls._lock:
            entry = dict(time=time.strftime("%H:%M:%S"), code=code,
                         what=what, why=why, fix=fix, impact=impact,
                         detail=str(exc) if exc else None,
                         tb=traceback.format_exc() if exc else None)
            cls._registry.append(entry)

        sym = {"minimal": "🟡", "moderate": "🟠",
               "severe":  "🔴", "none":     "🟢"}.get(impact, "⚪")
        border = "═" * 62
        logger.error(f"\n{border}")
        logger.error(f"  ❌  [{code}]")
        logger.error(f"  📋  Ne oldu     : {what}")
        logger.error(f"  🔍  Neden       : {why}")
        logger.error(f"  🔧  Çözüm       : {fix}")
        logger.error(f"  {sym}  Performans  : {impact}")
        if exc:
            logger.error(f"  💬  Detay       : {exc}")
        logger.error(border)
        if fatal:
            raise RuntimeError(f"[NexusLoRA] Fatal: {what}")

    @classmethod
    def guard(cls, code: str, what: str, impact: str = "minimal"):
        """Context manager: hata olursa yutup loglar, sistemi durdurmaz."""
        class _G:
            def __enter__(self_): return self_
            def __exit__(self_, t, v, tb):
                if v is not None:
                    cls.report(code, what, str(v),
                               "Otomatik geri dönüş aktif", impact, exc=v)
                    return True
        return _G()

    @classmethod
    def summary(cls):
        n = len(cls._registry)
        if n == 0:
            logger.info("Hata Özeti   : ✅  Sıfır hata — mükemmel çalışma")
            return
        logger.info(f"Hata Özeti   : {n} hata oluştu:")
        for i, e in enumerate(cls._registry, 1):
            logger.info(f"  {i:2d}. [{e['time']}] {e['code']}: {e['what']}")

    @classmethod
    def save(cls, path: str = "./nexuslora_errors.json"):
        try:
            with open(path, "w", encoding="utf-8") as f:
                json.dump(cls._registry, f, ensure_ascii=False, indent=2)
            if cls._registry:
                logger.info(f"Hata Raporu  : → {path}")
        except Exception:
            pass

    @classmethod
    def clear(cls):
        with cls._lock:
            cls._registry.clear()


# NexusLoRA uyumluluk köprüsü — mevcut kod değişmeden çalışır
class ErrorReport:
    """NexusLoRA v1.0 uyumluluk köprüsü → NexusError'a yönlendirir."""
    _history = NexusError._registry  # Aynı liste

    @classmethod
    def report(cls, error_type, what, why, fix, exception=None, fatal=False):
        NexusError.report(
            code=error_type, what=what, why=why, fix=fix,
            impact="severe" if fatal else "minimal",
            exc=exception, fatal=fatal)

    @classmethod
    def oom_report(cls, step, batch_size, new_batch, vram_used, vram_total):
        NexusError.report(
            code="OUT_OF_MEMORY",
            what=f"Step {step} sırasında GPU belleği doldu",
            why=f"VRAM kullanımı {vram_used:.1f}GB / {vram_total:.1f}GB",
            fix=f"Batch size {batch_size}→{new_batch} küçültüldü, step {step}'den devam",
            impact="moderate")

    @classmethod
    def summary(cls):
        NexusError.summary()

    @classmethod
    def save(cls, path="./fastlora_errors.json"):
        NexusError.save(path)


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 2 — BAĞIMLILIK KONTROLÜ
# ══════════════════════════════════════════════════════════════════════════════

def _version_tuple(v: str) -> tuple:
    try: return tuple(int(x) for x in v.split(".")[:3])
    except: return (0, 0, 0)

def _check_deps(strict: bool = False) -> Dict[str, bool]:
    result: Dict[str, bool] = {}
    for pkg in ["torch","transformers","accelerate","peft","bitsandbytes",
                "flash_attn","trl","datasets","triton","deepspeed","optuna"]:
        try:
            __import__(pkg); result[pkg] = True
            if pkg in _MIN_VERSIONS:
                import importlib.metadata
                try:
                    inst = importlib.metadata.version(pkg)
                    req  = _MIN_VERSIONS[pkg]
                    if _version_tuple(inst) < _version_tuple(req):
                        msg = f"{pkg} sürüm uyumsuzluğu: {inst} < {req}"
                        if strict:
                            ErrorReport.report("VERSION_MISMATCH", msg,
                                f"{pkg} minimum {req} gerekli", f"pip install {pkg}>={req}",
                                fatal=True)
                        else:
                            logger.warning(f"⚠️  {msg}")
                except importlib.metadata.PackageNotFoundError:
                    pass
        except ImportError:
            result[pkg] = False
    return result

DEPS: Dict[str, bool] = {}


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 3 — CUSTOM TRITON KERNELS  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class TritonKernels:
    @staticmethod
    def build_rmsnorm():
        if DEPS.get("triton"):
            try:
                import triton, triton.language as tl

                @triton.jit
                def _rms_norm_fwd(X, W, Y, stride, N, eps, BLOCK: tl.constexpr):
                    row = tl.program_id(0)
                    X  += row * stride; Y += row * stride
                    cols= tl.arange(0, BLOCK); mask = cols < N
                    x   = tl.load(X + cols, mask=mask, other=0.).to(tl.float32)
                    var = tl.sum(x * x, 0) / N
                    w   = tl.load(W + cols, mask=mask, other=1.)
                    tl.store(Y + cols, (x / tl.sqrt(var + eps) * w).to(tl.float16), mask=mask)

                class TritonRMSNorm(nn.Module):
                    def __init__(self, h, eps=1e-6):
                        super().__init__()
                        self.weight = nn.Parameter(torch.ones(h)); self.eps = eps
                    def forward(self, x):
                        d = x.dtype; x = x.float()
                        return (x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)).to(d) * self.weight
                return TritonRMSNorm
            except Exception as e:
                NexusError.report("TRITON_KERNEL", "Triton RMSNorm derlenemedi",
                    str(e), "PyTorch fallback kullanılıyor")

        class FastRMSNorm(nn.Module):
            def __init__(self, h, eps=1e-6):
                super().__init__()
                self.weight = nn.Parameter(torch.ones(h)); self.eps = eps
            def forward(self, x):
                d = x.dtype; x = x.float()
                return (x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)).to(d) * self.weight
        return FastRMSNorm

    @staticmethod
    def build_swiglu():
        class FastSwiGLU(nn.Module):
            def forward(self, x, gate): return F.silu(x) * gate
        return FastSwiGLU


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 4 — 2-BIT QUANTIZATION  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class TwoBitQuantizer:
    NF2_VALUES = torch.tensor([-1.0, -0.3333, 0.3333, 1.0])

    @classmethod
    def quantize_tensor(cls, x):
        scale = x.abs().max().clamp(min=1e-8)
        x_norm = x / scale
        vals = cls.NF2_VALUES.to(x.device)
        indices = (x_norm.unsqueeze(-1) - vals).abs().argmin(dim=-1).to(torch.uint8)
        return indices, scale

    @classmethod
    def dequantize_tensor(cls, indices, scale):
        return cls.NF2_VALUES.to(indices.device)[indices.long()] * scale

    @classmethod
    def quantize_model(cls, model, skip_modules=("lm_head", "embed")) -> int:
        replaced = 0
        try:
            for name, module in list(model.named_modules()):
                if not isinstance(module, nn.Linear): continue
                if any(s in name for s in skip_modules): continue
                w_idx, w_scale = cls.quantize_tensor(module.weight.data)
                module.weight_2bit  = nn.Parameter(w_idx, requires_grad=False)
                module.weight_scale = nn.Parameter(w_scale, requires_grad=False)
                module._2bit_enabled = True
                orig_fw = module.forward
                def make_fw(mod):
                    def fw(x):
                        if getattr(mod, "_2bit_enabled", False):
                            w = TwoBitQuantizer.dequantize_tensor(
                                mod.weight_2bit, mod.weight_scale
                            ).to(x.dtype).reshape(mod.weight.shape)
                            return F.linear(x, w, mod.bias)
                        return orig_fw(x)
                    return fw
                module.forward = make_fw(module)
                replaced += 1
        except Exception as e:
            NexusError.report("2BIT_QUANT", "2-bit quant kısmen başarısız",
                str(e), "Etkilenen katmanlar orijinal precision ile devam ediyor")
        return replaced


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 5 — CPU/NVMe OFFLOADING  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class OffloadManager:
    def __init__(self, cfg): self.cfg = cfg; self._offloaded_states: Dict = {}

    def offload_optimizer_state(self, optimizer) -> bool:
        if not self.cfg.cpu_offload: return False
        try:
            moved = 0
            for group in optimizer.param_groups:
                for p in group["params"]:
                    if p in optimizer.state:
                        for k, v in optimizer.state[p].items():
                            if isinstance(v, torch.Tensor) and v.device.type == "cuda":
                                optimizer.state[p][k] = v.cpu().pin_memory(); moved += 1
            if moved: logger.info(f"CPU Offload  : {moved} optimizer state CPU'ya taşındı")
            return True
        except Exception as e:
            NexusError.report("OFFLOAD", "Optimizer offload başarısız", str(e), "GPU'da devam")
            return False

    def offload_layers(self, model, keep_layers: int = 4) -> bool:
        if not self.cfg.layer_offload: return False
        try:
            layers = None
            for attr in ["model.layers", "transformer.h", "gpt_neox.layers"]:
                obj = model
                try:
                    for p in attr.split("."): obj = getattr(obj, p)
                    layers = obj; break
                except AttributeError: continue
            if layers is None:
                logger.info("Layer Offload: Katman yapısı bulunamadı → atlandı"); return False
            total = len(layers); off = max(0, total - keep_layers)
            for i in range(off): layers[i] = layers[i].cpu()
            logger.info(f"Layer Offload: ✓  {off}/{total} katman CPU'ya taşındı")
            return True
        except Exception as e:
            NexusError.report("LAYER_OFFLOAD", "Katman offload başarısız",
                str(e), "Tüm katmanlar GPU'da kalıyor")
            return False


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 6 — MIXTURE OF EXPERTS  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class MoERouter(nn.Module):
    def __init__(self, hidden_size, num_experts, top_k=2, threshold=0.2):
        super().__init__()
        self.num_experts = num_experts; self.top_k = top_k; self.threshold = threshold
        self.gate = nn.Linear(hidden_size, num_experts, bias=False)

    def forward(self, x):
        logits = self.gate(x); weights = F.softmax(logits, dim=-1)
        mask   = weights > self.threshold
        tv, ti = weights.topk(self.top_k, dim=-1)
        mask  |= torch.zeros_like(weights).scatter_(-1, ti, 1.).bool()
        rw     = weights * mask
        rw     = rw / rw.sum(dim=-1, keepdim=True).clamp(min=1e-8)
        eu     = mask.float().mean(0)
        return rw, mask, (eu * weights.mean(0)).sum() * self.num_experts


class MoELayer(nn.Module):
    def __init__(self, hidden_size, intermediate_size, num_experts=8, top_k=2, threshold=0.2):
        super().__init__()
        self.router  = MoERouter(hidden_size, num_experts, top_k, threshold)
        self.experts = nn.ModuleList([
            nn.Sequential(nn.Linear(hidden_size, intermediate_size, bias=False),
                          nn.SiLU(),
                          nn.Linear(intermediate_size, hidden_size, bias=False))
            for _ in range(num_experts)])
        self.num_experts = num_experts

    def forward(self, x):
        B, T, H = x.shape; xf = x.view(-1, H)
        weights, mask, bl = self.router(xf); out = torch.zeros_like(xf)
        for i, expert in enumerate(self.experts):
            em = mask[:, i]
            if not em.any(): continue
            out[em] += expert(xf[em]) * weights[em, i:i+1]
        return out.view(B, T, H), bl


class MoEPatcher:
    def __init__(self, cfg): self.cfg = cfg

    def patch(self, model) -> int:
        if not self.cfg.moe_enabled: return 0
        try:
            replaced = 0
            hidden   = model.config.hidden_size
            inter    = getattr(model.config, "intermediate_size",
                       getattr(model.config, "ffn_dim", hidden * 4))
            for name, module in list(model.named_modules()):
                if not any(x in type(module).__name__.lower() for x in ["mlp","feedforward","ffn"]): continue
                if replaced >= self.cfg.moe_max_layers: break
                moe = MoELayer(hidden, inter, self.cfg.moe_num_experts,
                               self.cfg.moe_top_k, self.cfg.moe_threshold
                               ).to(next(model.parameters()).device)
                parts = name.split("."); parent = model
                for p in parts[:-1]: parent = getattr(parent, p)
                setattr(parent, parts[-1], moe); replaced += 1
            if replaced:
                logger.info(f"MoE          : ✓  {replaced} MLP → MoE "
                            f"({self.cfg.moe_num_experts} uzman, top-k={self.cfg.moe_top_k})")
            return replaced
        except Exception as e:
            NexusError.report("MOE_PATCH", "MoE katman değiştirme başarısız",
                str(e), "Orijinal MLP korunuyor")
            return 0


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 7 — OPTUNA HYPERPARAMETRE TUNING  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class HyperparamTuner:
    def __init__(self, fl, n_trials=20, tune_steps=50,
                 tune_lr=True, tune_rank=True, tune_batch=False):
        self.fl=fl; self.n_trials=n_trials; self.tune_steps=tune_steps
        self.tune_lr=tune_lr; self.tune_rank=tune_rank; self.tune_batch=tune_batch
        self._best=None

    def tune(self, train_dataset, formatting_func=None) -> Dict:
        if not DEPS.get("optuna"):
            NexusError.report("OPTUNA", "Optuna kurulu değil",
                "optuna paketi bulunamadı", "pip install optuna"); return {}
        try:
            import optuna; optuna.logging.set_verbosity(optuna.logging.WARNING)
            fl = self.fl; ts = self.tune_steps

            def objective(trial):
                params = {}
                if self.tune_lr:    params["learning_rate"] = trial.suggest_float("lr",1e-5,1e-3,log=True)
                if self.tune_rank:  params["lora_r"] = trial.suggest_categorical("lora_r",[4,8,16,32])
                if self.tune_batch: params["per_device_train_batch_size"] = trial.suggest_categorical("bs",[1,2,4])
                for k,v in params.items(): setattr(fl.cfg, k, v)
                try:
                    if not DEPS.get("datasets"): return float("inf")
                    trainer = fl.get_trainer(train_dataset, formatting_func=formatting_func)
                    trainer.args.max_steps=ts; trainer.args.logging_steps=ts
                    trainer.args.save_steps=ts+1; trainer.train()
                    return trainer.state.log_history[-1].get("loss", float("inf"))
                except Exception as e:
                    NexusError.report("OPTUNA_TRIAL", f"Trial {trial.number} başarısız",
                        str(e), "Sonraki trial deneniyor"); return float("inf")

            study = optuna.create_study(direction="minimize")
            study.optimize(objective, n_trials=self.n_trials, catch=(Exception,))
            best = study.best_params; self._best = best
            for k,v in best.items(): setattr(fl.cfg, k, v)
            logger.info(f"Optuna       : ✓  {self.n_trials} trial — en iyi: {best}")
            return best
        except Exception as e:
            NexusError.report("OPTUNA", "Hyperparameter tuning başarısız",
                str(e), "Mevcut parametreler korunuyor"); return {}

    @property
    def best_params(self): return self._best


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 8 — SMART OOM RECOVERY  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

class OOMRecovery:
    def __init__(self, cfg, device):
        self.cfg=cfg; self.device=device
        self._batch=cfg.per_device_train_batch_size
        self._accum=cfg.gradient_accumulation_steps; self._count=0

    def handle(self, exception, step, trainer=None) -> bool:
        if not isinstance(exception,(torch.cuda.OutOfMemoryError,RuntimeError)) \
           or "out of memory" not in str(exception).lower(): return False
        self._count += 1
        vram_used  = torch.cuda.memory_allocated()/1e9 if torch.cuda.is_available() else 0
        vram_total = self.device.get_vram_gb()
        old = self._batch
        self._batch = max(self.cfg.vram_min_batch, self._batch//2)
        self._accum = self._accum * (old // max(self._batch,1))
        ErrorReport.oom_report(step, old, self._batch, vram_used, vram_total)
        gc.collect()
        if torch.cuda.is_available(): torch.cuda.empty_cache(); torch.cuda.synchronize()
        if trainer and hasattr(trainer,"args"):
            trainer.args.per_device_train_batch_size=self._batch
            trainer.args.gradient_accumulation_steps=self._accum
        return True

    def wrap_train(self, trainer, resume_path=None):
        for attempt in range(5):
            try:
                result = trainer.train(resume_from_checkpoint=resume_path)
                logger.info(f"OOM Recovery : Eğitim tamamlandı ({self._count} OOM kurtarma)")
                return result
            except (torch.cuda.OutOfMemoryError, RuntimeError) as e:
                if "out of memory" not in str(e).lower(): raise
                try:
                    ckpts = sorted([d for d in Path(trainer.args.output_dir).iterdir()
                        if d.is_dir() and "checkpoint" in d.name],
                        key=lambda x: int(x.name.split("-")[-1]) if x.name.split("-")[-1].isdigit() else 0)
                    resume_path = str(ckpts[-1]) if ckpts else resume_path
                except Exception: pass
                if not self.handle(e, trainer.state.global_step, trainer): raise
                if self._batch <= self.cfg.vram_min_batch and attempt > 2:
                    NexusError.report("OOM_FATAL", "Minimum batch size'a ulaşıldı",
                        f"Batch={self._batch}", "Daha küçük model veya daha fazla VRAM gerekiyor",
                        impact="severe", exc=e, fatal=True)
            except Exception as e:
                NexusError.report("TRAIN_ERROR", "Eğitim sırasında beklenmedik hata",
                    str(e), "Hata raporunu inceleyin", exc=e); raise
        raise RuntimeError("[NexusLoRA] 5 denemeden sonra tamamlanamadı")


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 8.5 — HIZ + VRAM OPTİMİZASYONLARI  (NexusLoRA v1.0)
# ══════════════════════════════════════════════════════════════════════════════

class ActivationOffloader:
    def __init__(self, enabled=False): self.enabled=enabled; self._hooks=[]

    def attach(self, model) -> int:
        if not self.enabled: return 0
        count = 0
        try:
            for name, module in model.named_modules():
                if not isinstance(module, nn.Linear): continue
                if "lm_head" in name or "embed" in name: continue
                def make_hook(mod):
                    def fwd_hook(m, inp, out):
                        if isinstance(out, torch.Tensor) and out.device.type=="cuda":
                            return out.cpu().pin_memory()
                        return out
                    return mod.register_forward_hook(fwd_hook)
                self._hooks.append(make_hook(module)); count += 1
            logger.info(f"Act Offload  : ✓  {count} katman activation CPU'ya")
        except Exception as e:
            NexusError.report("ACT_OFFLOAD","Activation offload başarısız",str(e),"Normal kullanılıyor")
        return count

    def detach(self):
        for h in self._hooks:
            try: h.remove()
            except: pass
        self._hooks.clear()


class KVCacheOptimizer:
    def __init__(self, enabled=True): self.enabled=enabled

    def apply(self, model) -> bool:
        if not self.enabled: return False
        try:
            if hasattr(model,"config"): model.config.use_cache=False
            if hasattr(model.config,"cache_implementation"): model.config.cache_implementation=None
            logger.info("KV Cache     : ✓  Eğitim modu, cache devre dışı"); return True
        except Exception as e:
            NexusError.report("KV_CACHE","KV cache opt başarısız",str(e),"Varsayılan korunuyor")
            return False


class GradientOptimizer:
    def __init__(self, cfg): self.cfg=cfg

    def apply(self, model) -> bool:
        try:
            frozen=0
            for name, param in model.named_parameters():
                if any(x in name for x in ["embed_tokens","embed_positions","wte","wpe"]):
                    if not param.requires_grad: continue
                    if self.cfg.lora: param.requires_grad_(False); frozen+=1
            if frozen: logger.info(f"Grad Opt     : ✓  {frozen} embedding katmanı donduruldu")
            if hasattr(model,"zero_grad"):
                orig=model.zero_grad
                model.zero_grad = lambda set_to_none=True: orig(set_to_none=True)
            return True
        except Exception as e:
            NexusError.report("GRAD_OPT","Gradient opt başarısız",str(e),"Normal kullanılıyor")
            return False


class MemoryFragmentationFixer:
    """
    Periyodik CUDA bellek defragmentation.
    ⚠️  ÇAKIŞMA UYARISI: MorphicMemory™ de GC yapar.
    İkisi birlikte aktifse çift GC çağrısı oluşur (zararsız ama gereksiz CPU yükü).
    Tavsiye: mem_defrag=True ve nexus_morphic_memory=True ise mem_defrag_interval'ı 2x artırın.
    """
    def __init__(self, enabled=True, interval_steps=50):
        self.enabled=enabled; self.interval_steps=interval_steps; self._step=0

    def step(self):
        if not self.enabled or not torch.cuda.is_available(): return
        self._step += 1
        if self._step % self.interval_steps == 0:
            gc.collect(); torch.cuda.empty_cache()
            alloc=torch.cuda.memory_allocated()/1e9; res=torch.cuda.memory_reserved()/1e9
            frag=res-alloc
            if frag>1.0: logger.info(f"Mem Defrag   : {frag:.1f}GB fragmented bellek temizlendi")

    def attach_to_trainer(self, trainer):
        if not self.enabled: return
        try:
            from transformers import TrainerCallback
            fixer=self
            class _DefragCb(TrainerCallback):
                def on_step_end(self,args,state,control,**kw): fixer.step()
            trainer.add_callback(_DefragCb())
            logger.info(f"Mem Defrag   : ✓  her {self.interval_steps} adımda")
        except Exception as e:
            NexusError.report("MEM_DEFRAG","Defrag callback başarısız",str(e),"Manuel fl.clear_cache()")


class DataLoaderOptimizer:
    def __init__(self, cfg): self.cfg=cfg

    def get_optimal_workers(self) -> int:
        try:
            import multiprocessing
            return min(multiprocessing.cpu_count(), max(4, self.cfg.dataloader_num_workers))
        except Exception: return self.cfg.dataloader_num_workers

    def patch_training_args(self, args):
        try:
            w = self.get_optimal_workers()
            args.dataloader_num_workers=w
            args.dataloader_pin_memory=self.cfg.pin_memory
            args.dataloader_persistent_workers=(w>0)
            if w>0: args.dataloader_prefetch_factor=self.cfg.dataloader_prefetch_factor
            logger.info(f"DataLoader   : ✓  workers={w}, persistent=True")
        except Exception as e:
            NexusError.report("DATALOADER","DataLoader opt başarısız",str(e),"Varsayılan kullanılıyor")


class SparseAttentionOptimizer:
    def __init__(self, enabled=False, threshold=0.01):
        self.enabled=enabled; self.sparsity_threshold=threshold

    def apply(self, model) -> bool:
        if not self.enabled: return False
        try:
            patched=0
            for name, module in model.named_modules():
                if "attention" not in type(module).__name__.lower(): continue
                if not hasattr(module,"forward"): continue
                orig=module.forward; thr=self.sparsity_threshold
                def make_sf(o,t):
                    def sf(*a,**kw):
                        if "attention_mask" in kw and kw["attention_mask"] is not None:
                            m=kw["attention_mask"]
                            if m.dtype==torch.float:
                                kw["attention_mask"]=torch.where(m.abs()<t,
                                    torch.full_like(m,float("-inf")),m)
                        return o(*a,**kw)
                    return sf
                module.forward=make_sf(orig,thr); patched+=1
            if patched: logger.info(f"Sparse Att   : ✓  {patched} katman (thr={self.sparsity_threshold})")
            return patched>0
        except Exception as e:
            NexusError.report("SPARSE_ATT","Sparse attention başarısız",str(e),"Normal attention")
            return False


class MixedPrecisionOptimizer:
    """
    Yükleme sırasında kritik katmanları fp32'de tutar.
    ⚠️  ÇAKIŞMA UYARISI: ChromaticPrecision™ de per-layer dtype atar (step 30'da).
    İkisi birlikte aktifse dtype atama çakışması oluşabilir.
    Tavsiye: mixed_precision_optimize=True ise nexus_chromatic_precision=False yapın, ya da tersi.
    """
    def __init__(self, enabled=True): self.enabled=enabled

    def apply(self, model, dtype) -> bool:
        if not self.enabled or dtype==torch.float32: return False
        try:
            kept=0
            for name, module in model.named_modules():
                if any(x in name for x in ["lm_head","norm","ln_f","layer_norm"]):
                    if hasattr(module,"weight") and module.weight is not None:
                        module.float(); kept+=1
            if kept: logger.info(f"Mixed Prec   : ✓  {kept} kritik katman fp32'de")
            return True
        except Exception as e:
            NexusError.report("MIXED_PREC","Mixed precision opt başarısız",str(e),"Tek precision")
            return False


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 8.6 — v4.2 YENİ SİSTEMLER  (NexusLoRA)
# ══════════════════════════════════════════════════════════════════════════════

_GPU_PROFILES = {
    "cpu":       {"quantization":"none","torch_compile":False,"flash_attention":False,
                  "batch_packing":False,"fused_ops":False,"cuda_optimizations":False,
                  "per_device_train_batch_size":1,"gradient_accumulation_steps":8,"precision":"fp32"},
    "low_end":   {"quantization":"4bit","torch_compile":True,"flash_attention":False,
                  "batch_packing":True,"fused_ops":True,"cuda_optimizations":True,
                  "per_device_train_batch_size":1,"gradient_accumulation_steps":8,
                  "precision":"auto","vram_guard":True,"vram_guard_power":0.75,
                  "cpu_offload":True,"gradient_checkpointing":True},
    "mid_range": {"quantization":"4bit","torch_compile":True,"flash_attention":True,
                  "batch_packing":True,"fused_ops":True,"cuda_optimizations":True,
                  "per_device_train_batch_size":2,"gradient_accumulation_steps":4,
                  "precision":"auto","vram_guard":True,"vram_guard_power":0.85,
                  "gradient_checkpointing":True},
    "high_end":  {"quantization":"4bit","torch_compile":True,"flash_attention":True,
                  "batch_packing":True,"fused_ops":True,"cuda_optimizations":True,
                  "per_device_train_batch_size":4,"gradient_accumulation_steps":2,
                  "precision":"bf16","vram_guard":True,"vram_guard_power":0.90},
    "datacenter":{"quantization":"none","torch_compile":True,"flash_attention":True,
                  "batch_packing":True,"fused_ops":True,"cuda_optimizations":True,
                  "per_device_train_batch_size":8,"gradient_accumulation_steps":1,
                  "precision":"bf16","vram_guard":True,"vram_guard_power":0.92,
                  "torch_compile_fullgraph":True},
    "flagship":  {"quantization":"none","torch_compile":True,"flash_attention":True,
                  "batch_packing":True,"fused_ops":True,"cuda_optimizations":True,
                  "per_device_train_batch_size":16,"gradient_accumulation_steps":1,
                  "precision":"bf16","vram_guard":True,"vram_guard_power":0.95,
                  "torch_compile_fullgraph":True},
}


class HardwareScanner:
    def __init__(self):
        self.profile="cpu"; self.vram_gb=0.; self.gpu_name="CPU"
        self.num_gpus=0; self.cpu_cores=4; self.ram_gb=8.; self._scanned=False

    def scan(self):
        try:
            import multiprocessing; self.cpu_cores=multiprocessing.cpu_count()
        except: pass
        try:
            import psutil; self.ram_gb=psutil.virtual_memory().total/1e9
        except: pass
        if torch.cuda.is_available():
            p=torch.cuda.get_device_properties(0)
            self.vram_gb=p.total_memory/1e9; self.gpu_name=p.name
            self.num_gpus=torch.cuda.device_count()
        elif hasattr(torch.backends,"mps") and torch.backends.mps.is_available():
            self.gpu_name="Apple Silicon (MPS)"; self.vram_gb=8.
        self.profile=self._select_profile(); self._scanned=True
        logger.info(f"Donanim Tara : {self.gpu_name} | {self.vram_gb:.1f}GB VRAM | Profil: {self.profile.upper()}")
        return _GPU_PROFILES.get(self.profile,{})

    def _select_profile(self):
        if self.vram_gb==0: return "cpu"
        if self.vram_gb>=80: return "flagship"
        if self.vram_gb>=40: return "datacenter"
        if self.vram_gb>=16: return "high_end"
        if self.vram_gb>=8:  return "mid_range"
        return "low_end"

    def apply_to_config(self, cfg, user_overrides):
        if not self._scanned: self.scan()
        settings=_GPU_PROFILES.get(self.profile,{})
        applied=[]
        for k,v in settings.items():
            if k in user_overrides: continue
            if hasattr(cfg,k): setattr(cfg,k,v); applied.append(k)
        if applied: logger.info(f"Oto Ayar     : {len(applied)} parametre profil ayarlandı")


class UnlimitedParamManager:
    STRATEGIES={"tiny":(0,3),"small":(3,10),"medium":(10,30),"large":(30,100),
                "xlarge":(100,300),"xxlarge":(300,float("inf"))}
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def get_param_count(self,model): return sum(p.numel() for p in model.parameters())/1e9

    def apply(self,model,cfg):
        b=self.get_param_count(model)
        for name,(lo,hi) in self.STRATEGIES.items():
            if lo<=b<hi: s=name; break
        else: s="xxlarge"
        vram=self.device.get_vram_gb()
        logger.info(f"Param Mgr    : {b:.1f}B parametre → strateji: {s.upper()}")
        if s=="medium":
            cfg.quantization="4bit"; cfg.gradient_checkpointing=True
            cfg.cpu_offload=True; cfg.layer_offload=True
            cfg.layer_offload_keep=max(2,int(vram/4))
        elif s=="large":
            cfg.quantization="4bit"; cfg.gradient_checkpointing=True
            cfg.cpu_offload=True; cfg.layer_offload=True
            cfg.layer_offload_keep=max(1,int(vram/8))
            cfg.per_device_train_batch_size=1
            cfg.gradient_accumulation_steps=max(16,cfg.gradient_accumulation_steps)
        elif s in ("xlarge","xxlarge"):
            cfg.quantization="4bit"; cfg.gradient_checkpointing=True
            cfg.cpu_offload=True; cfg.layer_offload=True; cfg.layer_offload_keep=1
            cfg.per_device_train_batch_size=1; cfg.gradient_accumulation_steps=32
            cfg.torch_compile=False; cfg.activation_offload=True
        return s


class AdvancedCrashHandler:
    def __init__(self,cfg,device):
        self.cfg=cfg; self.device=device
        self._nan_count=0; self._cuda_resets=0; self._skip_count=0
        self._safe_mode=False; self._history=[]

    def handle(self,exception,context=None):
        err=str(exception).lower(); ctx=context or {}
        if isinstance(exception,torch.cuda.OutOfMemoryError) or "out of memory" in err:
            gc.collect()
            if torch.cuda.is_available(): torch.cuda.empty_cache()
            self._log("OOM","Bellek temizlendi, devam"); return True
        if "cuda error" in err or "device-side assert" in err:
            self._cuda_resets+=1
            try:
                if torch.cuda.is_available(): torch.cuda.synchronize(); torch.cuda.empty_cache()
                self._log("CUDA_ERROR",f"CUDA reset #{self._cuda_resets}")
                if self._cuda_resets>3: self._activate_safe_mode()
                return True
            except: return False
        if "nan" in err or "inf" in err:
            self._nan_count+=1; self._log("NAN_LOSS",f"Adım atl #{self._nan_count}")
            if self._nan_count>5 and ctx.get("trainer"):
                try:
                    for pg in ctx["trainer"].optimizer.param_groups: pg["lr"]*=0.5
                    self._log("NAN_LOSS","LR %50 düşürüldü")
                except: pass
            return True
        if any(x in err for x in ["index","shape","size","key"]):
            self._skip_count+=1; self._log("DATA_ERROR",f"Örnek atlandı #{self._skip_count}"); return True
        self._log("UNKNOWN","Güvenli mod"); self._activate_safe_mode(); return True

    def _log(self,etype,solution):
        self._history.append({"time":time.strftime("%H:%M:%S"),"type":etype,"solution":solution})
        logger.warning(f"Kurtarma [{etype}] {solution}")

    def _activate_safe_mode(self):
        if self._safe_mode: return
        self._safe_mode=True
        self.cfg.torch_compile=False; self.cfg.flash_attention=False
        self.cfg.batch_packing=False; self.cfg.fused_ops=False
        self.cfg.per_device_train_batch_size=1
        gc.collect()
        if torch.cuda.is_available(): torch.cuda.empty_cache()
        logger.warning("GÜVENLI MOD AKTİF — tüm optimizasyonlar kapatıldı, eğitim devam ediyor")

    def summary(self):
        return {"total_errors":len(self._history),"nan_count":self._nan_count,
                "cuda_resets":self._cuda_resets,"skipped":self._skip_count,"safe_mode":self._safe_mode}


class LossSpikeDetector:
    """
    Loss spike tespiti.
    ⚠️  ÇAKIŞMA UYARISI: NeuralProfiler™ de loss izler.
    İkisi birlikte aktifse aynı spike iki kez loglanır ve iki farklı müdahale yapılabilir.
    Tavsiye: loss_spike_detection=True ise nexus_neural_profiler=False yapın, ya da tersi.
    """
    def __init__(self,threshold=3.0,window=20,action="skip"):
        self.threshold=threshold; self.window=window; self.action=action
        self._history=[]; self._spikes=0

    def check(self,loss,trainer=None):
        if math.isnan(loss) or math.isinf(loss):
            self._spikes+=1; logger.warning(f"Spike: NaN/Inf #{self._spikes}"); return False
        self._history.append(loss)
        if len(self._history)>self.window: self._history.pop(0)
        if len(self._history)<5: return True
        avg=sum(self._history[:-1])/len(self._history[:-1])
        if avg==0: return True
        ratio=loss/avg
        if ratio>self.threshold:
            self._spikes+=1
            if self.action=="skip":
                logger.warning(f"Spike: {loss:.4f} (x{ratio:.1f}) - adım atlandı"); return False
            elif self.action=="lr_reduce" and trainer:
                try:
                    for pg in trainer.optimizer.param_groups: pg["lr"]*=0.8
                    logger.warning(f"Spike: LR %20 düşürüldü")
                except: pass
        return True

    def patch_trainer(self,trainer):
        try:
            from transformers import TrainerCallback; det=self
            class _SCb(TrainerCallback):
                def on_log(self,args,state,control,logs=None,**kw):
                    if logs:
                        loss=logs.get("loss")
                        if loss is not None: det.check(float(loss),trainer)
            trainer.add_callback(_SCb())
        except Exception as e:
            NexusError.report("SPIKE_DET","LossSpikeDetector eklenemedi",str(e),"Devam")


class SmartCheckpoint:
    """
    Sadece gerçekten iyileşince checkpoint kaydeder.
    ⚠️  ÇAKIŞMA UYARISI: CrystalPipeline™ de async checkpoint kuyruğu yönetir.
    İkisi aynı anda aktifse çift checkpoint kaydı oluşabilir.
    Tavsiye: smart_checkpoint=True ise nexus_crystal_pipeline=False yapın, ya da tersi.
    """
    def __init__(self,output_dir,metric="loss",min_delta=0.005,keep_top=3):
        self.output_dir=output_dir; self.metric=metric
        self.min_delta=min_delta; self.keep_top=keep_top
        self._best=float("inf"); self._state_file=Path(output_dir)/".fastlora_state.json"
        os.makedirs(output_dir,exist_ok=True); self._load_state()

    def _load_state(self):
        try:
            if self._state_file.exists():
                s=json.loads(self._state_file.read_text())
                self._best=s.get("best_loss",float("inf"))
        except: pass

    def _save_state(self):
        try:
            self._state_file.write_text(json.dumps({"best_loss":self._best}))
        except: pass

    def should_save(self,loss):
        if loss<self._best-self.min_delta: self._best=loss; return True
        return False

    def cleanup_old(self):
        try:
            import shutil
            ckpts=sorted([d for d in Path(self.output_dir).iterdir()
                if d.is_dir() and d.name.startswith("checkpoint-")],
                key=lambda x:int(x.name.split("-")[-1]) if x.name.split("-")[-1].isdigit() else 0)
            for old in ckpts[:-self.keep_top]:
                shutil.rmtree(old,ignore_errors=True)
        except: pass

    def patch_trainer(self,trainer):
        try:
            from transformers import TrainerCallback; ckpt=self
            class _SCb(TrainerCallback):
                def on_evaluate(self,args,state,control,metrics=None,**kw):
                    if not metrics: return
                    loss=metrics.get("eval_loss",metrics.get("loss"))
                    if loss is None: return
                    if ckpt.should_save(loss):
                        control.should_save=True; ckpt._save_state(); ckpt.cleanup_old()
                        logger.info(f"Smart Ckpt   : Yeni en iyi={loss:.4f}")
                    else: control.should_save=False
            trainer.add_callback(_SCb())
        except Exception as e:
            NexusError.report("SMART_CKPT","Smart checkpoint eklenemedi",str(e),"Normal checkpoint")


class DynamicBatchScaler:
    """
    VRAM doluluguna göre batch size dinamik ayarlar.
    ⚠️  ÇAKIŞMA UYARISI: CrystalPipeline™ de VRAM'e göre gradient accumulation ayarlar.
    İkisi aynı anda aktifse batch ve grad_accum ters yönde değişebilir.
    Tavsiye: dynamic_batch_scaling=True ise nexus_crystal_pipeline=False yapın, ya da tersi.
    """
    def __init__(self,cfg,device,up=0.60,down=0.85,interval=25):
        self.cfg=cfg; self.device=device; self.up=up; self.down=down; self.interval=interval
        self._batch=cfg.per_device_train_batch_size; self._step=0

    def check(self,trainer=None):
        if self.device.device.type!="cuda": return self._batch
        self._step+=1
        if self._step%self.interval!=0: return self._batch
        ratio=self.device.get_vram_usage_ratio()
        if ratio<self.up:
            nb=min(self._batch*2,32)
            if nb>self._batch:
                self._batch=nb
                if trainer and hasattr(trainer,"args"): trainer.args.per_device_train_batch_size=self._batch
        elif ratio>self.down:
            nb=max(1,self._batch//2)
            if nb<self._batch:
                self._batch=nb
                if trainer and hasattr(trainer,"args"): trainer.args.per_device_train_batch_size=self._batch
        return self._batch

    def patch_trainer(self,trainer):
        try:
            from transformers import TrainerCallback; sc=self
            class _DBCb(TrainerCallback):
                def on_step_end(self,args,state,control,**kw): sc.check(trainer)
            trainer.add_callback(_DBCb())
        except Exception as e:
            NexusError.report("DYN_BATCH","Dynamic batch eklenemedi",str(e),"Sabit batch")


class GradientNoiseMonitor:
    """
    Exploding/vanishing gradient erken tespiti.
    ⚠️  ÇAKIŞMA UYARISI: GradientHarmonics™ gradient değerlerini değiştirir.
    GradientHarmonics aktifse bu monitörün ölçümleri gerçek orijinal değerleri yansıtmaz.
    Tavsiye: nexus_gradient_harmonics=True ise gradient_noise_monitor=False yapın.
    """
    def __init__(self,warn=10.,clip=100.,interval=10):
        self.warn=warn; self.clip=clip; self.interval=interval
        self._step=0; self._explode=0; self._vanish=0

    def check(self,model):
        self._step+=1
        if self._step%self.interval!=0: return None
        try:
            norm=sum(p.grad.data.norm(2).item()**2 for p in model.parameters() if p.grad is not None)**0.5
            if norm>self.clip:
                self._explode+=1; logger.warning(f"Grad Monitor : Exploding! norm={norm:.2f}")
            elif norm<1e-7:
                self._vanish+=1; logger.warning(f"Grad Monitor : Vanishing! norm={norm:.2e}")
            return norm
        except: return None

    def patch_trainer(self,trainer,model):
        try:
            from transformers import TrainerCallback; mon=self
            class _GCb(TrainerCallback):
                def on_step_end(self,args,state,control,**kw): mon.check(model)
            trainer.add_callback(_GCb())
        except Exception as e:
            NexusError.report("GRAD_MON","Gradient monitor eklenemedi",str(e),"Devam")


class UnstoppableTrainer:
    def __init__(self,fl,crash_handler):
        self.fl=fl; self.crash_handler=crash_handler; self._errors=0

    def train(self,trainer,resume_path=None):
        for attempt in range(10):
            try:
                result=trainer.train(resume_from_checkpoint=resume_path)
                s=self.crash_handler.summary()
                logger.info(f"Eğitim tamamlandı! {s['total_errors']} hata atlatıldı.")
                return result
            except KeyboardInterrupt:
                logger.info("Kullanıcı tarafından durduruldu"); raise
            except Exception as e:
                self._errors+=1
                if not self.crash_handler.handle(e,{"trainer":trainer}): raise
                try:
                    ckpts=sorted([d for d in Path(trainer.args.output_dir).iterdir()
                        if d.is_dir() and "checkpoint" in d.name],
                        key=lambda x:int(x.name.split("-")[-1]) if x.name.split("-")[-1].isdigit() else 0)
                    resume_path=str(ckpts[-1]) if ckpts else resume_path
                except: pass
                logger.info(f"Devam #{attempt+1} ({self._errors} hata atlatıldı)")
        raise RuntimeError("[NexusLoRA] 10 denemeden sonra tamamlanamadı")


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 9 — NEXUSTRAIN MODÜLLERİ (inline — paket bağımlılığı yok)
# ══════════════════════════════════════════════════════════════════════════════

# ── 9.1  CrystalCore™ ────────────────────────────────────────────────────────
# ⚠️  ÇAKIŞMA UYARISI: CrystalCore bireysel kernel'ları çalışma zamanında compile eder.
# NexusLoRA'nın torch_compile modeli toptan compile eder.
# Quantized modellerde (4bit/8bit) her ikisi de çalışmaz.
# Tavsiye: torch_compile=True ise nexus_crystal_core=False yapın, ya da tersi.
# Quantized model için: torch_compile=False, nexus_crystal_core=True daha güvenlidir.

class _OperationSignature:
    __slots__ = ("_hash","ops","shapes","dtype")
    def __init__(self,ops,shapes,dtype):
        self.ops=ops; self.shapes=shapes; self.dtype=dtype
        raw=json.dumps({"ops":ops,"shapes":shapes,"dtype":dtype},sort_keys=True)
        self._hash=hashlib.md5(raw.encode()).hexdigest()[:12]
    def __hash__(self): return hash(self._hash)
    def __eq__(self,o): return isinstance(o,_OperationSignature) and self._hash==o._hash
    def __repr__(self): return f"OpSig({self._hash})"


class _CrystalKernel:
    def __init__(self,sig,fn,compile_mode,min_freq):
        self.sig=sig; self._fn=fn; self._mode=compile_mode; self._min_freq=min_freq
        self.call_count=0; self.total_ms=0.0; self._compiled=None; self._crystallized=False

    def __call__(self,*args,**kwargs):
        if self._crystallized and self._compiled is not None:
            return self._compiled(*args,**kwargs)
        t0=time.perf_counter(); result=self._fn(*args,**kwargs)
        self.total_ms+=(time.perf_counter()-t0)*1000; self.call_count+=1
        if self.call_count>=self._min_freq and not self._crystallized and _HAS_COMPILE:
            self._crystallize()
        return result

    def _crystallize(self):
        try:
            self._compiled=torch.compile(self._fn,mode=self._mode,fullgraph=False)
            self._crystallized=True
            logger.info(f"CrystalCore  : 💎  {self.sig} kristalize ({self.call_count}x çağrıldı)")
        except Exception as e:
            NexusError.report("CRYSTAL_FAIL",f"Kristalizasyon başarısız: {self.sig}",
                str(e),"Ham fonksiyon kullanılıyor",exc=e)


class CrystalCore:
    """CrystalCore™ — Runtime Kernel Kristalizasyon Motoru (NexusLoRA v1.0)"""
    def __init__(self,cfg):
        self.cfg=cfg; self._store: Dict[_OperationSignature,_CrystalKernel]={}
        self._step=0; self._lock=threading.Lock()
        self._stats=dict(crystallized=0,calls=0,evaporized=0)
        logger.info(f"CrystalCore  : 💎  warmup={cfg.nexus_crystal_warmup_steps}, "
                    f"min_freq={cfg.nexus_crystal_min_freq}")

    def register(self,fn,ops,shapes,dtype):
        sig=_OperationSignature(ops,shapes,dtype)
        with self._lock:
            if sig not in self._store:
                if len(self._store)>=self.cfg.nexus_crystal_max_kernels: self._evaporate_lru()
                self._store[sig]=_CrystalKernel(sig,fn,self.cfg.nexus_compile_mode,
                                                 self.cfg.nexus_crystal_min_freq)
                self._stats["crystallized"]+=1
        return self._store[sig]

    def step(self): self._step+=1

    def _evaporate_lru(self):
        if not self._store: return
        lru=min(self._store,key=lambda s:self._store[s].call_count)
        del self._store[lru]; self._stats["evaporized"]+=1

    def wrap(self,fn):
        @wraps(fn)
        def _w(*args,**kwargs):
            if self._step<self.cfg.nexus_crystal_warmup_steps: return fn(*args,**kwargs)
            shapes=[tuple(a.shape) for a in args if isinstance(a,torch.Tensor)]
            dtype=str(args[0].dtype) if args and isinstance(args[0],torch.Tensor) else "?"
            k=self.register(fn,[fn.__name__],shapes,dtype); self._stats["calls"]+=1
            return k(*args,**kwargs)
        return _w

    def inject_model(self,model):
        patched=0
        for _,module in model.named_modules():
            if isinstance(module,(nn.Linear,nn.Embedding)):
                try: module.forward=self.wrap(module.forward); patched+=1
                except: pass
        logger.info(f"CrystalCore  : 💎  {patched} modül bağlandı"); return model

    def report(self):
        c=sum(1 for k in self._store.values() if k._crystallized)
        logger.info(f"CrystalCore  : {c}/{len(self._store)} kernel kristalize")


# ── 9.2  MorphicMemory™ ──────────────────────────────────────────────────────

class _TensorReincarnator:
    def __init__(self,max_pool=512):
        self._pool=[]; self._max=max_pool
        self._stats=dict(reincarnated=0,fresh=0,saved_bytes=0)

    def acquire(self,shape,dtype,device):
        numel=1
        for s in shape: numel*=s
        best_idx,best_diff=-1,float("inf")
        for i,t in enumerate(self._pool):
            if t.dtype==dtype and t.device==device:
                diff=abs(t.numel()-numel)
                if diff<best_diff and diff<numel*0.1: best_diff=diff; best_idx=i
        if best_idx>=0:
            t=self._pool.pop(best_idx)
            self._stats["reincarnated"]+=1; self._stats["saved_bytes"]+=t.numel()*t.element_size()
            flat=t.flatten()
            if flat.numel()>=numel: return flat[:numel].reshape(shape).zero_()
        self._stats["fresh"]+=1
        return torch.empty(shape,dtype=dtype,device=device)

    def release(self,t):
        if len(self._pool)<self._max: self._pool.append(t.detach())


class _MarkovMemoryPredictor:
    def __init__(self,history_len=128,order=2):
        self.order=order; self.history_len=history_len
        self._history=[]; self._transitions={}; self._stats=dict(prefetched=0)

    def observe(self,size_bytes):
        self._history.append(size_bytes)
        if len(self._history)>self.history_len: self._history.pop(0)
        if len(self._history)>=self.order+1:
            state=tuple(self._history[-self.order-1:-1])
            nxt=self._history[-1]
            if state not in self._transitions: self._transitions[state]={}
            self._transitions[state][nxt]=self._transitions[state].get(nxt,0)+1

    def predict_next(self):
        if len(self._history)<self.order: return None
        state=tuple(self._history[-self.order:])
        if state not in self._transitions: return None
        return max(self._transitions[state],key=self._transitions[state].get)

    def prefetch(self,device,dtype):
        size=self.predict_next()
        if size is None: return
        try:
            elem=torch.tensor([],dtype=dtype).element_size()
            torch.empty(max(1,size//elem),dtype=dtype,device=device)
            self._stats["prefetched"]+=1
        except: pass


class MorphicMemory:
    """
    MorphicMemory™ — Markov tahmini + tensor reincarnation + OOM öncesi GC.
    (NexusLoRA v1.0)
    ⚠️  ÇAKIŞMA UYARISI: MemoryFragmentationFixer de GC yapar.
    İkisi birlikte aktifse VRAM baskısında çift GC oluşur (zararsız ama CPU yükü artar).
    """
    def __init__(self,cfg,device):
        self.cfg=cfg; self.device=device
        self.predictor=_MarkovMemoryPredictor(cfg.nexus_morph_history_len)
        self.reincarnator=_TensorReincarnator() if cfg.nexus_tensor_reincarnation else None
        self._pressure_threshold=0.85; self._gc_count=0; self._step=0
        logger.info(f"MorphicMemory: 🧬  Markov geçmiş={cfg.nexus_morph_history_len}")

    def allocate(self,shape,dtype):
        elem=torch.tensor([],dtype=dtype).element_size()
        nb=elem; [nb:=nb*s for s in shape]  # noqa
        nb=elem
        for s in shape: nb*=s
        self.predictor.observe(nb); self._check_pressure()
        if self.reincarnator: return self.reincarnator.acquire(shape,dtype,self.device)
        return torch.empty(shape,dtype=dtype,device=self.device)

    def free(self,t):
        if self.reincarnator: self.reincarnator.release(t)

    def _check_pressure(self):
        if not torch.cuda.is_available(): return
        used=torch.cuda.memory_allocated(self.device)/1e9
        total=torch.cuda.get_device_properties(self.device).total_memory/1e9
        if total>0 and used/total>self._pressure_threshold:
            gc.collect(); torch.cuda.empty_cache(); self._gc_count+=1

    def step(self):
        self._step+=1
        if self._step%10==0:
            dtype=torch.bfloat16 if _HAS_BF16 else torch.float16
            self.predictor.prefetch(self.device,dtype)

    def report(self):
        logger.info(f"MorphicMemory: 🧬  {self._gc_count} otomatik GC")
        if self.reincarnator:
            r=self.reincarnator._stats
            saved_mb=r["saved_bytes"]/1e6
            logger.info(f"Reincarnator : ♻️   {r['reincarnated']} yeniden doğuş, {saved_mb:.1f}MB tasarruf")


# ── 9.3  SpectraOptimizer™ ───────────────────────────────────────────────────
# ⚠️  ÇAKIŞMA UYARISI: SpectraOptimizer, NexusLoRA'nın paged_adamw_8bit / adamw_fused yerine geçer.
# nexus_spectra_optimizer=True ise paged_optimizer=True olsa bile SpectraOptimizer kullanılır.
# Paged optimizer'ın VRAM kazanımı (sayfalanmış bellek) bu durumda kaybolur.
# Tavsiye: Küçük VRAM'de (≤8GB) paged_optimizer=True + nexus_spectra_optimizer=False tercih edin.

def _fft_spectrum(signal):
    n=len(signal)
    if n==0: return []
    try:
        import numpy as np; return list(abs(np.fft.fft(signal)[:n//2]))
    except ImportError:
        result=[]
        for k in range(n//2):
            re=sum(signal[t]*math.cos(2*math.pi*k*t/n) for t in range(n))
            im=sum(signal[t]*math.sin(2*math.pi*k*t/n) for t in range(n))
            result.append(math.sqrt(re*re+im*im))
        return result


class SpectraOptimizer(torch.optim.Optimizer):
    """SpectraOptimizer™ — Frekans alanında çalışan AdamW üstü optimizer (NexusLoRA v1.0)"""
    def __init__(self,params,lr=2e-4,betas=(0.9,0.999),eps=1e-8,
                 weight_decay=0.01,spectral_damping=0.1,history_len=64,power=1.0):
        defaults=dict(lr=lr,betas=betas,eps=eps,weight_decay=weight_decay,
                      spectral_damping=spectral_damping,history_len=history_len,power=power)
        super().__init__(params,defaults); self._step_count=0
        logger.info(f"SpectraOpt   : 🎵  lr={lr:.2e}, spectral_damping={spectral_damping}")

    @torch.no_grad()
    def step(self,closure=None):
        loss=None
        if closure is not None:
            with torch.enable_grad(): loss=closure()
        for group in self.param_groups:
            b1,b2=group["betas"]; eps=group["eps"]; lr=group["lr"]
            wd=group["weight_decay"]; sdamp=group["spectral_damping"]*group["power"]
            hlen=group["history_len"]
            for p in group["params"]:
                if p.grad is None: continue
                grad=p.grad
                if grad.is_sparse: continue
                state=self.state[p]
                if len(state)==0:
                    state["step"]=0; state["exp_avg"]=torch.zeros_like(p)
                    state["exp_avg_sq"]=torch.zeros_like(p); state["grad_history"]=[]
                state["step"]+=1
                ea=state["exp_avg"]; eas=state["exp_avg_sq"]
                ea.mul_(b1).add_(grad,alpha=1-b1)
                eas.mul_(b2).addcmul_(grad,grad,value=1-b2)
                bc1=1-b1**state["step"]; bc2=1-b2**state["step"]
                ss=lr*math.sqrt(bc2)/bc1; denom=eas.sqrt().add_(eps)
                if sdamp>0 and state["step"]>10:
                    try:
                        state["grad_history"].append(grad.detach().float().mean().item())
                        if len(state["grad_history"])>hlen: state["grad_history"].pop(0)
                        if len(state["grad_history"])>=8:
                            spec=_fft_spectrum(state["grad_history"])
                            if spec:
                                dom=spec.index(max(spec)); fr=dom/len(spec)
                                scale=max(0.1,min(1.0,1.0-sdamp*fr))
                                p.addcdiv_(ea*scale,denom,value=-ss)
                            else: p.addcdiv_(ea,denom,value=-ss)
                        else: p.addcdiv_(ea,denom,value=-ss)
                    except: p.addcdiv_(ea,denom,value=-ss)
                else: p.addcdiv_(ea,denom,value=-ss)
                if wd!=0: p.mul_(1-lr*wd)
        self._step_count+=1; return loss


# ── 9.4  ResonanceScheduler™ ─────────────────────────────────────────────────
# ⚠️  ÇAKIŞMA UYARISI: ResonanceScheduler LR'yi tamamen kontrol eder.
# nexus_resonance_scheduler=True ise NexusLoRA'nın lr_scheduler (cosine/linear/vs) config'i
# DEVRE DIŞI kalır. ResonanceScheduler kendi faz tespiti ile LR belirler.
# Tavsiye: ResonanceScheduler kullanıyorsanız lr_scheduler="constant" ayarlayın
# (TrainingArguments'ta scheduler'ın müdahale etmemesi için).

class TrainingPhase:
    WARMUP="warmup"; STABLE="stable"; CONVERGENCE="convergence"
    PLATEAU="plateau"; UNSTABLE="unstable"


class ResonanceScheduler:
    """ResonanceScheduler™ — Gradient spektrumu tabanlı öz-ayarlı LR (NexusLoRA v1.0)"""
    def __init__(self,optimizer,cfg):
        self.optimizer=optimizer; self.cfg=cfg
        self.base_lr=cfg.nexus_base_lr; self.min_lr=cfg.nexus_min_lr
        self._step=0; self._phase=TrainingPhase.WARMUP
        self._loss_hist=[]; self._gnorm_hist=[]; self._phase_hist=[]
        self._last_lr=cfg.nexus_base_lr; self._plateau_count=0
        logger.info(f"ResonanceSched: 🎼  base_lr={cfg.nexus_base_lr:.2e}")

    def step(self,loss,grad_norm):
        self._step+=1; self._loss_hist.append(loss); self._gnorm_hist.append(grad_norm)
        if len(self._loss_hist)>256: self._loss_hist.pop(0)
        if len(self._gnorm_hist)>256: self._gnorm_hist.pop(0)
        new_lr=self._compute_lr(); self._set_lr(new_lr)
        self._last_lr=new_lr; self._phase_hist.append(self._phase)

    def _compute_lr(self):
        step=self._step; cfg=self.cfg; sens=cfg.nexus_resonance_sensitivity
        if step<=cfg.nexus_warmup_steps:
            self._phase=TrainingPhase.WARMUP
            return self.base_lr*(step/max(cfg.nexus_warmup_steps,1))
        if len(self._gnorm_hist)>=4:
            avg8=sum(self._gnorm_hist[-8:])/max(len(self._gnorm_hist[-8:]),1)
            if self._gnorm_hist[-1]>avg8*(3.0-sens):
                self._phase=TrainingPhase.UNSTABLE
                return max(self._last_lr*0.5,self.min_lr)
        if len(self._loss_hist)>=16:
            recent=self._loss_hist[-8:]; delta=max(recent)-min(recent)
            avg=sum(recent)/8+1e-12
            if delta/avg<0.001:
                self._plateau_count+=1
                if self._plateau_count>5:
                    self._phase=TrainingPhase.PLATEAU
                    return min(self._last_lr*(1.0+0.05*sens),self.base_lr)
            else: self._plateau_count=0
        if len(self._gnorm_hist)>=16:
            spec=_fft_spectrum(self._gnorm_hist[-32:])
            if spec:
                tp=sum(spec)+1e-12
                ent=-sum((s/tp)*math.log(s/tp+1e-12) for s in spec)
                ne=ent/(math.log(len(spec)+1e-12)+1e-12)
                if ne<0.3:
                    self._phase=TrainingPhase.CONVERGENCE
                    prog=(step-cfg.nexus_warmup_steps)/max(1,step)
                    cos=0.5*(1+math.cos(math.pi*prog))
                    return max(self.min_lr+(self.base_lr-self.min_lr)*cos,self.min_lr)
                self._phase=TrainingPhase.STABLE
        return self._last_lr*(1.0-1e-4)

    def _set_lr(self,lr):
        lr=max(self.min_lr,min(lr,self.base_lr))
        for pg in self.optimizer.param_groups: pg["lr"]=lr

    @property
    def current_lr(self): return self._last_lr
    @property
    def current_phase(self): return self._phase

    def report(self):
        pc=collections.Counter(self._phase_hist)
        logger.info(f"ResonanceSched: 🎼  Fazlar={dict(pc)}, son LR={self._last_lr:.2e}")


# ── 9.5  ChromaticPrecision™ ─────────────────────────────────────────────────

def _clamp_float(v,lo,hi): return max(lo,min(hi,v))
def _to_float(x): return x.detach().float().mean().item()

class _LayerSensitivity:
    __slots__=("name","score","dtype","grad_var","update_count")
    def __init__(self,name): self.name=name; self.score=0.5; self.dtype=None; self.grad_var=[]; self.update_count=0


class ChromaticPrecision:
    """
    ChromaticPrecision™ — Gradient varyansına göre per-layer dtype atar (NexusLoRA v1.0).
    ⚠️  ÇAKIŞMA UYARISI: MixedPrecisionOptimizer de per-layer dtype atar (yükleme anında).
    İkisi aynı anda aktifse dtype çakışması oluşabilir.
    Tavsiye: mixed_precision_optimize=True ise nexus_chromatic_precision=False yapın, ya da tersi.
    """
    def __init__(self,cfg,model):
        self.cfg=cfg; self._sens: Dict[str,_LayerSensitivity]={}; self._step=0
        self._hooks=[]; self._analyzed=False; self._setup_hooks(model)
        logger.info(f"ChromaticPrec: 🌈  analiz_adımı={cfg.nexus_precision_analysis_steps}")

    def _setup_hooks(self,model):
        for name,module in model.named_modules():
            for pname,param in module.named_parameters(recurse=False):
                full=f"{name}.{pname}" if name else pname
                self._sens[full]=_LayerSensitivity(full)
                def make_hook(fname):
                    def _hook(grad):
                        with NexusError.guard("CHROMA_HOOK",f"Gradient hook: {fname}"):
                            if fname in self._sens and grad is not None:
                                s=self._sens[fname]
                                s.grad_var.append(_to_float(grad.float().var()))
                                if len(s.grad_var)>32: s.grad_var.pop(0)
                                s.update_count+=1
                        return grad
                    return _hook
                self._hooks.append(param.register_hook(make_hook(full)))

    def analyze_and_assign(self,model):
        da={}
        for name,module in model.named_modules():
            for pname,param in module.named_parameters(recurse=False):
                full=f"{name}.{pname}" if name else pname
                s=self._sens.get(full)
                force=any(kw in full for kw in self.cfg.nexus_force_fp32_layers)
                if force: target="fp32"
                elif s is None or not s.grad_var: target="bf16"
                else:
                    avg_var=sum(s.grad_var)/len(s.grad_var)
                    score=_clamp_float(math.log1p(avg_var)/10.0,0.0,1.0); s.score=score
                    if score>0.7: target="fp32"
                    elif score>0.3: target="bf16" if _HAS_BF16 else "fp32"
                    else: target="fp16"
                da[full]=target
        self._analyzed=True
        fp32=sum(1 for v in da.values() if v=="fp32")
        bf16=sum(1 for v in da.values() if v=="bf16")
        fp16=sum(1 for v in da.values() if v=="fp16")
        logger.info(f"ChromaticPrec: 🌈  FP32={fp32}, BF16={bf16}, FP16={fp16}")
        return da

    def step(self): self._step+=1
    def remove_hooks(self):
        for h in self._hooks:
            try: h.remove()
            except: pass
        self._hooks.clear()

    def report(self):
        if not self._analyzed: return
        high=[n for n,s in self._sens.items() if s.score>0.7]
        logger.info(f"ChromaticPrec: 🌈  {len(high)} hassas parametre FP32'de")


# ── 9.6  GradientHarmonics™ ──────────────────────────────────────────────────

def _wavelet_decompose(grad,levels=3):
    result=[]; x=grad.float().flatten()
    for _ in range(levels):
        if x.numel()<2: break
        n=(x.numel()//2)*2; x=x[:n]
        evens=x[0::2]; odds=x[1::2]
        result.append((evens-odds)*0.7071); x=(evens+odds)*0.7071
    result.append(x); return result[::-1]

def _wavelet_reconstruct(coeffs,shape):
    x=coeffs[0].float()
    for detail in coeffs[1:]:
        n=min(x.numel(),detail.numel()); x=x[:n]; d=detail[:n]
        merged=torch.empty(n*2,device=x.device)
        merged[0::2]=(x+d)*0.7071; merged[1::2]=(x-d)*0.7071; x=merged
    total=1
    for s in shape: total*=s
    if x.numel()>=total: return x[:total].reshape(shape)
    return F.pad(x,(0,total-x.numel())).reshape(shape)


class GradientHarmonics:
    """
    GradientHarmonics™ — Wavelet tabanlı gradient işleme (NexusLoRA v1.0).
    ⚠️  ÇAKIŞMA UYARISI: gradient_noise_monitor gradient değerlerini izler.
    GradientHarmonics gürültü eklediği için monitör ölçümleri orijinal değerleri yansıtmaz.
    Tavsiye: nexus_gradient_harmonics=True ise gradient_noise_monitor=False yapın.
    """
    def __init__(self,cfg):
        self.cfg=cfg; self._step=0; self._training=True
        self._stats=dict(injected=0,compressed=0,total=0)
        logger.info(f"GradHarmonics: 🌊  levels={cfg.nexus_harmonic_levels}")

    def process(self,grad,param_name=""):
        self._stats["total"]+=1
        try: return self._apply(grad,param_name)
        except Exception as e:
            NexusError.report("HARMONIC_ERR",f"GradHarmonics: {param_name}",
                str(e),"Ham gradient kullanılıyor",exc=e); return grad

    def _apply(self,grad,name):
        if grad.numel()<8: return grad
        cfg=self.cfg; orig_shape=grad.shape
        coeffs=_wavelet_decompose(grad,cfg.nexus_harmonic_levels)
        if cfg.nexus_harmonic_noise>0 and cfg.nexus_power>0 and self._training:
            scale=cfg.nexus_harmonic_noise*cfg.nexus_power
            for i in range(max(0,len(coeffs)-max(1,len(coeffs)//3)),len(coeffs)):
                c=coeffs[i]; std=c.float().std().item()+1e-12
                coeffs[i]=(c.float()+torch.randn_like(c.float())*std*scale).to(c.dtype)
            self._stats["injected"]+=1
        if cfg.nexus_harmonic_compress>0 and cfg.nexus_power>0:
            ratio=cfg.nexus_harmonic_compress*cfg.nexus_power
            for i,c in enumerate(coeffs):
                if c.numel()==0: continue
                threshold=c.float().abs().quantile(ratio)
                coeffs[i]=c*(c.float().abs()>=threshold).to(c.dtype)
            self._stats["compressed"]+=1
        return _wavelet_reconstruct(coeffs,orig_shape).to(grad.dtype)

    def register_hooks(self,model):
        hooks=[]; gh=self
        for name,param in model.named_parameters():
            if param.requires_grad:
                def make_hook(pname):
                    def _hook(grad): return gh.process(grad,pname)
                    return _hook
                hooks.append(param.register_hook(make_hook(name)))
        logger.info(f"GradHarmonics: 🌊  {len(hooks)} parametreye hook eklendi")
        return hooks

    def step(self): self._step+=1

    def report(self):
        t=self._stats["total"]
        logger.info(f"GradHarmonics: 🌊  {t} gradient — "
                    f"{self._stats['injected']} gürültü, {self._stats['compressed']} sıkıştırma")


# ── 9.7  NeuralProfiler™ ─────────────────────────────────────────────────────

class _TinyLSTM(nn.Module):
    def __init__(self,input_size=4,hidden=16,out=3):
        super().__init__()
        self.lstm=nn.LSTM(input_size,hidden,batch_first=True)
        self.out_fc=nn.Linear(hidden,out); self._hidden=None
    def forward(self,x):
        out,self._hidden=self.lstm(x,self._hidden); return self.out_fc(out[:,-1])
    def reset(self): self._hidden=None


class NeuralProfiler:
    """
    NeuralProfiler™ — LSTM tabanlı OOM ve gradient patlaması tahmini (NexusLoRA v1.0).
    ⚠️  ÇAKIŞMA UYARISI: LossSpikeDetector de loss izler ve müdahale eder.
    İkisi aynı anda aktifse aynı olaya çift müdahale olabilir.
    Tavsiye: loss_spike_detection=True ise nexus_neural_profiler=False yapın, ya da tersi.
    """
    def __init__(self,cfg):
        self.cfg=cfg; self.lstm=_TinyLSTM().eval()
        self._buffer=[]; self._step=0; self._alerts=0
        logger.info(f"NeuralProfiler: 🧠  pencere={cfg.nexus_profiler_window}")

    def observe(self,step_ms,loss,grad_norm,vram_pct):
        self._buffer.append([step_ms,loss,grad_norm,vram_pct])
        if len(self._buffer)>self.cfg.nexus_profiler_window: self._buffer.pop(0)
        self._step+=1
        if len(self._buffer)>=8: self._react(self._predict(),step_ms,grad_norm,vram_pct)

    def _predict(self):
        try:
            with torch.no_grad():
                x=torch.tensor(self._buffer,dtype=torch.float32).unsqueeze(0)
                x=(x-x.mean(1,keepdim=True))/(x.std(1,keepdim=True)+1e-6)
                out=torch.sigmoid(self.lstm(x)).squeeze().tolist()
                if not isinstance(out,list): out=[out,0.0,0.0]
            return {k:max(0.,min(1.,v)) for k,v in zip(["speed_risk","oom_risk","explode_risk"],out)}
        except: return {"speed_risk":0.,"oom_risk":0.,"explode_risk":0.}

    def _react(self,pred,step_ms,gnorm,vram_pct):
        if step_ms>self.cfg.nexus_profiler_alert_ms:
            logger.warning(f"NeuralProfiler: ⚠️  Yavaş adım: {step_ms:.0f}ms"); self._alerts+=1
        if pred["oom_risk"]>0.75:
            gc.collect()
            if torch.cuda.is_available(): torch.cuda.empty_cache()
            logger.warning(f"NeuralProfiler: 🧠  OOM riski {pred['oom_risk']:.0%} → önleyici GC")
            self._alerts+=1
        if pred["explode_risk"]>0.75 and gnorm>1.0:
            logger.warning(f"NeuralProfiler: 🧠  Gradient patlaması riski {pred['explode_risk']:.0%}")
            self._alerts+=1

    def report(self):
        avg=sum(b[0] for b in self._buffer)/max(len(self._buffer),1)
        logger.info(f"NeuralProfiler: 🧠  {self._step} adım, ort.{avg:.0f}ms, {self._alerts} uyarı")


# ── 9.8  CrystalPipeline™ ────────────────────────────────────────────────────

class CrystalPipeline:
    """
    CrystalPipeline™ — Dinamik grad-accum + async checkpoint (NexusLoRA v1.0).
    ⚠️  ÇAKIŞMA UYARISI 1: SmartCheckpoint de checkpoint yönetimi yapar.
    ⚠️  ÇAKIŞMA UYARISI 2: DynamicBatchScaler de VRAM'e göre batch ayarlar.
    Tavsiye: smart_checkpoint=False ve dynamic_batch_scaling=False iken kullanın.
    """
    def __init__(self,cfg):
        self.cfg=cfg; self._grad_accum=1
        self._ckpt_q=queue.Queue()
        self._ckpt_thread=threading.Thread(target=self._checkpoint_worker,daemon=True)
        self._ckpt_thread.start(); self._step=0
        logger.info(f"CrystalPipeline: 🔮  lookahead={cfg.nexus_pipeline_lookahead}")

    def adapt_grad_accum(self,vram_used_pct,loss_stability) -> int:
        if not self.cfg.nexus_dynamic_grad_accum: return self._grad_accum
        if vram_used_pct>0.9: self._grad_accum=max(1,self._grad_accum-1)
        elif vram_used_pct<0.6 and loss_stability>0.7:
            self._grad_accum=min(self.cfg.nexus_max_grad_accum,self._grad_accum+1)
        return self._grad_accum

    def queue_checkpoint(self,model,path,step):
        state={k:v.cpu().clone() for k,v in model.state_dict().items()}
        self._ckpt_q.put({"state":state,"path":path,"step":step})
        logger.info(f"CrystalPipeline: 🔮  Checkpoint kuyruğa eklendi (step={step})")

    def _checkpoint_worker(self):
        while True:
            try:
                item=self._ckpt_q.get(timeout=1)
                if item is None: break
                os.makedirs(os.path.dirname(item["path"]) or ".",exist_ok=True)
                torch.save(item["state"],item["path"])
                logger.info(f"CrystalPipeline: 💾  Checkpoint → {item['path']}")
            except queue.Empty: continue
            except Exception as e:
                NexusError.report("CKPT_FAIL","Async checkpoint başarısız",
                    str(e),"Manuel kaydetme deneyin",exc=e)

    def step(self): self._step+=1

    def report(self):
        logger.info(f"CrystalPipeline: 🔮  grad_accum={self._grad_accum}, kuyruk={self._ckpt_q.qsize()}")


# ── 9.9  ZeroWaste™ + UniversalAdapter™ ─────────────────────────────────────

class _OperationWatcher:
    __slots__=("name","total_ms","calls")
    def __init__(self,name): self.name=name; self.total_ms=0.; self.calls=0


class ZeroWaste:
    """ZeroWaste™ — Gereksiz hesap eliminasyonu (NexusLoRA v1.0)"""
    def __init__(self,cfg):
        self.cfg=cfg; self._watchers: Dict[str,_OperationWatcher]={}
        self._frozen: Set[str]=set(); self._step=0
        logger.info(f"ZeroWaste    : ♻️   periyot={cfg.nexus_waste_detect_steps} adım")

    def analyze_model(self,model):
        frozen=0
        for name,param in model.named_parameters():
            if not param.requires_grad: self._frozen.add(name); frozen+=1
        if frozen: logger.info(f"ZeroWaste    : ♻️   {frozen} parametre dondurulmuş")

    def watch(self,name,fn):
        if name not in self._watchers: self._watchers[name]=_OperationWatcher(name)
        w=self._watchers[name]
        @wraps(fn)
        def _wrapper(*a,**kw):
            t0=time.perf_counter(); r=fn(*a,**kw)
            w.total_ms+=(time.perf_counter()-t0)*1000; w.calls+=1; return r
        return _wrapper

    def step_analysis(self,model):
        if self._step%self.cfg.nexus_waste_detect_steps==0 and self._step>50:
            zero_grad=[n for n,p in model.named_parameters()
                       if p.requires_grad and p.grad is None]
            if zero_grad and len(zero_grad)<20:
                logger.debug(f"ZeroWaste    : {len(zero_grad)} gradient almayan parametre")
        self._step+=1

    def report(self):
        logger.info(f"ZeroWaste    : ♻️   {len(self._watchers)} op izlendi, "
                    f"{len(self._frozen)} dondurulmuş parametre")


def _try_import(name):
    try: return __import__(name)
    except ImportError: return None

_transformers_pkg = _try_import("transformers")
_peft_pkg         = _try_import("peft")


class FrameworkDetector:
    @staticmethod
    def detect() -> Dict:
        info={}
        for pkg in ["transformers","peft","accelerate","deepspeed","flash_attn"]:
            m=_try_import(pkg)
            if m:
                try: info[pkg]=getattr(m,"__version__","?")
                except: info[pkg]=True
        if torch.cuda.is_available():
            info["cuda"]=torch.version.cuda
            info["gpu_count"]=torch.cuda.device_count()
            info["gpu_name"]=torch.cuda.get_device_name(0)
            info["vram_gb"]=torch.cuda.get_device_properties(0).total_memory/1e9
        return info


class UniversalAdapter:
    """UniversalAdapter™ — HF, TRL, PEFT, DeepSpeed, vanilla PyTorch uyumluluğu (NexusLoRA v1.0)"""
    def __init__(self,cfg):
        self.cfg=cfg; self.env=FrameworkDetector.detect()
        logger.info("UniversalAdapt: 🌐  Framework tespiti tamamlandı")

    def patch_trainer(self,trainer,fl) -> Any:
        if trainer is None: return trainer
        try:
            if _transformers_pkg and isinstance(trainer,
                    getattr(_transformers_pkg,"Trainer",type(None))):
                return self._patch_hf_trainer(trainer,fl)
            try:
                import trl
                if isinstance(trainer,trl.SFTTrainer):
                    return self._patch_hf_trainer(trainer,fl)
            except: pass
            return self._patch_generic(trainer,fl)
        except Exception as e:
            NexusError.report("ADAPTER_FAIL","Trainer patch başarısız",
                str(e),"Manuel entegrasyon gerekebilir",exc=e); return trainer

    def _patch_hf_trainer(self,trainer,fl):
        try:
            from transformers import TrainerCallback
            class NexusCallback(TrainerCallback):
                def on_step_begin(self_,args,state,control,**kw):
                    fl._on_step_begin(state.global_step)
                def on_step_end(self_,args,state,control,**kw):
                    loss=state.log_history[-1].get("loss",0.) if state.log_history else 0.
                    fl._on_step_end(state.global_step,loss)
                def on_log(self_,args,state,control,logs=None,**kw):
                    if logs: fl._on_log(logs,state.global_step)
                def on_train_end(self_,args,state,control,**kw):
                    fl._nexus_summary()
            trainer.add_callback(NexusCallback())
            logger.info("UniversalAdapt: 🌐  ✅  HuggingFace Trainer patch'lendi")
            if fl.cfg.nexus_spectra_optimizer and fl.spectra_opt:
                try:
                    trainer.optimizer=fl.spectra_opt
                    logger.info("UniversalAdapt: 🌐  ✅  SpectraOptimizer bağlandı")
                except Exception as e:
                    NexusError.report("OPT_BIND","Optimizer binding başarısız",
                        str(e),"Mevcut optimizer korunuyor",exc=e)
        except Exception as e:
            NexusError.report("HF_PATCH","HF Trainer patch hatası",str(e),"Temel callback yok",exc=e)
        return trainer

    def _patch_generic(self,trainer,fl):
        original=getattr(trainer,"training_step",None)
        if original is None: return trainer
        @wraps(original)
        def nexus_step(*args,**kwargs):
            fl._on_step_begin(getattr(trainer,"_step",0))
            result=original(*args,**kwargs)
            loss=result.item() if isinstance(result,torch.Tensor) else float(result)
            fl._on_step_end(getattr(trainer,"_step",0),loss)
            return result
        trainer.training_step=nexus_step
        return trainer


# ── 9.10  NexusLoRA modülleri NexusLoRA'ya doğrudan entegre edildi ──────────
# NexusEngine sınıfı kaldırıldı; tüm Nexus yaşam döngüsü NexusLoRA içindedir.


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 10 — BİRLEŞİK KONFİGÜRASYON
# ══════════════════════════════════════════════════════════════════════════════

@dataclass
class NexusLoRAConfig:
    """
    NexusLoRA birleşik yapılandırması.
    Her özellik True/False + 0.0-1.0 güç kontrolü.

    Çakışma kısayolu:
        - nexus_crystal_core=True     ↔  torch_compile=False
        - nexus_spectra_optimizer=True↔  paged_optimizer=False (veya küçük VRAM'de kapalı bırakın)
        - nexus_chromatic_precision=True ↔ mixed_precision_optimize=False
        - nexus_crystal_pipeline=True ↔ dynamic_batch_scaling=False + smart_checkpoint=False
        - nexus_resonance_scheduler=True → lr_scheduler="constant" yapın
        - nexus_gradient_harmonics=True ↔ gradient_noise_monitor=False
    """
    # ── Model ────────────────────────────────────────────────────────────────
    model_name:        str  = "meta-llama/Llama-3.2-3B"
    max_seq_length:    int  = 2048
    allow_remote_code: bool = False
    strict_mode:       bool = False

    # ── LoRA ────────────────────────────────────────────────────────────────
    lora:                bool  = True
    lora_r:              int   = 16
    lora_alpha:          int   = 32
    lora_dropout:        float = 0.05
    lora_target_modules: Optional[List[str]] = None
    lora_bias:           str   = "none"
    use_rslora:          bool  = False
    lora_power:          float = 1.0

    # ── Quantization ────────────────────────────────────────────────────────
    quantization:              Optional[Literal["4bit","8bit","2bit","none"]] = "4bit"
    bnb_4bit_compute_dtype:    str   = "bf16"
    bnb_4bit_quant_type:       str   = "nf4"
    bnb_4bit_use_double_quant: bool  = True
    quantization_power:        float = 1.0
    two_bit_quant:             bool  = False

    # ── Attention ───────────────────────────────────────────────────────────
    flash_attention:     bool  = True
    sliding_window:      bool  = False
    sliding_window_size: int   = 4096
    ring_attention:      bool  = False
    attention_power:     float = 1.0

    # ── Gradient checkpointing ──────────────────────────────────────────────
    gradient_checkpointing:        bool = True
    gradient_checkpointing_kwargs: Dict = field(
        default_factory=lambda: {"use_reentrant": False})

    # ── Precision ───────────────────────────────────────────────────────────
    precision: Literal["bf16","fp16","fp32","auto"] = "auto"

    # ── Hız ─────────────────────────────────────────────────────────────────
    # ⚠️  torch_compile + nexus_crystal_core aynı anda aktifse çakışma riski!
    torch_compile:           bool  = True
    torch_compile_mode:      str   = "reduce-overhead"
    torch_compile_fullgraph: bool  = False
    compile_cache:           bool  = True
    compile_cache_dir:       str   = ".fastlora_cache"
    compile_power:           float = 0.8
    fused_ops:               bool  = True
    fused_cross_entropy:     bool  = True
    cuda_optimizations:      bool  = True
    batch_packing:           bool  = True
    packing_power:           float = 1.0
    pin_memory:              bool  = True
    auto_batch_size:         bool  = True

    # ── VRAM Guard ──────────────────────────────────────────────────────────
    vram_guard:           bool  = True
    vram_guard_power:     float = 0.85
    vram_min_batch:       int   = 1
    oom_retry:            bool  = True
    vram_guard_threshold: float = field(init=False)

    # ── Offloading ──────────────────────────────────────────────────────────
    cpu_offload:         bool = False
    layer_offload:       bool = False
    layer_offload_keep:  int  = 4
    nvme_offload:        bool = False

    # ── v4.1 Hız + VRAM ─────────────────────────────────────────────────────
    activation_offload:        bool  = False
    kv_cache_optimize:         bool  = True
    gradient_optimize:         bool  = True
    mem_defrag:                bool  = True
    mem_defrag_interval:       int   = 50
    dataloader_optimize:       bool  = True
    sparse_attention:          bool  = False
    sparse_attn_threshold:     float = 0.01
    # ⚠️  mixed_precision_optimize + nexus_chromatic_precision çakışma riski!
    mixed_precision_optimize:  bool  = True

    # ── v4.2 Yeni Sistemler ─────────────────────────────────────────────────
    auto_hardware_scan:         bool  = True
    unlimited_params:           bool  = True
    loss_spike_detection:       bool  = False   # ⚠️  nexus_neural_profiler ile çakışabilir
    loss_spike_threshold:       float = 3.0
    loss_spike_action:          str   = "skip"
    smart_checkpoint:           bool  = False   # ⚠️  nexus_crystal_pipeline ile çakışabilir
    smart_ckpt_min_delta:       float = 0.005
    smart_ckpt_keep_top:        int   = 3
    dynamic_batch_scaling:      bool  = False   # ⚠️  nexus_crystal_pipeline ile çakışabilir
    dyn_batch_up_threshold:     float = 0.60
    dyn_batch_down_threshold:   float = 0.85
    gradient_noise_monitor:     bool  = False   # ⚠️  nexus_gradient_harmonics ile çakışabilir
    unstoppable:                bool  = True

    # ── MoE ─────────────────────────────────────────────────────────────────
    moe_enabled:     bool  = False
    moe_num_experts: int   = 8
    moe_top_k:       int   = 2
    moe_threshold:   float = 0.2
    moe_max_layers:  int   = 4

    # ── Hyperparameter Tuning ────────────────────────────────────────────────
    auto_tune:    bool = False
    tune_trials:  int  = 20
    tune_steps:   int  = 50
    tune_lr:      bool = True
    tune_rank:    bool = True
    tune_batch:   bool = False

    # ── Optimizer ───────────────────────────────────────────────────────────
    # ⚠️  paged_optimizer + nexus_spectra_optimizer: SpectraOptimizer baskın gelir
    paged_optimizer:     bool  = True
    learning_rate:       float = 2e-4
    weight_decay:        float = 0.01
    warmup_ratio:        float = 0.03
    lr_scheduler:        str   = "cosine"  # ⚠️  nexus_resonance_scheduler aktifse "constant" yapın
    max_grad_norm:       float = 1.0

    # ── Distributed ─────────────────────────────────────────────────────────
    multi_gpu:              bool  = False
    distributed_backend:    Literal["ddp","fsdp","deepspeed"] = "ddp"
    deepspeed_stage:        int   = 2
    fsdp_sharding_strategy: str   = "FULL_SHARD"

    # ── Training ────────────────────────────────────────────────────────────
    per_device_train_batch_size: int   = 2
    gradient_accumulation_steps: int   = 4
    num_train_epochs:            int   = 1
    max_steps:                   int   = -1
    logging_steps:               int   = 10
    save_steps:                  int   = 100
    output_dir:                  str   = "./nexuslora_output"
    seed:                        int   = 42
    dataloader_num_workers:      int   = 4
    dataloader_prefetch_factor:  int   = 2
    device:                      str   = "auto"

    # ════════════════════════════════════════════════════════════════════════
    # NexusLoRA Modül Ayarları
    # ════════════════════════════════════════════════════════════════════════
    nexus_enabled: bool  = True
    nexus_power:   float = 1.0
    nexus_verbose: bool  = True

    # CrystalCore™ — ⚠️  torch_compile=True ise False önerilir
    nexus_crystal_core:          bool = True
    nexus_crystal_warmup_steps:  int  = 50
    nexus_crystal_min_freq:      int  = 5
    nexus_crystal_max_kernels:   int  = 32
    nexus_compile_mode:          str  = "reduce-overhead"

    # MorphicMemory™ — ⚠️  mem_defrag=True ile birlikte çift GC'ye yol açar
    nexus_morphic_memory:     bool  = True
    nexus_morph_pool_gb:      float = 1.0
    nexus_morph_history_len:  int   = 128
    nexus_tensor_reincarnation: bool = True

    # SpectraOptimizer™ — ⚠️  paged_optimizer=True ile birlikte SpectraOptimizer baskın gelir
    nexus_spectra_optimizer:  bool  = True
    nexus_spectral_damping:   float = 0.1
    nexus_spectra_history:    int   = 64

    # ResonanceScheduler™ — ⚠️  Aktifse lr_scheduler="constant" yapın
    nexus_resonance_scheduler:    bool  = True
    nexus_base_lr:                float = 2e-4
    nexus_min_lr:                 float = 1e-6
    nexus_resonance_sensitivity:  float = 0.5
    nexus_warmup_steps:           int   = 100

    # ChromaticPrecision™ — ⚠️  mixed_precision_optimize=True ile çakışır
    nexus_chromatic_precision:       bool      = True
    nexus_precision_analysis_steps:  int       = 30
    nexus_force_fp32_layers:         List[str] = field(
        default_factory=lambda: ["lm_head","embed"])

    # GradientHarmonics™ — ⚠️  gradient_noise_monitor=True ile çakışır
    nexus_gradient_harmonics: bool  = True
    nexus_harmonic_levels:    int   = 3
    nexus_harmonic_noise:     float = 0.001
    nexus_harmonic_compress:  float = 0.0

    # NeuralProfiler™ — ⚠️  loss_spike_detection=True ile çakışır
    nexus_neural_profiler:    bool  = True
    nexus_profiler_window:    int   = 32
    nexus_profiler_alert_ms:  float = 500.0

    # CrystalPipeline™ — ⚠️  smart_checkpoint=True ve dynamic_batch_scaling=True ile çakışır
    nexus_crystal_pipeline:    bool = True
    nexus_pipeline_lookahead:  int  = 4
    nexus_dynamic_grad_accum:  bool = True
    nexus_max_grad_accum:      int  = 16

    # ZeroWaste™
    nexus_zero_waste:          bool = True
    nexus_waste_detect_steps:  int  = 20

    # UniversalAdapter™
    nexus_universal_adapter:   bool = True

    def __post_init__(self):
        self.vram_guard_threshold=min(0.95,max(0.5,self.vram_guard_power))
        if self.lora_power<1.0:    self.lora_r=max(1,int(self.lora_r*self.lora_power))
        if self.compile_power>=0.9: self.torch_compile_mode="max-autotune"
        elif self.compile_power>=0.6: self.torch_compile_mode="reduce-overhead"
        else: self.torch_compile_mode="default"
        if self.quantization not in (None,"none") and self.quantization_power<0.7:
            self.quantization="8bit"
        if self.packing_power<0.1:   self.batch_packing=False
        if self.attention_power<0.3: self.flash_attention=False
        # Nexus senkronizasyon
        if not hasattr(self,"nexus_base_lr"): self.nexus_base_lr=self.learning_rate
        # Çakışma uyarıları
        self._warn_conflicts()

    def _warn_conflicts(self):
        if self.nexus_enabled:
            if self.torch_compile and self.nexus_crystal_core:
                logger.warning(
                    "⚠️  ÇAKIŞMA: torch_compile=True + nexus_crystal_core=True — "
                    "Quantized modellerde her ikisi de çalışmayabilir. "
                    "Öneri: torch_compile=False ise CrystalCore™ daha güvenlidir.")
            if self.mixed_precision_optimize and self.nexus_chromatic_precision:
                logger.warning(
                    "⚠️  ÇAKIŞMA: mixed_precision_optimize=True + nexus_chromatic_precision=True — "
                    "İkisi aynı anda dtype atar. Birini kapatın.")
            if self.dynamic_batch_scaling and self.nexus_crystal_pipeline:
                logger.warning(
                    "⚠️  ÇAKIŞMA: dynamic_batch_scaling=True + nexus_crystal_pipeline=True — "
                    "VRAM'e ters tepkiler verebilir. Birini kapatın.")
            if self.smart_checkpoint and self.nexus_crystal_pipeline:
                logger.warning(
                    "⚠️  ÇAKIŞMA: smart_checkpoint=True + nexus_crystal_pipeline=True — "
                    "Çift checkpoint kaydı oluşabilir. Birini kapatın.")
            if self.loss_spike_detection and self.nexus_neural_profiler:
                logger.warning(
                    "⚠️  ÇAKIŞMA: loss_spike_detection=True + nexus_neural_profiler=True — "
                    "Aynı olaya çift müdahale olabilir. Birini kapatın.")
            if self.gradient_noise_monitor and self.nexus_gradient_harmonics:
                logger.warning(
                    "⚠️  ÇAKIŞMA: gradient_noise_monitor=True + nexus_gradient_harmonics=True — "
                    "GradientHarmonics değerleri değiştirdiği için monitor ölçümleri yanıltıcı olur.")
            if self.nexus_resonance_scheduler and self.lr_scheduler!="constant":
                logger.warning(
                    "⚠️  ÇAKIŞMA: nexus_resonance_scheduler=True iken lr_scheduler='constant' "
                    "yapmanız önerilir; aksi halde ResonanceScheduler ve HF scheduler çakışır.")
            if self.nexus_spectra_optimizer and self.paged_optimizer:
                logger.warning(
                    "⚠️  BİLGİ: nexus_spectra_optimizer=True — paged_optimizer ayarı geçersiz, "
                    "SpectraOptimizer baskın gelir. Küçük VRAM'de öneri: nexus_spectra_optimizer=False.")
            if self.mem_defrag and self.nexus_morphic_memory:
                logger.info(
                    "ℹ️  BİLGİ: mem_defrag + nexus_morphic_memory ikisi de GC yapar. "
                    "Zararsız ama mem_defrag_interval'ı 2x artırabilirsiniz.")


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 11 — DEVICE YÖNETİCİSİ
# ══════════════════════════════════════════════════════════════════════════════

class DeviceManager:
    def __init__(self):
        self.device=self._detect(); self.device_name=self._get_name()

    def _detect(self):
        if torch.cuda.is_available():               return torch.device("cuda")
        if hasattr(torch.backends,"mps") and torch.backends.mps.is_available():
            return torch.device("mps")
        return torch.device("cpu")

    def _get_name(self):
        if self.device.type=="cuda": return torch.cuda.get_device_name(0)
        if self.device.type=="mps":  return "Apple Silicon (MPS)"
        return "CPU"

    def get_vram_gb(self):
        return torch.cuda.get_device_properties(0).total_memory/1e9 \
               if self.device.type=="cuda" else 0.

    def get_free_vram_gb(self):
        if self.device.type!="cuda": return 0.
        free,_=torch.cuda.mem_get_info(); return free/1e9

    def get_vram_usage_ratio(self):
        if self.device.type!="cuda": return 0.
        return torch.cuda.memory_allocated()/torch.cuda.get_device_properties(0).total_memory

    def best_dtype(self):
        if self.device.type=="cuda":
            return torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16
        return torch.float32

    def compute_capability(self):
        if self.device.type=="cuda":
            p=torch.cuda.get_device_properties(0); return (p.major,p.minor)
        return (0,0)

    def num_gpus(self):
        return torch.cuda.device_count() if torch.cuda.is_available() else 0

    def report(self):
        logger.info(f"Cihaz        : {self.device_name} ({self.device.type.upper()})")
        v=self.get_vram_gb()
        if v:
            cap=self.compute_capability()
            logger.info(f"VRAM         : {self.get_free_vram_gb():.1f}GB serbest / {v:.1f}GB toplam")
            logger.info(f"Compute Cap  : sm_{cap[0]}{cap[1]}")
        if self.device.type=="cuda" and self.num_gpus()>1:
            logger.info(f"GPU Sayısı   : {self.num_gpus()}")


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 12 — VRAM GUARD
# ══════════════════════════════════════════════════════════════════════════════

class VRAMGuard:
    def __init__(self,cfg,device):
        self.cfg=cfg; self.device=device; self._stop=threading.Event()
        self._monitor=None; self._batch=cfg.per_device_train_batch_size
        self._accum=cfg.gradient_accumulation_steps; self._count=0

    def check_and_adapt(self,trainer=None) -> bool:
        if not self.cfg.vram_guard or self.device.device.type!="cuda": return False
        ratio=self.device.get_vram_usage_ratio()
        if ratio<self.cfg.vram_guard_threshold: return False
        self._count+=1
        vram_used=torch.cuda.memory_allocated()/1e9
        vram_total=self.device.get_vram_gb()
        old=self._batch
        if self._batch>self.cfg.vram_min_batch:
            self._batch=max(self.cfg.vram_min_batch,self._batch//2)
            self._accum=self._accum*(old//max(self._batch,1))
            NexusError.report("VRAM_GUARD",f"VRAM %{ratio*100:.0f} — eşik aşıldı",
                f"{vram_used:.1f}GB/{vram_total:.1f}GB",
                f"Batch {old}→{self._batch}, Accum={self._accum}")
            if trainer and hasattr(trainer,"args"):
                trainer.args.per_device_train_batch_size=self._batch
                trainer.args.gradient_accumulation_steps=self._accum
        gc.collect(); torch.cuda.empty_cache(); return True

    def start_background_monitor(self,interval=5.,trainer=None):
        if not self.cfg.vram_guard: return
        def loop():
            while not self._stop.is_set():
                try: self.check_and_adapt(trainer)
                except: pass
                time.sleep(interval)
        self._monitor=threading.Thread(target=loop,daemon=True)
        self._monitor.start()
        logger.info(f"VRAM Guard   : ✓  eşik={self.cfg.vram_guard_threshold*100:.0f}%")

    def stop_monitor(self):
        self._stop.set()
        if self._monitor: self._monitor.join(timeout=2)

    @property
    def current_batch_size(self): return self._batch
    @property
    def current_accum_steps(self): return self._accum


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 13-22 — NexusLoRA Çekirdek Yöneticiler (değiştirilmeden)
# ══════════════════════════════════════════════════════════════════════════════

class SafeModelLoader:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def load(self,bnb_config=None,attn_impl="sdpa",torch_dtype=torch.float32):
        from transformers import AutoModelForCausalLM
        base=dict(pretrained_model_name_or_path=self.cfg.model_name,
                  trust_remote_code=self.cfg.allow_remote_code,
                  torch_dtype=torch_dtype,device_map="auto",
                  attn_implementation=attn_impl,low_cpu_mem_usage=True)
        if bnb_config: base["quantization_config"]=bnb_config
        chain=[base,
               {**base,"quantization_config":None,"torch_dtype":torch.float16},
               {**base,"quantization_config":None,"torch_dtype":torch.float32,"device_map":"cpu"}]
        last=None
        for i,kw in enumerate(chain):
            try:
                if i>0: logger.warning(f"Model yükleme fallback #{i} deneniyor...")
                m=AutoModelForCausalLM.from_pretrained(**kw)
                m.config.use_cache=False; m.config.pretraining_tp=1
                return m
            except torch.cuda.OutOfMemoryError as e:
                last=e
                NexusError.report("OOM_LOAD",f"Model yükleme OOM (fallback #{i+1})",
                    "VRAM yetersiz","Daha küçük model veya quantization deneyin",impact="severe")
                gc.collect(); torch.cuda.empty_cache()
            except Exception as e:
                last=e
                if self.cfg.strict_mode:
                    NexusError.report("MODEL_LOAD","Model yüklenemedi",str(e),
                        "Model adını ve internet bağlantısını kontrol edin",exc=e,fatal=True)
                NexusError.report("MODEL_LOAD",f"Yükleme hatası (fallback #{i+1})",
                    str(e),"Sonraki yöntem deneniyor",exc=e)
                if i<len(chain)-1: continue
                break
        raise RuntimeError(f"[NexusLoRA] Model yüklenemedi. Son hata: {last}")


class CompileManager:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def _cache_key(self):
        k=f"{self.cfg.model_name}_{self.cfg.torch_compile_mode}_{torch.__version__}"
        return hashlib.md5(k.encode()).hexdigest()[:12]

    def apply(self,model):
        if not self.cfg.torch_compile:
            logger.info("torch.compile: Devre dışı"); return model
        if not _HAS_COMPILE:
            logger.warning("torch.compile: PyTorch 2.0+ gerekli → atlandı"); return model
        if self.cfg.quantization in ("4bit","8bit"):
            logger.info("torch.compile: Quantized → atlandı"); return model
        if self.device.device.type=="mps":
            logger.info("torch.compile: MPS → atlandı"); return model
        if self.cfg.compile_cache:
            os.makedirs(self.cfg.compile_cache_dir,exist_ok=True)
            os.environ.setdefault("TORCHINDUCTOR_CACHE_DIR",
                str(Path(self.cfg.compile_cache_dir)/"inductor"))
        try:
            t0=time.perf_counter()
            model=torch.compile(model,mode=self.cfg.torch_compile_mode,
                                 fullgraph=self.cfg.torch_compile_fullgraph)
            logger.info(f"torch.compile: ✓  mode={self.cfg.torch_compile_mode} "
                        f"({time.perf_counter()-t0:.1f}s)")
        except Exception as e:
            NexusError.report("COMPILE","torch.compile başarısız",str(e),
                "Derlenmemiş modelle devam ediliyor",exc=e)
        return model


class CUDAOptimizer:
    def __init__(self,enabled=True): self.enabled=enabled

    def apply(self):
        if not self.enabled or not torch.cuda.is_available(): return
        torch.backends.cuda.matmul.allow_tf32=True
        torch.backends.cudnn.allow_tf32=True
        torch.backends.cudnn.benchmark=True
        torch.backends.cudnn.deterministic=False
        if _TORCH_VER>=(2,0):
            os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF",
                "max_split_size_mb:512,garbage_collection_threshold:0.8")
        logger.info("CUDA Opts    : TF32 ✓  cuDNN benchmark ✓  allocator ✓")


class QuantizationManager:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def get_bnb_config(self):
        if self.cfg.quantization in ("none","2bit",None): return None
        if not DEPS.get("bitsandbytes"):
            NexusError.report("QUANT","bitsandbytes kurulu değil",
                "4/8bit quantization için gerekli","pip install bitsandbytes"); return None
        if self.device.device.type!="cuda":
            logger.warning("Quantization sadece CUDA → devre dışı"); return None
        from transformers import BitsAndBytesConfig
        dm={"bf16":torch.bfloat16,"fp16":torch.float16,"fp32":torch.float32}
        cd=dm.get(self.cfg.bnb_4bit_compute_dtype,torch.bfloat16)
        if self.cfg.quantization=="4bit":
            logger.info("Quantization : 4-bit NF4 + double quant ✓")
            return BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_compute_dtype=cd,
                bnb_4bit_quant_type=self.cfg.bnb_4bit_quant_type,
                bnb_4bit_use_double_quant=self.cfg.bnb_4bit_use_double_quant)
        logger.info("Quantization : 8-bit ✓")
        return BitsAndBytesConfig(load_in_8bit=True)


class AttentionOptimizer:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def get_attn_implementation(self):
        if not self.cfg.flash_attention: return "sdpa" if _HAS_SDPA else "eager"
        if self.device.device.type!="cuda":
            logger.info("Attention    : SDPA (Flash Att sadece CUDA)"); return "sdpa"
        if DEPS.get("flash_attn"):
            logger.info("Attention    : Flash Attention 2 ✓"); return "flash_attention_2"
        if _HAS_SDPA:
            logger.info("Attention    : SDPA (built-in)"); return "sdpa"
        return "eager"

    def patch_sliding_window(self,model):
        if not self.cfg.sliding_window: return model
        try:
            if hasattr(model.config,"sliding_window"):
                model.config.sliding_window=self.cfg.sliding_window_size
                logger.info(f"Sliding Win  : ✓  window={self.cfg.sliding_window_size}")
            else: logger.info("Sliding Win  : Bu model desteklemiyor → atlandı")
        except Exception as e:
            NexusError.report("SLIDING_WIN","Sliding window patch başarısız",
                str(e),"Orijinal attention korunuyor")
        return model


_LORA_TARGETS = {
    "llama":   ["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
    "mistral": ["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
    "phi":     ["q_proj","k_proj","v_proj","dense","fc1","fc2"],
    "gemma":   ["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
    "qwen":    ["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
    "falcon":  ["query_key_value","dense","dense_h_to_4h","dense_4h_to_h"],
    "gpt2":    ["c_attn","c_proj","c_fc"],
    "bloom":   ["query_key_value","dense","dense_h_to_4h","dense_4h_to_h"],
    "t5":      ["q","v"],
    "default": ["q_proj","v_proj"],
}

class LoRAManager:
    def __init__(self,cfg): self.cfg=cfg

    def _detect_targets(self,model):
        mt=getattr(model.config,"model_type","").lower()
        for k,v in _LORA_TARGETS.items():
            if k in mt: logger.info(f"LoRA hedefler: {v}"); return v
        names=sorted({n.split(".")[-1] for n,m in model.named_modules()
            if isinstance(m,nn.Linear) and
            n.split(".")[-1] not in ("lm_head","embed_tokens","embed_positions")})[:8]
        logger.info(f"LoRA hedefler: {names} (otomatik)")
        return names or _LORA_TARGETS["default"]

    def apply(self,model):
        if not self.cfg.lora:
            logger.info("LoRA         : Devre dışı"); return model
        if not DEPS.get("peft"):
            NexusError.report("LORA","PEFT kurulu değil","LoRA için gerekli","pip install peft")
            return model
        try:
            from peft import LoraConfig,get_peft_model,prepare_model_for_kbit_training
            if self.cfg.quantization in ("4bit","8bit") and DEPS.get("bitsandbytes"):
                model=prepare_model_for_kbit_training(model,
                    use_gradient_checkpointing=self.cfg.gradient_checkpointing,
                    gradient_checkpointing_kwargs=self.cfg.gradient_checkpointing_kwargs)
            targets=self.cfg.lora_target_modules or self._detect_targets(model)
            model=get_peft_model(model,LoraConfig(
                r=self.cfg.lora_r,lora_alpha=self.cfg.lora_alpha,
                target_modules=targets,lora_dropout=self.cfg.lora_dropout,
                bias=self.cfg.lora_bias,task_type="CAUSAL_LM",
                use_rslora=self.cfg.use_rslora))
            tr=sum(p.numel() for p in model.parameters() if p.requires_grad)
            tt=sum(p.numel() for p in model.parameters())
            logger.info(f"LoRA         : ✓  r={self.cfg.lora_r}, α={self.cfg.lora_alpha}")
            logger.info(f"Params       : {tr:,}/{tt:,} ({100*tr/tt:.2f}% eğitilebilir)")
        except Exception as e:
            NexusError.report("LORA","LoRA uygulanamadı",str(e),
                "Base model ile devam ediliyor",exc=e)
        return model


class GradientCheckpointManager:
    def __init__(self,cfg): self.cfg=cfg

    def apply(self,model):
        if not self.cfg.gradient_checkpointing:
            logger.info("Grad Ckpt    : Devre dışı"); return model
        if getattr(model,"is_gradient_checkpointing",False):
            logger.info("Grad Ckpt    : Zaten aktif"); return model
        if hasattr(model,"gradient_checkpointing_enable"):
            try:
                model.gradient_checkpointing_enable(
                    gradient_checkpointing_kwargs=self.cfg.gradient_checkpointing_kwargs)
                logger.info("Grad Ckpt    : ✓")
            except Exception as e:
                NexusError.report("GRAD_CKPT","Gradient checkpointing başarısız",
                    str(e),"Checkpointing olmadan devam")
        return model


class SequencePacker:
    def __init__(self,tokenizer,cfg): self.tokenizer=tokenizer; self.cfg=cfg

    def pack_dataset(self,dataset,text_column="text"):
        if not DEPS.get("datasets"):
            NexusError.report("PACKING","datasets kurulu değil",
                "Sequence packing için gerekli","pip install datasets"); return dataset
        try:
            from datasets import Dataset
            all_ids: List[int]=[]
            for s in dataset:
                text=s.get(text_column,"")
                if not text: continue
                ids=self.tokenizer.encode(text,add_special_tokens=True)
                all_ids.extend(ids[:self.cfg.max_seq_length])
                all_ids.append(self.tokenizer.eos_token_id)
            L=self.cfg.max_seq_length
            chunks=[all_ids[i:i+L] for i in range(0,len(all_ids)-L,L)]
            packed=Dataset.from_dict({"input_ids":chunks,"labels":chunks,
                "attention_mask":[[1]*L for _ in chunks]})
            logger.info(f"Packing      : ✓  {len(dataset)}→{len(packed)} batch")
            return packed
        except Exception as e:
            NexusError.report("PACKING","Sequence packing başarısız",str(e),
                "Orijinal dataset kullanılıyor",exc=e); return dataset


class DistributedManager:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def setup(self) -> Dict:
        n=self.device.num_gpus()
        if not self.cfg.multi_gpu or n<=1: return {}
        b=self.cfg.distributed_backend
        logger.info(f"Distributed  : {b.upper()} ({n} GPU)")
        if b=="deepspeed": return self._deepspeed_args()
        if b=="fsdp": return self._fsdp_args()
        return {"ddp_find_unused_parameters":False}

    def _deepspeed_args(self) -> Dict:
        if not DEPS.get("deepspeed"):
            NexusError.report("DEEPSPEED","DeepSpeed kurulu değil",
                "distributed_backend='deepspeed'","pip install deepspeed")
            return {"ddp_find_unused_parameters":False}
        stage=self.cfg.deepspeed_stage
        cfg={"zero_optimization":{"stage":stage,"allgather_partitions":True,
             "reduce_scatter":True,"overlap_comm":True,"contiguous_gradients":True},
             "bf16":{"enabled":True},"gradient_clipping":self.cfg.max_grad_norm}
        if stage==3:
            cfg["zero_optimization"]["offload_optimizer"]={"device":"cpu"}
            cfg["zero_optimization"]["offload_param"]={"device":"cpu"}
        p=Path(self.cfg.output_dir)/"ds_config.json"
        p.parent.mkdir(exist_ok=True); p.write_text(json.dumps(cfg,indent=2))
        return {"deepspeed":str(p)}

    def _fsdp_args(self) -> Dict:
        return {"fsdp":self.cfg.fsdp_sharding_strategy,"fsdp_config":{
            "fsdp_auto_wrap_policy":"TRANSFORMER_BASED_WRAP",
            "fsdp_backward_prefetch":"BACKWARD_PRE","fsdp_use_orig_params":True}}


class BatchSizeFinder:
    def __init__(self,cfg,device): self.cfg=cfg; self.device=device

    def find(self,model) -> int:
        if not self.cfg.auto_batch_size or self.device.device.type!="cuda":
            return self.cfg.per_device_train_batch_size
        free=self.device.get_free_vram_gb()
        safe=min(max(1,int(free/0.5)),32)
        base=self.cfg.per_device_train_batch_size
        if safe>base:
            logger.info(f"Batch Size   : {base}→{safe} (oto, {free:.1f}GB serbest)")
            return safe
        return base


class AdapterManager:
    def __init__(self):
        self._active=None; self._adapters: Dict[str,str]={}

    def register(self,name,path):
        self._adapters[name]=path
        logger.info(f"Adapter      : '{name}' kaydedildi ({path})")

    def swap(self,model,name):
        if not DEPS.get("peft"):
            NexusError.report("ADAPTER","PEFT kurulu değil","Adapter swap","pip install peft")
            return model
        if name not in self._adapters:
            NexusError.report("ADAPTER",f"Adapter '{name}' bulunamadı",
                str(list(self._adapters.keys())),"fl.adapter_manager.register() çağırın")
            return model
        try:
            from peft import PeftModel
            path=self._adapters[name]
            if isinstance(model,PeftModel):
                if name not in model.peft_config: model.load_adapter(path,adapter_name=name)
                model.set_adapter(name)
            else: model=PeftModel.from_pretrained(model,path,adapter_name=name)
            self._active=name; logger.info(f"Adapter Swap : '{name}' ✓")
        except Exception as e:
            NexusError.report("ADAPTER",f"Adapter swap başarısız: '{name}'",
                str(e),"Önceki adapter korunuyor",exc=e)
        return model

    def save(self,model,name,path):
        try: model.save_pretrained(path); self.register(name,path)
        except Exception as e:
            NexusError.report("ADAPTER","Adapter kaydedilemedi",str(e),f"model.save_pretrained('{path}')",exc=e)

    @property
    def active(self): return self._active
    @property
    def available(self): return list(self._adapters.keys())


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 23 — ANA SINIF: NexusLoRA
# ══════════════════════════════════════════════════════════════════════════════

class NexusLoRA:
    """
    NexusLoRA — Birleşik LLM Fine-Tuning Motoru

    Hızlı başlangıç:
        fl = NexusLoRA("meta-llama/Llama-3.2-3B",
                      nexus_enabled=True, nexus_power=1.0)
        model, tokenizer = fl.load()
        trainer = fl.get_trainer(dataset)
        fl.train(trainer)

    Sadece NexusLoRA (NexusLoRA kapalı):
        fl = NexusLoRA("meta-llama/Llama-3.2-3B", nexus_enabled=False)

    Sadece NexusLoRA modülleri (belirli):
        fl = NexusLoRA("model",
                      nexus_enabled=True, nexus_power=1.0,
                      nexus_spectra_optimizer=False,  # Eski optimizer korunsun
                      nexus_chromatic_precision=False) # MixedPrecisionOptimizer baskın
    """

    def __init__(
        self,
        model_name_or_config: Union[str, NexusLoRAConfig] = "meta-llama/Llama-3.2-3B", *,
        lora: bool = True, lora_r: int = 16, lora_alpha: int = 32,
        lora_dropout: float = 0.05, lora_target_modules: Optional[List[str]] = None,
        use_rslora: bool = False,
        quantization: Optional[Literal["4bit","8bit","2bit","none"]] = "4bit",
        flash_attention: bool = True, gradient_checkpointing: bool = True,
        precision: Literal["bf16","fp16","fp32","auto"] = "auto",
        allow_remote_code: bool = False, strict_mode: bool = False,
        vram_guard: bool = True, vram_guard_power: float = 0.85, oom_retry: bool = True,
        torch_compile: bool = True, compile_power: float = 0.8,
        compile_cache: bool = True, torch_compile_fullgraph: bool = False,
        fused_ops: bool = True, fused_cross_entropy: bool = True,
        cuda_optimizations: bool = True, batch_packing: bool = True,
        packing_power: float = 1.0, pin_memory: bool = True, auto_batch_size: bool = True,
        lora_power: float = 1.0, quantization_power: float = 1.0, attention_power: float = 1.0,
        cpu_offload: bool = False, layer_offload: bool = False, layer_offload_keep: int = 4,
        two_bit_quant: bool = False, activation_offload: bool = False,
        kv_cache_optimize: bool = True, gradient_optimize: bool = True,
        mem_defrag: bool = True, mem_defrag_interval: int = 50,
        dataloader_optimize: bool = True, sparse_attention: bool = False,
        sparse_attn_threshold: float = 0.01, mixed_precision_optimize: bool = True,
        auto_hardware_scan: bool = True, unlimited_params: bool = True,
        loss_spike_detection: bool = False, loss_spike_threshold: float = 3.0,
        loss_spike_action: str = "skip", smart_checkpoint: bool = False,
        smart_ckpt_min_delta: float = 0.005, smart_ckpt_keep_top: int = 3,
        dynamic_batch_scaling: bool = False, dyn_batch_up_threshold: float = 0.60,
        dyn_batch_down_threshold: float = 0.85, gradient_noise_monitor: bool = False,
        unstoppable: bool = True,
        moe_enabled: bool = False, moe_num_experts: int = 8,
        moe_top_k: int = 2, moe_threshold: float = 0.2, moe_max_layers: int = 4,
        auto_tune: bool = False, tune_trials: int = 20, tune_steps: int = 50,
        tune_lr: bool = True, tune_rank: bool = True, tune_batch: bool = False,
        sliding_window: bool = False, sliding_window_size: int = 4096,
        ring_attention: bool = False, multi_gpu: bool = False,
        distributed_backend: Literal["ddp","fsdp","deepspeed"] = "ddp", deepspeed_stage: int = 2,
        paged_optimizer: bool = True, learning_rate: float = 2e-4,
        max_seq_length: int = 2048, per_device_train_batch_size: int = 2,
        gradient_accumulation_steps: int = 4, num_train_epochs: int = 1,
        output_dir: str = "./nexuslora_output",
        # ── NexusLoRA ──────────────────────────────────────────────────────
        nexus_enabled: bool = True, nexus_power: float = 1.0,
        nexus_crystal_core: bool = True, nexus_morphic_memory: bool = True,
        nexus_spectra_optimizer: bool = True, nexus_resonance_scheduler: bool = True,
        nexus_chromatic_precision: bool = True, nexus_gradient_harmonics: bool = True,
        nexus_neural_profiler: bool = True, nexus_crystal_pipeline: bool = True,
        nexus_zero_waste: bool = True, nexus_universal_adapter: bool = True,
        nexus_verbose: bool = True,
    ):
        if isinstance(model_name_or_config, NexusLoRAConfig):
            self.cfg = model_name_or_config
        else:
            self.cfg = NexusLoRAConfig(
                model_name=model_name_or_config, lora=lora, lora_r=lora_r,
                lora_alpha=lora_alpha, lora_dropout=lora_dropout,
                lora_target_modules=lora_target_modules, use_rslora=use_rslora,
                quantization=quantization, flash_attention=flash_attention,
                gradient_checkpointing=gradient_checkpointing, precision=precision,
                allow_remote_code=allow_remote_code, strict_mode=strict_mode,
                vram_guard=vram_guard, vram_guard_power=vram_guard_power, oom_retry=oom_retry,
                torch_compile=torch_compile, compile_power=compile_power,
                compile_cache=compile_cache, torch_compile_fullgraph=torch_compile_fullgraph,
                fused_ops=fused_ops, fused_cross_entropy=fused_cross_entropy,
                cuda_optimizations=cuda_optimizations, batch_packing=batch_packing,
                packing_power=packing_power, pin_memory=pin_memory, auto_batch_size=auto_batch_size,
                lora_power=lora_power, quantization_power=quantization_power,
                attention_power=attention_power, cpu_offload=cpu_offload,
                layer_offload=layer_offload, layer_offload_keep=layer_offload_keep,
                two_bit_quant=two_bit_quant, activation_offload=activation_offload,
                kv_cache_optimize=kv_cache_optimize, gradient_optimize=gradient_optimize,
                mem_defrag=mem_defrag, mem_defrag_interval=mem_defrag_interval,
                dataloader_optimize=dataloader_optimize, sparse_attention=sparse_attention,
                sparse_attn_threshold=sparse_attn_threshold,
                mixed_precision_optimize=mixed_precision_optimize,
                auto_hardware_scan=auto_hardware_scan, unlimited_params=unlimited_params,
                loss_spike_detection=loss_spike_detection,
                loss_spike_threshold=loss_spike_threshold, loss_spike_action=loss_spike_action,
                smart_checkpoint=smart_checkpoint, smart_ckpt_min_delta=smart_ckpt_min_delta,
                smart_ckpt_keep_top=smart_ckpt_keep_top,
                dynamic_batch_scaling=dynamic_batch_scaling,
                dyn_batch_up_threshold=dyn_batch_up_threshold,
                dyn_batch_down_threshold=dyn_batch_down_threshold,
                gradient_noise_monitor=gradient_noise_monitor, unstoppable=unstoppable,
                moe_enabled=moe_enabled, moe_num_experts=moe_num_experts,
                moe_top_k=moe_top_k, moe_threshold=moe_threshold, moe_max_layers=moe_max_layers,
                auto_tune=auto_tune, tune_trials=tune_trials, tune_steps=tune_steps,
                tune_lr=tune_lr, tune_rank=tune_rank, tune_batch=tune_batch,
                sliding_window=sliding_window, sliding_window_size=sliding_window_size,
                ring_attention=ring_attention, multi_gpu=multi_gpu,
                distributed_backend=distributed_backend, deepspeed_stage=deepspeed_stage,
                paged_optimizer=paged_optimizer, learning_rate=learning_rate,
                max_seq_length=max_seq_length,
                per_device_train_batch_size=per_device_train_batch_size,
                gradient_accumulation_steps=gradient_accumulation_steps,
                num_train_epochs=num_train_epochs, output_dir=output_dir,
                nexus_enabled=nexus_enabled, nexus_power=nexus_power,
                nexus_verbose=nexus_verbose, nexus_crystal_core=nexus_crystal_core,
                nexus_morphic_memory=nexus_morphic_memory,
                nexus_spectra_optimizer=nexus_spectra_optimizer,
                nexus_resonance_scheduler=nexus_resonance_scheduler,
                nexus_chromatic_precision=nexus_chromatic_precision,
                nexus_gradient_harmonics=nexus_gradient_harmonics,
                nexus_neural_profiler=nexus_neural_profiler,
                nexus_crystal_pipeline=nexus_crystal_pipeline,
                nexus_zero_waste=nexus_zero_waste,
                nexus_universal_adapter=nexus_universal_adapter,
            )

        global DEPS
        DEPS = _check_deps(strict=self.cfg.strict_mode)

        self.device_mgr     = DeviceManager()
        self.quant_mgr      = QuantizationManager(self.cfg, self.device_mgr)
        self.attn_mgr       = AttentionOptimizer(self.cfg, self.device_mgr)
        self.lora_mgr       = LoRAManager(self.cfg)
        self.grad_mgr       = GradientCheckpointManager(self.cfg)
        self.compile_mgr    = CompileManager(self.cfg, self.device_mgr)
        self.cuda_opt       = CUDAOptimizer(self.cfg.cuda_optimizations)
        self.bs_finder      = BatchSizeFinder(self.cfg, self.device_mgr)
        self.vram_guard     = VRAMGuard(self.cfg, self.device_mgr)
        self.safe_loader    = SafeModelLoader(self.cfg, self.device_mgr)
        self.dist_mgr       = DistributedManager(self.cfg, self.device_mgr)
        self.adapter_manager= AdapterManager()
        self.offload_mgr    = OffloadManager(self.cfg)
        self.moe_patcher    = MoEPatcher(self.cfg)
        self.oom_recovery   = OOMRecovery(self.cfg, self.device_mgr)
        self.act_offloader  = ActivationOffloader(self.cfg.activation_offload)
        self.kv_optimizer   = KVCacheOptimizer(self.cfg.kv_cache_optimize)
        self.grad_optimizer = GradientOptimizer(self.cfg)
        self.mem_defrag     = MemoryFragmentationFixer(self.cfg.mem_defrag, self.cfg.mem_defrag_interval)
        self.dl_optimizer   = DataLoaderOptimizer(self.cfg)
        self.sparse_attn    = SparseAttentionOptimizer(self.cfg.sparse_attention, self.cfg.sparse_attn_threshold)
        self.mp_optimizer   = MixedPrecisionOptimizer(self.cfg.mixed_precision_optimize)
        self.hw_scanner     = HardwareScanner()
        self.param_mgr      = UnlimitedParamManager(self.cfg, self.device_mgr)
        self.crash_handler  = AdvancedCrashHandler(self.cfg, self.device_mgr)
        self.model          = None
        self.tokenizer      = None

        # ── NexusLoRA modülleri (doğrudan NexusLoRA'da) ──────────────────────
        self.crystal_core:    Optional[CrystalCore]         = None
        self.morphic_memory:  Optional[MorphicMemory]       = None
        self.spectra_opt:     Optional[SpectraOptimizer]    = None
        self.resonance_sched: Optional[ResonanceScheduler]  = None
        self.chromatic_prec:  Optional[ChromaticPrecision]  = None
        self.grad_harmonics:  Optional[GradientHarmonics]   = None
        self.neural_profiler: Optional[NeuralProfiler]      = None
        self.crystal_pipeline:Optional[CrystalPipeline]     = None
        self.zero_waste:      Optional[ZeroWaste]           = None
        self.universal_adapter: Optional[UniversalAdapter]  = None
        self._harmonic_hooks: List = []
        self._nx_step        = 0
        self._nx_step_times: List[float] = []
        self._nx_t_start     = 0.

        self._print_banner()

    # ── Yükleme ──────────────────────────────────────────────────────────────

    def load(self):
        """Modeli yükler, tüm NexusLoRA + NexusLoRA optimizasyonlarını uygular."""
        self.cuda_opt.apply()
        self.device_mgr.report()
        logger.info(f"Model        : {self.cfg.model_name}")

        tokenizer = self._load_tokenizer()
        bnb       = self.quant_mgr.get_bnb_config()
        attn      = self.attn_mgr.get_attn_implementation()
        dtype     = self._resolve_dtype()
        logger.info(f"Dtype        : {dtype}")

        model = self.safe_loader.load(bnb_config=bnb, attn_impl=attn, torch_dtype=dtype)
        model = self.lora_mgr.apply(model)
        model = self.grad_mgr.apply(model)
        model = self.attn_mgr.patch_sliding_window(model)

        if self.cfg.two_bit_quant:
            replaced = TwoBitQuantizer.quantize_model(model)
            logger.info(f"2-bit Quant  : ✓  {replaced} katman quantize edildi")

        self.moe_patcher.patch(model)
        if self.cfg.unlimited_params:
            self.param_mgr.apply(model, self.cfg)

        self.kv_optimizer.apply(model)
        self.grad_optimizer.apply(model)
        self.sparse_attn.apply(model)
        self.mp_optimizer.apply(model, dtype)
        if self.cfg.activation_offload:
            self.act_offloader.attach(model)
        if self.cfg.layer_offload:
            self.offload_mgr.offload_layers(model, self.cfg.layer_offload_keep)
        if self.cfg.fused_ops:
            model = self._patch_rmsnorm(model)
        model = self.compile_mgr.apply(model)

        self.model     = model
        self.tokenizer = tokenizer

        # ── NexusLoRA doğrudan başlatma ─────────────────────────────────────
        if self.cfg.nexus_enabled and self.cfg.nexus_power > 0:
            logger.info("NexusLoRA   : 🔮  Modüller başlatılıyor...")
            self._nexus_init()
            logger.info("NexusLoRA   : ⚡  ENGAGE — tüm modüller aktif")

        self._memory_report()
        return model, tokenizer

    def _load_tokenizer(self):
        from transformers import AutoTokenizer
        try:
            tok = AutoTokenizer.from_pretrained(
                self.cfg.model_name,
                trust_remote_code=self.cfg.allow_remote_code,
                model_max_length=self.cfg.max_seq_length)
            if tok.pad_token is None:
                tok.pad_token=tok.eos_token; tok.pad_token_id=tok.eos_token_id
            tok.padding_side="right"; return tok
        except Exception as e:
            NexusError.report("TOKENIZER","Tokenizer yüklenemedi",str(e),
                "Model adını kontrol edin",exc=e,fatal=True)

    def _resolve_dtype(self):
        if self.cfg.precision=="auto": return self.device_mgr.best_dtype()
        return {"bf16":torch.bfloat16,"fp16":torch.float16,"fp32":torch.float32}[self.cfg.precision]

    def _patch_rmsnorm(self, model):
        try:
            FN=TritonKernels.build_rmsnorm(); replaced=0
            for name, module in list(model.named_modules()):
                if "rmsnorm" not in type(module).__name__.lower(): continue
                if not hasattr(module,"weight"): continue
                h=module.weight.shape[0]
                eps=getattr(module,"variance_epsilon",getattr(module,"eps",1e-6))
                nm=FN(h,eps).to(module.weight.device); nm.weight=module.weight
                parts=name.split("."); parent=model
                for p in parts[:-1]: parent=getattr(parent,p)
                setattr(parent,parts[-1],nm); replaced+=1
            if replaced: logger.info(f"Fused Ops    : ✓  {replaced} RMSNorm optimize edildi")
        except Exception as e:
            NexusError.report("FUSED_OPS","RMSNorm patch başarısız",str(e),"Orijinal korunuyor")
        return model

    # ── Trainer ──────────────────────────────────────────────────────────────

    def get_trainer(self, train_dataset, eval_dataset=None,
                    formatting_func=None, auto_pack=None):
        assert self.model is not None, "Önce fl.load() çağırın!"

        if self.cfg.auto_tune:
            HyperparamTuner(self, n_trials=self.cfg.tune_trials,
                            tune_steps=self.cfg.tune_steps, tune_lr=self.cfg.tune_lr,
                            tune_rank=self.cfg.tune_rank, tune_batch=self.cfg.tune_batch
                            ).tune(train_dataset, formatting_func)

        if (auto_pack is None and self.cfg.batch_packing) or auto_pack:
            train_dataset = SequencePacker(self.tokenizer, self.cfg).pack_dataset(train_dataset)

        bs      = self.bs_finder.find(self.model)
        dist_kw = self.dist_mgr.setup()

        if DEPS.get("trl"):
            trainer = self._sft_trainer(train_dataset, eval_dataset, formatting_func, bs, dist_kw)
        else:
            NexusError.report("TRL","TRL kurulu değil","SFTTrainer için gerekli","pip install trl")
            trainer = self._hf_trainer(train_dataset, eval_dataset, bs, dist_kw)

        if self.cfg.cpu_offload:
            self.offload_mgr.offload_optimizer_state(
                trainer.optimizer if hasattr(trainer,"optimizer") else None)

        self.vram_guard.start_background_monitor(interval=5.,trainer=trainer)
        self.dl_optimizer.patch_training_args(trainer.args)
        self.mem_defrag.attach_to_trainer(trainer)

        if self.cfg.loss_spike_detection:
            LossSpikeDetector(self.cfg.loss_spike_threshold,
                              action=self.cfg.loss_spike_action).patch_trainer(trainer)
        if self.cfg.dynamic_batch_scaling:
            DynamicBatchScaler(self.cfg, self.device_mgr,
                               self.cfg.dyn_batch_up_threshold,
                               self.cfg.dyn_batch_down_threshold).patch_trainer(trainer)
        if self.cfg.gradient_noise_monitor and self.model:
            GradientNoiseMonitor().patch_trainer(trainer, self.model)
        if self.cfg.smart_checkpoint:
            SmartCheckpoint(self.cfg.output_dir,
                            min_delta=self.cfg.smart_ckpt_min_delta,
                            keep_top=self.cfg.smart_ckpt_keep_top).patch_trainer(trainer)

        # ── NexusLoRA Trainer patch ─────────────────────────────────────────
        if self.cfg.nexus_enabled and self.universal_adapter:
            trainer = self.universal_adapter.patch_trainer(trainer, self)
            logger.info("NexusLoRA   : ✅  Trainer'a NexusLoRA modülleri bağlandı")
        elif self.cfg.nexus_enabled and self.cfg.nexus_power > 0:
            logger.warning("NexusLoRA   : UniversalAdapter devre dışı — trainer patch atlandı")

        return trainer

    def _optimizer_name(self):
        if self.cfg.paged_optimizer and DEPS.get("bitsandbytes"):
            return "paged_adamw_8bit"
        if _HAS_FUSED_ADAM: return "adamw_torch_fused"
        return "adamw_torch"

    def _sft_trainer(self, tds, eds, ff, bs, dkw):
        from trl import SFTTrainer, SFTConfig
        dtype=self._resolve_dtype(); opt=self._optimizer_name()
        logger.info(f"Optimizer    : {opt}")
        args=SFTConfig(
            output_dir=self.cfg.output_dir,
            per_device_train_batch_size=bs,
            gradient_accumulation_steps=self.vram_guard.current_accum_steps,
            num_train_epochs=self.cfg.num_train_epochs, max_steps=self.cfg.max_steps,
            learning_rate=self.cfg.learning_rate, weight_decay=self.cfg.weight_decay,
            warmup_ratio=self.cfg.warmup_ratio, lr_scheduler_type=self.cfg.lr_scheduler,
            max_grad_norm=self.cfg.max_grad_norm, logging_steps=self.cfg.logging_steps,
            save_steps=self.cfg.save_steps, bf16=(dtype==torch.bfloat16),
            fp16=(dtype==torch.float16), optim=opt, seed=self.cfg.seed,
            dataloader_num_workers=self.cfg.dataloader_num_workers,
            dataloader_pin_memory=self.cfg.pin_memory,
            dataloader_prefetch_factor=(self.cfg.dataloader_prefetch_factor
                if self.cfg.dataloader_num_workers>0 else None),
            report_to="none", max_seq_length=self.cfg.max_seq_length,
            dataset_num_proc=2, packing=False,
            group_by_length=not self.cfg.batch_packing, **dkw)
        return SFTTrainer(model=self.model, tokenizer=self.tokenizer,
            train_dataset=tds, eval_dataset=eds, formatting_func=ff, args=args)

    def _hf_trainer(self, tds, eds, bs, dkw):
        from transformers import Trainer, TrainingArguments, DataCollatorForLanguageModeling
        dtype=self._resolve_dtype()
        args=TrainingArguments(
            output_dir=self.cfg.output_dir,
            per_device_train_batch_size=bs,
            gradient_accumulation_steps=self.vram_guard.current_accum_steps,
            num_train_epochs=self.cfg.num_train_epochs, max_steps=self.cfg.max_steps,
            learning_rate=self.cfg.learning_rate, weight_decay=self.cfg.weight_decay,
            warmup_ratio=self.cfg.warmup_ratio, lr_scheduler_type=self.cfg.lr_scheduler,
            max_grad_norm=self.cfg.max_grad_norm, logging_steps=self.cfg.logging_steps,
            save_steps=self.cfg.save_steps, bf16=(dtype==torch.bfloat16),
            fp16=(dtype==torch.float16), optim=self._optimizer_name(), seed=self.cfg.seed,
            dataloader_num_workers=self.cfg.dataloader_num_workers,
            dataloader_pin_memory=self.cfg.pin_memory, report_to="none",
            group_by_length=not self.cfg.batch_packing, **dkw)
        return Trainer(model=self.model, args=args, train_dataset=tds, eval_dataset=eds,
            data_collator=DataCollatorForLanguageModeling(self.tokenizer,mlm=False))

    # ── Eğitim ───────────────────────────────────────────────────────────────

    def train(self, trainer, resume_path=None):
        """Durdurulmaz eğitim. Sadece kullanıcı durdurabilir (KeyboardInterrupt)."""
        if self.cfg.unstoppable:
            ut=UnstoppableTrainer(self,self.crash_handler)
            result=ut.train(trainer,resume_path)
        else:
            result=self.oom_recovery.wrap_train(trainer,resume_path)
        # Özetler
        NexusError.summary()
        NexusError.save(os.path.join(self.cfg.output_dir,"nexuslora_errors.json"))
        if self.cfg.nexus_enabled:
            self._nexus_summary()
        return result

    # ── Kaydet / Hub / Merge ─────────────────────────────────────────────────

    def save(self, path=None):
        assert self.model is not None, "Önce fl.load() çağırın!"
        self.vram_guard.stop_monitor()
        path=path or self.cfg.output_dir; os.makedirs(path,exist_ok=True)
        try:
            self.model.save_pretrained(path)
            if self.tokenizer: self.tokenizer.save_pretrained(path)
            logger.info(f"Kaydedildi   : {path}")
        except Exception as e:
            NexusError.report("SAVE","Model kaydedilemedi",str(e),
                f"Manuel: model.save_pretrained('{path}')",exc=e)

    def push_to_hub(self, repo_id, token=None):
        assert self.model is not None, "Önce fl.load() çağırın!"
        try:
            self.model.push_to_hub(repo_id,token=token)
            if self.tokenizer: self.tokenizer.push_to_hub(repo_id,token=token)
            logger.info(f"Hub          : https://huggingface.co/{repo_id}")
        except Exception as e:
            NexusError.report("HUB","Hub yükleme başarısız",str(e),
                "İnternet ve token'ı kontrol edin",exc=e)

    def merge_and_unload(self):
        if not DEPS.get("peft"): return self.model
        try:
            from peft import PeftModel
            if isinstance(self.model,PeftModel):
                logger.info("LoRA merge   : başlıyor...")
                self.model=self.model.merge_and_unload()
                logger.info("LoRA merge   : ✓")
        except Exception as e:
            NexusError.report("MERGE","LoRA merge başarısız",str(e),"LoRA ağırlıkları ayrı kaldı",exc=e)
        return self.model

    # ── Inference ────────────────────────────────────────────────────────────

    @torch.inference_mode()
    def generate(self, prompt, max_new_tokens=256, temperature=0.7,
                 top_p=0.9, do_sample=True, repetition_penalty=1.1):
        assert self.model is not None, "Önce fl.load() çağırın!"
        self.model.config.use_cache=True
        try:
            inp=self.tokenizer(prompt,return_tensors="pt").to(self.device_mgr.device)
            out=self.model.generate(**inp, max_new_tokens=max_new_tokens,
                temperature=temperature, top_p=top_p, do_sample=do_sample,
                repetition_penalty=repetition_penalty,
                pad_token_id=self.tokenizer.eos_token_id)
            return self.tokenizer.decode(out[0][inp["input_ids"].shape[1]:],skip_special_tokens=True)
        except Exception as e:
            NexusError.report("GENERATE","Metin üretimi başarısız",str(e),
                "Model ve tokenizer'ı kontrol edin",exc=e); return ""
        finally:
            self.model.config.use_cache=False

    # ── Benchmark / Utils ────────────────────────────────────────────────────

    def profile(self, n_steps=10):
        assert self.model is not None, "Önce fl.load() çağırın!"
        dummy=self.tokenizer("NexusLoRA benchmark "*40,return_tensors="pt",
            max_length=512,truncation=True).to(self.device_mgr.device)
        with torch.inference_mode():
            for _ in range(2): self.model(**dummy)
        if torch.cuda.is_available(): torch.cuda.synchronize()
        t0=time.perf_counter()
        with torch.inference_mode():
            for _ in range(n_steps): self.model(**dummy)
        if torch.cuda.is_available(): torch.cuda.synchronize()
        elapsed=time.perf_counter()-t0
        tps=dummy["input_ids"].numel()*n_steps/elapsed
        logger.info(f"Benchmark    : {tps:,.0f} token/s  ({elapsed:.2f}s, {n_steps} adım)")
        return tps

    def vram_status(self) -> Dict:
        return {"used_gb":    torch.cuda.memory_allocated()/1e9 if torch.cuda.is_available() else 0.,
                "reserved_gb":torch.cuda.memory_reserved()/1e9  if torch.cuda.is_available() else 0.,
                "total_gb":   self.device_mgr.get_vram_gb(),
                "free_gb":    self.device_mgr.get_free_vram_gb(),
                "ratio":      self.device_mgr.get_vram_usage_ratio()}

    def clear_cache(self):
        gc.collect()
        if torch.cuda.is_available(): torch.cuda.empty_cache()

    def stop(self):
        self.vram_guard.stop_monitor()
        if self.cfg.nexus_enabled: self._nexus_cleanup()
        NexusError.summary()

    # ── NexusLoRA — doğrudan entegre yaşam döngüsü ─────────────────────────

    def _nexus_init(self):
        """NexusLoRA'in 10 modülünü doğrudan NexusLoRA içinde başlatır."""
        cfg = self.cfg
        dev = self.device_mgr.device
        if cfg.nexus_crystal_core:
            with NexusError.guard("CRYSTAL_INIT","CrystalCore başlatılamadı"):
                self.crystal_core = CrystalCore(cfg)
                self.crystal_core.inject_model(self.model)
        if cfg.nexus_morphic_memory:
            with NexusError.guard("MORPH_INIT","MorphicMemory başlatılamadı"):
                self.morphic_memory = MorphicMemory(cfg, dev)
        if cfg.nexus_spectra_optimizer:
            with NexusError.guard("SPECTRA_INIT","SpectraOptimizer başlatılamadı"):
                self.spectra_opt = SpectraOptimizer(
                    self.model.parameters(), lr=cfg.nexus_base_lr,
                    spectral_damping=cfg.nexus_spectral_damping,
                    history_len=cfg.nexus_spectra_history, power=cfg.nexus_power)
        if cfg.nexus_resonance_scheduler and self.spectra_opt:
            with NexusError.guard("RESONANCE_INIT","ResonanceScheduler başlatılamadı"):
                self.resonance_sched = ResonanceScheduler(self.spectra_opt, cfg)
        if cfg.nexus_chromatic_precision:
            with NexusError.guard("CHROMA_INIT","ChromaticPrecision başlatılamadı"):
                self.chromatic_prec = ChromaticPrecision(cfg, self.model)
        if cfg.nexus_gradient_harmonics:
            with NexusError.guard("HARMONIC_INIT","GradientHarmonics başlatılamadı"):
                self.grad_harmonics = GradientHarmonics(cfg)
                self._harmonic_hooks = self.grad_harmonics.register_hooks(self.model)
        if cfg.nexus_neural_profiler:
            with NexusError.guard("PROFILER_INIT","NeuralProfiler başlatılamadı"):
                self.neural_profiler = NeuralProfiler(cfg)
        if cfg.nexus_crystal_pipeline:
            with NexusError.guard("PIPELINE_INIT","CrystalPipeline başlatılamadı"):
                self.crystal_pipeline = CrystalPipeline(cfg)
        if cfg.nexus_zero_waste:
            with NexusError.guard("WASTE_INIT","ZeroWaste başlatılamadı"):
                self.zero_waste = ZeroWaste(cfg)
                self.zero_waste.analyze_model(self.model)
        if cfg.nexus_universal_adapter:
            with NexusError.guard("ADAPTER_INIT","UniversalAdapter başlatılamadı"):
                self.universal_adapter = UniversalAdapter(cfg)
        logger.info("NexusLoRA   : ✅  Tüm modüller başlatıldı")

    # Callback entry-points (UniversalAdapter → NexusCallback → burası çağrılır)
    def _on_step_begin(self, step: int):
        self._nx_step = step
        self._nx_t_start = time.perf_counter()
        if self.crystal_core:      self.crystal_core.step()
        if self.morphic_memory:    self.morphic_memory.step()
        if self.grad_harmonics:    self.grad_harmonics.step()
        if self.crystal_pipeline:  self.crystal_pipeline.step()
        if self.zero_waste:        self.zero_waste.step_analysis(self.model)
        if self.chromatic_prec and step == self.cfg.nexus_precision_analysis_steps:
            self.chromatic_prec.analyze_and_assign(self.model)

    def _on_step_end(self, step: int, loss: float):
        ms = (time.perf_counter() - self._nx_t_start) * 1000
        self._nx_step_times.append(ms)
        if len(self._nx_step_times) > 256: self._nx_step_times.pop(0)
        gnorm = self._nx_grad_norm()
        if self.resonance_sched:   self.resonance_sched.step(loss, gnorm)
        if self.neural_profiler:
            used, total = self._nx_mem_gb()
            self.neural_profiler.observe(ms, loss, gnorm, used / (total + 1e-6))
        if self.crystal_pipeline:
            used, total = self._nx_mem_gb()
            self.crystal_pipeline.adapt_grad_accum(used / (total + 1e-6), 0.7)

    def _on_log(self, logs: dict, step: int):
        if not self.cfg.nexus_verbose: return
        phase = self.resonance_sched.current_phase if self.resonance_sched else "?"
        lr    = f"{self.resonance_sched.current_lr:.2e}" if self.resonance_sched else "?"
        loss  = logs.get("loss", "?")
        avg   = sum(self._nx_step_times[-8:]) / max(len(self._nx_step_times[-8:]), 1)
        logger.info(f"Step {step:6d} │ loss={loss} │ lr={lr} │ faz={phase} │ {avg:.0f}ms/adım")

    def _nexus_summary(self):
        avg = sum(self._nx_step_times) / max(len(self._nx_step_times), 1)
        logger.info(f"NexusLoRA   : 📊  Toplam adım={self._nx_step}, ort.{avg:.0f}ms/adım")
        if self.crystal_core:      self.crystal_core.report()
        if self.morphic_memory:    self.morphic_memory.report()
        if self.resonance_sched:   self.resonance_sched.report()
        if self.chromatic_prec:    self.chromatic_prec.report()
        if self.grad_harmonics:    self.grad_harmonics.report()
        if self.neural_profiler:   self.neural_profiler.report()
        if self.crystal_pipeline:  self.crystal_pipeline.report()
        if self.zero_waste:        self.zero_waste.report()

    def _nexus_cleanup(self):
        for h in self._harmonic_hooks:
            try: h.remove()
            except: pass
        self._harmonic_hooks.clear()
        if self.chromatic_prec: self.chromatic_prec.remove_hooks()
        gc.collect()
        if torch.cuda.is_available(): torch.cuda.empty_cache()
        logger.info("NexusLoRA   : 🧹  Kaynaklar temizlendi")

    def nexus_async_checkpoint(self, path: Optional[str] = None):
        """CrystalPipeline üzerinden async checkpoint kuyruğa ekler."""
        if self.crystal_pipeline:
            p = path or os.path.join(self.cfg.output_dir, f"nexus_step_{self._nx_step}.pt")
            self.crystal_pipeline.queue_checkpoint(self.model, p, self._nx_step)

    def _nx_grad_norm(self) -> float:
        try:
            return sum(p.grad.float().norm().item() ** 2
                       for p in self.model.parameters() if p.grad is not None) ** 0.5
        except: return 0.

    def _nx_mem_gb(self) -> Tuple[float, float]:
        if not torch.cuda.is_available(): return 0., 0.
        dev = self.device_mgr.device
        return (torch.cuda.memory_allocated(dev) / 1e9,
                torch.cuda.get_device_properties(dev).total_memory / 1e9)

    # ─────────────────────────────────────────────────────────────────────────

    def _memory_report(self):
        if self.device_mgr.device.type=="cuda":
            a=torch.cuda.memory_allocated()/1e9; r=torch.cuda.memory_reserved()/1e9
            logger.info(f"GPU Belleği  : {a:.2f}GB kullanımda / {r:.2f}GB rezerve")

    def _print_banner(self):
        c=self.cfg; on="✓ AÇIK "; off="✗ KAPALI"
        print("\n"+"═"*70)
        print("  NexusLoRA  ⚡🛡️🧠🔮  —  Unified Fine-Tuning Engine")
        print("═"*70)
        print(f"  Model         : {c.model_name}")
        print(f"  LoRA          : {on if c.lora else off}  (r={c.lora_r}, α={c.lora_alpha})")
        print(f"  Quantization  : {c.quantization or 'Yok'}")
        print(f"  Flash Att     : {on if c.flash_attention else off}")
        print(f"  torch.compile : {on if c.torch_compile else off}  ({c.torch_compile_mode})")
        print(f"  MoE           : {on if c.moe_enabled else off}  ({c.moe_num_experts} uzman)")
        print(f"  VRAM Guard    : {on if c.vram_guard else off}")
        print(f"  Unstoppable   : {on if c.unstoppable else off}")
        print(f"  ── NexusLoRA (power={c.nexus_power:.0%}) {'AKTIF' if c.nexus_enabled else 'KAPALI'} ──")
        if c.nexus_enabled:
            print(f"  💎 CrystalCore   : {on if c.nexus_crystal_core else off}")
            print(f"  🧬 MorphicMemory : {on if c.nexus_morphic_memory else off}")
            print(f"  🎵 SpectraOpt    : {on if c.nexus_spectra_optimizer else off}")
            print(f"  🎼 Resonance     : {on if c.nexus_resonance_scheduler else off}")
            print(f"  🌈 ChromaticPrec : {on if c.nexus_chromatic_precision else off}")
            print(f"  🌊 GradHarmonics : {on if c.nexus_gradient_harmonics else off}")
            print(f"  🧠 NeuralProfiler: {on if c.nexus_neural_profiler else off}")
            print(f"  🔮 CrystalPipeline:{on if c.nexus_crystal_pipeline else off}")
            print(f"  ♻️  ZeroWaste     : {on if c.nexus_zero_waste else off}")
            print(f"  🌐 UnivAdapter   : {on if c.nexus_universal_adapter else off}")
        print("═"*70+"\n")

    def __repr__(self):
        return (f"NexusLoRA(model={self.cfg.model_name!r}, "
                f"nexus={self.cfg.nexus_enabled}, power={self.cfg.nexus_power:.0%})")

    def __del__(self):
        try: self.vram_guard.stop_monitor()
        except: pass


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 24 — YARDIMCI SINIFLAR
# ══════════════════════════════════════════════════════════════════════════════

class CheckpointManager:
    def __init__(self,fl,checkpoint_dir="./checkpoints",save_total_limit=3):
        self.fl=fl; self.checkpoint_dir=checkpoint_dir
        self.save_total_limit=save_total_limit
        os.makedirs(checkpoint_dir,exist_ok=True)

    def latest_checkpoint(self):
        try:
            ckpts=sorted([d for d in Path(self.checkpoint_dir).iterdir()
                if d.is_dir() and d.name.startswith("checkpoint-")],
                key=lambda x:int(x.name.split("-")[-1]))
            if ckpts: return str(ckpts[-1])
        except Exception as e:
            NexusError.report("CHECKPOINT","Checkpoint bulunamadı",str(e),
                f"{self.checkpoint_dir} kontrol edin")
        return None

    def patch_trainer(self,trainer):
        resume=self.latest_checkpoint()
        try:
            trainer.args.output_dir=self.checkpoint_dir
            trainer.args.save_total_limit=self.save_total_limit
            trainer.args.save_strategy="steps"
        except Exception as e:
            NexusError.report("CHECKPOINT","Checkpoint patch başarısız",str(e),"Devam")
        return resume


class LRFinder:
    def __init__(self,fl,num_iter=100,start_lr=1e-7,end_lr=10.0):
        self.fl=fl; self.num_iter=num_iter; self.start_lr=start_lr; self.end_lr=end_lr

    def find(self,train_dataset,formatting_func=None):
        assert self.fl.model is not None, "Önce fl.load() çağırın!"
        logger.info(f"LR Finder    : {self.num_iter} adım, {self.start_lr:.0e}→{self.end_lr:.0e}")
        try:
            from torch.optim import AdamW
            from torch.utils.data import DataLoader
            from transformers import DataCollatorForLanguageModeling
            model=self.fl.model; model.train()
            opt=AdamW([p for p in model.parameters() if p.requires_grad],lr=self.start_lr)
            collator=DataCollatorForLanguageModeling(self.fl.tokenizer,mlm=False)
            loader=DataLoader(train_dataset,batch_size=1,collate_fn=collator,shuffle=True)
            lr_mult=(self.end_lr/self.start_lr)**(1./self.num_iter)
            lrs=[]; smoothed=[]; smooth_loss=0.; beta=0.98; best_lr=self.start_lr; best_loss=float("inf")
            for i,batch in enumerate(loader):
                if i>=self.num_iter: break
                lr=self.start_lr*(lr_mult**i)
                for pg in opt.param_groups: pg["lr"]=lr
                batch={k:v.to(self.fl.device_mgr.device) for k,v in batch.items() if isinstance(v,torch.Tensor)}
                out=model(**batch); loss=out.loss
                if loss is None or math.isnan(loss.item()): break
                smooth_loss=beta*smooth_loss+(1-beta)*loss.item()
                deb=smooth_loss/(1-beta**(i+1))
                lrs.append(lr); smoothed.append(deb)
                if deb<best_loss: best_loss=deb; best_lr=lr
                if i>10 and deb>4*min(smoothed): break
                loss.backward(); opt.step(); opt.zero_grad()
            if len(smoothed)>5:
                grads=[smoothed[i+1]-smoothed[i] for i in range(len(smoothed)-1)]
                best_lr=lrs[grads.index(min(grads))]
            best_lr=max(1e-6,min(best_lr,1e-2))
            self.fl.cfg.learning_rate=best_lr
            logger.info(f"LR Finder    : ✓  Önerilen LR={best_lr:.2e}")
            return best_lr
        except Exception as e:
            NexusError.report("LR_FINDER","LR Finder başarısız",str(e),"Mevcut LR korunuyor",exc=e)
            return self.fl.cfg.learning_rate


class EarlyStopping:
    def __init__(self,patience=3,min_delta=0.001,metric="eval_loss",mode="min"):
        self.patience=patience; self.min_delta=min_delta; self.metric=metric; self.mode=mode
        self._best=float("inf") if mode=="min" else float("-inf")
        self._counter=0; self._stopped=False

    def patch_trainer(self,trainer):
        try:
            from transformers import TrainerCallback; es=self
            class _ESCb(TrainerCallback):
                def on_evaluate(self,args,state,control,metrics=None,**kw):
                    if not metrics: return
                    val=metrics.get(es.metric)
                    if val is None: return
                    improved=(val<es._best-es.min_delta if es.mode=="min" else val>es._best+es.min_delta)
                    if improved: es._best=val; es._counter=0
                    else:
                        es._counter+=1
                        if es._counter>=es.patience:
                            es._stopped=True; control.should_training_stop=True
                            logger.info(f"EarlyStopping: 🛑  en iyi={es._best:.4f}")
            trainer.add_callback(_ESCb())
        except Exception as e:
            NexusError.report("EARLY_STOP","EarlyStopping patch başarısız",str(e),"Devam")

    @property
    def stopped(self): return self._stopped
    @property
    def best_value(self): return self._best


class ExperimentLogger:
    def __init__(self,fl,wandb=False,tensorboard=True,csv=True,
                 project="nexuslora",run_name=None,log_dir="./logs"):
        self.fl=fl; self.use_wandb=wandb; self.use_tb=tensorboard; self.use_csv=csv
        self.project=project; self.run_name=run_name or f"run_{int(time.time())}"
        self.log_dir=log_dir; self._tb_writer=None; self._csv_file=None
        os.makedirs(log_dir,exist_ok=True); self._init()

    def _init(self):
        if self.use_wandb:
            try:
                import wandb as _wb
                _wb.init(project=self.project,name=self.run_name,
                         config=self.fl.cfg.__dict__,reinit=True)
                logger.info(f"Wandb        : ✓  project={self.project}")
            except Exception as e:
                self.use_wandb=False
                NexusError.report("WANDB","Wandb başlatılamadı",str(e),"pip install wandb")
        if self.use_tb:
            try:
                from torch.utils.tensorboard import SummaryWriter
                d=os.path.join(self.log_dir,"tensorboard",self.run_name)
                self._tb_writer=SummaryWriter(log_dir=d)
                logger.info(f"TensorBoard  : ✓  tensorboard --logdir {d}")
            except Exception as e:
                self.use_tb=False
                NexusError.report("TENSORBOARD","TensorBoard başlatılamadı",str(e),"pip install tensorboard")
        if self.use_csv:
            try:
                import csv as _csv
                p=os.path.join(self.log_dir,f"{self.run_name}.csv")
                self._csv_file=open(p,"w",newline=""); self._csv_w=_csv.writer(self._csv_file)
                self._csv_w.writerow(["step","epoch","loss","eval_loss","lr","timestamp"])
                logger.info(f"CSV Log      : ✓  {p}")
            except Exception as e:
                self.use_csv=False
                NexusError.report("CSV_LOG","CSV log başlatılamadı",str(e),"Log klasörünü kontrol edin")

    def log(self,metrics,step=None):
        if self.use_wandb:
            try: import wandb as _wb; _wb.log(metrics,step=step)
            except: pass
        if self.use_tb and self._tb_writer:
            try:
                for k,v in metrics.items():
                    if isinstance(v,(int,float)): self._tb_writer.add_scalar(k,v,step)
            except: pass
        if self.use_csv and self._csv_file:
            try:
                self._csv_w.writerow([step,metrics.get("epoch",""),
                    metrics.get("loss",""),metrics.get("eval_loss",""),
                    metrics.get("learning_rate",""),time.strftime("%H:%M:%S")])
                self._csv_file.flush()
            except: pass

    def patch_trainer(self,trainer):
        try:
            from transformers import TrainerCallback; lg=self
            class _LCb(TrainerCallback):
                def on_log(self,args,state,control,logs=None,**kw):
                    if logs: lg.log(logs,step=state.global_step)
            trainer.add_callback(_LCb())
        except Exception as e:
            NexusError.report("LOGGING","Logger patch başarısız",str(e),"Logging yok")

    def finish(self):
        if self.use_wandb:
            try: import wandb as _wb; _wb.finish()
            except: pass
        if self.use_tb and self._tb_writer:
            try: self._tb_writer.close()
            except: pass
        if self._csv_file:
            try: self._csv_file.close()
            except: pass


# ══════════════════════════════════════════════════════════════════════════════
# BÖLÜM 25 — YARDIMCI FONKSİYONLAR
# ══════════════════════════════════════════════════════════════════════════════

def check_environment(strict: bool = False):
    """NexusLoRA ortam kontrolü."""
    print("\n[NexusLoRA] Ortam Kontrolü"); print("─"*58)
    dm=DeviceManager(); dm.report()
    print(f"\nPyTorch       : {torch.__version__}")
    print(f"torch.compile : {'✓' if _HAS_COMPILE else '✗ (2.0+ gerekli)'}")
    print(f"BF16          : {'✓' if _HAS_BF16 else '✗'}")
    print(f"SDPA          : {'✓' if _HAS_SDPA else '✗'}")
    deps=_check_deps(strict=strict)
    print("\nPaket Durumu:")
    for pkg,ok in deps.items():
        try:
            import importlib.metadata; ver=importlib.metadata.version(pkg)
            print(f"  {'✓' if ok else '✗'}  {pkg:<18} {ver}")
        except: print(f"  {'✓' if ok else '✗'}  {pkg}")
    missing=[p for p,ok in deps.items() if not ok and p in
             ["flash_attn","bitsandbytes","peft","trl","datasets","triton","deepspeed","optuna"]]
    if missing: print(f"\n  Kurmak için: pip install {' '.join(missing)}")
    print()




def format_alpaca(example: dict, tokenizer=None) -> str:
    if example.get("input"):
        return (f"### Talimat:\n{example['instruction']}\n\n"
                f"### Giriş:\n{example['input']}\n\n### Yanıt:\n{example['output']}")
    return f"### Talimat:\n{example['instruction']}\n\n### Yanıt:\n{example['output']}"


def format_chatml(example: dict, tokenizer=None) -> str:
    return "".join(f"<|im_start|>{m['role']}\n{m['content']}<|im_end|>\n"
                   for m in example.get("messages",[]))


if __name__ == "__main__":
    check_environment()
