"""F4-conf-02: verify six assertions against cited source extracts. Reads only data/; writes out/results.json deterministically. No randomness.""" import json, math, re, os ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) D = os.path.join(ROOT, "data") DCR, RES = "arxiv-2609.27732v1", "arxiv-2606.14621v1" def lines(p): with open(p, encoding="utf-8") as f: return f.read().split("\n")[:-1] if True else None def wc_l(p): with open(p, "rb") as f: return f.read().count(b"\n") assertions = json.load(open(os.path.join(D, "assertions.json"), encoding="utf-8")) src = {s: open(os.path.join(D, "sources", s + ".txt"), encoding="utf-8").read().split("\n") for s in (DCR, RES)} def find(sid, prefix, after=None): """Return (lineno, line) of first line starting with prefix (optionally after a line index).""" L = src[sid] start = 0 if after is None else after for i in range(start, len(L)): if L[i].startswith(prefix): return i, L[i] raise ValueError(f"{prefix!r} not found in {sid}") def cells(line): return [c.strip() for c in line.split("|")] def num(s): s = s.replace("−", "-").replace("*", "").replace("%", "").replace("(", "").replace(")", "") return float(s) def show(sid, i, line): print(f" [{sid} L{i+1}] {line}") pct = lambda b: 100 * (math.exp(b) - 1) # ---- Baseline (P2): naive literal check: are all numbers of the assertion printed in the cited extract? def baseline(a): text = open(os.path.join(D, "sources", a["cites"] + ".txt"), encoding="utf-8").read().replace("−", "-") nums = re.findall(r"\d+\.\d+", a["text"].replace("−", "-")) return "supported" if all(n in text for n in nums) else "not_supported" baseline_verdicts = {a["id"]: baseline(a) for a in assertions} V, LOC, R = {}, {}, {} derived = {} # ---- Table 6 (DCR) t6, _ = find(DCR, "Table 6:") i_att, l_att = find(DCR, "ATT |", t6); i_se = i_att + 2; l_se = src[DCR][i_se] i_pc, l_pc = find(DCR, "% change |", t6) att6 = [num(c) for c in cells(l_att)[1:]]; se6 = [num(c) for c in cells(l_se)[1:]]; pc6 = [num(c) for c in cells(l_pc)[1:]] stars5 = cells(l_att)[3].count("*") print("A1:"); [show(DCR, i, src[DCR][i]) for i in (i_att, i_se, i_pc)] i_txt, l_txt = find(DCR, "Table 6 reports the pooled ATT"); show(DCR, i_txt, l_txt[:200] + " ...") p5 = pct(att6[2]); derived["A1_pct_change_5km"] = round(p5, 2) ok = att6[2] == -0.431 and se6[2] == 0.210 and stars5 == 2 and abs(p5 - (-35.0)) < 0.05 and pc6[2] == -35.0 V["A1"] = "supported" if ok else "not_supported" LOC["A1"] = f'{DCR} | Table 6 | row "ATT" | column "5 km"' R["A1"] = ("Table 6 prints ATT -0.431** (SE 0.210) at 5 km, ** denotes p<0.05, and the % change row prints -35.0% " f"(100(exp(-0.431)-1) = {p5:.1f}%), so every element matches.") # ---- Table 7 (DCR) t7, _ = find(DCR, "Table 7:") def t7row(name): i, l = find(DCR, name + " |", t7) return i, l, [num(c) for c in cells(l)[1:]], [num(c) for c in cells(src[DCR][i + 2])[1:]] i_hiv, l_hiv, hiv, hiv_se = t7row("HIV") print("A2:"); show(DCR, i_hiv, l_hiv); show(DCR, i_hiv + 2, src[DCR][i_hiv + 2]) V["A2"] = "supported" if hiv[0] < 0 else "not_supported" LOC["A2"] = f'{DCR} | Table 7 | row "HIV" | column "1 km"' R["A2"] = (f"Table 7 prints the 1 km HIV ATT as +{hiv[0]:.3f} (SE {hiv_se[0]:.3f}), positive and insignificant, " "so the asserted negative sign and the claimed fall in HIV hospitalisations are contradicted.") print("A3:"); show(DCR, i_att, l_att); show(DCR, i_pc, l_pc) p3 = pct(att6[1]); derived["A3_pct_change_3km"] = round(p3, 2) V["A3"] = "supported" if abs(p3 - (-28.3)) < 0.05 else "not_supported" LOC["A3"] = f'{DCR} | Table 6 | row "% change" | column "3 km"' R["A3"] = (f"Table 6 converts the 3 km ATT of -0.283 into a -24.7% change (100(exp(-0.283)-1) = {p3:.2f}%), " "not 28.3%, which is the log-point coefficient misread as a percentage.") i_hep, l_hep, hep, hep_se = t7row("Hepatitis") print("A4:"); show(DCR, i_hep, l_hep); show(DCR, i_hep + 2, src[DCR][i_hep + 2]) b, s = hep[2], hep_se[2] ci196 = (b - 1.96 * s, b + 1.96 * s); ci2 = (b - 2 * s, b + 2 * s); ci1 = (b - s, b + s) derived["A4_ci95_1.96"] = [round(x, 3) for x in ci196]; derived["A4_ci95_2.0"] = [round(x, 3) for x in ci2] derived["A4_ci_pm_1se"] = [round(x, 3) for x in ci1] excl = ci196[1] < 0 and ci2[1] < 0 V["A4"] = "supported" if excl and abs(ci196[0] + 0.66) < 0.02 and abs(ci196[1] + 0.16) < 0.02 else "not_supported" LOC["A4"] = f'{DCR} | Table 7 | row "Hepatitis" | column "5 km"' R["A4"] = (f"With ATT -0.406 and SE 0.250 (no stars), the 95% CI is [{ci196[0]:.2f}, {ci196[1]:.2f}] (±1.96·SE), which " f"includes zero; the asserted [-0.66, -0.16] is only ±1 SE ([{ci1[0]:.3f}, {ci1[1]:.3f}]).") print("A5: search for sex-specific results") hits = [(s_, i, l) for s_ in (DCR,) for i, l in enumerate(src[s_]) if re.search(r"\b(men|women|male|female|sex|gender)\b", l, re.I)] for h in hits: show(*h) print(f" {len(hits)} lines mention sex/gender in {DCR}") V["A5"] = "not_assessable" if not hits else "REVIEW" LOC["A5"] = f"not reported in {DCR}" R["A5"] = ("The extract reports ATTs only by buffer, estimator and diagnostic category (Tables 6, 7, A19) and never by sex, " "so a men-versus-women comparison can be neither confirmed nor refuted.") # ---- RESEA Table 2 i_w, l_w = find(RES, "Weeks on UI |") print("A6:"); show(RES, i_w, l_w) i_t, l_t = find(RES, "Overall, we find"); show(RES, i_t, l_t[l_t.find("and a 1.99"):]) c = cells(l_w) ctrl = float(re.search(r"([\d.]+) weeks", c[2]).group(1)) ate = c[4] est = float(re.search(r"(-?[\d.]+) weeks", ate).group(1)) lo, hi = [float(x) for x in re.search(r"\[(-?[\d.]+), (-?[\d.]+)\]", ate).groups()] rel = 100 * est / ctrl; derived["A6_pct_of_control_mean"] = round(rel, 2) ok6 = est == -1.99 and (lo, hi) == (-2.24, -1.75) and ctrl == 17.3 and abs(rel + 11.5) < 0.05 V["A6"] = "supported" if ok6 else "not_supported" LOC["A6"] = f'{RES} | Table 2 | row "Weeks on UI" | column "Average treatment effect estimate"' R["A6"] = (f"Table 2 prints the ATE as -1.99 weeks (95% CI [-2.24, -1.75]) against a control mean of 17.3 weeks, " f"and -1.99/17.3 = {rel:.1f}%, matching the 11.5% decrease stated in the results text.") assert "REVIEW" not in V.values() vals = list(V.values()) data_issues = [ {"issue": "arxiv-2609.27732v1 Table A19 prints the CS-DR 5 km ATT -0.431** with SE (0.218), while Table 6 prints the same specification with SE (0.210).", "handling": "A1 cites the main result; judged against Table 6 (SE 0.210). With SE 0.210, |t|=2.05 exceeds both 1.96 and 2.0; with SE 0.218, |t|=1.98 exceeds 1.96 but not 2.0, yet ** is printed in both tables, so the verdict rests on the printed significance stars."}, {"issue": "arxiv-2609.27732v1 Table A19 note states 640 never-treated comparison regions; table body and Tables 6-7 state 608.", "handling": "Recorded only; no assertion depends on the control-region count."}, {"issue": "arxiv-2609.27732v1 abstract says fatal hospitalisations fall by 35%, but Table 7 5 km fatal ATT -0.354 implies -29.8% (Section 6.1 says ~30%).", "handling": "Recorded only; no assertion concerns fatal outcomes."}, {"issue": "arxiv-2609.27732v1 Figure 7 note mentions four sub-categories while the text and Table 7 report five.", "handling": "Recorded only; not decision-relevant."}, {"issue": "arxiv-2606.14621v1 results text reports CIs of reductions as unsigned magnitudes ([1.75, 2.24]) while Table 2 uses signed values; rendering defect 'p ¡ 0.001'.", "handling": "Treated as equivalent; A6 judged against the signed Table 2 values."}, ] n_input_rows = { "assertions.json": len(assertions), "README.md": wc_l(os.path.join(D, "README.md")), f"sources/{DCR}.txt": wc_l(os.path.join(D, "sources", DCR + ".txt")), f"sources/{RES}.txt": wc_l(os.path.join(D, "sources", RES + ".txt")), } results = { "task_id": "F4-conf-02", "verdicts": V, "locators": LOC, "reasons": R, "n_supported": vals.count("supported"), "n_not_supported": vals.count("not_supported"), "n_not_assessable": vals.count("not_assessable"), "feasibility": "complete", "feasibility_reason": None, "data_issues": data_issues, "n_input_rows": n_input_rows, "n_analysed": len(assertions), "random_seed": None, "baseline_verdicts_number_match": baseline_verdicts, "baseline_agreement_with_final": sum(baseline_verdicts[k] == V[k] for k in V), "derived_quantities": derived, } os.makedirs(os.path.join(ROOT, "out"), exist_ok=True) with open(os.path.join(ROOT, "out", "results.json"), "w", encoding="utf-8") as f: json.dump(results, f, indent=2, ensure_ascii=False) print("verdicts:", V) print("baseline:", baseline_verdicts)