Add quality criteria registry

This commit is contained in:
2026-05-15 15:22:45 +02:00
parent f029d6bba9
commit a9baf5ae52
15 changed files with 629 additions and 7 deletions

View File

@@ -0,0 +1,15 @@
from repo_registry.acceptance.criteria import (
active_quality_criteria_version,
criteria_registry_dict,
criteria_registry_json,
criteria_registry_markdown,
load_quality_criteria,
)
__all__ = [
"active_quality_criteria_version",
"criteria_registry_dict",
"criteria_registry_json",
"criteria_registry_markdown",
"load_quality_criteria",
]

View File

@@ -0,0 +1,148 @@
from __future__ import annotations
import json
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any
CRITERIA_SCHEMA_VERSION = "quality-criteria-registry/v1"
DEFAULT_CRITERIA_PATH = (
Path(__file__).resolve().parents[3]
/ "docs"
/ "quality-criteria"
/ "acceptance-quality-criteria.v1.json"
)
REQUIRED_CRITERION_FIELDS = {
"id",
"title",
"category",
"severity",
"applies_to",
"description",
"deterministic_action",
"deterministic_action_when",
"reviewer_guidance",
}
@dataclass(frozen=True)
class QualityCriterion:
id: str
title: str
category: str
severity: str
applies_to: list[str]
description: str
deterministic_action: str
deterministic_action_when: str
reviewer_guidance: str
agentic_guidance: str = ""
examples: list[str] | None = None
@dataclass(frozen=True)
class QualityCriteriaRegistry:
schema_version: str
criteria_version: str
status: str
updated_at: str
criteria: list[QualityCriterion]
def load_quality_criteria(path: str | Path | None = None) -> QualityCriteriaRegistry:
criteria_path = Path(path) if path is not None else DEFAULT_CRITERIA_PATH
payload = json.loads(criteria_path.read_text(encoding="utf-8"))
return _registry_from_payload(payload)
def active_quality_criteria_version(path: str | Path | None = None) -> str:
return load_quality_criteria(path).criteria_version
def criteria_registry_dict(registry: QualityCriteriaRegistry) -> dict[str, Any]:
return asdict(registry)
def criteria_registry_json(registry: QualityCriteriaRegistry) -> str:
return json.dumps(criteria_registry_dict(registry), indent=2, sort_keys=True) + "\n"
def criteria_registry_markdown(registry: QualityCriteriaRegistry) -> str:
lines = [
f"# Quality Criteria Registry: {registry.criteria_version}",
"",
f"- Schema: `{registry.schema_version}`",
f"- Status: `{registry.status}`",
f"- Updated: `{registry.updated_at}`",
"",
]
for criterion in registry.criteria:
lines.extend(
[
f"## {criterion.id}: {criterion.title}",
"",
f"- Category: `{criterion.category}`",
f"- Severity: `{criterion.severity}`",
f"- Applies to: `{', '.join(criterion.applies_to)}`",
f"- Deterministic action: `{criterion.deterministic_action}`",
"",
criterion.description,
"",
f"Deterministic trigger: {criterion.deterministic_action_when}",
"",
f"Reviewer guidance: {criterion.reviewer_guidance}",
"",
]
)
return "\n".join(lines)
def _registry_from_payload(payload: dict[str, Any]) -> QualityCriteriaRegistry:
if payload.get("schema_version") != CRITERIA_SCHEMA_VERSION:
raise ValueError(
"unsupported quality criteria schema: "
f"{payload.get('schema_version', '<missing>')}"
)
criteria_payload = payload.get("criteria")
if not isinstance(criteria_payload, list) or not criteria_payload:
raise ValueError("quality criteria registry must contain criteria")
criteria = [_criterion_from_payload(item) for item in criteria_payload]
ids = [criterion.id for criterion in criteria]
if len(ids) != len(set(ids)):
raise ValueError("quality criteria ids must be unique")
return QualityCriteriaRegistry(
schema_version=str(payload.get("schema_version", "")),
criteria_version=str(payload.get("criteria_version", "")),
status=str(payload.get("status", "")),
updated_at=str(payload.get("updated_at", "")),
criteria=criteria,
)
def _criterion_from_payload(payload: dict[str, Any]) -> QualityCriterion:
missing = sorted(REQUIRED_CRITERION_FIELDS - set(payload))
if missing:
raise ValueError(
f"quality criterion {payload.get('id', '<unknown>')} missing fields: "
f"{', '.join(missing)}"
)
applies_to = payload.get("applies_to")
if not isinstance(applies_to, list) or not applies_to:
raise ValueError(
f"quality criterion {payload.get('id', '<unknown>')} must list applies_to"
)
examples = payload.get("examples") or []
return QualityCriterion(
id=str(payload["id"]),
title=str(payload["title"]),
category=str(payload["category"]),
severity=str(payload["severity"]),
applies_to=[str(item) for item in applies_to],
description=str(payload["description"]),
deterministic_action=str(payload["deterministic_action"]),
deterministic_action_when=str(payload["deterministic_action_when"]),
reviewer_guidance=str(payload["reviewer_guidance"]),
agentic_guidance=str(payload.get("agentic_guidance", "")),
examples=[str(item) for item in examples],
)