Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
979001d
fix: flag fallback byte widths in roofline graphs
nicholaslawrence-hub Aug 11, 2026
8c6fc38
fix: surface saturated residual magnitude
nicholaslawrence-hub Aug 11, 2026
ee1c58c
fix: surface residual matching coverage
nicholaslawrence-hub Aug 11, 2026
c6227cd
fix: refuse unpriceable execution graphs
nicholaslawrence-hub Aug 11, 2026
78dac33
fix: flag each unpriced roofline dimension
nicholaslawrence-hub Aug 11, 2026
693bb5c
fix: refuse unqualified benchmark baselines
nicholaslawrence-hub Aug 11, 2026
db892d4
fix: distinguish estimated serving token counts
nicholaslawrence-hub Aug 11, 2026
9d19721
fix: surface degraded runtime measurements
nicholaslawrence-hub Aug 11, 2026
7c2b81a
fix: surface runtime fallback diagnostics
nicholaslawrence-hub Aug 11, 2026
13ba794
fix: refuse invalid benchmark timing
nicholaslawrence-hub Aug 11, 2026
aae4903
fix: surface degraded control paths
nicholaslawrence-hub Aug 11, 2026
1a68425
fix: refuse invalid importer rollups
nicholaslawrence-hub Aug 11, 2026
1997159
fix: make degraded loop outcomes fail visibly
nicholaslawrence-hub Aug 11, 2026
4d4f250
fix: reject invalid kernel timestamps
nicholaslawrence-hub Aug 11, 2026
c12cc6f
fix: surface partial serving telemetry
nicholaslawrence-hub Aug 11, 2026
517c8b1
fix: refuse invalid optimization evidence
nicholaslawrence-hub Aug 11, 2026
7a4e834
fix: gate edge timing and wire kitti planner
nicholaslawrence-hub Aug 11, 2026
c709a07
fix: refuse unpriced dense and A/B inputs
nicholaslawrence-hub Aug 11, 2026
503d459
fix: surface missing server metrics
nicholaslawrence-hub Aug 11, 2026
d1da021
fix: surface sink and model discovery fallbacks
nicholaslawrence-hub Aug 11, 2026
4b7d36e
fix: refuse invalid replay validation truth
nicholaslawrence-hub Aug 11, 2026
afa5ca4
fix: price dense graphs at their compute dtype
nicholaslawrence-hub Aug 11, 2026
3010e9f
fix: refuse invalid headroom evidence
nicholaslawrence-hub Aug 11, 2026
30364a9
fix: refuse invalid A/B samples and surface cleanup failures
nicholaslawrence-hub Aug 11, 2026
ac5c73d
fix: refuse zero-duration serving traces
nicholaslawrence-hub Aug 11, 2026
c69e515
fix: wire CUDA compatibility gate into vLLM workload
nicholaslawrence-hub Aug 11, 2026
fa7d20a
fix: refuse non-finite report deltas
nicholaslawrence-hub Aug 11, 2026
9927ce2
fix: refuse invalid benchmark sign-off evidence
nicholaslawrence-hub Aug 11, 2026
c2d944a
fix: surface fallback GPU counts
nicholaslawrence-hub Aug 11, 2026
30f9483
fix: surface trace device-count failures
nicholaslawrence-hub Aug 11, 2026
e1c40ac
fix: wire resident footprint provenance
nicholaslawrence-hub Aug 11, 2026
fcf1d72
fix: surface autoresearch GPU-count fallback
nicholaslawrence-hub Aug 11, 2026
efe9f4a
fix: refuse default-shaped sparse predictions
nicholaslawrence-hub Aug 11, 2026
d07e7db
fix: surface incomplete injected traces
nicholaslawrence-hub Aug 11, 2026
e1634f4
fix: refuse invalid public runtime inputs
nicholaslawrence-hub Aug 11, 2026
e331073
fix: surface telemetry discovery failures
nicholaslawrence-hub Aug 11, 2026
6a9128c
fix: refuse invalid attach windows
nicholaslawrence-hub Aug 11, 2026
d741f4f
fix: refuse invalid optimization gate evidence
nicholaslawrence-hub Aug 11, 2026
9e44680
fix: surface imported launch-shape fallbacks
nicholaslawrence-hub Aug 11, 2026
3f28595
fix: surface dense graph shape assumptions
nicholaslawrence-hub Aug 11, 2026
08c84d6
fix: wire dense graph sharding and weight precision
nicholaslawrence-hub Aug 11, 2026
70aae4b
fix: wire live GPU headroom to CLI
nicholaslawrence-hub Aug 11, 2026
733ea2a
fix: surface scheduler field probe failures
nicholaslawrence-hub Aug 11, 2026
48af62b
fix: refuse invalid A/B gate controls
nicholaslawrence-hub Aug 11, 2026
69faeb7
fix: refuse contradictory benchmark timing partitions
nicholaslawrence-hub Aug 11, 2026
9a1b7fd
fix: refuse invalid OpenFold A/B evidence
nicholaslawrence-hub Aug 11, 2026
0883e80
fix: refuse contradictory utilization windows
nicholaslawrence-hub Aug 11, 2026
96c9678
fix: reject invalid scheduler telemetry values
nicholaslawrence-hub Aug 11, 2026
a67c3c3
fix: surface unverified CUDA build versions
nicholaslawrence-hub Aug 11, 2026
b19a6d8
fix: honor declared bf16 roofline peaks
nicholaslawrence-hub Aug 11, 2026
ffedbf4
fix: wire host flamegraph capture
nicholaslawrence-hub Aug 11, 2026
6235cdc
fix: surface importer cleanup losses
nicholaslawrence-hub Aug 11, 2026
767e6cb
fix: surface every profile bundle artifact
nicholaslawrence-hub Aug 11, 2026
124575f
fix: wire fail-open guard into live applies
nicholaslawrence-hub Aug 11, 2026
d3e0831
fix: refuse invalid auto-revert evidence
nicholaslawrence-hub Aug 11, 2026
e8b6c2b
fix: share unverified CUDA build diagnostics
nicholaslawrence-hub Aug 11, 2026
81550f9
fix: surface malformed GPU trace drops
nicholaslawrence-hub Aug 11, 2026
e0ca8f8
fix: wire sparse KV sizing into prediction artifacts
nicholaslawrence-hub Aug 11, 2026
cd99784
fix: refuse unsupported stream-concurrency evidence
nicholaslawrence-hub Aug 11, 2026
360aa50
fix: remove unhonored runtime schema fields
nicholaslawrence-hub Aug 11, 2026
08a898d
fix: refuse inferred interconnect topology
nicholaslawrence-hub Aug 11, 2026
ad6e6c4
fix: stop sparse dtype and KV defaults masking pricing
nicholaslawrence-hub Aug 12, 2026
e7c422c
fix: surface importer decoder and verification fallbacks
nicholaslawrence-hub Aug 12, 2026
fd7e611
docs: complete graceful fallback audit ledger
nicholaslawrence-hub Aug 12, 2026
cd40fd9
fix: normalize declared dtype aliases before pricing
nicholaslawrence-hub Aug 12, 2026
f647ea4
docs: record audit verification and branch split
nicholaslawrence-hub Aug 12, 2026
6898ff0
docs: clarify separated expert signal branches
nicholaslawrence-hub Aug 12, 2026
2975a72
merge: sync graceful fallback audit with main
nicholaslawrence-hub Aug 14, 2026
8f03430
docs: record synchronized audit verification
nicholaslawrence-hub Aug 14, 2026
0e7da1e
fix: satisfy CI lint for sparse config validation
nicholaslawrence-hub Aug 14, 2026
0193c41
docs: summarize graceful fallback audit changes
nicholaslawrence-hub Aug 14, 2026
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
263 changes: 263 additions & 0 deletions AUDIT.md

