ICSAC commited on
Commit
78bdfdf
·
1 Parent(s): 674aff0

Stats count every review on record: the published copies of the reviews from before the public flip, the new score-table heading and the old dimension label; a record in both places counts once

Browse files
crossref_deposit.py CHANGED
@@ -911,7 +911,8 @@ def _push_publications(sub_dir: Path, submission: dict, doi: str, *, log) -> dic
911
  try:
912
  import stats as _stats
913
  out = os.path.join(publications.WEBSITE_REPO, "src", "data", "stats.json")
914
- fresh = _stats.compute_stats(config.REVIEWS_DIR)
 
915
  try:
916
  published = json.loads(Path(out).read_text()).get("total_reviewed") or 0
917
  except Exception:
@@ -920,7 +921,7 @@ def _push_publications(sub_dir: Path, submission: dict, doi: str, *, log) -> dic
920
  log(f" crossref: stats snapshot kept: a fresh count of {fresh.get(total_reviewed)} "
921
  f"would replace the published {published}")
922
  else:
923
- stats_path = _stats.write_stats(config.REVIEWS_DIR, out)
924
  if stats_path:
925
  extra.append(stats_path)
926
  except Exception as exc: # the stats page must never block a registration
 
911
  try:
912
  import stats as _stats
913
  out = os.path.join(publications.WEBSITE_REPO, "src", "data", "stats.json")
914
+ pub = os.path.join(publications.WEBSITE_REPO, "src", "data", "public-reviews")
915
+ fresh = _stats.compute_stats(config.REVIEWS_DIR, pub)
916
  try:
917
  published = json.loads(Path(out).read_text()).get("total_reviewed") or 0
918
  except Exception:
 
921
  log(f" crossref: stats snapshot kept: a fresh count of {fresh.get(total_reviewed)} "
922
  f"would replace the published {published}")
923
  else:
924
+ stats_path = _stats.write_stats(config.REVIEWS_DIR, out, pub)
925
  if stats_path:
926
  extra.append(stats_path)
927
  except Exception as exc: # the stats page must never block a registration
intake/scripts/test_audit_20260928b.py CHANGED
@@ -113,8 +113,21 @@ try:
113
  check(stats.compute_stats(str(rdir)).get("total_reviewed") == 0, "an empty reviews dir counts zero")
114
  cd = (ROOT / "crossref_deposit.py").read_text()
115
  g = cd.find("if (fresh.get(\"total_reviewed\") or 0) < published:")
116
- w = cd.find("stats_path = _stats.write_stats(config.REVIEWS_DIR, out)")
117
  check(0 < g < w, "a fresh count below the published total is never written")
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  finally:
119
  shutil.rmtree(tmp, ignore_errors=True)
120
 
 
113
  check(stats.compute_stats(str(rdir)).get("total_reviewed") == 0, "an empty reviews dir counts zero")
114
  cd = (ROOT / "crossref_deposit.py").read_text()
115
  g = cd.find("if (fresh.get(\"total_reviewed\") or 0) < published:")
116
+ w = cd.find("stats_path = _stats.write_stats(config.REVIEWS_DIR, out, pub)")
117
  check(0 < g < w, "a fresh count below the published total is never written")
118
+ pub = tmp / "public-reviews"; pub.mkdir()
119
+ (pub / "111.md").write_text("---\nrecord_id: 111\nreview_date: 2026-04-28T18:15:05Z\nrecommendation: RECOMMEND\n"
120
+ "consensus: divided\n---\n\n### Aggregate scores\n\n| Dimension | Mean | Scores |\n|---|---|---|\n"
121
+ "| Domain Fit | 4.6 | 4, 5 |\n| AI Slop Detection | 4.0 | 4, 4 |\n\n### Individual\n")
122
+ (pub / "111_review_quality_control.md").write_text("---\nrecord_id: 111\nreview_quality_control_flag: false\n---\n")
123
+ (pub / "ICSAC-SUB-00001.md").write_text("---\nrecord_id: ICSAC-SUB-00001\nrecommendation: REJECT\n---\n")
124
+ (rdir / "ICSAC-SUB-00001_x.md").write_text("---\nrecord_id: ICSAC-SUB-00001\nrecommendation: RECOMMEND\ndisagreement: False\n---\n")
125
+ st = stats.compute_stats(str(rdir), str(pub))
126
+ check(st["total_reviewed"] == 2, "published records count, and a record in both places counts once")
127
+ check(st["recommendation_mix"]["RECOMMEND"] == 2, "the raw record wins over its published copy")
128
+ check(st["dimension_means_overall"].get("Domain Fit") == 4.6, "the published ### Aggregate scores table is read")
129
+ check(st["dimension_means_overall"].get("AI Provenance Signal") == 4.0, "the old AI Slop Detection label counts as AI Provenance Signal")
130
+ check(st["rqc_audited_count"] == 1, "published RQC flags are read")
131
  finally:
132
  shutil.rmtree(tmp, ignore_errors=True)
133
 
stats.py CHANGED
@@ -49,16 +49,23 @@ def _parse_frontmatter(text: str) -> dict:
49
  return out
50
 
51
 
 
 
 
 
 
 
 
52
  def _parse_aggregate_means(text: str) -> dict[str, float]:
53
  """Pull dimension → mean from the aggregate markdown table."""
54
  means: dict[str, float] = {}
55
  in_table = False
56
  for line in text.splitlines():
57
  stripped = line.strip()
58
- if stripped.startswith("## Aggregate Scores"):
59
  in_table = True
