"""Recompute fact-ledger metrics for chain experiments from the stored hop messages (runs/raw/chains/*.json) with the current `_ledger_metrics` implementation, so that metric fixes apply uniformly to all runs (records keep the original values).""" from __future__ import annotations import json, glob, re from pathlib import Path import pandas as pd from ..util import ROOT, read_json from ..chains import _ledger_metrics from ..data.prepare import load_doc, load_key def recompute(df: pd.DataFrame, exp: str) -> pd.DataFrame: files = glob.glob(str(ROOT / "runs/raw/chains" / f"{exp}_*.json")) cache = {} for f in files: name = Path(f).stem[len(exp) + 1:] m = re.match(r"(syn_\d+_\d+)_(.*)", name) if not m: continue doc_id, cid = m.group(1), m.group(2).replace("_", "|", 2) d = json.load(open(f)) key = load_key(doc_id, "synthetic"); doc = load_doc(doc_id, "synthetic") for h, msg in d["hops"].items(): L = _ledger_metrics(msg, key["facts"], doc["text"]) cache[(doc_id, cid, int(h))] = L def upd(row): cid = row["run_group_id"].split(":")[1].replace("-", "_") if isinstance(row["run_group_id"], str) else None for (doc_id, c, h), L in cache.items(): if doc_id == row["document_id"] and h == row["handoff_index"] and c.replace("-", "_") == cid.replace("-", "_"): row["retention_rate"] = L["retention_rate"]; row["unsupported"] = L["unsupported_numbers"] + L["unsupported_identifiers"]; row["distorted"] = L["distorted_sentences"] break return row return df.apply(upd, axis=1)