"""nisse-review's state store (architecture L8): the shared one, with its own name and roles. A work item is one PR (R1); what the reviewer keeps about it is in its row's data, as ``PR``.""" from dataclasses import asdict, dataclass from typing import Any from nisse_core.state import store from nisse_core.state.store import WorkItem # A review item's positions. READY = "ready" # a run is due: a review, a later review, or replies RUNNING = "running" # a run is under way; on boot, interrupted REVIEWED = "reviewed" # nothing due: watching for pushes and comments WAITING = "waiting" # not ready: a draft or work in progress FAILED = "failed" # runs kept failing; said so on the PR CAPPED = "capped" # the round cap: summed up for the operator, quiet (R2) STOPPED = "stopped" # an operator said `stop` on the PR; `review` resumes (R5) CLOSED = "closed" POST_REVIEW = "post_review" # the intent around posting one (L8) # What a run is, from the item (``Scheduler._kind``). FIRST = "first" # the whole PR: its first review, or one asked for LATER = "later" # what changed since its last review, and its earlier points REPLIES = "replies" # answering what was said since, at the same head SUMMARY = "summary" # the round cap: what is still open, for the operator class StateStore(store.StateStore): AGENT = "nisse-review" # The reviewer drives as "driver" (the shared views and tools expect # it); "memory" is its pass at a close. ACTORS = store.ACTORS | {"memory"} @dataclass(frozen=True) class PR: repo: str # owner/name number: int head: str = "" # the commit last seen at the PR's head reviewed: str = "" # the commit its last review was posted on attempts: int = 0 # failed runs at this head seen_at: float = 0.0 # when this head was first seen (the CI wait) # M7.5: the discussion. seen: tuple[str, ...] = () # keys of everything said on it, taken in fresh: tuple[str, ...] = () # keys said since its last run, to answer rounds: int = 0 # reviews and reply sets since the last reset (R2) posts: int = 0 # reviews it posted on the PR: their markers' numbers happy: bool = False # its last review signed off: no repeats while so full: bool = False # an operator asked for a fresh review (`review`) run: str = "" # the kind of run under way, for recovery def item_id(repo: str, number: int) -> str: return f"{repo}#{number}" def pr_of(item: WorkItem) -> PR: raw = dict(item.data["pr"]) for key in ("seen", "fresh"): raw[key] = tuple(raw.get(key) or ()) if "posts" not in raw and raw.get("reviewed"): raw["posts"] = 1 # reviewed before M7.5, which numbered them return PR(**raw) def data(pr: PR) -> dict[str, Any]: return {"pr": asdict(pr)}