Team Ai
Apppublic

evalstate/diffusers-pr-api

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
read_views.py792 linesDownload Raw Back to reports
1from __future__ import annotations2 3from dataclasses import dataclass4from pathlib import Path5from typing import Any, Literal6 7from slop_farmer.data.parquet_io import read_json, read_parquet_rows8from slop_farmer.data.snapshot_paths import (9    CURRENT_ANALYSIS_MANIFEST_PATH,10    load_current_analysis_manifest,11    repo_relative_path_to_local,12)13 14AnalysisVariant = Literal["auto", "hybrid", "deterministic"]15 16 17@dataclass(slots=True, frozen=True)18class _SnapshotMetadata:19    repo: str20    snapshot_id: str21 22 23@dataclass(slots=True, frozen=True)24class _AnalysisSelection:25    path: Path26    payload: dict[str, Any]27    variant_used: str28    llm_enrichment: bool29 30 31def get_snapshot_surfaces(snapshot_dir: Path) -> dict[str, Any]:32    issue_status = get_issue_cluster_status(snapshot_dir, variant="auto")33    contributor_status = get_contributor_status(snapshot_dir)34    return {35        "issues": {36            "available": issue_status["available"],37            "variant_used": issue_status.get("variant_used"),38            "llm_enrichment": issue_status.get("llm_enrichment"),39            "generated_at": issue_status.get("generated_at"),40            "cluster_count": (issue_status.get("counts") or {}).get("meta_bugs", 0),41            "duplicate_pr_count": (issue_status.get("counts") or {}).get("duplicate_prs", 0),42            "available_variants": issue_status.get("available_variants") or [],43        },44        "contributors": {45            "available": contributor_status["available"],46            "generated_at": contributor_status.get("generated_at"),47            "contributor_count": contributor_status.get("contributor_count", 0),48        },49    }50 51 52def get_issue_cluster_status(snapshot_dir: Path, *, variant: AnalysisVariant) -> dict[str, Any]:53    metadata = _snapshot_metadata(snapshot_dir)54    candidates = _analysis_candidates(snapshot_dir)55    selection = _select_analysis_report(candidates, variant=variant)56    status = {57        "repo": metadata.repo,58        "snapshot_id": metadata.snapshot_id,59        "variant_requested": variant,60        "available": selection is not None,61        "available_variants": sorted({candidate["variant"] for candidate in candidates}),62    }63    if selection is None:64        return {65            **status,66            "variant_used": None,67            "llm_enrichment": False,68            "generated_at": None,69            "report_path": None,70            "counts": {"meta_bugs": 0, "duplicate_issues": 0, "duplicate_prs": 0},71        }72    payload = selection.payload73    return {74        **status,75        "variant_used": selection.variant_used,76        "llm_enrichment": selection.llm_enrichment,77        "generated_at": payload.get("generated_at"),78        "report_path": selection.path.name,79        "counts": _analysis_counts(payload),80    }81 82 83def list_issue_clusters(84    snapshot_dir: Path,85    *,86    limit: int | None,87    variant: AnalysisVariant,88) -> dict[str, Any]:89    metadata, selection, issue_map, pr_map = _analysis_context(snapshot_dir, variant=variant)90    base = _analysis_base_payload(metadata, selection, variant=variant)91    if selection is None:92        return {**base, "clusters": [], "cluster_count": 0}93    clusters = [94        _issue_cluster_summary(cluster, issue_map, pr_map, rank=index)95        for index, cluster in enumerate(selection.payload.get("meta_bugs") or [], start=1)96    ]97    total = len(clusters)98    return {99        **base,100        "clusters": clusters[:limit] if limit is not None else clusters,101        "cluster_count": total,102    }103 104 105def get_issue_cluster(106    snapshot_dir: Path,107    *,108    cluster_id: str,109    variant: AnalysisVariant,110) -> dict[str, Any]:111    metadata, selection, issue_map, pr_map = _analysis_context(snapshot_dir, variant=variant)112    base = _analysis_base_payload(metadata, selection, variant=variant)113    if selection is None:114        return {115            **base,116            "cluster_id": cluster_id,117            "found": False,118            "cluster": None,119            "issues": [],120            "pull_requests": [],121        }122    cluster = next(123        (124            row125            for row in selection.payload.get("meta_bugs") or []126            if str(row.get("cluster_id") or "") == cluster_id127        ),128        None,129    )130    if cluster is None:131        return {132            **base,133            "cluster_id": cluster_id,134            "found": False,135            "cluster": None,136            "issues": [],137            "pull_requests": [],138        }139    issue_numbers = _ordered_ints(cluster.get("issue_numbers"))140    pr_numbers = _ordered_ints(cluster.get("pr_numbers"))141    canonical_pr_number = _coerce_int(cluster.get("canonical_pr_number"))142    return {143        **base,144        "cluster_id": cluster_id,145        "found": True,146        "cluster": {147            **_issue_cluster_summary(cluster, issue_map, pr_map),148            "canonical_issue_reason": cluster.get("canonical_issue_reason"),149            "canonical_pr_reason": cluster.get("canonical_pr_reason"),150            "best_issue_reason": cluster.get("best_issue_reason"),151            "best_pr_reason": cluster.get("best_pr_reason"),152        },153        "issues": [_issue_member_row(number, issue_map.get(number)) for number in issue_numbers],154        "pull_requests": [155            _pr_member_row(156                number,157                pr_map.get(number),158                role="canonical" if canonical_pr_number == number else "member",159            )160            for number in pr_numbers161        ],162    }163 164 165def get_issue_clusters_for_pr(166    snapshot_dir: Path,167    *,168    pr_number: int,169    variant: AnalysisVariant,170) -> dict[str, Any]:171    metadata, selection, issue_map, pr_map = _analysis_context(snapshot_dir, variant=variant)172    base = _analysis_base_payload(metadata, selection, variant=variant)173    if selection is None:174        return {**base, "pr_number": pr_number, "found": False, "clusters": [], "cluster_count": 0}175    matches = []176    for index, cluster in enumerate(selection.payload.get("meta_bugs") or [], start=1):177        pr_numbers = _ordered_ints(cluster.get("pr_numbers"))178        if pr_number not in pr_numbers:179            continue180        canonical_pr_number = _coerce_int(cluster.get("canonical_pr_number"))181        matches.append(182            {183                **_issue_cluster_summary(cluster, issue_map, pr_map, rank=index),184                "membership_role": "canonical" if canonical_pr_number == pr_number else "member",185            }186        )187    return {188        **base,189        "pr_number": pr_number,190        "found": bool(matches),191        "clusters": matches,192        "cluster_count": len(matches),193    }194 195 196def check_issue_cluster_membership(197    snapshot_dir: Path,198    *,199    pr_number: int,200    cluster_id: str | None,201    variant: AnalysisVariant,202) -> dict[str, Any]:203    lookup = get_issue_clusters_for_pr(snapshot_dir, pr_number=pr_number, variant=variant)204    matches = list(lookup.get("clusters") or [])205    matching_cluster_ids = [str(row.get("cluster_id")) for row in matches if row.get("cluster_id")]206    if cluster_id is None:207        return {208            **lookup,209            "cluster_id": None,210            "matched": bool(matching_cluster_ids),211            "matching_cluster_ids": matching_cluster_ids,212        }213    match = next((row for row in matches if row.get("cluster_id") == cluster_id), None)214    return {215        **lookup,216        "cluster_id": cluster_id,217        "matched": match is not None,218        "matching_cluster_ids": matching_cluster_ids,219        "membership": match,220    }221 222 223def list_issue_duplicate_prs(224    snapshot_dir: Path,225    *,226    limit: int | None,227    variant: AnalysisVariant,228) -> dict[str, Any]:229    metadata, selection, issue_map, pr_map = _analysis_context(snapshot_dir, variant=variant)230    base = _analysis_base_payload(metadata, selection, variant=variant)231    if selection is None:232        return {**base, "duplicate_prs": [], "duplicate_pr_count": 0}233    rows = [234        _duplicate_pr_summary(entry, issue_map, pr_map, rank=index)235        for index, entry in enumerate(selection.payload.get("duplicate_prs") or [], start=1)236    ]237    total = len(rows)238    return {239        **base,240        "duplicate_prs": rows[:limit] if limit is not None else rows,241        "duplicate_pr_count": total,242    }243 244 245def get_issue_best(snapshot_dir: Path, *, variant: AnalysisVariant) -> dict[str, Any]:246    metadata, selection, issue_map, pr_map = _analysis_context(snapshot_dir, variant=variant)247    base = _analysis_base_payload(metadata, selection, variant=variant)248    if selection is None:249        return {**base, "best_issue": None, "best_pr": None}250    return {251        **base,252        "best_issue": _best_issue_summary(selection.payload.get("best_issue"), issue_map),253        "best_pr": _best_pr_summary(selection.payload.get("best_pr"), pr_map),254    }255 256 257def get_contributor_status(snapshot_dir: Path) -> dict[str, Any]:258    metadata = _snapshot_metadata(snapshot_dir)259    report = _read_optional_json(snapshot_dir / "new-contributors-report.json")260    raw_contributors = report.get("contributors")261    contributors: list[Any] = raw_contributors if isinstance(raw_contributors, list) else []262    return {263        "repo": str(report.get("repo") or metadata.repo),264        "snapshot_id": str(report.get("snapshot_id") or metadata.snapshot_id),265        "available": bool(report),266        "generated_at": report.get("generated_at"),267        "window_days": _coerce_int(report.get("window_days")),268        "contributor_count": len(contributors),269    }270 271 272def list_contributors(snapshot_dir: Path, *, limit: int | None) -> dict[str, Any]:273    status = get_contributor_status(snapshot_dir)274    report = _read_optional_json(snapshot_dir / "new-contributors-report.json")275    rows = [276        _contributor_summary(entry, rank=index)277        for index, entry in enumerate(report.get("contributors") or [], start=1)278        if isinstance(entry, dict)279    ]280    total = len(rows)281    return {282        **status,283        "contributors": rows[:limit] if limit is not None else rows,284        "contributor_count": total,285    }286 287 288def get_contributor(snapshot_dir: Path, *, author_login: str) -> dict[str, Any]:289    status = get_contributor_status(snapshot_dir)290    report = _read_optional_json(snapshot_dir / "new-contributors-report.json")291    contributor = _find_contributor(report.get("contributors") or [], author_login)292    if contributor is None:293        return {294            **status,295            "author_login": author_login,296            "found": False,297            "summary": None,298            "risk": None,299            "contributor": None,300        }301    return {302        **status,303        "author_login": str(contributor.get("author_login") or author_login),304        "found": True,305        "summary": _contributor_summary(contributor),306        "risk": _contributor_risk(contributor),307        "contributor": contributor,308    }309 310 311def get_contributor_risk(snapshot_dir: Path, *, author_login: str) -> dict[str, Any]:312    contributor = get_contributor(snapshot_dir, author_login=author_login)313    risk = contributor.get("risk")314    return {315        "repo": contributor.get("repo"),316        "snapshot_id": contributor.get("snapshot_id"),317        "available": contributor.get("available"),318        "generated_at": contributor.get("generated_at"),319        "author_login": contributor.get("author_login"),320        "found": contributor.get("found"),321        "risk_available": risk is not None,322        "risk": risk,323    }324 325 326def _analysis_context(327    snapshot_dir: Path,328    *,329    variant: AnalysisVariant,330) -> tuple[331    _SnapshotMetadata,332    _AnalysisSelection | None,333    dict[int, dict[str, Any]],334    dict[int, dict[str, Any]],335]:336    metadata = _snapshot_metadata(snapshot_dir)337    selection = _select_analysis_report(_analysis_candidates(snapshot_dir), variant=variant)338    issue_map, pr_map = _artifact_maps(snapshot_dir)339    return metadata, selection, issue_map, pr_map340 341 342def _analysis_base_payload(343    metadata: _SnapshotMetadata,344    selection: _AnalysisSelection | None,345    *,346    variant: AnalysisVariant,347) -> dict[str, Any]:348    base = {349        "repo": metadata.repo,350        "snapshot_id": metadata.snapshot_id,351        "variant_requested": variant,352        "available": selection is not None,353        "variant_used": None,354        "llm_enrichment": False,355        "generated_at": None,356    }357    if selection is None:358        return base359    return {360        **base,361        "variant_used": selection.variant_used,362        "llm_enrichment": selection.llm_enrichment,363        "generated_at": selection.payload.get("generated_at"),364    }365 366 367def _analysis_candidates(snapshot_dir: Path) -> list[dict[str, Any]]:368    candidates: list[dict[str, Any]] = []369    for path in _analysis_report_paths(snapshot_dir):370        payload = _read_optional_json(path)371        if not payload:372            continue373        llm_enrichment = bool(payload.get("llm_enrichment"))374        candidates.append(375            {376                "path": path,377                "payload": payload,378                "variant": _analysis_variant(path.name, payload, llm_enrichment=llm_enrichment),379                "llm_enrichment": llm_enrichment,380            }381        )382    return candidates383 384 385def _select_analysis_report(386    candidates: list[dict[str, Any]],387    *,388    variant: AnalysisVariant,389) -> _AnalysisSelection | None:390    if not candidates:391        return None392    if variant == "auto":393        ordered = sorted(candidates, key=_analysis_auto_priority)394    else:395        ordered = [candidate for candidate in candidates if candidate["variant"] == variant]396        ordered.sort(key=_analysis_specific_priority)397    if not ordered:398        return None399    winner = ordered[0]400    return _AnalysisSelection(401        path=Path(winner["path"]),402        payload=dict(winner["payload"]),403        variant_used=str(winner["variant"]),404        llm_enrichment=bool(winner["llm_enrichment"]),405    )406 407 408def _analysis_report_paths(snapshot_dir: Path) -> list[Path]:409    ordered: list[Path] = []410    current_manifest_path = repo_relative_path_to_local(411        snapshot_dir, CURRENT_ANALYSIS_MANIFEST_PATH412    )413    if current_manifest_path.exists():414        try:415            current_manifest = load_current_analysis_manifest(current_manifest_path)416        except ValueError:417            current_manifest = None418        if current_manifest is not None:419            for artifact_path in (current_manifest.get("artifacts") or {}).values():420                if not isinstance(artifact_path, str):421                    continue422                ordered.append(repo_relative_path_to_local(snapshot_dir, artifact_path))423    ordered.extend(424        [425            snapshot_dir / "analysis-report-hybrid.json",426            snapshot_dir / "analysis-report-deterministic.json",427            snapshot_dir / "analysis-report.json",428        ]429    )430    seen: set[Path] = set()431    deduped: list[Path] = []432    for path in ordered:433        if path in seen:434            continue435        seen.add(path)436        deduped.append(path)437    deduped.extend(438        path for path in sorted(snapshot_dir.glob("analysis-report*.json")) if path not in seen439    )440    return [path for path in deduped if path.exists()]441 442 443def _analysis_auto_priority(candidate: dict[str, Any]) -> tuple[int, str]:444    path = Path(candidate["path"])445    if path.name == "analysis-report-hybrid.json":446        return (0, path.name)447    if bool(candidate.get("llm_enrichment")):448        return (1, path.name)449    if path.name == "analysis-report.json":450        return (2, path.name)451    return (3, path.name)452 453 454def _analysis_specific_priority(candidate: dict[str, Any]) -> tuple[int, str]:455    path = Path(candidate["path"])456    if path.name.endswith(f"-{candidate['variant']}.json"):457        return (0, path.name)458    if path.name == "analysis-report.json":459        return (1, path.name)460    return (2, path.name)461 462 463def _analysis_variant(path_name: str, payload: dict[str, Any], *, llm_enrichment: bool) -> str:464    lowered = path_name.lower()465    if "hybrid" in lowered:466        return "hybrid"467    if "deterministic" in lowered:468        return "deterministic"469    if isinstance(payload.get("variant_used"), str):470        variant_used = str(payload["variant_used"]).strip().lower()471        if variant_used in {"hybrid", "deterministic"}:472            return variant_used473    return "hybrid" if llm_enrichment else "deterministic"474 475 476def _analysis_counts(payload: dict[str, Any]) -> dict[str, int]:477    return {478        "meta_bugs": len(payload.get("meta_bugs") or []),479        "duplicate_issues": len(payload.get("duplicate_issues") or []),480        "duplicate_prs": len(payload.get("duplicate_prs") or []),481    }482 483 484def _artifact_maps(485    snapshot_dir: Path,486) -> tuple[dict[int, dict[str, Any]], dict[int, dict[str, Any]]]:487    issue_rows = (488        read_parquet_rows(snapshot_dir / "issues.parquet")489        if (snapshot_dir / "issues.parquet").exists()490        else []491    )492    pr_rows = (493        read_parquet_rows(snapshot_dir / "pull_requests.parquet")494        if (snapshot_dir / "pull_requests.parquet").exists()495        else []496    )497    issue_map = {498        int(row["number"]): row for row in issue_rows if _coerce_int(row.get("number")) is not None499    }500    pr_map = {501        int(row["number"]): row for row in pr_rows if _coerce_int(row.get("number")) is not None502    }503    return issue_map, pr_map504 505 506def _issue_cluster_summary(507    cluster: dict[str, Any],508    issue_map: dict[int, dict[str, Any]],509    pr_map: dict[int, dict[str, Any]],510    *,511    rank: int | None = None,512) -> dict[str, Any]:513    canonical_issue_number = _coerce_int(cluster.get("canonical_issue_number"))514    canonical_pr_number = _coerce_int(cluster.get("canonical_pr_number"))515    issue_numbers = _ordered_ints(cluster.get("issue_numbers"))516    pr_numbers = _ordered_ints(cluster.get("pr_numbers"))517    return {518        "rank": rank,519        "cluster_id": str(cluster.get("cluster_id") or f"cluster-{rank or 0}"),520        "title": _cluster_title(521            cluster, issue_map, pr_map, canonical_issue_number, canonical_pr_number522        ),523        "summary": cluster.get("summary"),524        "status": cluster.get("status"),525        "confidence": _coerce_float(cluster.get("confidence")),526        "canonical_issue_number": canonical_issue_number,527        "canonical_issue_title": _title_for_issue(canonical_issue_number, issue_map),528        "canonical_issue_url": _url_for_issue(canonical_issue_number, issue_map),529        "canonical_pr_number": canonical_pr_number,530        "canonical_pr_title": _title_for_pr(canonical_pr_number, pr_map),531        "canonical_pr_url": _url_for_pr(canonical_pr_number, pr_map),532        "issue_numbers": issue_numbers,533        "issue_count": len(issue_numbers),534        "pr_numbers": pr_numbers,535        "pr_count": len(pr_numbers),536        "evidence_types": [str(value) for value in (cluster.get("evidence_types") or []) if value],537        "github_url": _cluster_url(canonical_issue_number, canonical_pr_number, issue_map, pr_map),538    }539 540 541def _cluster_title(542    cluster: dict[str, Any],543    issue_map: dict[int, dict[str, Any]],544    pr_map: dict[int, dict[str, Any]],545    canonical_issue_number: int | None,546    canonical_pr_number: int | None,547) -> str:548    issue_title = _title_for_issue(canonical_issue_number, issue_map)549    if issue_title:550        return issue_title551    pr_title = _title_for_pr(canonical_pr_number, pr_map)552    if pr_title:553        return pr_title554    summary = str(cluster.get("summary") or "").strip()555    if summary:556        return summary557    return str(cluster.get("cluster_id") or "cluster")558 559 560def _cluster_url(561    canonical_issue_number: int | None,562    canonical_pr_number: int | None,563    issue_map: dict[int, dict[str, Any]],564    pr_map: dict[int, dict[str, Any]],565) -> str | None:566    return _url_for_issue(canonical_issue_number, issue_map) or _url_for_pr(567        canonical_pr_number, pr_map568    )569 570 571def _duplicate_pr_summary(572    entry: dict[str, Any],573    issue_map: dict[int, dict[str, Any]],574    pr_map: dict[int, dict[str, Any]],575    *,576    rank: int,577) -> dict[str, Any]:578    canonical_pr_number = _coerce_int(entry.get("canonical_pr_number"))579    target_issue_number = _coerce_int(entry.get("target_issue_number"))580    duplicates = _ordered_ints(entry.get("duplicate_pr_numbers"))581    return {582        "rank": rank,583        "cluster_id": str(entry.get("cluster_id") or f"duplicate-pr-{rank}"),584        "canonical_pr_number": canonical_pr_number,585        "canonical_pr_title": _title_for_pr(canonical_pr_number, pr_map),586        "canonical_pr_url": _url_for_pr(canonical_pr_number, pr_map),587        "target_issue_number": target_issue_number,588        "target_issue_title": _title_for_issue(target_issue_number, issue_map),589        "target_issue_url": _url_for_issue(target_issue_number, issue_map),590        "duplicate_pr_numbers": duplicates,591        "duplicate_pr_count": len(duplicates),592        "reason": entry.get("reason"),593    }594 595 596def _best_issue_summary(entry: Any, issue_map: dict[int, dict[str, Any]]) -> dict[str, Any] | None:597    if not isinstance(entry, dict):598        return None599    issue_number = _coerce_int(entry.get("issue_number"))600    return {601        "cluster_id": entry.get("cluster_id"),602        "issue_number": issue_number,603        "title": _title_for_issue(issue_number, issue_map),604        "url": _url_for_issue(issue_number, issue_map),605        "reason": entry.get("reason"),606        "score": _coerce_float(entry.get("score")),607    }608 609 610def _best_pr_summary(entry: Any, pr_map: dict[int, dict[str, Any]]) -> dict[str, Any] | None:611    if not isinstance(entry, dict):612        return None613    pr_number = _coerce_int(entry.get("pr_number"))614    return {615        "cluster_id": entry.get("cluster_id"),616        "pr_number": pr_number,617        "title": _title_for_pr(pr_number, pr_map),618        "url": _url_for_pr(pr_number, pr_map),619        "reason": entry.get("reason"),620        "score": _coerce_float(entry.get("score")),621    }622 623 624def _issue_member_row(number: int, row: dict[str, Any] | None) -> dict[str, Any]:625    row = row or {}626    return {627        "number": number,628        "title": row.get("title"),629        "state": row.get("state"),630        "author_login": row.get("author_login"),631        "created_at": row.get("created_at"),632        "updated_at": row.get("updated_at"),633        "html_url": row.get("html_url"),634    }635 636 637def _pr_member_row(number: int, row: dict[str, Any] | None, *, role: str) -> dict[str, Any]:638    row = row or {}639    return {640        "number": number,641        "role": role,642        "title": row.get("title"),643        "author_login": row.get("author_login"),644        "state": row.get("state"),645        "draft": bool(row.get("draft")),646        "merged": bool(row.get("merged")),647        "author_association": row.get("author_association"),648        "created_at": row.get("created_at"),649        "updated_at": row.get("updated_at"),650        "html_url": row.get("html_url"),651    }652 653 654def _contributor_summary(contributor: dict[str, Any], *, rank: int | None = None) -> dict[str, Any]:655    raw_activity = contributor.get("activity")656    activity: dict[str, Any] = raw_activity if isinstance(raw_activity, dict) else {}657    return {658        "rank": rank,659        "author_login": contributor.get("author_login"),660        "name": contributor.get("name"),661        "profile_url": contributor.get("profile_url"),662        "repo_association": contributor.get("repo_association"),663        "first_seen_in_snapshot": contributor.get("first_seen_in_snapshot"),664        "new_to_repo": contributor.get("new_to_repo"),665        "snapshot_pr_count": _coerce_int(contributor.get("snapshot_pr_count")) or 0,666        "snapshot_issue_count": _coerce_int(contributor.get("snapshot_issue_count")) or 0,667        "follow_through_score": contributor.get("follow_through_score"),668        "breadth_score": contributor.get("breadth_score"),669        "automation_risk_signal": contributor.get("automation_risk_signal"),670        "heuristic_note": contributor.get("heuristic_note"),671        "account_age_days": _coerce_int(contributor.get("account_age_days")),672        "public_pr_count_42d": _coerce_int(activity.get("visible_authored_pr_count")),673        "public_repo_count_42d": _coerce_int(activity.get("distinct_repos_with_authored_prs")),674        "repo_pull_requests_url": contributor.get("repo_pull_requests_url"),675        "repo_issues_url": contributor.get("repo_issues_url"),676    }677 678 679def _contributor_risk(contributor: dict[str, Any]) -> dict[str, Any]:680    raw_activity = contributor.get("activity")681    activity: dict[str, Any] = raw_activity if isinstance(raw_activity, dict) else {}682    return {683        "automation_risk_signal": contributor.get("automation_risk_signal"),684        "heuristic_note": contributor.get("heuristic_note"),685        "follow_through_score": contributor.get("follow_through_score"),686        "breadth_score": contributor.get("breadth_score"),687        "account_age_days": _coerce_int(contributor.get("account_age_days")),688        "public_pr_count_42d": _coerce_int(activity.get("visible_authored_pr_count")),689        "public_repo_count_42d": _coerce_int(activity.get("distinct_repos_with_authored_prs")),690        "report_reason": contributor.get("report_reason"),691    }692 693 694def _find_contributor(entries: list[Any], author_login: str) -> dict[str, Any] | None:695    lowered = author_login.casefold()696    for entry in entries:697        if not isinstance(entry, dict):698            continue699        login = str(entry.get("author_login") or "")700        if login.casefold() == lowered:701            return entry702    return None703 704 705def _snapshot_metadata(snapshot_dir: Path) -> _SnapshotMetadata:706    manifest = _read_optional_json(snapshot_dir / "manifest.json")707    repo = str(manifest.get("repo") or _infer_repo(snapshot_dir) or "")708    snapshot_id = str(manifest.get("snapshot_id") or snapshot_dir.name)709    return _SnapshotMetadata(repo=repo, snapshot_id=snapshot_id)710 711 712def _infer_repo(snapshot_dir: Path) -> str | None:713    for filename in ("pull_requests.parquet", "issues.parquet"):714        path = snapshot_dir / filename715        if not path.exists():716            continue717        rows = read_parquet_rows(path)718        if rows and rows[0].get("repo"):719            return str(rows[0]["repo"])720    for filename in _analysis_report_paths(snapshot_dir):721        payload = _read_optional_json(filename)722        if payload.get("repo"):723            return str(payload["repo"])724    report = _read_optional_json(snapshot_dir / "new-contributors-report.json")725    if report.get("repo"):726        return str(report["repo"])727    return None728 729 730def _title_for_issue(number: int | None, issue_map: dict[int, dict[str, Any]]) -> str | None:731    if number is None or number not in issue_map:732        return None733    title = issue_map[number].get("title")734    return str(title) if title else None735 736 737def _url_for_issue(number: int | None, issue_map: dict[int, dict[str, Any]]) -> str | None:738    if number is None or number not in issue_map:739        return None740    value = issue_map[number].get("html_url")741    return str(value) if value else None742 743 744def _title_for_pr(number: int | None, pr_map: dict[int, dict[str, Any]]) -> str | None:745    if number is None or number not in pr_map:746        return None747    title = pr_map[number].get("title")748    return str(title) if title else None749 750 751def _url_for_pr(number: int | None, pr_map: dict[int, dict[str, Any]]) -> str | None:752    if number is None or number not in pr_map:753        return None754    value = pr_map[number].get("html_url")755    return str(value) if value else None756 757 758def _ordered_ints(values: Any) -> list[int]:759    if not isinstance(values, list):760        return []761    ordered: list[int] = []762    for value in values:763        number = _coerce_int(value)764        if number is not None:765            ordered.append(number)766    return ordered767 768 769def _coerce_int(value: Any) -> int | None:770    if value is None:771        return None772    try:773        return int(value)774    except (TypeError, ValueError):775        return None776 777 778def _coerce_float(value: Any) -> float | None:779    if value is None:780        return None781    try:782        return float(value)783    except (TypeError, ValueError):784        return None785 786 787def _read_optional_json(path: Path) -> dict[str, Any]:788    if not path.exists():789        return {}790    payload = read_json(path)791    return payload if isinstance(payload, dict) else {}792