Maturity from run history, pack revision digests, attribute sets, projects and templates (RBT-WP-0008)
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Work Records / validate (push) Has been cancelled

Also fixes run lists and scores mixing runs of different packs in one repository.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 295952@bnt-lap001
Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
This commit is contained in:
tegwick 2026-09-29 12:36:34 +02:00
parent 2f60d47746
commit 0203bf553c
19 changed files with 1311 additions and 33 deletions

View file

@ -135,3 +135,25 @@ def render(command: str, values: dict[str, str], pack: Pack) -> str:
return val
return PLACEHOLDER.sub(sub, command)
REVIEW_FILE = "REVIEWS.yaml"
def digest(pack: "Pack") -> str:
"""Revision of a pack: hash of every file in its directory, except review records and local state.
`exercise_status:` lines are ignored, so recording an exercise never changes the revision.
"""
import hashlib
h = hashlib.sha256()
root = pack.path.resolve().parent
for f in sorted(root.rglob("*")):
rel = f.relative_to(root)
if not f.is_file() or f.name == REVIEW_FILE or ".local" in rel.parts or "__pycache__" in rel.parts:
continue
data = f.read_bytes()
if f.name == "pack.yaml" or f.name.startswith("pack."):
data = b"\n".join(x for x in data.split(b"\n") if not x.startswith(b"exercise_status:"))
h.update(str(rel).encode() + b"\0" + data + b"\0")
return h.hexdigest()[:16]