checklist.py
python
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83
chore(governance): sync handover+roadmap to 84db8c8 (drift:…
Human
1 day ago
| 1 | """Built-in freeze reviewer checklist (§K5.5).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from pathlib import Path |
| 6 | |
| 7 | import yaml |
| 8 | |
| 9 | from adapters.errors import ConfigError |
| 10 | from tools.freeze_reviewer.types import ChecklistItem, Severity |
| 11 | |
| 12 | BUILTIN_CHECKLIST: tuple[ChecklistItem, ...] = ( |
| 13 | ChecklistItem("C1", "Ground-truth edge", "MAJOR"), |
| 14 | ChecklistItem("C2", "Completeness", "BLOCKER"), |
| 15 | ChecklistItem("C3", "Internal consistency", "MAJOR"), |
| 16 | ChecklistItem("C4", "Security", "BLOCKER"), |
| 17 | ChecklistItem("C5", "Irreversibility", "BLOCKER"), |
| 18 | ChecklistItem("C6", "Real money", "BLOCKER"), |
| 19 | ChecklistItem("C7", "Tier-3 linkage", "BLOCKER"), |
| 20 | ChecklistItem("C8", "Citation readiness", "MINOR"), |
| 21 | ) |
| 22 | |
| 23 | VALID_SEVERITIES = frozenset({"BLOCKER", "MAJOR", "MINOR"}) |
| 24 | |
| 25 | |
| 26 | def builtin_checklist() -> list[ChecklistItem]: |
| 27 | """Return a copy of the §K5.5 built-in checklist.""" |
| 28 | return list(BUILTIN_CHECKLIST) |
| 29 | |
| 30 | |
| 31 | def load_checklist_file(path: Path) -> list[ChecklistItem]: |
| 32 | """Parse and validate an operator ``--checklist`` file.""" |
| 33 | try: |
| 34 | raw = yaml.safe_load(path.read_text(encoding="utf-8")) |
| 35 | except yaml.YAMLError as exc: |
| 36 | raise ConfigError(f"invalid checklist YAML: {exc}", str(path)) from exc |
| 37 | if not isinstance(raw, dict): |
| 38 | raise ConfigError("checklist root must be a mapping", str(path)) |
| 39 | checks = raw.get("checks") |
| 40 | if not isinstance(checks, list) or not checks: |
| 41 | raise ConfigError("checklist checks must be a non-empty list", str(path)) |
| 42 | items: list[ChecklistItem] = [] |
| 43 | for index, entry in enumerate(checks): |
| 44 | if not isinstance(entry, dict): |
| 45 | raise ConfigError(f"checks[{index}] must be a mapping", str(path)) |
| 46 | check_id = entry.get("id") |
| 47 | title = entry.get("title") |
| 48 | severity = entry.get("typical_severity") |
| 49 | if not isinstance(check_id, str) or not check_id.strip(): |
| 50 | raise ConfigError(f"checks[{index}].id must be a non-empty string", str(path)) |
| 51 | if not isinstance(title, str) or not title.strip(): |
| 52 | raise ConfigError(f"checks[{index}].title must be a non-empty string", str(path)) |
| 53 | if severity not in VALID_SEVERITIES: |
| 54 | raise ConfigError( |
| 55 | f"checks[{index}].typical_severity must be BLOCKER|MAJOR|MINOR", |
| 56 | str(path), |
| 57 | ) |
| 58 | items.append(ChecklistItem(check_id, title, severity)) # type: ignore[arg-type] |
| 59 | return items |
File History
1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199
fix(ISR): default require_independent_second_reviewer to require
Human
minor
⚠
1 day ago