feat(learning-harness): publish every number from the artifacts that produced it

Task 3.8. A number in a roadmap that nobody can regenerate is a claim, not a
measurement. One entry point now writes them all from the committed artifacts
and puts the denominator beside each: how many pairs could be scored, why the
rest could not, which taxonomy version scored them, the noise the family shows
against itself, and what the run cost per pair it got right. Every table says
whether hierarchical partial credit could apply, which today it cannot.

The roadmap section is replaced in place between markers rather than appended,
so the file cannot accumulate a stale number beside a fresh one, and running the
command twice without new artifacts changes nothing. With no baseline recorded
it says so instead of printing an empty table.

The corrected mechanism-lever number travels with the rest: detected five of
seventeen at a negative Youden once only train-split pairs teach, against seven
when every pair taught, with the difference named as what holdout pairs stopped
teaching. Round zero now records what it spent so the cost column has a source.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
Marius Ciepluch
2026-09-06 11:59:13 +02:00
co-authored by Claude Opus 5
parent b9552518b9
commit b8ad42c57e
4 changed files with 363 additions and 0 deletions
+184
View File
@@ -0,0 +1,184 @@
"""Every published number, regenerated from the artifacts that produced it (learning-harness, Req 11.1, 11.2, 4.5, 5.3).
A number in a roadmap that nobody can regenerate is a claim, not a measurement. This writes them all
from one entry point, out of the artifacts committed beside them, and puts the denominator next to each:
how many pairs could be scored, why the rest could not, which taxonomy version scored them, the noise
the family shows against itself, and what the run cost per pair it got right.
Running it twice without new artifacts changes nothing, and the roadmap section is replaced in place
rather than appended, so the file cannot accumulate stale numbers beside fresh ones.
"""
from __future__ import annotations
import json
from collections.abc import Mapping
from dataclasses import dataclass, field
from datetime import UTC, datetime
from pathlib import Path
BEGIN = "<!-- learning-harness:begin -->"
END = "<!-- learning-harness:end -->"
COMMAND = "uv run ousast learning publish"
@dataclass(frozen=True)
class Baseline:
"""One model's round-zero artifact, read back."""
model: str
metrics: dict[str, Mapping[str, object]]
floors: dict[str, Mapping[str, object]]
cost_usd: float
k_runs: int
@dataclass(frozen=True)
class PublishReport:
command: str
table: str
families: tuple[str, ...] = ()
models: tuple[str, ...] = ()
artifacts: tuple[Path, ...] = field(default_factory=tuple)
def publish(*, learning_dir: Path, measurements_dir: Path, roadmap: Path, date: str | None = None) -> PublishReport:
"""Regenerate the family numbers, write the artifact, and replace the roadmap section in place."""
stamp = date or datetime.now(UTC).strftime("%Y-%m-%d")
models = _baselines(learning_dir)
families = tuple(sorted({family for baseline in models.values() for family in baseline.metrics}))
lever = _lever(measurements_dir)
table = _table(models, families, lever)
artifacts: list[Path] = []
if models:
measurements_dir.mkdir(parents=True, exist_ok=True)
artifact = measurements_dir / f"{stamp}-learning-families.json"
artifact.write_text(
json.dumps(
{
"generated": stamp,
"command": COMMAND,
"models": {name: dict(baseline.metrics) for name, baseline in sorted(models.items())},
"floors": {name: dict(baseline.floors) for name, baseline in sorted(models.items())},
},
indent=2,
sort_keys=True,
)
+ "\n",
encoding="utf-8",
)
artifacts.append(artifact)
_replace_section(roadmap, table)
return PublishReport(command=COMMAND, table=table, families=families, models=tuple(sorted(models)), artifacts=tuple(artifacts))
def _baselines(learning_dir: Path) -> dict[str, Baseline]:
root = learning_dir / "baseline"
found: dict[str, Baseline] = {}
for directory in sorted(path for path in root.iterdir() if path.is_dir()) if root.is_dir() else []:
report = directory / "report.json"
if not report.is_file():
continue
payload = json.loads(report.read_text(encoding="utf-8"))
model = str(payload.get("model", directory.name))
found[model] = Baseline(
model=model,
metrics={str(name): block for name, block in (payload.get("metrics") or {}).items() if isinstance(block, Mapping)},
floors={str(name): block for name, block in (payload.get("floors") or {}).items() if isinstance(block, Mapping)},
cost_usd=float(payload.get("cost_usd", 0.0) or 0.0),
k_runs=int(payload.get("k_runs", 0) or 0),
)
return found
def _lever(measurements_dir: Path) -> Mapping[str, object] | None:
path = measurements_dir / "2026-09-06-mechanism-lever-split.json"
if not path.is_file():
return None
payload = json.loads(path.read_text(encoding="utf-8"))
return payload if isinstance(payload, dict) else None
def _table(models: Mapping[str, Baseline], families: tuple[str, ...], lever: Mapping[str, object] | None) -> str:
if not models:
return (
f"Generated by `{COMMAND}`.\n\nNo baseline has been recorded yet, so there is nothing to publish. "
"Run round zero first; a number without the run that produced it is a claim, not a measurement.\n"
)
lines = [
f"Generated by `{COMMAND}` from the artifacts committed beside these numbers.",
"",
"| model | family | scorable | unscorable | recall | silence | Youden | at fixed FPR | noise floor | cost per correct pair |",
"|---|---|---|---|---|---|---|---|---|---|",
]
for model, baseline in sorted(models.items()):
for family in families:
row = baseline.metrics.get(family)
if row is None:
continue
outcomes = row.get("outcomes")
raw_correct = outcomes.get("pair_correct") if isinstance(outcomes, Mapping) else None
correct = int(raw_correct) if isinstance(raw_correct, int | float) else 0
floor = baseline.floors.get(family)
raw_budget = floor.get("budget_flips") if floor is not None else None
budget = int(raw_budget) if isinstance(raw_budget, int | float) else 0
cost = baseline.cost_usd
lines.append(
f"| {model} | {family} | {row.get('scorable', 0)} (taxonomy {row.get('taxonomy_version', '')}) "
f"| {_reasons(row)} | {_num(row.get('recall'))} | {_num(row.get('silence'))} | {_num(row.get('youden'))} "
f"| {_num(row.get('fixed_fpr_recall'))} | budget {budget} | {_cost(cost, correct)} |"
)
lines += ["", _credit_note(models), ""]
if lever is not None:
lines += [_lever_note(lever), ""]
return "\n".join(lines)
def _credit_note(models: Mapping[str, Baseline]) -> str:
hierarchical = any(bool(row.get("hierarchical_credit")) for baseline in models.values() for row in baseline.metrics.values())
if hierarchical:
return "A parent-child answer earned partial credit in these figures."
return "No family in this taxonomy declares a parent, so hierarchical partial credit could not apply to any figure above."
def _lever_note(lever: Mapping[str, object]) -> str:
before = lever.get("before")
after = lever.get("after")
before_map = before if isinstance(before, Mapping) else {}
after_map = after if isinstance(after, Mapping) else {}
pairs = lever.get("holdout_pairs", 0)
return (
f"Mechanism lever on the {lever.get('slice', '')} holdout: detected {after_map.get('detected')} of {pairs} at Youden "
f"{after_map.get('youden')} once only train-split pairs teach, against detected {before_map.get('detected')} at Youden "
f"{before_map.get('youden')} when every pair taught. The difference is what holdout pairs stopped teaching."
)
def _reasons(row: Mapping[str, object]) -> str:
reasons = row.get("unscorable") or {}
if not isinstance(reasons, Mapping) or not reasons:
return "none"
return ", ".join(f"{name}: {count}" for name, count in sorted(reasons.items()))
def _num(value: object) -> str:
return f"{float(value):.3f}" if isinstance(value, int | float) else "-"
def _cost(cost: float, correct: int) -> str:
return f"{cost / correct:.2f}" if cost and correct else "-"
def _replace_section(roadmap: Path, table: str) -> None:
body = f"{BEGIN}\n\n## Classified detector numbers\n\n{table.rstrip()}\n\n{END}\n"
text = roadmap.read_text(encoding="utf-8") if roadmap.is_file() else ""
if BEGIN in text and END in text:
head, _, rest = text.partition(BEGIN)
_, _, tail = rest.partition(END)
roadmap.write_text(head + body + tail.lstrip("\n"), encoding="utf-8")
return
roadmap.parent.mkdir(parents=True, exist_ok=True)
roadmap.write_text((text.rstrip("\n") + "\n\n" if text else "") + body, encoding="utf-8")
__all__ = ["BEGIN", "COMMAND", "END", "Baseline", "PublishReport", "publish"]
+4
View File
@@ -69,6 +69,7 @@ class BaselineReport:
floors: dict[str, NoiseFloor] = field(default_factory=dict)
metrics: dict[str, dict[str, object]] = field(default_factory=dict)
scores: tuple[PairFamilyScore, ...] = ()
cost_usd: float = 0.0
def to_dict(self) -> dict[str, object]:
return {
@@ -76,6 +77,7 @@ class BaselineReport:
"k_runs": self.k_runs,
"taxonomy_version": self.taxonomy_version,
"slices": list(self.slices),
"cost_usd": self.cost_usd,
"floors": {name: floor.to_dict() for name, floor in sorted(self.floors.items())},
"metrics": {name: dict(block) for name, block in sorted(self.metrics.items())},
}
@@ -92,6 +94,7 @@ def run_baseline(
slices: Sequence[str] = DEFAULT_SLICES,
k_runs: int = DEFAULT_K_RUNS,
prompt: str | None = None,
spent_usd: Callable[[], float] | None = None,
) -> BaselineReport:
"""Clone one detector into every family, measure each family against itself, and write the artifacts."""
from ..tool_hunter import _SYSTEM_PROMPT
@@ -110,6 +113,7 @@ def run_baseline(
floors=floors,
metrics={name: block.to_dict() for name, block in metrics.items()},
scores=tuple(scores),
cost_usd=spent_usd() if spent_usd is not None else 0.0,
)
_write(out_dir, report)
return report
+158
View File
@@ -0,0 +1,158 @@
"""learning-harness task 3.8: publishing every number from its committed artifacts (offline)."""
from __future__ import annotations
import json
from pathlib import Path
ROADMAP = "# Roadmap\n\n## Overview\n\nSomething about the project.\n\n## Constraints\n\nCore dependencies stay empty.\n"
def _baseline(out: Path, model: str, *, recall: float = 1.0, cost: float = 0.5) -> None:
directory = out / "baseline" / model
directory.mkdir(parents=True, exist_ok=True)
(directory / "report.json").write_text(
json.dumps(
{
"model": model,
"k_runs": 5,
"taxonomy_version": "1",
"slices": ["vibe-py"],
"cost_usd": cost,
"floors": {"injection": {"family": "injection", "budget_flips": 1, "negative_flip_rate": 0.1, "k_runs": 5, "gates": True}},
"metrics": {
"injection": {
"family": "injection",
"taxonomy_version": "1",
"scorable": 10,
"unscorable": {"identical_twin": 2},
"outcomes": {"pair_correct": round(recall * 10)}, # keep the fixture internally consistent
"recall": recall,
"silence": 1.0,
"youden": recall,
"directional_bias": 0.0,
"leak_rate": 0.0,
"fixed_fpr_recall": recall,
"hierarchical_credit": False,
}
},
},
indent=2,
sort_keys=True,
)
+ "\n"
)
def test_publishing_twice_without_new_artifacts_is_byte_identical(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash")
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
measurements = tmp_path / "measurements"
first = publish(learning_dir=out, measurements_dir=measurements, roadmap=roadmap)
text = roadmap.read_text()
second = publish(learning_dir=out, measurements_dir=measurements, roadmap=roadmap)
assert roadmap.read_text() == text
assert first.table == second.table and first.families == second.families
def test_every_number_carries_its_denominator_floor_and_cost(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash", recall=0.9, cost=1.8)
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
report = publish(learning_dir=out, measurements_dir=tmp_path / "m", roadmap=roadmap)
table = report.table
assert "| injection |" in table
assert "10" in table and "identical_twin: 2" in table # scorable and why the rest are not
assert "taxonomy 1" in table and "budget 1" in table
assert "0.20" in table # cost per pair-correct: 1.8 over 9
assert "hierarchical partial credit could not apply" in table
assert report.command and report.command in roadmap.read_text()
def test_a_second_model_appears_beside_the_first(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash", recall=0.9)
_baseline(out, "deepseek-v4-pro", recall=1.0)
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
report = publish(learning_dir=out, measurements_dir=tmp_path / "m", roadmap=roadmap)
assert "deepseek-v4-flash" in report.table and "deepseek-v4-pro" in report.table
assert set(report.families) == {"injection"}
def test_the_corrected_lever_number_replaces_the_earlier_one(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash")
measurements = tmp_path / "m"
measurements.mkdir()
(measurements / "2026-09-06-mechanism-lever-split.json").write_text(
json.dumps(
{
"slice": "vibe-py",
"holdout_pairs": 17,
"before": {"detected": 7, "youden": 0.0588},
"after": {"detected": 5, "youden": -0.0588},
}
)
)
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP + "\nThe lever recovered 7 of 17 holdout pairs at Youden +0.059.\n")
report = publish(learning_dir=out, measurements_dir=measurements, roadmap=roadmap)
text = roadmap.read_text()
assert "-0.0588" in report.table or "-0.059" in report.table
assert "5 of 17" in report.table or "detected 5" in report.table
assert "holdout pairs stopped teaching" in report.table.lower() or "train split only" in report.table.lower()
assert text.count("learning-harness:begin") == 1
def test_the_roadmap_section_is_replaced_not_appended_again(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash", recall=0.5)
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
publish(learning_dir=out, measurements_dir=tmp_path / "m", roadmap=roadmap)
_baseline(out, "deepseek-v4-flash", recall=0.9)
publish(learning_dir=out, measurements_dir=tmp_path / "m", roadmap=roadmap)
text = roadmap.read_text()
assert text.count("learning-harness:begin") == 1 and text.count("learning-harness:end") == 1
assert "## Overview" in text and "## Constraints" in text # nothing else in the roadmap is disturbed
assert "0.5" not in text.split("learning-harness:begin")[1] # the stale number is gone
def test_the_raw_artifacts_are_written_where_the_numbers_are_read_from(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
out = tmp_path / "learning"
_baseline(out, "deepseek-v4-flash")
measurements = tmp_path / "m"
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
publish(learning_dir=out, measurements_dir=measurements, roadmap=roadmap)
written = sorted(path.name for path in measurements.iterdir())
assert any(name.endswith("-learning-families.json") for name in written)
payload = json.loads((measurements / next(name for name in written if name.endswith("-learning-families.json"))).read_text())
assert payload["models"]["deepseek-v4-flash"]["injection"]["scorable"] == 10
assert payload["command"]
def test_publishing_with_no_baseline_says_so_rather_than_inventing_a_table(tmp_path: Path) -> None:
from openultrasast.learning.publish import publish
roadmap = tmp_path / "roadmap.md"
roadmap.write_text(ROADMAP)
report = publish(learning_dir=tmp_path / "empty", measurements_dir=tmp_path / "m", roadmap=roadmap)
assert report.families == () and "no baseline" in report.table.lower()
assert "learning-harness:begin" in roadmap.read_text()
+17
View File
@@ -188,3 +188,20 @@ def test_an_unscorable_pair_is_listed_and_never_run(tmp_path: Path) -> None:
assert report.metrics["injection"]["scorable"] == 0
assert report.metrics["injection"]["unscorable"] == {"identical_twin": 1}
assert calls == []
def test_round_zero_records_what_it_spent(tmp_path: Path) -> None:
"""Publishing puts a cost beside every number, so the baseline has to know what it cost."""
from openultrasast.learning.rounds import run_baseline
report = run_baseline(
[_case(tmp_path, "a")],
taxonomy=load_families(),
configs_dir=tmp_path / "configs",
scan=_steady,
model="m",
out_dir=tmp_path / "out",
spent_usd=lambda: 1.25,
)
assert report.cost_usd == 1.25
assert json.loads((tmp_path / "out" / "baseline" / "m" / "report.json").read_text())["cost_usd"] == 1.25