cjc0013 commited on
Commit
6a78301
·
verified ·
1 Parent(s): f14edf7

Refresh public Space consistency and detail copy

Browse files
dataset_bundle/evidence_audit/consistency_report.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "generated_at": "2026-04-19T19:38:57-04:00",
3
  "event_provenance": {
4
  "event_count": 3918,
5
  "events_with_artifacts": 3878,
 
1
  {
2
+ "generated_at": "2026-04-19T20:18:33-04:00",
3
  "event_provenance": {
4
  "event_count": 3918,
5
  "events_with_artifacts": 3878,
dataset_bundle/public_release_manifest.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "public_version": "congress-public-records-slice-2026-04-v1",
3
  "title": "Congress Public Records Slice",
4
- "release_date": "2026-04-19T19:40:15-04:00",
5
  "slice_description": "A neutral, review-oriented slice of House public-record linkages across financial disclosures, sector overlap, and community project funding recipient relationships.",
6
  "source_run_name": "house_all_baseline_20260418_v21_recipienthardening",
7
  "dataset_repo_id": "cjc0013/cmp-data",
 
1
  {
2
  "public_version": "congress-public-records-slice-2026-04-v1",
3
  "title": "Congress Public Records Slice",
4
+ "release_date": "2026-04-19T20:19:47-04:00",
5
  "slice_description": "A neutral, review-oriented slice of House public-record linkages across financial disclosures, sector overlap, and community project funding recipient relationships.",
6
  "source_run_name": "house_all_baseline_20260418_v21_recipienthardening",
7
  "dataset_repo_id": "cjc0013/cmp-data",
public_space_app.py CHANGED
@@ -842,7 +842,7 @@ def _plain_strengthener(value: str) -> str:
842
  normalized = str(value or "").strip()
843
  mapping = {
844
  "bill_sector_mapping_weak": "Requires stronger correlation between the trade window and related bill subject matter.",
845
- "donor_industry_mapping_weak": "Missing granular donor industry classification.",
846
  "committee_history_missing": "Committee history is missing or incomplete for this row.",
847
  "lobbying_issue_mapping_weak": "Requires clearer mapping between lobbying issue tags and the policy area in this row.",
848
  "recipient_identity_ambiguous": "The recipient identity needs a cleaner match before this can be treated as a stronger link.",
@@ -868,7 +868,7 @@ def _evidence_chip_help(label: str) -> str:
868
  "annual disclosure": "Annual financial disclosure records support this relationship.",
869
  "bill record": "Bill-status records help show legislative activity in the same topic area.",
870
  "funding award": "Published federal award records support a funding-recipient link in this slice.",
871
- "committee roster": "Committee records show committee context related to the same topic area.",
872
  "vote activity": "Roll-call vote records add legislative activity in the same topic window.",
873
  "lobbying activity": "Lobbying filings add public activity in the same issue area.",
874
  "member profile": "Member-published profile or committee context contributes to this relationship summary.",
@@ -881,8 +881,8 @@ def _score_help_text(ranking_mode: str) -> str:
881
  normalized = str(ranking_mode or "raw").strip().lower()
882
  if normalized == "relative":
883
  return (
884
- "Experimental relative score. It compares this relationship with the same member's other visible "
885
- "relationships in the current view so unusually strong links stand out against that member's baseline activity."
886
  )
887
  return (
888
  "Raw score. It favors clearer public support, more supporting rows, more integrity-checked records, "
@@ -1017,14 +1017,42 @@ def _collect_pipe_values(frame: pd.DataFrame, column: str, *, limit: int = 20) -
1017
  return items
1018
 
1019
 
1020
- def _relationship_reason_labels(link_rows: pd.DataFrame, event_rows: pd.DataFrame, row: Dict[str, Any]) -> list[str]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1021
  labels = [
1022
  _plain_reason_code(item)
1023
- for item in _collect_pipe_values(link_rows, "reason_codes", limit=20)
1024
- + _collect_pipe_values(event_rows, "reason_codes", limit=20)
1025
  ]
1026
- if not labels:
1027
- labels = [_plain_reason_code(item) for item in _split_pipe_values(row.get("reason_codes", ""), limit=20)]
1028
  ordered: list[str] = []
1029
  for label in labels:
1030
  if label and label not in ordered:
@@ -1032,6 +1060,15 @@ def _relationship_reason_labels(link_rows: pd.DataFrame, event_rows: pd.DataFram
1032
  return ordered[:10]
1033
 
1034
 
 
 
 
 
 
 
 
 
 
1035
  def _relationship_strengtheners(link_rows: pd.DataFrame, event_rows: pd.DataFrame) -> list[str]:
1036
  labels = [
1037
  _plain_strengthener(item)
@@ -1216,21 +1253,21 @@ def _relationship_context(
1216
  link_rows, event_rows = _relationship_constituents(links, events, row)
1217
  raw_score = _relationship_score(row)
1218
  relative_score = _relative_relationship_score(row, _member_activity_baselines(edges))
1219
- normalized_mode = str(ranking_mode or "raw").strip().lower()
1220
- display_score = relative_score if normalized_mode == "relative" else raw_score
1221
  surfaced_urls = _select_example_urls(row, link_rows, event_rows, limit=6)
1222
  all_urls = [record.get("url", "") for record in sorted(_relationship_source_records(link_rows, event_rows, str(row.get("target_label") or "")), key=lambda item: _source_record_priority(item, str(row.get("target_label") or "")))]
1223
  all_urls = [url for url in all_urls if url]
1224
- reason_labels = _relationship_reason_labels(link_rows, event_rows, row)
 
1225
  strengtheners = _relationship_strengtheners(link_rows, event_rows)
1226
  sha_values = _relationship_sha_values(link_rows, event_rows)
1227
- evidence_chips = _edge_evidence_chips(row, surfaced_urls)
1228
  link_type_mix = _relationship_link_type_mix(link_rows)
1229
  return {
1230
  "row": row,
1231
  "raw_score": raw_score,
1232
  "relative_score": relative_score,
1233
  "display_score": display_score,
 
1234
  "surfaced_urls": surfaced_urls,
1235
  "all_urls": all_urls,
1236
  "reason_labels": reason_labels,
@@ -1324,8 +1361,10 @@ def _rank_relationships(edges: pd.DataFrame, ranking_mode: str = "raw") -> pd.Da
1324
  "member",
1325
  "counterparty / sector",
1326
  "overall score",
 
1327
  "raw score",
1328
  "relative score",
 
1329
  "strength",
1330
  "evidence",
1331
  "time-window overlap",
@@ -1351,15 +1390,17 @@ def _rank_relationships(edges: pd.DataFrame, ranking_mode: str = "raw") -> pd.Da
1351
  chips = _edge_evidence_chips(row)
1352
  raw_score = _relationship_score(row)
1353
  relative_score = _relative_relationship_score(row, baselines)
1354
- display_score = relative_score if normalized_mode == "relative" else raw_score
1355
  rows.append(
1356
  {
1357
  "relationship_id": str(row.get("edge_id") or ""),
1358
  "member": str(row.get("member_name") or row.get("member_slug") or ""),
1359
  "counterparty / sector": _display_target_label(row),
1360
- "overall score": display_score,
 
1361
  "raw score": raw_score,
1362
  "relative score": relative_score,
 
1363
  "status_code": str(row.get("relationship_status", "") or ""),
1364
  "strength": _plain_status_label(str(row.get("relationship_status", "") or "")),
1365
  "evidence": " | ".join(chips) if chips else "published source support",
@@ -1372,8 +1413,8 @@ def _rank_relationships(edges: pd.DataFrame, ranking_mode: str = "raw") -> pd.Da
1372
  }
1373
  )
1374
  ranked = pd.DataFrame(rows).sort_values(
1375
- ["overall score", "supporting rows", "stronger support", "counterparty / sector"],
1376
- ascending=[False, False, False, True],
1377
  ).reset_index(drop=True)
1378
  ranked.insert(0, "rank", range(1, len(ranked) + 1))
1379
  return ranked
@@ -1406,7 +1447,8 @@ def _overview_summary_markdown(
1406
  f"- Showing the top `{min(int(top_n), len(ranked))}` `{_plain_family_label(family).lower()}` for `{focus_label}`.",
1407
  f"- Filtered to stronger links only: `{str(bool(only_strong_links)).lower()}`.",
1408
  f"- Ranking mode: `{'experimental relative to this member baseline' if str(ranking_mode or 'raw').strip().lower() == 'relative' else 'raw score'}`.",
1409
- f"- Highest score in this view: `{int(ranked['overall score'].max())}`.",
 
1410
  "- Pick one relationship below to see the evidence breakdown and coarse evidence window.",
1411
  ]
1412
  if not str(member_query or "").strip():
@@ -1438,7 +1480,9 @@ def _overview_cards_html(
1438
  f"for <strong>{html.escape(focus_label)}</strong>. "
1439
  f"Filtered to stronger links only: <strong>{'yes' if bool(only_strong_links) else 'no'}</strong>. "
1440
  f"Ranking mode: <strong>{'experimental relative to this member baseline' if str(ranking_mode or 'raw').strip().lower() == 'relative' else 'raw score'}</strong>. "
1441
- "Hover over score badges and evidence chips for why they matter. Pick one relationship below to open the plain-English explanation and evidence window."
 
 
1442
  "</div>"
1443
  )
1444
  cards: list[str] = []
@@ -1454,7 +1498,14 @@ def _overview_cards_html(
1454
  unresolved_refs = int(row.get("unresolved refs", 0) or 0)
1455
  raw_score = int(row.get("raw score", 0) or 0)
1456
  relative_score = int(row.get("relative score", 0) or 0)
 
1457
  score_note = _score_help_text(ranking_mode)
 
 
 
 
 
 
1458
  cards.append(
1459
  f"""
1460
  <div class="result-card">
@@ -1465,11 +1516,12 @@ def _overview_cards_html(
1465
  <div class="result-subtitle">For {html.escape(str(row.get("member", "") or ""))} in the {_plain_family_label(family).lower()} view.</div>
1466
  </div>
1467
  <div class="metric-stack">
1468
- <span class="score-pill" title="{html.escape(score_note)}">Score {int(row.get("overall score", 0) or 0)}</span>
1469
  <span class="strength-pill" title="{html.escape(_plain_status_explainer(str(row.get('status_code', '') or '')))}">{html.escape(str(row.get("strength", "") or ""))}</span>
1470
  </div>
1471
  </div>
1472
  <div class="chip-row">{chip_html or '<span class="chip">published source support</span>'}</div>
 
1473
  <div class="meta-grid">
1474
  <div><strong>Evidence window</strong>{html.escape(str(row.get("time-window overlap", "") or ""))}</div>
1475
  <div><strong>Supporting rows</strong>{supporting_rows}</div>
@@ -1477,7 +1529,7 @@ def _overview_cards_html(
1477
  <div><strong>Needs caution</strong>{needs_caution}</div>
1478
  <div><strong>Unresolved refs</strong>{unresolved_refs}</div>
1479
  <div><strong>Raw score</strong>{raw_score}</div>
1480
- <div><strong>Relative score</strong>{relative_score}</div>
1481
  </div>
1482
  <div class="result-hint">Use Explain this link below to open the detailed breakdown and export files for this relationship.</div>
1483
  </div>
@@ -1496,7 +1548,7 @@ def _relationship_options(ranked: pd.DataFrame) -> list[tuple[str, str]]:
1496
  return []
1497
  options: list[tuple[str, str]] = []
1498
  for row in ranked.to_dict("records"):
1499
- label = f"#{int(row['rank'])} {row['counterparty / sector']} - {row['strength']} (score {row['overall score']})"
1500
  options.append((label, str(row["relationship_id"])))
1501
  return options
1502
 
@@ -1527,15 +1579,16 @@ def _relationship_detail_markdown(
1527
  urls = context["surfaced_urls"]
1528
  raw_score = int(context["raw_score"])
1529
  relative_score = int(context["relative_score"])
1530
- display_score = int(context["display_score"])
1531
  lines = [
1532
  f"### {row.get('member_name') or row.get('member_slug')} -> {context['display_target_label']}",
1533
  "",
 
1534
  f"- Relationship view: `{_plain_family_label(family)}`",
1535
  f"- Strength label: `{_plain_status_label(str(row.get('relationship_status', '') or ''))}`",
1536
- f"- Displayed score in this view: `{display_score}`",
1537
  f"- Raw score: `{raw_score}`",
1538
  f"- Relative-to-baseline score (experimental): `{relative_score}`",
 
1539
  f"- Supporting relationship rows: `{int(row.get('link_count', 0) or 0)}`",
1540
  f"- Stronger-support rows: `{int(row.get('linked_count', 0) or 0) if family == 'recipient' else int(row.get('strong_event_count', 0) or 0)}`",
1541
  f"- Caution / weaker rows: `{int(row.get('review_count', 0) or 0) if family == 'recipient' else int(row.get('weak_event_count', 0) or 0)}`",
@@ -1548,6 +1601,10 @@ def _relationship_detail_markdown(
1548
  lines.append(f"- Released row kinds involved: `{'; '.join(context['link_type_mix'])}`")
1549
  if context["topic_area_note"]:
1550
  lines.append(f"- Topic-area note: {context['topic_area_note']}")
 
 
 
 
1551
  if reason_codes:
1552
  lines.extend(["", "#### Why it is linked in this slice", ""])
1553
  lines.extend(f"- {item}" for item in reason_codes)
@@ -1864,7 +1921,7 @@ def _timeline_window_from_url(url: str) -> tuple[int, str, str]:
1864
  if "usaspending.gov/award/" in normalized:
1865
  return (40, "Published award record", "Federal award record")
1866
  if "committee_info" in normalized:
1867
- return (50, "Current committee reference", "Committee roster")
1868
  return (60, "Published source", urlparse(normalized).netloc if normalized.startswith("http") else "Published source")
1869
 
1870
 
 
842
  normalized = str(value or "").strip()
843
  mapping = {
844
  "bill_sector_mapping_weak": "Requires stronger correlation between the trade window and related bill subject matter.",
845
+ "donor_industry_mapping_weak": "More granular industry tagging would improve precision.",
846
  "committee_history_missing": "Committee history is missing or incomplete for this row.",
847
  "lobbying_issue_mapping_weak": "Requires clearer mapping between lobbying issue tags and the policy area in this row.",
848
  "recipient_identity_ambiguous": "The recipient identity needs a cleaner match before this can be treated as a stronger link.",
 
868
  "annual disclosure": "Annual financial disclosure records support this relationship.",
869
  "bill record": "Bill-status records help show legislative activity in the same topic area.",
870
  "funding award": "Published federal award records support a funding-recipient link in this slice.",
871
+ "committee roster": "Committee records here provide current committee context. They are not presented as exact time-overlap proof.",
872
  "vote activity": "Roll-call vote records add legislative activity in the same topic window.",
873
  "lobbying activity": "Lobbying filings add public activity in the same issue area.",
874
  "member profile": "Member-published profile or committee context contributes to this relationship summary.",
 
881
  normalized = str(ranking_mode or "raw").strip().lower()
882
  if normalized == "relative":
883
  return (
884
+ "Raw score is still the main public score shown on the card. Experimental relative ordering only changes how the list is sorted "
885
+ "compared with the same member's other visible relationships in the current view."
886
  )
887
  return (
888
  "Raw score. It favors clearer public support, more supporting rows, more integrity-checked records, "
 
1017
  return items
1018
 
1019
 
1020
+ def _relationship_reason_codes(link_rows: pd.DataFrame, event_rows: pd.DataFrame, row: Dict[str, Any]) -> list[str]:
1021
+ codes = _collect_pipe_values(link_rows, "reason_codes", limit=20) + _collect_pipe_values(event_rows, "reason_codes", limit=20)
1022
+ if not codes:
1023
+ codes = _split_pipe_values(row.get("reason_codes", ""), limit=20)
1024
+ ordered: list[str] = []
1025
+ for code in codes:
1026
+ normalized = str(code or "").strip()
1027
+ if normalized and normalized not in ordered:
1028
+ ordered.append(normalized)
1029
+ return ordered[:12]
1030
+
1031
+
1032
+ def _reason_visible_in_public_card(reason_code: str, evidence_chips: list[str]) -> bool:
1033
+ chip_set = {str(item or "").strip().lower() for item in evidence_chips}
1034
+ requirements = {
1035
+ "committee_jurisdiction_match": {"committee roster"},
1036
+ "major_vote_overlap": {"vote activity"},
1037
+ "vote_density_support": {"vote activity"},
1038
+ "lobbying_issue_overlap": {"lobbying activity"},
1039
+ "lobbying_density_support": {"lobbying activity"},
1040
+ "bill_sponsor_overlap": {"bill record", "vote activity"},
1041
+ "legislative_relevance_match": {"bill record", "vote activity"},
1042
+ "legislative_density_support": {"bill record", "vote activity"},
1043
+ }
1044
+ required = requirements.get(str(reason_code or "").strip())
1045
+ if not required:
1046
+ return True
1047
+ return bool(chip_set.intersection(required))
1048
+
1049
+
1050
+ def _relationship_reason_labels(link_rows: pd.DataFrame, event_rows: pd.DataFrame, row: Dict[str, Any], evidence_chips: list[str]) -> list[str]:
1051
  labels = [
1052
  _plain_reason_code(item)
1053
+ for item in _relationship_reason_codes(link_rows, event_rows, row)
1054
+ if _reason_visible_in_public_card(item, evidence_chips)
1055
  ]
 
 
1056
  ordered: list[str] = []
1057
  for label in labels:
1058
  if label and label not in ordered:
 
1060
  return ordered[:10]
1061
 
1062
 
1063
+ def _relative_bucket(value: int) -> str:
1064
+ score = int(value or 0)
1065
+ if score >= 70:
1066
+ return "above this member's baseline"
1067
+ if score <= 30:
1068
+ return "below this member's baseline"
1069
+ return "near this member's baseline"
1070
+
1071
+
1072
  def _relationship_strengtheners(link_rows: pd.DataFrame, event_rows: pd.DataFrame) -> list[str]:
1073
  labels = [
1074
  _plain_strengthener(item)
 
1253
  link_rows, event_rows = _relationship_constituents(links, events, row)
1254
  raw_score = _relationship_score(row)
1255
  relative_score = _relative_relationship_score(row, _member_activity_baselines(edges))
1256
+ display_score = raw_score
 
1257
  surfaced_urls = _select_example_urls(row, link_rows, event_rows, limit=6)
1258
  all_urls = [record.get("url", "") for record in sorted(_relationship_source_records(link_rows, event_rows, str(row.get("target_label") or "")), key=lambda item: _source_record_priority(item, str(row.get("target_label") or "")))]
1259
  all_urls = [url for url in all_urls if url]
1260
+ evidence_chips = _edge_evidence_chips(row, surfaced_urls)
1261
+ reason_labels = _relationship_reason_labels(link_rows, event_rows, row, evidence_chips)
1262
  strengtheners = _relationship_strengtheners(link_rows, event_rows)
1263
  sha_values = _relationship_sha_values(link_rows, event_rows)
 
1264
  link_type_mix = _relationship_link_type_mix(link_rows)
1265
  return {
1266
  "row": row,
1267
  "raw_score": raw_score,
1268
  "relative_score": relative_score,
1269
  "display_score": display_score,
1270
+ "relative_bucket": _relative_bucket(relative_score),
1271
  "surfaced_urls": surfaced_urls,
1272
  "all_urls": all_urls,
1273
  "reason_labels": reason_labels,
 
1361
  "member",
1362
  "counterparty / sector",
1363
  "overall score",
1364
+ "sort score",
1365
  "raw score",
1366
  "relative score",
1367
+ "relative view",
1368
  "strength",
1369
  "evidence",
1370
  "time-window overlap",
 
1390
  chips = _edge_evidence_chips(row)
1391
  raw_score = _relationship_score(row)
1392
  relative_score = _relative_relationship_score(row, baselines)
1393
+ sort_score = relative_score if normalized_mode == "relative" else raw_score
1394
  rows.append(
1395
  {
1396
  "relationship_id": str(row.get("edge_id") or ""),
1397
  "member": str(row.get("member_name") or row.get("member_slug") or ""),
1398
  "counterparty / sector": _display_target_label(row),
1399
+ "overall score": raw_score,
1400
+ "sort score": sort_score,
1401
  "raw score": raw_score,
1402
  "relative score": relative_score,
1403
+ "relative view": _relative_bucket(relative_score),
1404
  "status_code": str(row.get("relationship_status", "") or ""),
1405
  "strength": _plain_status_label(str(row.get("relationship_status", "") or "")),
1406
  "evidence": " | ".join(chips) if chips else "published source support",
 
1413
  }
1414
  )
1415
  ranked = pd.DataFrame(rows).sort_values(
1416
+ ["sort score", "overall score", "supporting rows", "stronger support", "counterparty / sector"],
1417
+ ascending=[False, False, False, False, True],
1418
  ).reset_index(drop=True)
1419
  ranked.insert(0, "rank", range(1, len(ranked) + 1))
1420
  return ranked
 
1447
  f"- Showing the top `{min(int(top_n), len(ranked))}` `{_plain_family_label(family).lower()}` for `{focus_label}`.",
1448
  f"- Filtered to stronger links only: `{str(bool(only_strong_links)).lower()}`.",
1449
  f"- Ranking mode: `{'experimental relative to this member baseline' if str(ranking_mode or 'raw').strip().lower() == 'relative' else 'raw score'}`.",
1450
+ f"- Highest raw score in this view: `{int(ranked['overall score'].max())}`.",
1451
+ "- `Only stronger links` filters by the overall relationship bucket. A visible card can still include some caution rows inside it.",
1452
  "- Pick one relationship below to see the evidence breakdown and coarse evidence window.",
1453
  ]
1454
  if not str(member_query or "").strip():
 
1480
  f"for <strong>{html.escape(focus_label)}</strong>. "
1481
  f"Filtered to stronger links only: <strong>{'yes' if bool(only_strong_links) else 'no'}</strong>. "
1482
  f"Ranking mode: <strong>{'experimental relative to this member baseline' if str(ranking_mode or 'raw').strip().lower() == 'relative' else 'raw score'}</strong>. "
1483
+ "Hover over score badges and evidence chips for why they matter. "
1484
+ "A card can still include some caution rows here because the stronger-only filter applies to the overall relationship bucket, not every contributing row. "
1485
+ "Pick one relationship below to open the plain-English explanation and evidence window."
1486
  "</div>"
1487
  )
1488
  cards: list[str] = []
 
1498
  unresolved_refs = int(row.get("unresolved refs", 0) or 0)
1499
  raw_score = int(row.get("raw score", 0) or 0)
1500
  relative_score = int(row.get("relative score", 0) or 0)
1501
+ relative_view = str(row.get("relative view", "") or "")
1502
  score_note = _score_help_text(ranking_mode)
1503
+ ranking_mode_note = (
1504
+ f"<div class=\"result-note\"><strong>Experimental relative ordering:</strong> this relationship currently ranks "
1505
+ f"<strong>{html.escape(relative_view)}</strong> ({relative_score}) compared with the same member's other visible links.</div>"
1506
+ if str(ranking_mode or "raw").strip().lower() == "relative"
1507
+ else ""
1508
+ )
1509
  cards.append(
1510
  f"""
1511
  <div class="result-card">
 
1516
  <div class="result-subtitle">For {html.escape(str(row.get("member", "") or ""))} in the {_plain_family_label(family).lower()} view.</div>
1517
  </div>
1518
  <div class="metric-stack">
1519
+ <span class="score-pill" title="{html.escape(score_note)}">Raw score {raw_score}</span>
1520
  <span class="strength-pill" title="{html.escape(_plain_status_explainer(str(row.get('status_code', '') or '')))}">{html.escape(str(row.get("strength", "") or ""))}</span>
1521
  </div>
1522
  </div>
1523
  <div class="chip-row">{chip_html or '<span class="chip">published source support</span>'}</div>
1524
+ {ranking_mode_note}
1525
  <div class="meta-grid">
1526
  <div><strong>Evidence window</strong>{html.escape(str(row.get("time-window overlap", "") or ""))}</div>
1527
  <div><strong>Supporting rows</strong>{supporting_rows}</div>
 
1529
  <div><strong>Needs caution</strong>{needs_caution}</div>
1530
  <div><strong>Unresolved refs</strong>{unresolved_refs}</div>
1531
  <div><strong>Raw score</strong>{raw_score}</div>
1532
+ <div><strong>Relative view</strong>{html.escape(relative_view)} ({relative_score})</div>
1533
  </div>
1534
  <div class="result-hint">Use Explain this link below to open the detailed breakdown and export files for this relationship.</div>
1535
  </div>
 
1548
  return []
1549
  options: list[tuple[str, str]] = []
1550
  for row in ranked.to_dict("records"):
1551
+ label = f"#{int(row['rank'])} {row['counterparty / sector']} - {row['strength']} (raw {row['overall score']})"
1552
  options.append((label, str(row["relationship_id"])))
1553
  return options
1554
 
 
1579
  urls = context["surfaced_urls"]
1580
  raw_score = int(context["raw_score"])
1581
  relative_score = int(context["relative_score"])
 
1582
  lines = [
1583
  f"### {row.get('member_name') or row.get('member_slug')} -> {context['display_target_label']}",
1584
  "",
1585
+ "- This is a lead for inspection, not a claim of wrongdoing, intent, causality, or exact chronology.",
1586
  f"- Relationship view: `{_plain_family_label(family)}`",
1587
  f"- Strength label: `{_plain_status_label(str(row.get('relationship_status', '') or ''))}`",
1588
+ f"- Public score shown on the card: `{raw_score}`",
1589
  f"- Raw score: `{raw_score}`",
1590
  f"- Relative-to-baseline score (experimental): `{relative_score}`",
1591
+ f"- Relative view in the current filter set: `{context['relative_bucket']}`",
1592
  f"- Supporting relationship rows: `{int(row.get('link_count', 0) or 0)}`",
1593
  f"- Stronger-support rows: `{int(row.get('linked_count', 0) or 0) if family == 'recipient' else int(row.get('strong_event_count', 0) or 0)}`",
1594
  f"- Caution / weaker rows: `{int(row.get('review_count', 0) or 0) if family == 'recipient' else int(row.get('weak_event_count', 0) or 0)}`",
 
1601
  lines.append(f"- Released row kinds involved: `{'; '.join(context['link_type_mix'])}`")
1602
  if context["topic_area_note"]:
1603
  lines.append(f"- Topic-area note: {context['topic_area_note']}")
1604
+ if "committee roster" in chips:
1605
+ lines.append(
1606
+ "- Committee context note: committee records shown here provide current reference context and are not part of an exact time-overlap claim."
1607
+ )
1608
  if reason_codes:
1609
  lines.extend(["", "#### Why it is linked in this slice", ""])
1610
  lines.extend(f"- {item}" for item in reason_codes)
 
1921
  if "usaspending.gov/award/" in normalized:
1922
  return (40, "Published award record", "Federal award record")
1923
  if "committee_info" in normalized:
1924
+ return (50, "Current reference only", "Committee context (not part of the time-overlap claim)")
1925
  return (60, "Published source", urlparse(normalized).netloc if normalized.startswith("http") else "Published source")
1926
 
1927