"""Personal-data screen for public nonprofit requests (AGENTS.md hard rule 1). A deterministic, limited filter: it finds common contact, identity and payment patterns and lines that look like a record about a person. It is not a claim that every kind of personal data can be detected. Findings name the kind of data and the field, never the matched text, so a refusal can be shown and stored without repeating what it refused. """ from __future__ import annotations import re _EMAIL = re.compile( r"[A-Za-z0-9._%+-]+@(?!example\.(?:com|org|net)\b)[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}" ) _HANDLE = re.compile(r"(? list[str]: """Kinds of personal data found per field, as `field: kind` strings, without the matched text. A line shaped like a record about a person (`Name: ...`, `Phone: ...`) counts unless the line itself carries a visible SYNTHETIC mark, so made-up examples stay possible. """ findings: list[str] = [] for field, text in fields.items(): for kind, pattern in PATTERNS: if pattern.search(text): findings.append(f"{field}: {kind}") for line in text.splitlines(): if _RECORD_LINE.search(line) and "SYNTHETIC" not in line: findings.append(f"{field}: a record about a person without a SYNTHETIC mark") break return list(dict.fromkeys(findings))