Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/milestones.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ it passes through, and how the freeze is performed all belong to
[process-version.md](process-version.md#freezing-the-cutover-procedure);
**record the resulting commit here when it happens.**

- Freeze commit: _not yet frozen — the shakedown is ongoing._
- Freeze commit: `8bf09ed2bd1ee42e4475cc616536ebab6b1d5a4b` — the six proc-v1
digests (three predictors, three evaluators) blessed into
`FROZEN_PROCESS_DIGESTS`. The freeze takes effect on `main` at the promotion
that carries this commit.

## The near-term target: the OT2026 long-conference cert release

Expand Down
24 changes: 18 additions & 6 deletions src/fedcourtsai/process_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,24 @@
# named process change; the digest moves on *any* input change regardless.
CURRENT_PROCESS_LABEL = "proc-v1"

# The blessed process digests — the frozen-headline set. EMPTY during the
# shakedown: the freeze is a future one-line commit that pastes the digest(s)
# from `fedcourts process-digest --all` in here. Keyed on the digest, never the
# label, so a process that drifted under an unchanged label is not silently
# blessed.
FROZEN_PROCESS_DIGESTS: frozenset[str] = frozenset()
# The blessed process digests — the frozen-headline set: the six proc-v1
# processes (three predictors, three evaluators) read off
# `fedcourts process-digest --all` at the freeze. Keyed on the digest, never
# the label, so a process that drifts under an unchanged label is not silently
# blessed; a material change bumps CURRENT_PROCESS_LABEL and earns a fresh
# blessing here.
FROZEN_PROCESS_DIGESTS: frozenset[str] = frozenset(
{
# predictors: claude-baseline, codex-baseline, gemini-baseline
"sha256:460abab2fe175059ca588fd1f72cefb15fb3beaab2e2ec4732f8c42c7c6c66a7",
"sha256:940cd32d118bb174faed45cbcc2e8eeb18161b2c24c4c81fac85a56c686f205e",
"sha256:526b83dcd18ee0d1a4ee026f4f5f20ee115bdf546a1360a58828481951442494",
# evaluators: claude-judge, codex-judge, gemini-judge
"sha256:42a33a2d79f7ebccf79e6a00ae233b241314e863f60616562fc46063f98a3427",
"sha256:0cee3de6951543bb302104aa44260a5f066d23523951e9610b8b0efc43f84d95",
"sha256:3c0d725159f8dc4c4a58c384da9497bb44f1948e9d043b55b5e2e1345e82dc2a",
}
)

# The retrieval surface each engine's cells run with. Folded into the digest
# because it is a process input as much as the model or the prompt: a cell that
Expand Down
21 changes: 17 additions & 4 deletions tests/test_process_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from fedcourtsai import process_version
from fedcourtsai.process_version import _config_canonical
from fedcourtsai.registry import load_predictors
from fedcourtsai.registry import enabled_evaluators, enabled_predictors, load_predictors
from fedcourtsai.schemas import ProcessVersion

CONFIG = Path("config")
Expand Down Expand Up @@ -129,7 +129,20 @@ def test_is_frozen_gates_on_the_digest_not_the_label(monkeypatch) -> None: # ty
assert not process_version.is_frozen(None)


def test_the_frozen_set_is_empty_until_the_freeze_commit() -> None:
"""The shakedown state: nothing is blessed yet, so nothing is frozen."""
assert frozenset() == process_version.FROZEN_PROCESS_DIGESTS
def test_the_frozen_set_blesses_exactly_the_registry_digests() -> None:
"""The frozen set holds one digest per registered process — the six
proc-v1 processes blessed at the freeze — and every entry actually
resolves against the current registry, so a prompt or config drift after
the freeze shows up here as a digest that no longer matches."""
assert len(process_version.FROZEN_PROCESS_DIGESTS) == 6
assert all(d.startswith("sha256:") for d in process_version.FROZEN_PROCESS_DIGESTS)
repo_root = Path(__file__).resolve().parent.parent
config_root = repo_root / "config"
rows = [("predictor", p.id) for p in enabled_predictors(config_root / "predictors.yaml")]
rows += [("evaluator", e.id) for e in enabled_evaluators(config_root / "evaluators.yaml")]
current = {
process_version.digest_for_actor(repo_root, config_root, role, actor_id)
for role, actor_id in rows
}
assert current == set(process_version.FROZEN_PROCESS_DIGESTS)
assert not process_version.is_frozen(_pv("sha256:anything"))