Large diffs are not rendered by default.

21 changes: 14 additions & 7 deletions benchmarks/biotech/harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from typing import Protocol

from benchmarks.biotech.fetch import FastaRecord, read_fasta
from gitm._timing import require_positive_duration, require_timing_partition

OPENFOLD_COMMIT = "v1.0.1" # pinned; weight hashes pinned in datasets.md
MODEL_NAME = "model_1" # single-model AF2 monomer; weights = params_model_1.npz
Expand Down Expand Up @@ -193,12 +194,16 @@ def _build_stall_phase(timings: list[dict], wall_clock_s: float) -> dict:
t_feat = sum(t["_t_featurize_s"] for t in timings)
t_inf = sum(t["_t_inference_s"] for t in timings)
t_post = sum(t["_t_post_s"] for t in timings)
total = max(sum(t["_t_total_s"] for t in timings), 1e-9)

data_stall = min(1.0, t_feat / total)
gpu_active = min(1.0, t_inf / total)
sync = min(1.0, t_post / total)
cpu = max(0.0, 1.0 - data_stall - gpu_active - sync)
total = sum(t["_t_total_s"] for t in timings)
split = require_timing_partition(
total,
{"data_stall": t_feat, "gpu_active": t_inf, "sync": t_post},
context="biotech stall breakdown",
)
data_stall = split["data_stall"]
gpu_active = split["gpu_active"]
sync = split["sync"]
cpu = split["unattributed"]

