"""F4-conf-02: verify six assertions against cited source extracts. Reads only data/; writes out/results.json deterministically. No randomness.""" import json, math, os, re 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") assertions = json.load(open(os.path.join(D, "assertions.json"), encoding="utf-8")) src = {s: lines(os.path.join(D, "sources", s + ".txt")) for s in (DCR, RES)} srctext = {s: "\n".join(v) for s, v in src.items()} def wc_l(p): with open(p, "rb") as f: return f.read().count(b"\n") n_input_rows = { "assertions.json": len(assertions), "README.md": wc_l(os.path.join(D, "README.md")), DCR + ".txt": wc_l(os.path.join(D, "sources", DCR + ".txt")), RES + ".txt": wc_l(os.path.join(D, "sources", RES + ".txt")), } def find(s, prefix, after=None): """Return (lineno, line) of first line starting with prefix (after a given line index).""" start = 0 if after is None else after for i in range(start, len(src[s])): if src[s][i].startswith(prefix): return i, src[s][i] raise ValueError(f"{prefix!r} not found in {s}") def cells(line): return [c.strip() for c in line.split("|")] def num(c): return float(re.sub(r"[^0-9.\-]", "", c.replace("−", "-"))) def show(tag, s, i): print(f" [{tag}] {s} line {i+1}: {src[s][i]}") pct = lambda b: 100.0 * (math.exp(b) - 1.0) cols = {"1 km": 1, "3 km": 2, "5 km": 3} # ---- parse DCR Table 6 ---- t6, _ = find(DCR, "Table 6:") i_att, l_att = find(DCR, "ATT |", t6) i_se, l_se = find(DCR, "| (", i_att) i_pc, l_pc = find(DCR, "% change |", i_att) # ---- parse DCR Table 7 ---- t7, _ = find(DCR, "Table 7:") def t7row(name): i, l = find(DCR, name + " |", t7) j, m = find(DCR, "| (", i) return i, l, j, m V, L, R, details = {}, {}, {}, {} # A1: 5 km overall ATT, SE, 5% significance, 35.0% print("A1:", assertions[0]["text"]) for i in (i_att, i_se, i_pc): show("Table 6", DCR, i) att5 = cells(l_att)[cols["5 km"]]; se5 = cells(l_se)[cols["5 km"]]; pc5 = cells(l_pc)[cols["5 km"]] b, se = num(att5), num(se5) stars_ok = att5.endswith("**") # ** => p<0.05 ok = (b == -0.431 and se == 0.210 and stars_ok and pc5 == "-35.0%" and abs(pct(b) - (-35.0)) < 0.05) details["A1"] = {"att": att5, "se": se5, "pct_printed": pc5, "pct_computed": round(pct(b), 2), "z": round(b / se, 3)} V["A1"] = "supported" if ok else "not_supported" L["A1"] = f'{DCR} | Table 6 | row "ATT" | column "5 km"' R["A1"] = ("Table 6 prints the 5 km ATT as -0.431** with SE (0.210) (** = p<0.05) and a % change of -35.0%, " "which equals 100(exp(-0.431)-1) = -35.0%, so sign, magnitude, SE, significance and conversion all match.") # A2: HIV 1 km negative? print("A2:", assertions[1]["text"]) i, l, j, m = t7row("HIV"); show("Table 7", DCR, i); show("Table 7", DCR, j) hiv1 = cells(l)[cols["1 km"]] details["A2"] = {"att_1km": hiv1, "se_1km": cells(m)[cols["1 km"]]} V["A2"] = "supported" if num(hiv1) == -0.063 else "not_supported" L["A2"] = f'{DCR} | Table 7 | row "HIV" | column "1 km"' R["A2"] = ("Table 7 prints the 1 km HIV ATT as +0.063 (SE 0.801), positive and insignificant, so the assertion's " "negative sign (-0.063) and the claimed fall in HIV hospitalisations are contradicted.") # A3: 3 km -0.283 => 28.3% reduction? print("A3:", assertions[2]["text"]) for i in (i_att, i_pc): show("Table 6", DCR, i) att3 = num(cells(l_att)[cols["3 km"]]); pc3 = cells(l_pc)[cols["3 km"]] details["A3"] = {"att_3km": att3, "pct_printed": pc3, "pct_computed": round(pct(att3), 2)} V["A3"] = "supported" if abs(pct(att3) - (-28.3)) < 0.05 else "not_supported" L["A3"] = f'{DCR} | Table 6 | row "% change" | column "3 km"' R["A3"] = ("Table 6 converts the 3 km ATT of -0.283 to a -24.7% change (100(exp(-0.283)-1) = -24.6%), not 28.3%, " "so the magnitude is wrong (log points were read as percent); the estimate is also insignificant (SE 0.279).") # A4: hepatitis 5 km 95% CI approx [-0.66,-0.16], excludes zero? print("A4:", assertions[3]["text"]) i, l, j, m = t7row("Hepatitis"); show("Table 7", DCR, i); show("Table 7", DCR, j) hb, hse = num(cells(l)[cols["5 km"]]), num(cells(m)[cols["5 km"]]) ci196 = [round(hb - 1.96 * hse, 3), round(hb + 1.96 * hse, 3)] ci200 = [round(hb - 2.0 * hse, 3), round(hb + 2.0 * hse, 3)] ci1se = [round(hb - hse, 3), round(hb + hse, 3)] details["A4"] = {"att_5km": hb, "se_5km": hse, "ci95_1.96": ci196, "ci95_2.00": ci200, "pm_1se": ci1se, "stars": "none"} excl = ci196[1] < 0 or ci196[0] > 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" L["A4"] = f'{DCR} | Table 7 | row "Hepatitis" | column "5 km"' R["A4"] = (f"Table 7 prints the 5 km hepatitis ATT as -0.406 with SE (0.250) and no star, giving a 95% CI of " f"[{ci196[0]}, {ci196[1]}] (±1.96 SE), which includes zero; the asserted [-0.66, -0.16] is only ±1 SE.") # A5: men vs women -- search for sex/gender breakdown print("A5:", assertions[4]["text"]) pat = re.compile(r"\b(men|women|male|female|sex|gender)\b", re.I) hits = [(k + 1, ln) for k, ln in enumerate(src[DCR]) if pat.search(ln)] print(f" sex/gender terms found in {DCR}: {len(hits)}", hits) details["A5"] = {"sex_term_hits": len(hits)} V["A5"] = "not_assessable" if not hits else "REVIEW" L["A5"] = f"not reported in {DCR}" R["A5"] = ("The extract reports ATTs only by buffer, diagnostic category and estimator (Tables 6, 7, A19) and contains " "no estimate by sex, so the men-versus-women comparison can be neither confirmed nor refuted.") # A6: RESEA weeks on UI print("A6:", assertions[5]["text"]) k, row = find(RES, "Weeks on UI |"); show("Table 2", RES, k) kt, _ = find(RES, "Overall, we find"); print(f" [Section 3 text] {RES} line {kt+1}: (contains '1.99 week reduction' and '11.5% decrease ... 17.3 weeks')") c = cells(row) ctrl = num(c[2].split("weeks")[0]); ate = c[4] ate_val = float(re.search(r"(-?\d+\.\d+) weeks", ate).group(1)) ci = [float(x) for x in re.search(r"\[(-?\d+\.\d+), (-?\d+\.\d+)\]", ate).groups()] rel = 100 * abs(ate_val) / ctrl details["A6"] = {"ate": ate_val, "ci": ci, "control_mean": ctrl, "pct_of_control": round(rel, 2), "text_has_11.5": "11.5% decrease" in src[RES][kt]} ok = ate_val == -1.99 and ci == [-2.24, -1.75] and ctrl == 17.3 and abs(rel - 11.5) < 0.05 V["A6"] = "supported" if ok else "not_supported" L["A6"] = f'{RES} | Table 2 | row "Weeks on UI" | column "Average treatment effect estimate"' R["A6"] = ("Table 2 prints the ATE on weeks on UI as -1.99 weeks (95% CI [-2.24, -1.75], p<0.001) with control mean 17.3 weeks, " "and 1.99/17.3 = 11.5%, matching the Section 3 text.") # ---- naive baseline: 'supported' iff every number in the assertion appears literally in the cited extract ---- def nums_in(t): return re.findall(r"\d+\.\d+|\d+", t.replace("−", "-")) baseline = {} for a in assertions: ns = [n for n in nums_in(a["text"]) if n not in ("1", "3", "5", "95")] baseline[a["id"]] = "supported" if all(n in srctext[a["cites"]] for n in ns) else "not_supported" data_issues = [ {"issue": "DCR Table A19 prints SE (0.218) for the CS-DR 5 km ATT -0.431, while Table 6 prints (0.210) for the same estimate; the A19 note says 640 never-treated regions while A19's body and Tables 6-7 say 608.", "handling": "A1 decided on Table 6 (the cited overall-ATT table); the 5% significance claim holds under either SE (z=-2.05 or -1.98), so the verdict is unaffected; flagged."}, {"issue": "DCR abstract states fatal hospitalisations fall by 35% and narcotics rise 'by a comparable amount', but Table 7 (5 km: -0.354, +0.390) implies -29.8% and +47.7%, and Section 6.1 says ~30% and 47%.", "handling": "Not decisive for any assertion; tables used as the authoritative values; flagged."}, {"issue": "DCR text describes HIV estimates as 'close to zero' although the 3 km and 5 km cells are -0.239 and -0.340 (insignificant).", "handling": "A2 decided on the printed sign of the 1 km Table 7 cell (+0.063), not on the prose."}, {"issue": "DCR Figure 7 note refers to four diagnostic sub-categories whereas Table 7 and the text list five.", "handling": "Not decisive; noted only."}, {"issue": "RESEA results text prints CIs of reductions as positive magnitudes ([1.75, 2.24]) while Table 2 prints signed bounds [-2.24, -1.75]; the text also contains a rendering defect 'p ¡ 0.001' for p < 0.001.", "handling": "Treated as equivalent representations; A6 decided on Table 2 signed values."}, ] counts = {v: sum(1 for x in V.values() if x == v) for v in ("supported", "not_supported", "not_assessable")} results = { "task_id": "F4-conf-02", "verdicts": V, "locators": L, "reasons": R, "n_supported": counts["supported"], "n_not_supported": counts["not_supported"], "n_not_assessable": counts["not_assessable"], "feasibility": "complete", "feasibility_reason": None, "data_issues": data_issues, "n_input_rows": n_input_rows, "n_analysed": len(V), "random_seed": None, "baseline_verdicts_literal_number_match": baseline, "computation_details": details, } assert sum(counts.values()) == 6 and "REVIEW" not in V.values() 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, sort_keys=True) print("\nVerdicts:", V) print("Counts:", counts) print("Baseline (literal number match):", baseline)