3e07e86187
Per sub-project-2 plan Task 11 / spec §8.1. proposed_records filter and approve() return an approved copy via dataclasses.replace (no in-place mutation), with optional coordinate/rationale override and an injected reviewed_at timestamp. Pure, no I/O, no clock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
35 lines
1.2 KiB
Python
35 lines
1.2 KiB
Python
"""Review state-transition core (pure, tested): proposed -> approved.
|
|
|
|
No I/O, no clock — the timestamp is injected so the logic stays deterministic.
|
|
The CLI persists the result via hef.catalog.save_catalog after re-validating.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import replace
|
|
|
|
|
|
def proposed_records(records):
|
|
"""Records still awaiting review."""
|
|
return [r for r in records if r.review_status == "proposed"]
|
|
|
|
|
|
def approve(record, *, reviewed_at, coordinate=None, rationale=None):
|
|
"""Return an approved copy of `record` (the input is not mutated).
|
|
|
|
review_status -> 'approved' and reviewed_at is stamped. Optionally override
|
|
the four coordinates with a human correction and/or replace the rationale.
|
|
The caller re-validates before saving.
|
|
"""
|
|
changes = {"review_status": "approved", "reviewed_at": reviewed_at}
|
|
if coordinate is not None:
|
|
changes.update(
|
|
left=coordinate.left,
|
|
right=coordinate.right,
|
|
dark=coordinate.dark,
|
|
light=coordinate.light,
|
|
)
|
|
if rationale is not None:
|
|
changes["rationale"] = rationale
|
|
return replace(record, **changes)
|