feat: advance repository records and provenance
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
This commit is contained in:
parent
329af60753
commit
35e86d7b85
24 changed files with 1618 additions and 51 deletions
78
src/repo_manager/parse/record.py
Normal file
78
src/repo_manager/parse/record.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
"""Parse repository-owned intake and decision records from Markdown YAML fences."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
_YAML_FENCE_RE = re.compile(r"```ya?ml\s*\n(.*?)\n```", re.DOTALL | re.IGNORECASE)
|
||||
SUPPORTED_RECORD_KINDS = frozenset({"intake", "decision"})
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParsedRecord:
|
||||
kind: str
|
||||
id: str
|
||||
title: str | None
|
||||
status: str | None
|
||||
uuid: str | None
|
||||
source_path: str
|
||||
raw: dict[str, Any] = field(default_factory=dict)
|
||||
block_start: int = 0
|
||||
block_end: int = 0
|
||||
|
||||
|
||||
def parse_record_text(text: str, *, relative_path: str) -> list[ParsedRecord]:
|
||||
"""Return intake/decision records embedded in YAML fenced blocks."""
|
||||
records: list[ParsedRecord] = []
|
||||
for match in _YAML_FENCE_RE.finditer(text):
|
||||
try:
|
||||
data = yaml.safe_load(match.group(1)) or {}
|
||||
except yaml.YAMLError:
|
||||
continue
|
||||
if not isinstance(data, dict) or data.get("kind") not in SUPPORTED_RECORD_KINDS:
|
||||
continue
|
||||
record_id = data.get("id")
|
||||
if record_id is None:
|
||||
continue
|
||||
kind = str(data["kind"])
|
||||
uuid_field = "state_hub_intake_id" if kind == "intake" else "state_hub_decision_id"
|
||||
records.append(
|
||||
ParsedRecord(
|
||||
kind=kind,
|
||||
id=str(record_id),
|
||||
title=str(data["title"]) if data.get("title") is not None else None,
|
||||
status=str(data["status"]) if data.get("status") is not None else None,
|
||||
uuid=str(data[uuid_field]) if data.get(uuid_field) is not None else None,
|
||||
source_path=relative_path,
|
||||
raw=data,
|
||||
block_start=match.start(),
|
||||
block_end=match.end(),
|
||||
)
|
||||
)
|
||||
return records
|
||||
|
||||
|
||||
def parse_record_file(path: Path, *, repo_root: Path) -> list[ParsedRecord]:
|
||||
return parse_record_text(
|
||||
path.read_text(encoding="utf-8"),
|
||||
relative_path=str(path.relative_to(repo_root)),
|
||||
)
|
||||
|
||||
|
||||
def iter_record_files(repo_root: Path) -> list[Path]:
|
||||
"""Find only the governed record locations; do not interpret arbitrary docs."""
|
||||
files: set[Path] = set()
|
||||
for relative in ("intakes", "decisions", "docs/intakes", "docs/decisions", "workplans"):
|
||||
root = repo_root / relative
|
||||
if root.is_dir():
|
||||
files.update(path for path in root.rglob("*.md") if not path.name.startswith("."))
|
||||
for name in ("INTAKES.md", "DECISIONS.md"):
|
||||
path = repo_root / name
|
||||
if path.is_file():
|
||||
files.add(path)
|
||||
return sorted(files)
|
||||
Loading…
Add table
Add a link
Reference in a new issue