60
  continue
61
- if in_table and stripped.startswith("## "):
62
  break
63
  if not in_table or not stripped.startswith("|"):
64
  continue
@@ -67,7 +74,7 @@ def _parse_aggregate_means(text: str) -> dict[str, float]:
67
  continue
68
  if set("".join(cells)) <= set("- "):
69
  continue
70
- label = cells[0]
71
  try:
72
  means[label] = float(cells[1])
73
  except ValueError:
@@ -144,7 +151,9 @@ def _load_reviews(reviews_dir: str) -> list[dict]:
144
  {
145
  "record_id": rid,
146
  "recommendation": fm.get("recommendation", "REVIEW_FURTHER"),
147
- "disagreement": fm.get("disagreement", "False").lower() == "true",
 
 
148
  "review_date": _parse_review_date(fm.get("review_date", "")),
149
  "dimension_means": means,
150
  "rqc_flag": rqc_flags.get(rid),
@@ -170,8 +179,15 @@ def _histogram(values: list[float]) -> dict[str, int]:
170
  return bins
171
 
172
 
173
- def compute_stats(reviews_dir: str) -> dict:
 
 
 
 
174
  reviews = _load_reviews(reviews_dir)
 
 
 
175
  now = _dt.datetime.now(_dt.timezone.utc)
176
  cutoff = now - _dt.timedelta(days=30)
177
 
@@ -226,8 +242,8 @@ def compute_stats(reviews_dir: str) -> dict:
226
  }
227
 
228
 
229
- def write_stats(reviews_dir: str, out_path: str) -> str:
230
- stats = compute_stats(reviews_dir)
231
  os.makedirs(os.path.dirname(out_path), exist_ok=True)
232
  with open(out_path, "w", encoding="utf-8") as f:
233
  json.dump(stats, f, indent=2, ensure_ascii=False)
@@ -250,5 +266,10 @@ if __name__ == "__main__":
250
  "~/Desktop/icsac/icsacinstitute.org/src/data/stats.json"
251
  )
252
  )
253
- written = write_stats(rdir, out)
 
 
 
 
 
254
  print(f"wrote {written}")
 
49
  return out
50
 
51
 
52
+ # The raw review writes "## Aggregate Scores"; the published copy writes
53
+ # "### Aggregate scores". Reviews before 2026-05-17 name the last dimension
54
+ # by its old label.
55
+ _AGG_HEADING = re.compile(r"^#{2,3}\s+aggregate\s+scores\b", re.I)
56
+ _LABEL_ALIASES = {"AI Slop Detection": "AI Provenance Signal"}
57
+
58
+
59
  def _parse_aggregate_means(text: str) -> dict[str, float]:
60
  """Pull dimension → mean from the aggregate markdown table."""
61
  means: dict[str, float] = {}
62
  in_table = False
63
  for line in text.splitlines():
64
  stripped = line.strip()
65
+ if _AGG_HEADING.match(stripped):
66
  in_table = True
67
  continue
68
+ if in_table and stripped.startswith("#"):
69
  break
70
  if not in_table or not stripped.startswith("|"):
71
  continue
 
74
  continue
75
  if set("".join(cells)) <= set("- "):
76
  continue
77
+ label = _LABEL_ALIASES.get(cells[0], cells[0])
78
  try:
79
  means[label] = float(cells[1])
80
  except ValueError:
 
151
  {
152
  "record_id": rid,
153
  "recommendation": fm.get("recommendation", "REVIEW_FURTHER"),
154
+ # Published copies carry "consensus: divided" instead.
155
+ "disagreement": (fm["disagreement"].lower() == "true") if "disagreement" in fm
156
+ else fm.get("consensus", "").lower() == "divided",
157
  "review_date": _parse_review_date(fm.get("review_date", "")),
158
  "dimension_means": means,
159
  "rqc_flag": rqc_flags.get(rid),
 
179
  return bins
180
 
181
 
182
+ def compute_stats(reviews_dir: str, public_dir: str | None = None) -> dict:
183
+ """public_dir: the website's published review records. The raw files behind
184
+ the papers reviewed before the public flip (2026-05-16) are gone from
185
+ reviews/, so the published copies are the only record of those reviews;
186
+ a record in both places counts once (raw wins)."""
187
  reviews = _load_reviews(reviews_dir)
188
+ if public_dir:
189
+ seen = {r["record_id"] for r in reviews}
190
+ reviews += [r for r in _load_reviews(public_dir) if r["record_id"] not in seen]
191
  now = _dt.datetime.now(_dt.timezone.utc)
192
  cutoff = now - _dt.timedelta(days=30)
193
 
 
242
  }
243
 
244
 
245
+ def write_stats(reviews_dir: str, out_path: str, public_dir: str | None = None) -> str:
246
+ stats = compute_stats(reviews_dir, public_dir)
247
  os.makedirs(os.path.dirname(out_path), exist_ok=True)
248
  with open(out_path, "w", encoding="utf-8") as f:
249
  json.dump(stats, f, indent=2, ensure_ascii=False)
 
266
  "~/Desktop/icsac/icsacinstitute.org/src/data/stats.json"
267
  )
268
  )
269
+ pub = (
270
+ sys.argv[3]
271
+ if len(sys.argv) > 3
272
+ else os.path.join(os.path.dirname(os.path.dirname(out)), "data", "public-reviews")
273
+ )
274
+ written = write_stats(rdir, out, pub if os.path.isdir(pub) else None)
275
  print(f"wrote {written}")