candidate_clauses() — NLI now runs only on the top-N source clauses by content-token overlap with the answer claim (max_candidate_clauses=6), not the whole context; records n_candidate_clauses / best_clause_overlap / recombination_risk. Synthetic sweep unchanged (28/28 recombination, 0/26 legit FP, mean 1.45 candidate clauses/record). Real-traffic smoke re-run: STRICT would-demote 30% → 20%, overall 47% → 33% — better, not fixed; recombination-risk split doesn't separate either. Residual STRICT false-contras at ~0.83-0.92 → θc would need ≈ 0.90 (vs the clean-set 0.5); at θc=0.90 the data in hand gives 27/28 synthetic recall, 0/26 legit FP, 0/10 smoke STRICT FP — but n=10 is too small to set on. Next: a fuller ARBORIST_NLI_SHADOW=1 bench-qa run → sweep θc on hundreds of STRICT cells → confirm → set it. θc stays 0.5; runtime NLI demotion stays off. Production verifier unchanged; falsification-hard stays 10/12.
This commit is contained in:
parent
f4de936ff9
commit
02f8dfec07
8 changed files with 730 additions and 124 deletions
|
|
@ -92,18 +92,25 @@ def main(argv=None) -> int:
|
|||
nli = ShadowNLI()
|
||||
|
||||
by_bucket: dict[str, dict] = defaultdict(lambda: {"n": 0, "would_demote": 0})
|
||||
by_recomb_risk: dict[str, dict] = {"risk": {"n": 0, "would_demote": 0},
|
||||
"no_risk": {"n": 0, "would_demote": 0}}
|
||||
fp_probe = {"n": 0, "would_demote": 0}
|
||||
rows = []
|
||||
n_available = 0
|
||||
n_candidate_clauses_total = 0
|
||||
t0 = time.time()
|
||||
for r in recs:
|
||||
res = nli.check(r["claim"], r["source"])
|
||||
if res.available:
|
||||
n_available += 1
|
||||
n_candidate_clauses_total += res.n_candidate_clauses
|
||||
b = by_bucket[r["bucket"]]
|
||||
b["n"] += 1
|
||||
rr = by_recomb_risk["risk" if res.recombination_risk else "no_risk"]
|
||||
rr["n"] += 1
|
||||
if res.would_demote:
|
||||
b["would_demote"] += 1
|
||||
rr["would_demote"] += 1
|
||||
if r["is_fp_probe"]:
|
||||
fp_probe["n"] += 1
|
||||
if res.would_demote:
|
||||
|
|
@ -127,8 +134,12 @@ def main(argv=None) -> int:
|
|||
"elapsed_seconds": round(elapsed, 1),
|
||||
"would_demote_total": total_demote,
|
||||
"would_demote_rate": round(total_demote / len(recs), 4) if recs else 0.0,
|
||||
"mean_candidate_clauses": round(n_candidate_clauses_total / len(recs), 2) if recs else 0.0,
|
||||
"max_candidate_clauses_cap": nli.max_candidate_clauses,
|
||||
"by_bucket": {k: {**v, "rate": round(v["would_demote"] / v["n"], 4) if v["n"] else 0.0}
|
||||
for k, v in sorted(by_bucket.items())},
|
||||
"by_recombination_risk": {k: {**v, "rate": round(v["would_demote"] / v["n"], 4) if v["n"] else 0.0}
|
||||
for k, v in by_recomb_risk.items()},
|
||||
"false_positive_probe": {**fp_probe,
|
||||
"rate": round(fp_probe["would_demote"] / fp_probe["n"], 4) if fp_probe["n"] else None,
|
||||
"note": "would_demote on records labeled want=not_contradiction — these are shadow FALSE POSITIVES; this is §7 #12 gate item 4 when the input is a real legit-answer sample"},
|
||||
|
|
@ -146,8 +157,13 @@ def main(argv=None) -> int:
|
|||
print(" (install the runtime to get real numbers: pip install 'arborist[nli]')")
|
||||
print(f" swept {len(recs)} records structurally; would-demote rate not measured.")
|
||||
return 0
|
||||
print(f" model {nli.model_version} · θc={nli.theta_contra} θe={nli.theta_entail} · {len(recs)} records · {elapsed:.1f}s")
|
||||
print(f" model {nli.model_version} · θc={nli.theta_contra} θe={nli.theta_entail} · cand-clause cap {nli.max_candidate_clauses} · {len(recs)} records · {elapsed:.1f}s")
|
||||
print(f" mean candidate clauses NLI'd / record: {report['mean_candidate_clauses']} (vs the whole context — the §7 #20 restriction)")
|
||||
print(f" would_demote overall: {total_demote}/{len(recs)} = {report['would_demote_rate']:.3f}")
|
||||
rr = report["by_recombination_risk"]
|
||||
print(f" by recombination-risk: risk {rr['risk']['would_demote']}/{rr['risk']['n']}={rr['risk']['rate']:.3f} "
|
||||
f"no_risk {rr['no_risk']['would_demote']}/{rr['no_risk']['n']}={rr['no_risk']['rate']:.3f} "
|
||||
f"(if no_risk-rate is high too, the risk-gate alone isn't enough)")
|
||||
print(f" {'bucket':<28} {'n':>5} {'would_demote':>13} {'rate':>7}")
|
||||
print(" " + "-" * 56)
|
||||
for k, v in report["by_bucket"].items():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue