-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintegrity.py
More file actions
115 lines (87 loc) · 3.91 KB
/
Copy pathintegrity.py
File metadata and controls
115 lines (87 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Lightweight integrity helpers for subjective/review scoring.
This module intentionally lives outside ``intelligence.review`` so command/state
paths can import it without loading the heavier review package.
"""
from __future__ import annotations
from collections.abc import Iterable, Mapping
from scoring import (
SUBJECTIVE_TARGET_MATCH_TOLERANCE,
matches_target_score,
)
__all__ = [
"SUBJECTIVE_TARGET_MATCH_TOLERANCE",
"is_holistic_subjective_finding",
"is_subjective_review_open",
"matches_target_score",
"subjective_review_open_breakdown",
"unassessed_subjective_dimensions",
]
# ---------------------------------------------------------------------------
# Internal iteration helper
# ---------------------------------------------------------------------------
def _iter_findings(
findings: Mapping[str, dict] | Iterable[dict],
) -> Iterable[tuple[str, dict]]:
"""Yield (finding_id, finding) pairs from mapping or iterable inputs."""
if isinstance(findings, Mapping):
for finding_id, finding in findings.items():
if isinstance(finding, dict):
yield str(finding_id), finding
return
for index, finding in enumerate(findings):
if isinstance(finding, dict):
yield str(index), finding
# ---------------------------------------------------------------------------
# Public helpers (formerly in integrity/review.py)
# ---------------------------------------------------------------------------
def is_subjective_review_open(finding: dict) -> bool:
"""Return True when a finding is an open subjective-review signal."""
return (
finding.get("status") == "open"
and finding.get("detector") == "subjective_review"
)
def is_holistic_subjective_finding(finding: dict, *, finding_id: str = "") -> bool:
"""Best-effort check for holistic subjective-review coverage findings."""
candidate_id = str(finding.get("id") or finding_id or "")
if "::holistic_unreviewed" in candidate_id or "::holistic_stale" in candidate_id:
return True
summary = str(finding.get("summary", "") or "").lower()
if "holistic" in summary and "review" in summary:
return True
detail = finding.get("detail", {})
return bool(detail.get("holistic"))
def subjective_review_open_breakdown(
findings: Mapping[str, dict] | Iterable[dict],
) -> tuple[int, dict[str, int], dict[str, int]]:
"""Return open subjective count plus reason and holistic-reason breakdowns."""
reason_counts: dict[str, int] = {}
holistic_reason_counts: dict[str, int] = {}
total = 0
for finding_id, finding in _iter_findings(findings):
if not is_subjective_review_open(finding):
continue
total += 1
reason = str(finding.get("detail", {}).get("reason", "other") or "other")
reason_counts[reason] = reason_counts.get(reason, 0) + 1
if is_holistic_subjective_finding(finding, finding_id=finding_id):
holistic_reason_counts[reason] = holistic_reason_counts.get(reason, 0) + 1
return total, reason_counts, holistic_reason_counts
def unassessed_subjective_dimensions(dim_scores: dict | None) -> list[str]:
"""Return subjective dimension display names that are still 0% placeholders."""
if not dim_scores:
return []
unassessed: list[str] = []
for name, info in dim_scores.items():
detectors = info.get("detectors", {})
if "subjective_assessment" not in detectors:
continue
assessment_meta = detectors.get("subjective_assessment", {})
if isinstance(assessment_meta, dict) and assessment_meta.get("placeholder"):
unassessed.append(name)
continue
strict_val = float(info.get("strict", info.get("score", 100.0)))
issues = int(info.get("issues", 0))
if strict_val <= 0.0 and issues == 0:
unassessed.append(name)
unassessed.sort()
return unassessed