"""F4-conf-02: verdicts on six assertions against cited source extracts. Run from workspace root: ~/wp29/venv/bin/python out/analysis.py""" import json, math, re, os D = "data" S1, S2 = "arxiv-2609.27732v1", "arxiv-2606.14621v1" src = {s: open(f"{D}/sources/{s}.txt", encoding="utf-8").read().splitlines() for s in (S1, S2)} assertions = json.load(open(f"{D}/assertions.json", encoding="utf-8")) def line(s, startswith): for i, l in enumerate(src[s]): if l.startswith(startswith): print(f"[{s} L{i+1}] {l}") return i, l raise ValueError(f"not found: {startswith}") def se_line(s, i): # next non-empty line after coefficient row for j in range(i + 1, len(src[s])): if src[s][j].strip(): print(f"[{s} L{j+1}] {src[s][j]}") return src[s][j] def nums(l): return [float(x.replace("−", "-")) for x in re.findall(r"-?\d+\.\d+", l)] pct = lambda b: 100 * (math.exp(b) - 1) V, L, R = {}, {}, {} # ---- Table 6 ---- i6 = [k for k, l in enumerate(src[S1]) if l.startswith("Table 6:")][0] i, att = None, None for k in range(i6, len(src[S1])): if src[S1][k].startswith("ATT |"): i, att = k, src[S1][k]; print(f"[{S1} L{k+1}] {att}"); break b6 = nums(att); se6 = nums(se_line(S1, i)) _, pc = line(S1, "% change |") pc6 = [float(x) for x in re.findall(r"-?\d+\.\d+(?=%)", pc)] line(S1, "corresponding to a 35% reduction") # A1: 5 km b, se, star = b6[2], se6[2], "**" in att.split("|")[3] ok = b == -0.431 and se == 0.210 and star and pc6[2] == -35.0 print(f"A1: b={b}, se={se}, ** p<0.05={star}, printed %={pc6[2]}, exp-conv={pct(b):.2f}%") V["A1"] = "supported" if ok else "not_supported" L["A1"] = f'{S1} | Table 6 | row "ATT" / "% change" | column "5 km"' R["A1"] = ("Table 6 prints ATT -0.431** (0.210) and -35.0% at 5 km, with ** denoting p<0.05, matching every element " f"(100*(exp(-0.431)-1) = {pct(b):.1f}%).") # ---- Table 7 ---- def t7(row): i, l = line(S1, row + " |") return nums(l), nums(se_line(S1, i)), l hiv_b, hiv_se, _ = t7("HIV") hep_b, hep_se, hep_l = t7("Hepatitis") # A2: HIV 1 km print(f"A2: HIV 1 km ATT = {hiv_b[0]} (SE {hiv_se[0]})") V["A2"] = "supported" if hiv_b[0] < 0 else "not_supported" L["A2"] = f'{S1} | Table 7 | row "HIV" | column "1 km"' R["A2"] = (f"Table 7 prints the 1 km HIV ATT as +{hiv_b[0]:.3f} (SE {hiv_se[0]:.3f}), positive and insignificant, so the sign " "and the claimed fall in HIV hospitalisations are contradicted.") # A3: 3 km % change print(f"A3: 3 km ATT={b6[1]}, printed %={pc6[1]}, exp-conv={pct(b6[1]):.2f}%") V["A3"] = "supported" if abs(pct(b6[1]) - (-28.3)) < 0.5 else "not_supported" L["A3"] = f'{S1} | Table 6 | row "% change" | column "3 km"' R["A3"] = (f"Table 6 converts the 3 km ATT of -0.283 to {pc6[1]}% (100*(exp(-0.283)-1) = {pct(b6[1]):.1f}%), not 28.3%; " "the assertion equates log points with percent (and omits that the estimate is insignificant, SE 0.279).") # A4: hepatitis 5 km CI b, se = hep_b[2], hep_se[2] ci196 = (b - 1.96 * se, b + 1.96 * se); ci2 = (b - 2 * se, b + 2 * se); ci1 = (b - se, b + se) print(f"A4: hep 5 km b={b}, se={se}; 1.96-CI=[{ci196[0]:.3f},{ci196[1]:.3f}]; 2.0-CI=[{ci2[0]:.3f},{ci2[1]:.3f}]; " f"+/-1SE=[{ci1[0]:.3f},{ci1[1]:.3f}]; stars={'*' in hep_l.split('|')[3]}") excl = ci196[0] > 0 or ci196[1] < 0 V["A4"] = "supported" if excl else "not_supported" L["A4"] = f'{S1} | Table 7 | row "Hepatitis" | column "5 km"' R["A4"] = (f"With ATT -0.406 and SE 0.250 the 95% CI is [{ci196[0]:.2f}, {ci196[1]:.2f}] (±1.96·SE), which includes zero " f"(the asserted [-0.66, -0.16] is ±1·SE) and the estimate carries no significance star.") # A5: sex heterogeneity hits = [k + 1 for k, l in enumerate(src[S1]) if re.search(r"\b(men|women|male|female|sex|gender)\b", l, re.I)] print(f"A5: lines mentioning men/women/sex/gender in {S1}: {hits}") V["A5"] = "not_assessable" if not hits else "REVIEW" L["A5"] = f"not reported in {S1}" R["A5"] = ("The extract reports ATTs only by buffer, outcome category and estimator (Tables 6, 7, A19) and contains no " "estimate by sex, so the men-vs-women comparison can be neither confirmed nor refuted.") # A6: RESEA weeks on UI _, w = line(S2, "Weeks on UI |") line(S2, "Overall, we find that RESEA selection") cells = [c.strip() for c in w.split("|")] ate = cells[4]; ctrl = cells[2] ok = ("-1.99 weeks" in ate and "[-2.24, -1.75]" in ate and "17.3 weeks" in ctrl) rel = 100 * 1.99 / 17.3 print(f"A6: ATE cell='{ate}', control='{ctrl}', 1.99/17.3={rel:.2f}%") V["A6"] = "supported" if ok and round(rel, 1) == 11.5 else "not_supported" L["A6"] = f'{S2} | 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, and " f"1.99/17.3 = {rel:.1f}%, matching the 11.5% stated in the Section 3 text.") data_issues = [ {"issue": "Table A19 reports the CS-DR 5 km ATT -0.431** with SE (0.218), while Table 6 reports the same estimate with SE (0.210).", "handling": "A1 cites the main Table 6 and asserts SE 0.210; judged against Table 6. Significance at 5% holds under either SE (|t|=2.05 or 1.98 vs 1.96); noted as an internal inconsistency."}, {"issue": "Table A19 note states 640 never-treated comparison regions, while Tables 6/7, A19 body and Figure 6 note state 608.", "handling": "Not decisive for any assertion; recorded only."}, {"issue": "Abstract says fatal hospitalisations 'fall by 35%', whereas Table 7 (-0.354 at 5 km) implies -29.8% and Section 6.1 says 'approximately 30%'.", "handling": "Not decisive for any assertion; recorded only."}, {"issue": "Results text says HIV estimates are 'close to zero', though the 5 km HIV ATT is -0.340 (insignificant).", "handling": "A2 judged on the Table 7 number (1 km = +0.063), not the prose."}, {"issue": "RESEA text writes the weeks-on-UI CI as positive magnitudes '[1.75 weeks, 2.24 weeks]' for the reduction, while Table 2 gives [-2.24, -1.75]; also a rendering defect 'p ¡ 0.001' in Section 3.", "handling": "Sign-convention difference only; A6 judged against Table 2 values, which are consistent with the text."}, ] def nlines(p): with open(p, "rb") as f: return f.read().count(b"\n") n_input_rows = {"assertions.json": len(assertions), "README.md": nlines(f"{D}/README.md"), f"sources/{S1}.txt": nlines(f"{D}/sources/{S1}.txt"), f"sources/{S2}.txt": nlines(f"{D}/sources/{S2}.txt")} vals = list(V.values()) res = {"task_id": "F4-conf-02", "verdicts": V, "locators": L, "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} os.makedirs("out", exist_ok=True) json.dump(res, open("out/results.json", "w", encoding="utf-8"), indent=2, ensure_ascii=False) print(json.dumps(V, indent=1))