return {
"phase": "all",
Expand Down Expand Up @@ -246,7 +251,9 @@ def run(
plddts.append(float(result["plddt"]))
if "_t_total_s" in result:
timings.append(result)
elapsed = max(time.perf_counter() - t0, 1e-9)
elapsed = require_positive_duration(
time.perf_counter() - t0, context="biotech harness"
)

structures_per_hour = len(proteins) / elapsed * 3600.0
payload: dict = {
Expand Down
23 changes: 20 additions & 3 deletions benchmarks/biotech/optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import argparse
import json
import math
import os
import statistics
import time
Expand All @@ -33,6 +34,7 @@

from benchmarks.biotech.fetch import read_fasta
from benchmarks.biotech.harness import _msa_path, load_openfold_runner
from gitm._timing import require_positive_duration, require_positive_work
from gitm.kernels.spec import Applicability, InterventionSpec, SafetyGate


Expand All @@ -57,11 +59,17 @@ def _fold_all(runner, proteins) -> tuple[float, float | None]:
for r, msa in proteins:
out = runner.predict(r, msa)
if "plddt" in out:
plddts.append(float(out["plddt"]))
plddt = float(out["plddt"])
if not math.isfinite(plddt):
raise RuntimeError(f"OpenFold quality evidence is non-finite: {plddt!r}")
plddts.append(plddt)
if torch.cuda.is_available():
torch.cuda.synchronize()
elapsed = max(time.perf_counter() - t0, 1e-9)
sph = len(proteins) / elapsed * 3600.0
elapsed = require_positive_duration(
time.perf_counter() - t0, context="OpenFold A/B"
)
count = require_positive_work(len(proteins), context="OpenFold A/B")
sph = count / elapsed * 3600.0
return sph, (statistics.median(plddts) if plddts else None)


Expand Down Expand Up @@ -91,6 +99,15 @@ def verdict(self) -> str:
def optimize_af2(stage: Path, seed: int, *, n_proteins: int, max_len: int,
warmup: int, plddt_tol: float) -> AF2ABResult:
"""Run the fp32-vs-bf16 A/B and return a gated verdict."""
for name, value, minimum in (
("n_proteins", n_proteins, 1),
("max_len", max_len, 1),
("warmup", warmup, 0),
):
if isinstance(value, bool) or not isinstance(value, int) or value < minimum:
raise ValueError(f"{name} must be an integer >= {minimum}, got {value!r}")
if not math.isfinite(plddt_tol) or plddt_tol < 0.0:
raise ValueError(f"plddt_tol must be finite and non-negative, got {plddt_tol!r}")
import torch

proteins = _select(stage, max_len=max_len, n=n_proteins)
Expand Down
9 changes: 8 additions & 1 deletion benchmarks/biotech/sanity.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
load_openfold_runner,
select_proteins,
)
from gitm._timing import require_positive_duration


def _fmt(result: dict) -> str:
Expand Down Expand Up @@ -85,7 +86,13 @@ def main(argv: list[str] | None = None) -> int:
warm = runner.predict(target, msa)
print(f" WARM {_fmt(warm)}")

speedup = cold["_t_total_s"] / max(warm["_t_total_s"], 1e-9)
cold_s = require_positive_duration(
float(cold["_t_total_s"]), context="OpenFold cold sanity pass"
)
warm_s = require_positive_duration(
float(warm["_t_total_s"]), context="OpenFold warm sanity pass"
)
speedup = cold_s / warm_s
print(f"cold/warm total speedup: {speedup:.2f}x (kernel cache + allocator warm-up)")
if abs(cold["plddt"] - warm["plddt"]) > 1.0:
print(
Expand Down
26 changes: 19 additions & 7 deletions benchmarks/edge/harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from pathlib import Path
from typing import Any, Protocol

from gitm._timing import require_positive_duration, require_timing_partition

OPENPCDET_COMMIT = "v0.6.0" # pinned; config hash pinned in datasets.md

_OPENPCDET_DEFAULT_CFG = (
Expand Down Expand Up @@ -231,7 +233,9 @@ def run(stage: Path, *, warm: int, runner: Runner) -> dict:
maps.append(float(result["map"]))
if "_t_total_s" in result:
timings.append(result)
elapsed = max(time.perf_counter() - t0, 1e-9)
elapsed = require_positive_duration(
time.perf_counter() - t0, context="edge harness"
)

if n == 0:
raise RuntimeError(f"no frames in {manifest}")
Expand Down Expand Up @@ -259,12 +263,20 @@ def _build_stall_phase(timings: list[dict], wall_clock_s: float) -> dict:
t_pre = sum(t["_t_preprocess_s"] for t in timings)
t_inf = sum(t["_t_inference_s"] for t in timings)
t_post = sum(t["_t_postprocess_s"] for t in timings)
total = max(sum(t["_t_total_s"] for t in timings), 1e-9)

data_stall = min(1.0, (t_load + t_pre) / total)
gpu_active = min(1.0, t_inf / total)
sync = min(1.0, t_post / total)
cpu = max(0.0, 1.0 - data_stall - gpu_active - sync)
total = sum(t["_t_total_s"] for t in timings)
split = require_timing_partition(
total,
{
"data_stall": t_load + t_pre,
"gpu_active": t_inf,
"sync": t_post,
},
context="edge stall breakdown",
)
data_stall = split["data_stall"]
gpu_active = split["gpu_active"]
sync = split["sync"]
cpu = split["unattributed"]

return {
"phase": "all",
Expand Down
52 changes: 52 additions & 0 deletions gitm/_timing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Shared timing trust predicates."""

from __future__ import annotations

import math


def require_positive_duration(duration_s: float, *, context: str) -> float:
"""Return a usable duration or refuse to fabricate a throughput denominator."""
if not math.isfinite(duration_s) or duration_s <= 0.0:
raise RuntimeError(
f"{context} timing unavailable: expected a finite positive duration, "
f"got {duration_s!r}"
)
return duration_s


def require_positive_work(value: int | float, *, context: str) -> int | float:
"""Refuse throughput or speedup claims over an empty work unit."""
if not math.isfinite(float(value)) or value <= 0:
raise RuntimeError(f"{context} work coverage unavailable: expected > 0, got {value!r}")
return value


def require_timing_partition(
total_s: float, components_s: dict[str, float], *, context: str
) -> dict[str, float]:
"""Return component fractions plus ``unattributed`` or refuse overlap.

Benchmark stall breakdowns are sign-off evidence. Repairing a zero total or
independently clamping overlapping phase timers would turn broken evidence
into a plausible partition, so validate the complete partition in one place.
"""
total = require_positive_duration(total_s, context=context)
invalid = {
name: value
for name, value in components_s.items()
if not math.isfinite(value) or value < 0.0
}
if invalid:
raise RuntimeError(f"{context} timing unavailable: invalid components {invalid}")
assigned = sum(components_s.values())
tolerance = max(1e-12, total * 1e-9)
if assigned > total + tolerance:
detail = ", ".join(f"{name}={value:.6g}s" for name, value in components_s.items())
raise RuntimeError(
f"{context} timing attribution overlaps: {detail}, total={total:.6g}s; "
"refusing to clamp"
)
fractions = {name: value / total for name, value in components_s.items()}
fractions["unattributed"] = max(0.0, total - assigned) / total
return fractions
77 changes: 65 additions & 12 deletions gitm/agents/autoresearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from __future__ import annotations

import random
import warnings
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Protocol
Expand All @@ -63,6 +64,7 @@
"IDLE_STALL",
"MEMORY_BOUND",
"COMPUTE_BOUND",
"UNCLASSIFIED",
"classify_bottleneck",
"ResidualTarget",
"largest_residual",
Expand Down Expand Up @@ -97,7 +99,8 @@
IDLE_STALL = "idle_stall"
MEMORY_BOUND = "memory_bound"
COMPUTE_BOUND = "compute_bound"
BOTTLENECK_CLASSES = (IDLE_STALL, MEMORY_BOUND, COMPUTE_BOUND)
UNCLASSIFIED = "unclassified"
BOTTLENECK_CLASSES = (IDLE_STALL, MEMORY_BOUND, COMPUTE_BOUND, UNCLASSIFIED)

#: Serialized-concurrency fraction above this ⇒ kernels ran back-to-back on one
#: stream instead of overlapping: scheduling gaps / launch-bound idle time.
Expand Down Expand Up @@ -125,18 +128,18 @@ def _roofline_memory_fraction(residuals: Residuals | None) -> float | None:


def classify_bottleneck(trace: Trace, residuals: Residuals | None = None) -> str:
"""Map a captured trace to one of ``idle_stall`` / ``memory_bound`` / ``compute_bound``.
"""Classify a measured trace, or return ``unclassified`` without valid kernels.

Two signals, scored against a threshold each; the stronger wins, neither
crossing defaults to compute bound: serialized-concurrency fraction (poor
crossing selects compute bound: serialized-concurrency fraction (poor
kernel overlap ⇒ idle/scheduling gaps), and memory pressure (memcpy share
of GPU-op time, widened by the roofline-predicted memory-bound fraction of
matched kernel time when ``residuals`` is passed). Without ``residuals``
this is the memcpy-only heuristic.
"""
kernels = trace.kernels()
kernels = [k for k in trace.kernels() if k.end_ns > k.start_ns]
if not kernels:
return COMPUTE_BOUND
return UNCLASSIFIED

memcpys = [e for e in trace.events if e.kind == "memcpy"]
sc = _serialized_fraction(kernels)
Expand All @@ -145,11 +148,15 @@ def classify_bottleneck(trace: Trace, residuals: Residuals | None = None) -> str
gpu_op_ns = kernel_ns + memcpy_ns
memcpy_frac = memcpy_ns / gpu_op_ns if gpu_op_ns else 0.0

sc_score = sc / _SC_THRESHOLD
sc_score = sc / _SC_THRESHOLD if sc is not None else None
mem_score = memcpy_frac / _MEMCPY_THRESHOLD
roofline_frac = _roofline_memory_fraction(residuals)
if roofline_frac is not None:
mem_score = max(mem_score, roofline_frac / _MEMCPY_THRESHOLD)
if mem_score >= 1.0 and (sc_score is None or mem_score > sc_score):
return MEMORY_BOUND
if sc_score is None:
return UNCLASSIFIED
if max(sc_score, mem_score) < 1.0:
return COMPUTE_BOUND
return IDLE_STALL if sc_score >= mem_score else MEMORY_BOUND # ties favor idle_stall
Expand Down Expand Up @@ -213,6 +220,7 @@ def _op_present(trace: Trace, op: str) -> bool:
("compilation_config", 3,
"raise torch.compile to level 3 for kernel fusion + piecewise CUDA graphs"),
],
"unclassified": [],
}


Expand Down Expand Up @@ -393,6 +401,7 @@ class Knob:
"idle_stall": ("prefill", "partial", "schedul", "chunk", "overlap"),
"memory_bound": ("cache", "swap", "offload", "block", "gpu_memory", "kv", "preempt", "cpu"),
"compute_bound": ("compil", "cudagraph", "cuda_graph", "graph", "quant", "fus", "eager"),
"unclassified": (),
}


Expand Down Expand Up @@ -553,8 +562,23 @@ def _visible_gpu_count() -> int:
try:
import torch

return torch.cuda.device_count() or 1
except Exception:
count = int(torch.cuda.device_count())
if count > 0:
return count
warnings.warn(
f"GPU-count detection reported {count}; autoresearch is using 1 and "
"may omit multi-GPU candidates",
RuntimeWarning,
stacklevel=2,
)
return 1
except Exception as exc:
warnings.warn(
"GPU-count detection failed; autoresearch is using 1 and may omit "
f"multi-GPU candidates ({type(exc).__name__}: {exc})",
RuntimeWarning,
stacklevel=2,
)
return 1


Expand Down Expand Up @@ -585,7 +609,13 @@ def _argparse_domains(engine_args_cls: object) -> dict[str, _ArgDomain]:
import argparse

parser = engine_args_cls.add_cli_args(argparse.ArgumentParser()) # type: ignore[attr-defined]
except Exception:
except Exception as exc:
warnings.warn(
"vLLM CLI-domain introspection unavailable; candidate grids will use "
f"coarser dataclass annotations ({type(exc).__name__}: {exc})",
RuntimeWarning,
stacklevel=2,
)
return {}
out: dict[str, _ArgDomain] = {}
for action in getattr(parser, "_actions", []):
Expand Down Expand Up @@ -634,6 +664,8 @@ def _knobs_from_engine_args(
"""
import dataclasses

if gpu_count is not None and gpu_count <= 0:
raise ValueError(f"gpu_count must be positive when supplied, got {gpu_count}")
gpus = _visible_gpu_count() if gpu_count is None else gpu_count
domains = _argparse_domains(engine_args_cls)
knobs: list[Knob] = []
Expand Down Expand Up @@ -668,11 +700,32 @@ def _engine_arg_knobs(*, gpu_count: int | None = None) -> list[Knob]:
"""
try:
from vllm import EngineArgs # type: ignore
except Exception:
except Exception as exc:
warnings.warn(
"vLLM EngineArgs unavailable; autoresearch is using the frozen fallback "
f"knob catalog ({type(exc).__name__}: {exc})",
RuntimeWarning,
stacklevel=2,
)
return list(_FALLBACK_KNOBS)
try:
return _knobs_from_engine_args(EngineArgs, gpu_count=gpu_count) or list(_FALLBACK_KNOBS)
except Exception:
knobs = _knobs_from_engine_args(EngineArgs, gpu_count=gpu_count)
if knobs:
return knobs
warnings.warn(
"vLLM EngineArgs introspection produced no searchable knobs; autoresearch "
"is using the frozen fallback knob catalog",
RuntimeWarning,
stacklevel=2,
)
return list(_FALLBACK_KNOBS)
except Exception as exc:
warnings.warn(
"vLLM EngineArgs introspection failed; autoresearch is using the frozen "
f"fallback knob catalog ({type(exc).__name__}: {exc})",
RuntimeWarning,
stacklevel=2,
)
return list(_FALLBACK_KNOBS)


Expand Down
2 changes: 2 additions & 0 deletions gitm/agents/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def select_interventions(
*,
ctx: GateContext | None = None,
) -> list[RankedCandidate]:
if isinstance(top_n, bool) or not isinstance(top_n, int) or top_n <= 0:
raise ValueError(f"top_n must be a positive integer, got {top_n!r}")
candidates: list[RankedCandidate] = []

for spec in library:
Expand Down
Loading
Loading