85 lines
2.9 KiB
Python
85 lines
2.9 KiB
Python
"""RAT-1 — unified pack compile step.
|
|
|
|
Single entry point that regenerates compiled-artifact bytes for every
|
|
optional ratification surface (frames + compositions) AND updates the
|
|
pack manifest's checksum fields atomically.
|
|
|
|
This is the missing link between operator ratification (which writes
|
|
source files under ``{pack}/frames/`` or ``{pack}/compositions/``) and
|
|
runtime visibility (which loads from compiled artifacts +
|
|
manifest-declared checksums).
|
|
|
|
Doctrine:
|
|
|
|
- The compile step is **read-only over reviewed source files**.
|
|
- Manifest mutation is the only side effect besides the compiled
|
|
artifacts. The lexicon checksum (``checksum`` field) is preserved
|
|
byte-equal — only ``frame_checksum`` and ``composition_checksum``
|
|
fields are added/updated.
|
|
- Empty source directory produces a zero-byte compiled artifact AND
|
|
``manifest_checksum_field = sha256("")`` — the loader treats this
|
|
as an empty-registry no-op.
|
|
- Idempotent: running compile twice in a row is a no-op.
|
|
|
|
Trust boundary identical to the per-surface handlers (ADR-0168 §"Mutation
|
|
boundary", ADR-0169 §"Mutation boundary"): the compile step does NOT
|
|
touch solver, parser, decomposer, arithmetic operators, runtime graph
|
|
execution, or refusal logic. It writes ``compositions.jsonl`` +
|
|
``frames.jsonl`` + ``manifest.json``. Nothing else.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
from packs.compile_compositions import compile_compositions
|
|
from packs.compile_frames import compile_frames
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class CompilePackReceipt:
|
|
pack_path: Path
|
|
frame_checksum: str
|
|
composition_checksum: str
|
|
frame_bytes_written: int
|
|
composition_bytes_written: int
|
|
manifest_updated: bool
|
|
|
|
|
|
def compile_pack(pack_path: Path) -> CompilePackReceipt:
|
|
"""Compile all ratification surfaces for *pack_path* + update manifest.
|
|
|
|
Returns the receipt with computed checksums + I/O counts.
|
|
"""
|
|
pack_path = Path(pack_path).resolve()
|
|
manifest_path = pack_path / "manifest.json"
|
|
if not manifest_path.exists():
|
|
raise FileNotFoundError(f"Pack manifest missing: {manifest_path}")
|
|
|
|
frame_bytes, frame_sha = compile_frames(pack_path)
|
|
comp_bytes, comp_sha = compile_compositions(pack_path)
|
|
|
|
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
before = dict(manifest)
|
|
manifest["frame_checksum"] = frame_sha
|
|
manifest["composition_checksum"] = comp_sha
|
|
updated = manifest != before
|
|
if updated:
|
|
manifest_path.write_text(
|
|
json.dumps(manifest, indent=2, sort_keys=True) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
return CompilePackReceipt(
|
|
pack_path=pack_path,
|
|
frame_checksum=frame_sha,
|
|
composition_checksum=comp_sha,
|
|
frame_bytes_written=len(frame_bytes),
|
|
composition_bytes_written=len(comp_bytes),
|
|
manifest_updated=updated,
|
|
)
|
|
|
|
|
|
__all__ = ["compile_pack", "CompilePackReceipt"]
|