| 1 | """Interleaved, A/A-controlled execution of the scale op catalog on one tier.
|
| 2 |
|
| 3 | Schedule: for each run, for each unit (an op or a short dependent op
|
| 4 | sequence, see ops.UNIT_ORDER), subjects execute in a freshly shuffled
|
| 5 | (seeded) order, so every subject sees the same drift and host noise. A/A
|
| 6 | control subjects (``git_aa``, ``oak_installed_aa``: the same binary under a
|
| 7 | second name) share their kind's workspace and are interleaved exactly like
|
| 8 | the real arms; every cell gets its own A/A floor (oakbench.cellstats).
|
| 9 |
|
| 10 | Measurement is serialized with the cross-process measurement lock around
|
| 11 | the whole timed schedule (preparation runs outside it).
|
| 12 |
|
| 13 | Every row is development evidence: ``evidence_class`` says so and
|
| 14 | ``claim_eligible`` is false. The calibrated campaign re-runs the same
|
| 15 | machinery on a quiet host.
|
| 16 | """
|
| 17 |
|
| 18 | from __future__ import annotations
|
| 19 |
|
| 20 | import json
|
| 21 | import platform
|
| 22 | import random
|
| 23 | import statistics
|
| 24 | import sys
|
| 25 | import time
|
| 26 | from pathlib import Path
|
| 27 | from typing import Any, Dict, List, Optional, Sequence, Tuple
|
| 28 |
|
| 29 | from . import ops as ops_mod
|
| 30 | from .workspace import TRANSPORT_GIT, TRANSPORT_OAK, Prepared
|
| 31 |
|
| 32 | _scripts = str(Path(__file__).resolve().parents[3] / "scripts")
|
| 33 | if _scripts not in sys.path:
|
| 34 | sys.path.insert(0, _scripts)
|
| 35 | from oakbench import scale_calibration # noqa: E402
|
| 36 |
|
| 37 | SCALE_ROW_VERSION = "scale-2026-09-28.1"
|
| 38 | EVIDENCE_CLASS = "development_only_loaded_host"
|
| 39 | AA_PAIRS = {"git": ("git", "git_aa"), "oak": ("oak_installed", "oak_installed_aa")}
|
| 40 | NETWORK_OPS = frozenset({"push.branch", "pull.ff", "pull.diverged", "clone.full"})
|
| 41 |
|
| 42 |
|
| 43 | def _say(message: str) -> None:
|
| 44 | print(message, file=sys.stderr, flush=True)
|
| 45 |
|
| 46 |
|
| 47 | def _subject_meta(subject: Any, details: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
|
| 48 | item = details.get(subject.name, {})
|
| 49 | return {"subject_bin": item.get("bin"), "subject_version": item.get("version"),
|
| 50 | "binary_sha256": item.get("binary_sha256"), "subject_role": item.get("role"),
|
| 51 | "git_shim_measured": item.get("git_shim_measured"), "git_config_profile": item.get("git_config_profile")}
|
| 52 |
|
| 53 |
|
| 54 | def build_row(*, bench_id: str, prepared: Prepared, subject: Any, op: str, run: int, outcome: ops_mod.Outcome,
|
| 55 | details: Dict[str, Dict[str, Any]], env_sample: Dict[str, Any], lock_wait_ms: Optional[float],
|
| 56 | order_position: int, runner_fields: Dict[str, Any],
|
| 57 | calibration: Optional[Tuple[Dict[str, Any], Dict[str, Any], List[str]]] = None
|
| 58 | ) -> Dict[str, Any]:
|
| 59 | info = ops_mod.OP_INFO[op]
|
| 60 | captures = [item.capture for item in outcome.timed]
|
| 61 |
|
| 62 | def total(attr: str) -> Optional[float]:
|
| 63 | values = [getattr(c, attr) for c in captures]
|
| 64 | if not values or any(v is None for v in values):
|
| 65 | return None
|
| 66 | return round(sum(values), 3)
|
| 67 |
|
| 68 | row: Dict[str, Any] = {
|
| 69 | "bench_id": bench_id,
|
| 70 | "profile": "scale",
|
| 71 | "scale_row_version": SCALE_ROW_VERSION,
|
| 72 | "scenario": prepared.tier.tier_id,
|
| 73 | "operation": op,
|
| 74 | "run": run,
|
| 75 | "subject": subject.name,
|
| 76 | "subject_kind": subject.kind,
|
| 77 | "command": [item.command for item in outcome.timed],
|
| 78 | "component_elapsed_ms": {item.label: round(item.capture.elapsed_ms, 3) for item in outcome.timed},
|
| 79 | "elapsed_ms": round(sum(c.elapsed_ms for c in captures), 3) if captures else None,
|
| 80 | "cpu_user_ms": total("cpu_user_ms"),
|
| 81 | "cpu_sys_ms": total("cpu_sys_ms"),
|
| 82 | "io_read_blocks": total("io_read_blocks"),
|
| 83 | "io_write_blocks": total("io_write_blocks"),
|
| 84 | "peak_rss_bytes": max((c.peak_rss_bytes or 0 for c in captures), default=None) if captures else None,
|
| 85 | "stdout_bytes": sum(c.stdout_bytes for c in captures) if captures else None,
|
| 86 | "timed_out": any(c.timed_out for c in captures),
|
| 87 | "measurement_source": "direct_cli_timed_subprocess",
|
| 88 | "rusage_source": "os_wait4_child_rusage",
|
| 89 | "page_cache_state": "warm",
|
| 90 | "cache_mode_requested": "warm",
|
| 91 | "tperf_refs": list(info.tperf),
|
| 92 | "core_yaml_ops": list(info.core_yaml),
|
| 93 | "oracle_ok": outcome.oracle_ok,
|
| 94 | "oracle_method": outcome.oracle_method,
|
| 95 | "oracle_reader": outcome.oracle_reader,
|
| 96 | "oracle_timed": False,
|
| 97 | "oracle_detail": outcome.oracle_detail,
|
| 98 | "semantic_class": outcome.semantic_class,
|
| 99 | "transport": (TRANSPORT_GIT if subject.kind == "git" else TRANSPORT_OAK) if op in NETWORK_OPS else None,
|
| 100 | "order_position": order_position,
|
| 101 | "environment_sample": env_sample,
|
| 102 | "measurement_lock_wait_ms": lock_wait_ms,
|
| 103 | **_subject_meta(subject, details),
|
| 104 | **prepared.fixture_fields(),
|
| 105 | **runner_fields,
|
| 106 | **outcome.extra,
|
| 107 | }
|
| 108 | if outcome.skip_reason is not None:
|
| 109 | # Skip rows follow the core lane: elapsed 0.0 with skipped: true (never a measurement).
|
| 110 | row.update(returncode=77, skipped=True, skip_reason=outcome.skip_reason, elapsed_ms=0.0)
|
| 111 | row.pop("measurement_source", None)
|
| 112 | elif outcome.failed is not None:
|
| 113 | process_rc = captures[-1].returncode if captures and captures[-1].returncode != 0 else None
|
| 114 | row.update(returncode=1, process_returncode=process_rc, failure=outcome.failed,
|
| 115 | elapsed_ms=row["elapsed_ms"] if row["elapsed_ms"] is not None else 0.0)
|
| 116 | elif outcome.oracle_ok is False:
|
| 117 | row.update(returncode=1, process_returncode=captures[-1].returncode if captures else None,
|
| 118 | failure="oracle_failed")
|
| 119 | else:
|
| 120 | row.update(returncode=0)
|
| 121 | # evidence_class / claim_eligible are derived from a validated quiet-host
|
| 122 | # calibration record, never set freely (oakbench.scale_calibration).
|
| 123 | record, facts, reasons = calibration if calibration else (None, None, [])
|
| 124 | return scale_calibration.stamp(row, record, facts, reasons)
|
| 125 |
|
| 126 |
|
| 127 | def abort_row(base: Dict[str, Any], op: str, after: str) -> Dict[str, Any]:
|
| 128 | row = dict(base)
|
| 129 | info = ops_mod.OP_INFO[op]
|
| 130 | for key in ("oracle_ok", "oracle_method", "oracle_reader", "semantic_class", "failure", "process_returncode",
|
| 131 | "component_elapsed_ms", "cpu_user_ms", "cpu_sys_ms", "io_read_blocks", "io_write_blocks",
|
| 132 | "peak_rss_bytes", "stdout_bytes", "dirty_applied", "harness_error"):
|
| 133 | row.pop(key, None)
|
| 134 | row.pop("measurement_source", None)
|
| 135 | for key in ("calibration_record", "calibration_record_sha256"):
|
| 136 | row.pop(key, None)
|
| 137 | row.update(evidence_class=EVIDENCE_CLASS, claim_eligible=False, claim_ineligible_reasons=["skip row"])
|
| 138 | row.update(operation=op, command=[], elapsed_ms=0.0, returncode=77, skipped=True, oracle_detail={},
|
| 139 | skip_reason=f"aborted_after_failed_prerequisite:{after}", tperf_refs=list(info.tperf),
|
| 140 | core_yaml_ops=list(info.core_yaml))
|
| 141 | return row
|
| 142 |
|
| 143 |
|
| 144 | def run_schedule(prepared: Prepared, subjects: Sequence[Any], *, runs: int, ops: Sequence[str], bench_id: str,
|
| 145 | seed: int, scratch: Path, details: Dict[str, Dict[str, Any]], runner_fields: Dict[str, Any],
|
| 146 | timeout_s: float, lock_wait_ms: Optional[float], log=None,
|
| 147 | calibration: Optional[Tuple[Dict[str, Any], Dict[str, Any], List[str]]] = None
|
| 148 | ) -> List[Dict[str, Any]]:
|
| 149 | scripts = str(Path(__file__).resolve().parents[3] / "scripts")
|
| 150 | if scripts not in sys.path:
|
| 151 | sys.path.insert(0, scripts)
|
| 152 | from oakbench.envwatch import sample_environment
|
| 153 | from oakbench.execution import run_timed
|
| 154 |
|
| 155 | scratch.mkdir(parents=True, exist_ok=True)
|
| 156 | rng = random.Random(seed)
|
| 157 | wanted = set(ops)
|
| 158 | units = [tuple(op for op in unit if op in wanted) for unit in ops_mod.UNIT_ORDER]
|
| 159 | units = [unit for unit in units if unit]
|
| 160 | rows: List[Dict[str, Any]] = []
|
| 161 | skip_by_tier = set(prepared.tier.skip_ops)
|
| 162 | for run in range(1, runs + 1):
|
| 163 | started = time.perf_counter()
|
| 164 | for unit in units:
|
| 165 | order = list(subjects)
|
| 166 | rng.shuffle(order)
|
| 167 | env_sample = sample_environment()
|
| 168 | for position, subject in enumerate(order):
|
| 169 | failed_at: Optional[str] = None
|
| 170 | for op in unit:
|
| 171 | ctx = ops_mod.Ctx(prepared, subject, run, run_timed, scratch, timeout_s)
|
| 172 | if failed_at is not None:
|
| 173 | base = build_row(bench_id=bench_id, prepared=prepared, subject=subject, op=op, run=run,
|
| 174 | outcome=ops_mod.Outcome(), details=details, env_sample=env_sample,
|
| 175 | lock_wait_ms=lock_wait_ms, order_position=position,
|
| 176 | runner_fields=runner_fields)
|
| 177 | rows.append(abort_row(base, op, failed_at))
|
| 178 | continue
|
| 179 | if op in skip_by_tier:
|
| 180 | outcome = ops_mod.Outcome(skip_reason=f"tier_excludes_op_per_run_cost:{prepared.tier.tier_id}")
|
| 181 | elif subject.kind not in prepared.kinds:
|
| 182 | outcome = ops_mod.Outcome(skip_reason=f"kind_not_prepared:{subject.kind}")
|
| 183 | else:
|
| 184 | outcome = ops_mod.execute(ctx, op)
|
| 185 | row = build_row(bench_id=bench_id, prepared=prepared, subject=subject, op=op, run=run,
|
| 186 | outcome=outcome, details=details, env_sample=env_sample,
|
| 187 | lock_wait_ms=lock_wait_ms, order_position=position,
|
| 188 | runner_fields=runner_fields, calibration=calibration)
|
| 189 | rows.append(row)
|
| 190 | if row["returncode"] == 1:
|
| 191 | if len(unit) > 1:
|
| 192 | failed_at = op
|
| 193 | # Untimed repair so one failure cannot poison later units.
|
| 194 | problem = ops_mod.recover(ctx)
|
| 195 | if problem:
|
| 196 | row["recover_error"] = problem
|
| 197 | (log or _say)(f"[scale] {prepared.tier.tier_id}: run {run}/{runs} done in {time.perf_counter() - started:.1f}s")
|
| 198 | return rows
|
| 199 |
|
| 200 |
|
| 201 | # ---------------------------------------------------------------------------
|
| 202 | # Statistics: per-cell A/A floors, dev-only oak/git ratio, MDE per cell
|
| 203 | # ---------------------------------------------------------------------------
|
| 204 |
|
| 205 |
|
| 206 | COMPARABLE = "comparable"
|
| 207 |
|
| 208 |
|
| 209 | def cell_comparability(rows: List[Dict[str, Any]], key: Tuple[str, str]) -> str:
|
| 210 | """Whether Oak and Git measured the same thing in a cell.
|
| 211 |
|
| 212 | An Oak server seeded with a one-commit snapshot (push admission caps)
|
| 213 | serves a different repository than Git's full-history server, so
|
| 214 | push/pull/clone Oak-vs-Git deltas are meaningless there; only the Oak A/A
|
| 215 | (oak-vs-oak) evidence stays valid.
|
| 216 | """
|
| 217 | seeds = {r.get("oak_server_seed") for r in rows if (r.get("scenario"), r.get("operation")) == key
|
| 218 | and r.get("subject_kind") == "oak" and r.get("returncode") != 77}
|
| 219 | seeds.discard(None)
|
| 220 | seeds.discard("full_history")
|
| 221 | if seeds:
|
| 222 | return "not_comparable:oak_server_seed_" + ",".join(sorted(seeds))
|
| 223 | return COMPARABLE
|
| 224 |
|
| 225 |
|
| 226 | def cell_report(rows: List[Dict[str, Any]], subjects: Sequence[str]) -> List[Dict[str, Any]]:
|
| 227 | from oakbench import cellstats
|
| 228 |
|
| 229 | measured = [r for r in rows if r.get("returncode") == 0 and isinstance(r.get("elapsed_ms"), (int, float))]
|
| 230 | floors: Dict[str, Dict[Tuple[str, str], float]] = {}
|
| 231 | for kind, (arm, control) in AA_PAIRS.items():
|
| 232 | if arm in subjects and control in subjects:
|
| 233 | floors[kind] = cellstats.cell_floors(measured, arm, control, lambda r: r.get("elapsed_ms"))
|
| 234 | comparability = {key: cell_comparability(rows, key) for key in {(r["scenario"], r["operation"]) for r in rows}}
|
| 235 | cross: Dict[Tuple[str, str], Dict[str, Any]] = {}
|
| 236 | if "git" in subjects and "oak_installed" in subjects:
|
| 237 | keys = set(floors.get("git", {})) | set(floors.get("oak", {}))
|
| 238 | combined = {key: max(floors.get("git", {}).get(key, 0.0), floors.get("oak", {}).get(key, 0.0))
|
| 239 | for key in keys}
|
| 240 | # Only comparable cells enter the Oak-vs-Git family (and its BH).
|
| 241 | comparable = [key for key, label in comparability.items() if label == COMPARABLE]
|
| 242 | cross = cellstats.classify_cells(measured, "oak_installed", "git", combined, cells=comparable)
|
| 243 | # Oak-vs-Oak resolution: what an oak changeset comparison can detect here.
|
| 244 | self_mde: Dict[Tuple[str, str], Optional[float]] = {}
|
| 245 | if "oak" in floors:
|
| 246 | aa = cellstats.classify_cells(measured, "oak_installed_aa", "oak_installed", floors["oak"])
|
| 247 | self_mde = {key: item.get("mde_pct") for key, item in aa.items()}
|
| 248 | cells = sorted({(r["scenario"], r["operation"]) for r in rows})
|
| 249 | report = []
|
| 250 | for key in cells:
|
| 251 | per_subject: Dict[str, Any] = {}
|
| 252 | for name in subjects:
|
| 253 | values = [r["elapsed_ms"] for r in measured if r["subject"] == name and (r["scenario"], r["operation"]) == key]
|
| 254 | fails = [r for r in rows if r["subject"] == name and (r["scenario"], r["operation"]) == key
|
| 255 | and r.get("returncode") == 1]
|
| 256 | skips = [r for r in rows if r["subject"] == name and (r["scenario"], r["operation"]) == key
|
| 257 | and r.get("returncode") == 77]
|
| 258 | per_subject[name] = {
|
| 259 | "n": len(values), "median_ms": round(statistics.median(values), 3) if values else None,
|
| 260 | "failures": len(fails), "skips": len(skips),
|
| 261 | "skip_reason": skips[0].get("skip_reason") if skips else None,
|
| 262 | "failure": (fails[0].get("failure") or "")[:200] if fails else None,
|
| 263 | "teardown_errors": sum(1 for r in rows if r["subject"] == name
|
| 264 | and (r["scenario"], r["operation"]) == key and r.get("teardown_error")),
|
| 265 | }
|
| 266 | item = cross.get(key, {})
|
| 267 | cell_rows = [r for r in rows if (r["scenario"], r["operation"]) == key and r.get("returncode") == 0]
|
| 268 | report.append({
|
| 269 | "scenario": key[0], "operation": key[1], "subjects": per_subject,
|
| 270 | "oak_vs_git_comparability": comparability[key],
|
| 271 | "git_aa_floor_pct": floors.get("git", {}).get(key), "oak_aa_floor_pct": floors.get("oak", {}).get(key),
|
| 272 | "oak_vs_git_delta_pct_dev_only": item.get("delta_pct"),
|
| 273 | "oak_vs_git_ci_pct_dev_only": [item.get("ci_low_pct"), item.get("ci_high_pct")] if item else None,
|
| 274 | "oak_vs_git_mde_pct_80": item.get("mde_pct"),
|
| 275 | "oak_vs_oak_mde_pct_80": self_mde.get(key),
|
| 276 | "verdict_suppressed": item.get("verdict"),
|
| 277 | "claim_eligible": bool(cell_rows) and all(r.get("claim_eligible") is True for r in cell_rows),
|
| 278 | })
|
| 279 | return report
|
| 280 |
|
| 281 |
|
| 282 | def _fmt(value: Any, suffix: str = "") -> str:
|
| 283 | if value is None:
|
| 284 | return "-"
|
| 285 | if isinstance(value, float):
|
| 286 | return f"{value:.1f}{suffix}"
|
| 287 | return f"{value}{suffix}"
|
| 288 |
|
| 289 |
|
| 290 | def summary_markdown(prepared: Prepared, report: List[Dict[str, Any]], meta: Dict[str, Any]) -> str:
|
| 291 | lines = [
|
| 292 | f"# Scale lane: {prepared.tier.tier_id} "
|
| 293 | f"({'calibrated quiet host' if meta.get('calibrated') else 'DEVELOPMENT ONLY - not a claim'})",
|
| 294 | "",
|
| 295 | f"- bench_id `{meta['bench_id']}`; runs {meta['runs']}; subjects {', '.join(meta['subjects'])}",
|
| 296 | f"- fixture `{prepared.tier.fixture_id}` refs_sha256 `{prepared.manifest['refs_sha256'][:16]}` "
|
| 297 | f"spec_sha256 `{prepared.manifest['spec_sha256'][:16]}`",
|
| 298 | f"- host load at start {meta.get('loadavg_start')} / end {meta.get('loadavg_end')}. Rows are claimable only "
|
| 299 | "with a validated quiet-host calibration record (oakbench.scale_calibration). MDE = smallest change "
|
| 300 | "detectable at 80% power here.",
|
| 301 | "",
|
| 302 | "| op | git ms | oak ms | oak/git (dev) | git A/A floor | oak A/A floor | oak-vs-git MDE | oak-vs-oak MDE | notes |",
|
| 303 | "|---|---:|---:|---:|---:|---:|---:|---:|---|",
|
| 304 | ]
|
| 305 | diagnostic_ops = {phase for phase in prepared.phases}
|
| 306 | for item in report:
|
| 307 | if item["operation"] in diagnostic_ops:
|
| 308 | continue
|
| 309 | g = item["subjects"].get("git", {})
|
| 310 | o = item["subjects"].get("oak_installed", {})
|
| 311 | ratio = None
|
| 312 | comparable = item.get("oak_vs_git_comparability", COMPARABLE) == COMPARABLE
|
| 313 | if comparable and g.get("median_ms") and o.get("median_ms"):
|
| 314 | ratio = o["median_ms"] / g["median_ms"]
|
| 315 | notes = [] if comparable else [f"oak-vs-git suppressed ({item['oak_vs_git_comparability']}); oak-vs-oak only"]
|
| 316 | for name, data in item["subjects"].items():
|
| 317 | if data.get("skip_reason"):
|
| 318 | notes.append(f"{name}: skip {data['skip_reason']}")
|
| 319 | elif data.get("failures"):
|
| 320 | notes.append(f"{name}: {data['failures']} fail ({data.get('failure')})")
|
| 321 | if data.get("teardown_errors"):
|
| 322 | notes.append(f"{name}: {data['teardown_errors']} untimed-teardown defect(s)")
|
| 323 | lines.append(
|
| 324 | f"| {item['operation']} | {_fmt(g.get('median_ms'))} | {_fmt(o.get('median_ms'))} | "
|
| 325 | f"{('n/c' if not comparable else _fmt(ratio)) if ratio is None else f'{ratio:.2f}x'} | {_fmt(item['git_aa_floor_pct'], '%')} | "
|
| 326 | f"{_fmt(item['oak_aa_floor_pct'], '%')} | {_fmt(item['oak_vs_git_mde_pct_80'], '%')} | "
|
| 327 | f"{_fmt(item['oak_vs_oak_mde_pct_80'], '%')} | {'; '.join(notes)[:300]} |")
|
| 328 | lines += ["", "## Fixture preparation (untimed, seconds)", ""]
|
| 329 | for key, value in prepared.phases.items():
|
| 330 | lines.append(f"- {key}: {value}")
|
| 331 | if prepared.notes:
|
| 332 | lines += ["", "## Notes", ""] + [f"- {note}" for note in prepared.notes]
|
| 333 | return "\n".join(lines) + "\n"
|
| 334 |
|
| 335 |
|
| 336 | def ingest_rows(prepared: Prepared, bench_id: str, runner_fields: Dict[str, Any]) -> List[Dict[str, Any]]:
|
| 337 | """One diagnostic row per preparation phase (setup cost is scale evidence)."""
|
| 338 | rows = []
|
| 339 | oak_identity = getattr(prepared, "oak_identity", None) or {}
|
| 340 | for phase_name, seconds in prepared.phases.items():
|
| 341 | if phase_name.endswith("_reused"):
|
| 342 | continue
|
| 343 | kind = "oak" if ".oak_" in phase_name else ("git" if ".git_" in phase_name else "harness")
|
| 344 | rows.append({
|
| 345 | "bench_id": bench_id, "profile": "scale", "scale_row_version": SCALE_ROW_VERSION,
|
| 346 | "scenario": prepared.tier.tier_id, "operation": phase_name, "run": 0,
|
| 347 | "subject": {"oak": "oak_installed", "git": "git"}.get(kind, "harness"), "subject_kind": kind,
|
| 348 | "command": [], "elapsed_ms": round(seconds * 1000.0, 3), "returncode": 0, "diagnostic": True,
|
| 349 | "claim_ineligible_reasons": ["untimed preparation phase (diagnostic)"],
|
| 350 | "measurement_source": "harness_phase_wall_clock", "evidence_class": EVIDENCE_CLASS,
|
| 351 | "claim_eligible": False, **prepared.fixture_fields(), **runner_fields,
|
| 352 | # Oak rows carry binary identity (publish_gate conformance check).
|
| 353 | **(oak_identity if kind == "oak" else {}),
|
| 354 | })
|
| 355 | return rows
|