1"""Recompute fact-ledger metrics for chain experiments from the stored hop messages (runs/raw/chains/*.json) with the2current `_ledger_metrics` implementation, so that metric fixes apply uniformly to all runs (records keep the original values)."""3from __future__ import annotations4import json, glob, re5from pathlib import Path6import pandas as pd7from ..util import ROOT, read_json8from ..chains import _ledger_metrics9from ..data.prepare import load_doc, load_key1011def recompute(df: pd.DataFrame, exp: str) -> pd.DataFrame:12 files = glob.glob(str(ROOT / "runs/raw/chains" / f"{exp}_*.json"))13 cache = {}14 for f in files:15 name = Path(f).stem[len(exp) + 1:]16 m = re.match(r"(syn_\d+_\d+)_(.*)", name)17 if not m: continue18 doc_id, cid = m.group(1), m.group(2).replace("_", "|", 2)19 d = json.load(open(f))20 key = load_key(doc_id, "synthetic"); doc = load_doc(doc_id, "synthetic")21 for h, msg in d["hops"].items():22 L = _ledger_metrics(msg, key["facts"], doc["text"])23 cache[(doc_id, cid, int(h))] = L24 def upd(row):25 cid = row["run_group_id"].split(":")[1].replace("-", "_") if isinstance(row["run_group_id"], str) else None26 for (doc_id, c, h), L in cache.items():27 if doc_id == row["document_id"] and h == row["handoff_index"] and c.replace("-", "_") == cid.replace("-", "_"):28 row["retention_rate"] = L["retention_rate"]; row["unsupported"] = L["unsupported_numbers"] + L["unsupported_identifiers"]; row["distorted"] = L["distorted_sentences"]29 break30 return row31 return df.apply(upd, axis=1)32