diff --git a/benchmarks/audit_native_outputs.py b/benchmarks/audit_native_outputs.py
new file mode 100644
index 000000000..86cfc36f7
--- /dev/null
+++ b/benchmarks/audit_native_outputs.py
@@ -0,0 +1,228 @@
+"""Compare complete native training and held-out outputs across fresh recovery."""
+
+import argparse
+import hashlib
+import json
+from pathlib import Path
+
+import torch
+
+from benchmarks.audit_native_learning_signal import audit as audit_signal
+from benchmarks.audit_native_runtime import audit as audit_runtime
+from vime.rollout.native_eval import evaluation_seed
+from vime.rollout.rm_hub.math_utils import grade_answer_verl
+
+SCORE_ATOL, SCORE_RTOL = 1e-5, 3e-5
+DATASET = "qualification-development"
+
+
+def compare_samples(left: dict, right: dict) -> float:
+ for key in (
+ "index",
+ "group_index",
+ "prompt",
+ "tokens",
+ "response_length",
+ "response",
+ "label",
+ "reward",
+ "status",
+ "metadata",
+ "weight_versions",
+ ):
+ assert left[key] == right[key], f"Changed sample {left['index']}: {key}"
+ traces = [
+ {key: value for key, value in sample["recurrent_trace"].items() if key not in {"runtime_epoch", "request_id"}}
+ for sample in (left, right)
+ ]
+ assert traces[0] == traces[1], "Changed semantic trace"
+ return compare_scores(left["rollout_log_probs"], right["rollout_log_probs"])
+
+
+def compare_scores(left, right) -> float:
+ a, b = torch.as_tensor(left), torch.as_tensor(right)
+ assert a.shape == b.shape and a.numel() > 0 and bool(torch.isfinite(a).all()) and bool(torch.isfinite(b).all())
+ torch.testing.assert_close(a, b, atol=SCORE_ATOL, rtol=SCORE_RTOL)
+ return float((a - b).abs().max())
+
+
+def validate_response(sample: dict, limit: int, tokenizer) -> None:
+ length, trace = sample["response_length"], sample["recurrent_trace"]
+ assert 0 < length <= limit and len(sample["tokens"]) > length
+ assert trace["finish_reason"] in ("stop", "length")
+ assert sample["status"] == ("completed" if trace["finish_reason"] == "stop" else "truncated")
+ if trace["finish_reason"] == "length":
+ assert length == limit
+ else:
+ assert sample["tokens"][-1] == tokenizer.eos_token_id
+ assert sample["response"] == tokenizer.decode(sample["tokens"][-length:], skip_special_tokens=True), (
+ "Saved text does not decode from its tokens"
+ )
+ assert (
+ sample["reward"] in (0, 1) and int(grade_answer_verl(sample["response"], sample["label"])) == sample["reward"]
+ )
+ scores = torch.as_tensor(sample["rollout_log_probs"])
+ assert scores.shape == (length,) and bool(torch.isfinite(scores).all())
+
+
+def audit(continuous: Path, resumed: Path, packet: Path, input_audit: Path, algorithm: str, tokenizer) -> dict:
+ runtime = audit_runtime(continuous, resumed, packet)
+ signals = [audit_signal(run, packet, input_audit, algorithm) for run in (continuous, resumed)]
+ consumed = dict(runtime["consumed_sha256"])
+
+ def consume(path):
+ consumed[str(path.resolve())] = hashlib.sha256(path.read_bytes()).hexdigest()
+ return path
+
+ def load(path):
+ return torch.load(consume(path), map_location="cpu", weights_only=False)
+
+ profile = json.loads(consume(packet / "qualification.json").read_text())
+ assert profile["eval_completions_per_prompt"] == 1
+ assert profile["prompts_per_rollout"] == 4 and profile["completions_per_prompt"] == 8
+ train_rows = [json.loads(line) for line in consume(packet / "train.jsonl").read_text().splitlines()]
+ train_ids = [row["metadata"]["id"] for row in train_rows]
+ assert len(train_ids) == len(set(train_ids)) == 12 and train_ids == profile["selected_ids"]["train"]
+ inputs = json.loads(consume(input_audit).read_text())
+ development = packet / "development.jsonl"
+ assert (
+ hashlib.sha256(consume(development).read_bytes()).hexdigest() == profile["files"][development.name]["sha256"]
+ )
+ rows = [json.loads(line) for line in development.read_text().splitlines()]
+ ids = [row["metadata"]["id"] for row in rows]
+ assert len(ids) == len(set(ids)) == profile["files"][development.name]["rows"] == 8
+ assert ids == profile["selected_ids"]["development"] and not set(ids) & set(profile["selected_ids"]["train"])
+ assert len(inputs["rows"]) == 20 and {row["id"] for row in inputs["rows"]} == set(train_ids + ids)
+ token_rows = [row for row in inputs["rows"] if row["split"] == "development"]
+ assert len(token_rows) == 8 and [row["id"] for row in token_rows] == ids
+ token_hashes = {row["id"]: row["token_ids_sha256"] for row in token_rows}
+ training, evaluation, summaries = [], [], []
+ for run_index, run in enumerate((continuous, resumed)):
+ train_rounds, eval_rounds, curve = [], [], []
+ for step in range(3):
+ data = load(run / f"details/rollout_data/{step}.pt")
+ trained = load(run / f"details/train_data/{step}.pt")
+ for sample in data["samples"]:
+ validate_response(sample, profile["response_limit"], tokenizer)
+ train_rounds.append((data["samples"], trained["samples"]))
+ consume(run / f"grad-actor-{step}-0.pt")
+ for step in range(4):
+ data = load(run / f"details/rollout_data/eval_{step}.pt")
+ samples = data["samples"]
+ assert data["rollout_id"] == step and len(samples) == len(rows)
+ phase = "continuous" if run_index == 0 else ("split" if step <= 2 else "resume")
+ epoch = runtime["phases"][phase]["runtime_epoch"]
+ digests, requests = set(), set()
+ for index, (sample, row) in enumerate(zip(samples, rows, strict=True)):
+ assert sample["index"] == sample["group_index"] == index
+ assert sample["metadata"]["id"] == row["metadata"]["id"] and sample["label"] == row["label"]
+ assert sample["metadata"]["native_eval"] == {
+ "dataset": DATASET,
+ "prompt_index": index,
+ "completion": 0,
+ "seed_profile": "native-heldout-v1",
+ "top_p": 1,
+ "top_k": -1,
+ "max_tokens": profile["response_limit"],
+ "stop_token_ids": [],
+ }
+ length, trace = sample["response_length"], sample["recurrent_trace"]
+ validate_response(sample, profile["response_limit"], tokenizer)
+ prefix = hashlib.sha256(json.dumps(sample["tokens"][:-length]).encode()).hexdigest()
+ assert prefix == token_hashes[row["metadata"]["id"]]
+ assert trace["runtime_epoch"] == epoch and trace["policy_version"] == step + 1
+ assert sample["weight_versions"] == [str(step + 1)]
+ assert trace["model_family"] == "ouro" and trace["schema_version"] == 1
+ assert (
+ trace["model_revision"] == profile["model_revision"]
+ and trace["engine_revision"] == profile["engine_revision"]
+ )
+ assert trace["prefill_depth"] == 4 and trace["decode_depths"] == [4] * length
+ assert trace["temperature"] == 0 and trace["seed"] == evaluation_seed(
+ profile["seed"], DATASET, index, 0
+ )
+ assert trace["latent_seed"] is None and trace["latent_profile"] is None
+ assert (
+ isinstance(trace["request_id"], str)
+ and trace["request_id"]
+ and trace["request_id"] not in requests
+ )
+ requests.add(trace["request_id"])
+ assert len(trace["publication_digest"]) == 64
+ digests.add(trace["publication_digest"])
+ assert len(digests) == 1, "Mixed held-out policy publications"
+ digest = digests.pop()
+ if step < 3:
+ assert digest == signals[run_index]["rounds"][step]["publication_digest"], (
+ "Held-out and training policy differ"
+ )
+ curve.append(
+ dict(
+ completed_updates=step,
+ reward_mean=sum(sample["reward"] for sample in samples) / len(samples),
+ response_tokens=sum(sample["response_length"] for sample in samples),
+ truncated=sum(sample["status"] == "truncated" for sample in samples),
+ publication_digest=digest,
+ )
+ )
+ eval_rounds.append(samples)
+ assert len({row["publication_digest"] for row in curve}) == 4, "An update reused an old publication"
+ training.append(train_rounds)
+ evaluation.append(eval_rounds)
+ summaries.append(curve)
+ errors = {"training_scores": 0.0, "heldout_scores": 0.0, "training_tensors": 0.0, "gradient_norm": 0.0}
+ for left, right in zip(signals[0]["rounds"], signals[1]["rounds"], strict=True):
+ errors["gradient_norm"] = max(
+ errors["gradient_norm"], compare_scores(left["gradient_norm"], right["gradient_norm"])
+ )
+ for left, right in zip(*training, strict=True):
+ for a, b in zip(left[0], right[0], strict=True):
+ errors["training_scores"] = max(errors["training_scores"], compare_samples(a, b))
+ for a, b in zip(left[1], right[1], strict=True):
+ assert torch.equal(torch.as_tensor(a["loss_masks"]), torch.as_tensor(b["loss_masks"]))
+ for key in ("advantages", "returns", "kl", "ref_log_probs" if algorithm == "rltt" else "log_probs"):
+ errors["training_tensors"] = max(errors["training_tensors"], compare_scores(a[key], b[key]))
+ for left, right in zip(*evaluation, strict=True):
+ for a, b in zip(left, right, strict=True):
+ errors["heldout_scores"] = max(errors["heldout_scores"], compare_samples(a, b))
+ useful = sorted(set(signals[0]["useful_updates"]) & set(signals[1]["useful_updates"]))
+ return {
+ "output_equivalence_pass": True,
+ "joint_signal_updates": useful,
+ "output_and_signal_pass": bool(useful),
+ "training_samples_per_run": 96,
+ "heldout_samples_per_run": 32,
+ "numeric_tolerance": {"atol": SCORE_ATOL, "rtol": SCORE_RTOL},
+ "max_absolute_errors": errors,
+ "continuous_curve": summaries[0],
+ "resumed_curve": summaries[1],
+ "runtime": runtime,
+ "signals": signals,
+ "consumed_sha256": consumed,
+ "scope": "complete three-update native output/held-out recovery qualification, not a convergence experiment",
+ "weights_optimizer_frozen_sources": "REQUIRES_SEPARATE_AUDITS",
+ "reward_convergence": "NOT_ESTABLISHED",
+ }
+
+
+def main():
+ from transformers import AutoTokenizer
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ for name in ("continuous", "resumed", "packet", "input-audit", "tokenizer", "output"):
+ parser.add_argument("--" + name, type=Path, required=True)
+ parser.add_argument("--algorithm", choices=("grpo", "rltt"), required=True)
+ args = parser.parse_args()
+ tokenizer = AutoTokenizer.from_pretrained(args.tokenizer, local_files_only=True, trust_remote_code=False)
+ report = audit(args.continuous, args.resumed, args.packet, args.input_audit, args.algorithm, tokenizer)
+ report["tokenizer_sha256"] = {
+ name: hashlib.sha256((args.tokenizer / name).read_bytes()).hexdigest()
+ for name in ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt")
+ if (args.tokenizer / name).is_file()
+ }
+ args.output.write_text(json.dumps(report, indent=2) + "\n")
+ raise SystemExit(0 if report["output_and_signal_pass"] else 1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py b/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py
new file mode 100644
index 000000000..428e15698
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py
@@ -0,0 +1,55 @@
+"""Validate answer-replay controls with the retained official tokenizer, not model output."""
+
+import hashlib
+import json
+from pathlib import Path
+
+import torch
+from transformers import AutoTokenizer
+
+from benchmarks.audit_native_outputs import validate_response
+from vime.rollout.rm_hub.math_utils import grade_answer_verl
+from vime.utils.data import Dataset
+
+task = Path(__file__).resolve().parents[1]
+packet = task / "data/native-qualification-v1"
+model = task / "data/math-v1/model-config/ouro-thinking"
+profile = json.loads((packet / "qualification.json").read_text())
+inputs = json.loads((task / "evidence/native-qualification-input-audit.json").read_text())
+assert inputs["qualification_sha256"] == hashlib.sha256((packet / "qualification.json").read_bytes()).hexdigest()
+token_hashes = {row["id"]: row["token_ids_sha256"] for row in inputs["rows"]}
+tokenizer = AutoTokenizer.from_pretrained(model, local_files_only=True, trust_remote_code=False)
+assert tokenizer.eos_token_id == json.loads((model / "config.json").read_text())["eos_token_id"] == 2
+rows = []
+for split in ("train", "development"):
+ source = packet / f"{split}.jsonl"
+ assert hashlib.sha256(source.read_bytes()).hexdigest() == profile["files"][source.name]["sha256"]
+ dataset = Dataset(str(source), tokenizer, None, None, prompt_key="prompt", label_key="label",
+ metadata_key="metadata", apply_chat_template=True, apply_chat_template_kwargs={})
+ for sample in dataset.samples:
+ prefix = tokenizer.encode(sample.prompt, add_special_tokens=False)
+ assert hashlib.sha256(json.dumps(prefix).encode()).hexdigest() == token_hashes[sample.metadata["id"]]
+ wrong = r"\boxed{0}" if not grade_answer_verl(r"\boxed{0}", sample.label) else r"\boxed{1}"
+ for expected, response in ((1, r"\boxed{" + sample.label + "}"), (0, wrong)):
+ output = tokenizer.encode(response, add_special_tokens=False) + [tokenizer.eos_token_id]
+ decoded = tokenizer.decode(output, skip_special_tokens=True)
+ assert int(grade_answer_verl(decoded, sample.label)) == expected
+ record = dict(tokens=prefix + output, response_length=len(output), response=decoded, label=sample.label,
+ reward=expected, status="completed", recurrent_trace={"finish_reason": "stop"},
+ rollout_log_probs=[-1.0] * len(output))
+ validate_response(record, profile["response_limit"], tokenizer)
+ rows.append(dict(split=split, id=sample.metadata["id"], expected_reward=expected,
+ response_tokens=len(output), token_sha256=hashlib.sha256(json.dumps(output).encode()).hexdigest()))
+assert len(rows) == 40 and not torch.cuda.is_initialized()
+result = {
+ "scope": "answer-replay controls from known labels with invented scores; no model generation or training",
+ "qualification_sha256": inputs["qualification_sha256"], "eos_token_id": tokenizer.eos_token_id,
+ "tokenizer_class": type(tokenizer).__name__, "trust_remote_code": False, "local_files_only": True,
+ "rows": rows, "cuda_initialized": False, "model_generation": "NOT_RUN",
+ "source_sha256": hashlib.sha256((task / "vime/benchmarks/audit_native_outputs.py").read_bytes()).hexdigest(),
+ "tokenizer_sha256": {name: hashlib.sha256((model / name).read_bytes()).hexdigest() for name in
+ ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt")},
+}
+(task / "evidence/native-output-tokenizer.json").write_text(json.dumps(result, indent=2) + "\n")
+print(json.dumps({"answer_replay_controls": len(rows), "eos_token_id": tokenizer.eos_token_id,
+ "model_generation": "NOT_RUN", "cuda_initialized": False}))
diff --git a/benchmarks/results/native-output-recovery/manifest.json b/benchmarks/results/native-output-recovery/manifest.json
new file mode 100644
index 000000000..290c279aa
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/manifest.json
@@ -0,0 +1,33 @@
+{
+ "source_sha256": {
+ "benchmarks/audit_native_outputs.py": "e55d2fa5f89a45d7afdb8fa22724f33f4fb70396830e4584957bcffbcb6fb598",
+ "benchmarks/audit_native_runtime.py": "b676295b99a7489d7d80810186e5b414bbeb36a3258d073fd696cc92dad40e50",
+ "benchmarks/audit_native_learning_signal.py": "48dda7c53d488d826e6ee19dfa8dff4342c6f68c7b104109ba02f9ea33930fbd",
+ "tests/test_native_output_audit.py": "07eed856325720541eb67842fea529c6decf7fb9f86932e95d85035e4b24515a",
+ "tests/plugins/test_native_heldout_training.py": "d18dca50a47aaa4a7bd49d644e8b74a4651225a79e23a3935bd833f4ff54f738",
+ "tests/plugins/test_rltt_online_cycle.py": "d2e36ca16f5fed6d229612aa42da0c97cfc53147f9936b89e5c614814190d893",
+ "tests/plugins/test_looped_grpo.py": "51af0f220b21331b745a0a3fdd21e403dec31cc8053c5f1ac41e9839b4479610",
+ "tests/test_native_learning_signal_audit.py": "60674e58a5a6ab1e42c8e080d02ae2fc255baa73e5d5ec6137b7d70b0eba505c",
+ "tests/test_native_runtime_audit.py": "583de0496f5b3424c617dd7238f7c1500da68a4864fa400d9548ac207a0da15f",
+ "vime/rollout/native_eval.py": "06a7aab463bd888f4d7946544f8f390d1d462504fe88120305e0fa5f4ca4a363",
+ "vime/rollout/vllm_rlt_rollout.py": "aa18f8806f6bfa0a894b3b0f67ecad0e669f7695351309e6f2f4e5b55ddbbeee",
+ "docs/native_output_recovery.md": "d3e1df1441a0e87ffdd5bfd128b61d142fb67f06989f4522cc538d42e26e9429"
+ },
+ "artifact_sha256": {
+ "audit_native_response_tokenizer.py": "0216710e96363e0c9d32f83bf53701e4acae71f37906b2c12cd9de529f79d321",
+ "native-output-final.log": "2fd155bf8c51f66251af04e218270ec383a6db962e63500495ad0411bb25f273",
+ "native-output-final.xml": "f5c4a9f88986fe8a674c9a346fbc7d5e32cd8e94c15cb1eb92e4b25a2654b7a0",
+ "native-output-initial.log": "d4867a66fdc061af434e11cb92ec551223f1190a2ac581eced1b876361eb022e",
+ "native-output-initial.xml": "66b8a1636dd56ea3df2e3f935f147d5371fdc91ddd1912a00b301caeaaf9af5f",
+ "native-output-tiny.log": "3352127eebc7b499ccfeb03af616890924ee0f9bb8a97cd9e92117067a0bd46f",
+ "native-output-tiny.xml": "f74f3d826fa947e9c34f7815a9e81aac8dfceae8a4954a74c5bedf68bacbda5e",
+ "native-output-tokenizer-source.json": "bdd16bb7077b9548dc9f0a690b41ef6e439072331980413bcb289942f52c1542",
+ "native-output-tokenizer-v1.json": "812e0cfa18af358ff9ca1e490bbb1c038bca1fdf09b3d3f9454069b5ceedcb90",
+ "native-output-tokenizer-v1.log": "c17bfecb66747c0e4a67ee13d6490400fa03dcf682d7545c80d1297d5cb38514",
+ "native-output-tokenizer.json": "6ce20866b2fc7dd5f0b0f3f3d4f0cb485c9a73ff0d0651d62fc39c598fe591bd",
+ "native-output-tokenizer.log": "c17bfecb66747c0e4a67ee13d6490400fa03dcf682d7545c80d1297d5cb38514",
+ "ouro-thinking-model-manifest.json": "22b0ab9886d283181acb6e51a4dbd19420be8c2da4474b653a042d2bb2e36081",
+ "resident_pytest.py": "2af5ce445da14f656c71e8d4817dcf85cd57402a77f50f612898c47f52f4d4f4",
+ "validation.json": "ef6cbaeb1f4b2f2ebb090cec90d689c25b7f4ca26dc5129cc6305dd1e12c9583"
+ }
+}
diff --git a/benchmarks/results/native-output-recovery/native-output-final.log b/benchmarks/results/native-output-recovery/native-output-final.log
new file mode 100644
index 000000000..12602c688
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-final.log
@@ -0,0 +1,244 @@
+torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py
+setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py
+============================= test session starts ==============================
+platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0
+rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime
+configfile: pyproject.toml
+plugins: platformdirs-4.12.2, anyio-4.15.1
+collected 245 items
+
+tests/test_native_output_audit.py .................... [ 8%]
+tests/plugins/test_native_heldout_training.py ... [ 9%]
+tests/test_native_eval_schedule.py ..... [ 11%]
+tests/test_native_runtime_identity.py ............ [ 16%]
+tests/test_native_runtime_audit.py ............. [ 21%]
+tests/test_native_runtime_mcore.py ... [ 22%]
+tests/test_native_checkpoint_audit.py ................... [ 30%]
+tests/test_native_learning_signal_audit.py ........ [ 33%]
+tests/test_native_qualification_recipe.py ....... [ 36%]
+tests/test_looped_grpo_recipe.py ....................................... [ 52%]
+........................................................................ [ 82%]
+.......... [ 86%]
+tests/rollout_backends/test_native_rlt_contract.py ..... [ 88%]
+tests/rollout_backends/test_native_colocation.py ............ [ 93%]
+tests/rollout_backends/test_native_rlt_evaluation.py ................. [100%]
+
+=============================== warnings summary ===============================
+../../looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: 14 warnings
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: DeprecationWarning: `torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9: DeprecationWarning: The following imports from `dynamic_context.py` will be removed in this file in `megatron-core` 0.14. The imports here result in a cyclic import issue that causes rotary embeddings to import from Apex rather than Transformer Engine.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24: UserWarning: Transformer Engine and Apex are not installed. Falling back to Torch optimizers.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier, multi_tensor_l2norm, and multi_tensor_scale
+ warnings.warn(
+
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige]
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/transformer/transformer_config.py:1734: UserWarning: full scope is deprecated. Use empty cuda_graph_scope to capture the whole layer.
+ warnings.warn(
+
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/models/backends.py:21: UserWarning: Apex is not installed. Falling back to Torch Norm
+ warnings.warn("Apex is not installed. Falling back to Torch Norm")
+
+tests/test_native_checkpoint_audit.py: 16 warnings
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/utils.py:485: UserWarning: torch.distributed is disabled, unavailable or uninitialized, assuming the intent is to save in a single process.
+ return func(*args, **kwargs)
+
+tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[model]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e0/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found.
+ local_plan = storage_writer.prepare_local_plan(local_plan)
+
+tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[moment]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e1/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found.
+ local_plan = storage_writer.prepare_local_plan(local_plan)
+
+tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[rng]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e2/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found.
+ local_plan = storage_writer.prepare_local_plan(local_plan)
+
+-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
+- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-final.xml -
+============================== slowest durations ===============================
+2.66s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+0.89s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]
+0.79s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite]
+0.60s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication]
+0.50s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige]
+0.49s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round]
+0.48s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt]
+0.48s call tests/test_native_output_audit.py::test_identical_outputs_with_zero_learning_signal_do_not_qualify
+0.45s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo]
+0.38s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[None]
+0.36s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication]
+0.36s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round]
+0.36s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version]
+0.35s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo]
+0.35s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor]
+0.34s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text]
+0.34s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite]
+0.33s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient]
+0.33s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor]
+0.33s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[reward]
+0.32s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt]
+0.32s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final]
+0.32s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row]
+0.31s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output]
+0.31s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed]
+0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id]
+0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text]
+0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix]
+0.29s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[prefix]
+0.29s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version]
+0.28s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch]
+0.28s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text]
+0.28s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed]
+0.27s call tests/test_native_output_audit.py::test_predeclared_score_tolerance_reports_small_finite_difference
+0.27s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos]
+0.26s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final]
+0.25s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix]
+0.25s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient]
+0.24s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[counters]
+0.23s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row]
+0.22s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos]
+0.22s setup tests/test_native_output_audit.py::test_identical_outputs_with_zero_learning_signal_do_not_qualify
+0.20s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text]
+0.20s call tests/test_native_runtime_identity.py::test_reports_process_and_loaded_bytes_without_copying_model_state
+0.20s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id]
+0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch]
+0.19s setup tests/test_native_output_audit.py::test_predeclared_score_tolerance_reports_small_finite_difference
+0.18s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output]
+0.16s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[optimizer_mode]
+0.13s call tests/test_native_learning_signal_audit.py::test_signal_gate_never_claims_optimizer_resume_or_convergence[grpo]
+0.13s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[gradient]
+0.13s call tests/test_native_learning_signal_audit.py::test_signal_gate_never_claims_optimizer_resume_or_convergence[rltt]
+0.12s call tests/test_native_learning_signal_audit.py::test_nonzero_gradient_and_new_versions_alone_do_not_pass
+0.09s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[optimizer_step]
+0.08s call tests/rollout_backends/test_native_rlt_contract.py::test_http_client_concurrency_matches_backend[vllm]
+0.07s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[ouro]
+0.06s call tests/test_native_runtime_identity.py::test_native_init_records_real_model_through_explicit_cpu_transport[True]
+0.06s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[huginn]
+0.05s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[reference]
+0.05s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[iteration]
+0.04s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-learning-expected0]
+0.04s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[index]
+0.04s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[rng]
+0.04s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-nanbeige]
+0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[moment]
+0.03s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[environment]
+0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[model]
+0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[scheduler]
+0.03s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[nanbeige]
+0.03s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-grpo]
+0.03s call tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization
+0.03s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-learning-expected0]
+0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-momentum-expected2]
+0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-momentum-expected2]
+0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-decay-expected1]
+0.02s call tests/rollout_backends/test_native_rlt_contract.py::test_huginn_aliases_static_buffer_and_noise_profile
+0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-decay-expected1]
+0.02s setup tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization
+0.02s call tests/test_native_checkpoint_audit.py::test_missing_adam_and_rng_do_not_qualify
+0.02s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[revision]
+0.01s call tests/rollout_backends/test_native_rlt_contract.py::test_incomplete_publication_cannot_resume_or_reuse_old_manifest
+0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_policy_publication_between_batches_invalidates_evaluation
+0.01s setup tests/rollout_backends/test_native_rlt_evaluation.py::test_unsupported_eval_settings_reject_before_generation[min_new_tokens-1]
+0.01s setup tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[scheduler]
+0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_sampling_and_chat_overrides_are_used
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[job]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-nanbeige]
+0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_reward_key_and_metadata_override
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[actor]
+0.01s setup tests/test_native_runtime_audit.py::test_cli_binds_all_six_synthetic_reports_and_records_input_hashes
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[epoch]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[source]
+0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-True]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-nanbeige]
+0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-grpo]
+0.01s teardown tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[worker]
+0.01s call tests/rollout_backends/test_native_rlt_contract.py::test_http_client_concurrency_matches_backend[vllm-rlt]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[optimizer]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[duplicate]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[iteration]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[process]
+0.01s teardown tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[gradient]
+0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-rlt-True]
+0.01s setup tests/test_native_qualification_recipe.py::test_changed_data_and_new_cluster_are_rejected
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-False-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-huginn_raven]
+0.01s call tests/test_native_runtime_audit.py::test_cli_binds_all_six_synthetic_reports_and_records_input_hashes
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-ouro]
+0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[unfinished]
+0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-rltt]
+0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-rlt-False]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-True-ouro]
+0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-rltt]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-True-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-False-nanbeige]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-ppo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-False-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-ouro]
+0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_reordered_or_missing_heldout_samples_are_rejected
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-huginn_raven]
+0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[split-grpo]
+0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-grpo]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-ppo-False-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-ppo-True-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-False-huginn_raven]
+0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[iteration]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-True-nanbeige]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-ouro]
+0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[split-rltt]
+0.01s setup tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-nanbeige]
+0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-rltt]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-nanbeige]
+0.01s setup tests/rollout_backends/test_native_rlt_contract.py::test_huginn_aliases_static_buffer_and_noise_profile
+0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-rltt]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-ppo-True-nanbeige]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-nanbeige]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-True-huginn_raven]
+0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-grpo]
+0.01s setup tests/rollout_backends/test_native_rlt_contract.py::test_incomplete_publication_cannot_resume_or_reuse_old_manifest
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-False-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-False-nanbeige]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-3-dppo-False-nanbeige]
+0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[worker]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-flow-dppo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-True-ouro]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-nanbeige]
+0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[revision]
+0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[epoch]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-False-huginn_raven]
+0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-False-ouro]
+
+(573 durations < 0.005s hidden. Use -vv to show these durations.)
+====================== 245 passed, 42 warnings in 34.25s =======================
diff --git a/benchmarks/results/native-output-recovery/native-output-final.xml b/benchmarks/results/native-output-recovery/native-output-final.xml
new file mode 100644
index 000000000..e1b4553f7
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-final.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/benchmarks/results/native-output-recovery/native-output-initial.log b/benchmarks/results/native-output-recovery/native-output-initial.log
new file mode 100644
index 000000000..7fbadb3a8
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-initial.log
@@ -0,0 +1,52 @@
+torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py
+setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py
+============================= test session starts ==============================
+platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0
+rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime
+configfile: pyproject.toml
+plugins: platformdirs-4.12.2, anyio-4.15.1
+collected 18 items
+
+tests/test_native_output_audit.py .................. [100%]
+
+- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-initial.xml -
+============================== slowest durations ===============================
+0.25s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output]
+0.23s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch]
+0.23s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo]
+0.22s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final]
+0.22s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor]
+0.22s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt]
+0.21s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite]
+0.20s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row]
+0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor]
+0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos]
+0.18s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient]
+0.18s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo]
+0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient]
+0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round]
+0.17s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output]
+0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite]
+0.17s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication]
+0.17s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt]
+0.16s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos]
+0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final]
+0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text]
+0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row]
+0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round]
+0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication]
+0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text]
+0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix]
+0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text]
+0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text]
+0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed]
+0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed]
+0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version]
+0.14s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id]
+0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix]
+0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id]
+0.14s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version]
+0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch]
+
+(18 durations < 0.005s hidden. Use -vv to show these durations.)
+============================= 18 passed in 10.66s ==============================
diff --git a/benchmarks/results/native-output-recovery/native-output-initial.xml b/benchmarks/results/native-output-recovery/native-output-initial.xml
new file mode 100644
index 000000000..6c0278ec9
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-initial.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/benchmarks/results/native-output-recovery/native-output-tiny.log b/benchmarks/results/native-output-recovery/native-output-tiny.log
new file mode 100644
index 000000000..762fcb7aa
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tiny.log
@@ -0,0 +1,55 @@
+torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py
+setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py
+============================= test session starts ==============================
+platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0
+rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime
+configfile: pyproject.toml
+plugins: platformdirs-4.12.2, anyio-4.15.1
+collected 3 items
+
+tests/plugins/test_native_heldout_training.py ... [100%]
+
+=============================== warnings summary ===============================
+../../looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: 14 warnings
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: DeprecationWarning: `torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9: DeprecationWarning: The following imports from `dynamic_context.py` will be removed in this file in `megatron-core` 0.14. The imports here result in a cyclic import issue that causes rotary embeddings to import from Apex rather than Transformer Engine.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24: UserWarning: Transformer Engine and Apex are not installed. Falling back to Torch optimizers.
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale
+ warnings.warn(
+
+../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier, multi_tensor_l2norm, and multi_tensor_scale
+ warnings.warn(
+
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige]
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/transformer/transformer_config.py:1734: UserWarning: full scope is deprecated. Use empty cuda_graph_scope to capture the whole layer.
+ warnings.warn(
+
+tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+ /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/models/backends.py:21: UserWarning: Apex is not installed. Falling back to Torch Norm
+ warnings.warn("Apex is not installed. Falling back to Torch Norm")
+
+-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
+- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-tiny.xml -
+============================== slowest durations ===============================
+0.55s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]
+0.44s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro]
+0.26s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige]
+
+(6 durations < 0.005s hidden. Use -vv to show these durations.)
+======================== 3 passed, 23 warnings in 7.18s ========================
diff --git a/benchmarks/results/native-output-recovery/native-output-tiny.xml b/benchmarks/results/native-output-recovery/native-output-tiny.xml
new file mode 100644
index 000000000..061b6715d
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tiny.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json b/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json
new file mode 100644
index 000000000..2ea7515ae
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json
@@ -0,0 +1,13 @@
+{
+ "revision": "3aaa2224253a92ca45cf2e3d427c360e1ef9c93d",
+ "source_manifest_sha256": "22b0ab9886d283181acb6e51a4dbd19420be8c2da4474b653a042d2bb2e36081",
+ "verified_local_sha256": {
+ "config.json": "44e42ec2ed97f49f20f87985688b6e1be9dd61bbfe9f8a349daac192126e2c55",
+ "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510",
+ "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685",
+ "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d",
+ "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448",
+ "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c"
+ },
+ "scope": "six retained local configuration/tokenizer files; no weight file or remote node read"
+}
diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json
new file mode 100644
index 000000000..6e3b14e76
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json
@@ -0,0 +1,300 @@
+{
+ "scope": "answer-replay controls from known labels with invented scores; no model generation or training",
+ "qualification_sha256": "d7bf3edcd0a05ee25b93bf7abaf1f739a4f8da4a769ac5fc00cf87a423e67f9c",
+ "eos_token_id": 2,
+ "tokenizer_class": "GPT2TokenizerFast",
+ "trust_remote_code": false,
+ "local_files_only": true,
+ "rows": [
+ {
+ "split": "train",
+ "id": "number_theory/train/483",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "fc1f7be12dbfa224a035deacb237385eaa186254f1bb5c0ec09d88b16c040fda"
+ },
+ {
+ "split": "train",
+ "id": "number_theory/train/483",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/799",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "f6685e2e3e68191bf764c6522e00cbbb3c4a0418273b0849026cbf249914abb6"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/799",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/445",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "095e4e4bd915611b027de271873d6290329f8bf905f2df91e996ea6403ad27ad"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/445",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1647",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "7cf3be7279e406330d89d2f9fe549bff02019fb3bb5c15646d836b4f06ae2e41"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1647",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/161",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "fa315fb7666d9cb89a5bbfb70b23326f9b9709281d35cf44749156c70b39319a"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/161",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "precalculus/train/467",
+ "expected_reward": 1,
+ "response_tokens": 17,
+ "token_sha256": "2549be62b1653f6ac90e1c0342a29db92860aeb858eb6b5dc5b3dc582165f0cc"
+ },
+ {
+ "split": "train",
+ "id": "precalculus/train/467",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/963",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "24ab47bd34a444b3d3a2aab5f325ee0eccde32e0ab679f07ccf0412981f6b665"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/963",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1201",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "29555376478bc957b03657f950165fc0bbf29cd570d498a735e9fa70185e6f21"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1201",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/264",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "b0f6ebc703631ae26a44d7e5a44e1ea79edd2d61067318fcc82ce66b186a1154"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/264",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/682",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "4f1aec4a17fc68722817f90a976ab9394ae6921953a978df7447444109f7c49c"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/682",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/304",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "84cdf72152c7a477452a56afb50422429510a9f3fa9c89422c9f003262662c55"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/304",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/496",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "109b0ae07355941d124dcdc04519aaae711021b08c1cbdaa7e9659fda9978467"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/496",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/309",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "2bf959d161f53afd06216fd96013e723b8121129c3b88d40748b9824637ed1f6"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/309",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "algebra/test/348",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "3f39f147dc7f937eda7abcc49449cb2fdaadfd511e12a38b0f17dd32e4dbcbc3"
+ },
+ {
+ "split": "development",
+ "id": "algebra/test/348",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/72",
+ "expected_reward": 1,
+ "response_tokens": 13,
+ "token_sha256": "5b93508ebc8426814ba885a3731c087995b3d66a7afea226a119870416d4b5c3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/72",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/267",
+ "expected_reward": 1,
+ "response_tokens": 13,
+ "token_sha256": "bc42ed00afc072fa9957397815f2c935e7bab86131ac675ee554da6444c8bdbd"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/267",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/285",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "9a78c195a1a46e853ffb6106c66ec595bdc0a1dd799372af509699f3df40295d"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/285",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "geometry/test/284",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "geometry/test/284",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "7acedb2271a5fef175b49f5e86e0546ba44fcbe6dfef254139e2d58f80413e15"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/822",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "286ce91e738b4aacb334049b5cd9cc221a374a1865f120b31561f031843e12f3"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/822",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/748",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "d766509ed8a47817b152b1b1a9558a9b8dac03859e17be0a35adb58a96fa0ebf"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/748",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ }
+ ],
+ "cuda_initialized": false,
+ "model_generation": "NOT_RUN",
+ "source_sha256": "d8c99bfc902c5b24973d0b00b03d5d8f8b7fab98cb5ce77e0827fb1cac666a92",
+ "tokenizer_sha256": {
+ "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d",
+ "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448",
+ "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685",
+ "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c",
+ "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510"
+ }
+}
diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log
new file mode 100644
index 000000000..a59ddbfe8
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log
@@ -0,0 +1,3 @@
+torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py
+setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py
+{"answer_replay_controls": 40, "eos_token_id": 2, "model_generation": "NOT_RUN", "cuda_initialized": false}
diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer.json b/benchmarks/results/native-output-recovery/native-output-tokenizer.json
new file mode 100644
index 000000000..af7fa02a6
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tokenizer.json
@@ -0,0 +1,300 @@
+{
+ "scope": "answer-replay controls from known labels with invented scores; no model generation or training",
+ "qualification_sha256": "d7bf3edcd0a05ee25b93bf7abaf1f739a4f8da4a769ac5fc00cf87a423e67f9c",
+ "eos_token_id": 2,
+ "tokenizer_class": "GPT2TokenizerFast",
+ "trust_remote_code": false,
+ "local_files_only": true,
+ "rows": [
+ {
+ "split": "train",
+ "id": "number_theory/train/483",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "fc1f7be12dbfa224a035deacb237385eaa186254f1bb5c0ec09d88b16c040fda"
+ },
+ {
+ "split": "train",
+ "id": "number_theory/train/483",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/799",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "f6685e2e3e68191bf764c6522e00cbbb3c4a0418273b0849026cbf249914abb6"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/799",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/445",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "095e4e4bd915611b027de271873d6290329f8bf905f2df91e996ea6403ad27ad"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/445",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1647",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "7cf3be7279e406330d89d2f9fe549bff02019fb3bb5c15646d836b4f06ae2e41"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1647",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/161",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "fa315fb7666d9cb89a5bbfb70b23326f9b9709281d35cf44749156c70b39319a"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/161",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "precalculus/train/467",
+ "expected_reward": 1,
+ "response_tokens": 17,
+ "token_sha256": "2549be62b1653f6ac90e1c0342a29db92860aeb858eb6b5dc5b3dc582165f0cc"
+ },
+ {
+ "split": "train",
+ "id": "precalculus/train/467",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/963",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "24ab47bd34a444b3d3a2aab5f325ee0eccde32e0ab679f07ccf0412981f6b665"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/963",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1201",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "29555376478bc957b03657f950165fc0bbf29cd570d498a735e9fa70185e6f21"
+ },
+ {
+ "split": "train",
+ "id": "algebra/train/1201",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/264",
+ "expected_reward": 1,
+ "response_tokens": 8,
+ "token_sha256": "b0f6ebc703631ae26a44d7e5a44e1ea79edd2d61067318fcc82ce66b186a1154"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/264",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/682",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "4f1aec4a17fc68722817f90a976ab9394ae6921953a978df7447444109f7c49c"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/682",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/304",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "84cdf72152c7a477452a56afb50422429510a9f3fa9c89422c9f003262662c55"
+ },
+ {
+ "split": "train",
+ "id": "prealgebra/train/304",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/496",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "109b0ae07355941d124dcdc04519aaae711021b08c1cbdaa7e9659fda9978467"
+ },
+ {
+ "split": "train",
+ "id": "geometry/train/496",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/309",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "2bf959d161f53afd06216fd96013e723b8121129c3b88d40748b9824637ed1f6"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/309",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "algebra/test/348",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "3f39f147dc7f937eda7abcc49449cb2fdaadfd511e12a38b0f17dd32e4dbcbc3"
+ },
+ {
+ "split": "development",
+ "id": "algebra/test/348",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/72",
+ "expected_reward": 1,
+ "response_tokens": 13,
+ "token_sha256": "5b93508ebc8426814ba885a3731c087995b3d66a7afea226a119870416d4b5c3"
+ },
+ {
+ "split": "development",
+ "id": "precalculus/test/72",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/267",
+ "expected_reward": 1,
+ "response_tokens": 13,
+ "token_sha256": "bc42ed00afc072fa9957397815f2c935e7bab86131ac675ee554da6444c8bdbd"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/267",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/285",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "9a78c195a1a46e853ffb6106c66ec595bdc0a1dd799372af509699f3df40295d"
+ },
+ {
+ "split": "development",
+ "id": "intermediate_algebra/test/285",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "geometry/test/284",
+ "expected_reward": 1,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "geometry/test/284",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "7acedb2271a5fef175b49f5e86e0546ba44fcbe6dfef254139e2d58f80413e15"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/822",
+ "expected_reward": 1,
+ "response_tokens": 11,
+ "token_sha256": "286ce91e738b4aacb334049b5cd9cc221a374a1865f120b31561f031843e12f3"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/822",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/748",
+ "expected_reward": 1,
+ "response_tokens": 9,
+ "token_sha256": "d766509ed8a47817b152b1b1a9558a9b8dac03859e17be0a35adb58a96fa0ebf"
+ },
+ {
+ "split": "development",
+ "id": "prealgebra/test/748",
+ "expected_reward": 0,
+ "response_tokens": 7,
+ "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3"
+ }
+ ],
+ "cuda_initialized": false,
+ "model_generation": "NOT_RUN",
+ "source_sha256": "e55d2fa5f89a45d7afdb8fa22724f33f4fb70396830e4584957bcffbcb6fb598",
+ "tokenizer_sha256": {
+ "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d",
+ "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448",
+ "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685",
+ "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c",
+ "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510"
+ }
+}
diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer.log b/benchmarks/results/native-output-recovery/native-output-tokenizer.log
new file mode 100644
index 000000000..a59ddbfe8
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/native-output-tokenizer.log
@@ -0,0 +1,3 @@
+torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py
+setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py
+{"answer_replay_controls": 40, "eos_token_id": 2, "model_generation": "NOT_RUN", "cuda_initialized": false}
diff --git a/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json b/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json
new file mode 100644
index 000000000..96f2b6edd
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json
@@ -0,0 +1,49 @@
+{
+ "repo": "ByteDance/Ouro-1.4B-Thinking",
+ "revision": "3aaa2224253a92ca45cf2e3d427c360e1ef9c93d",
+ "files": [
+ {
+ "path": "config.json",
+ "bytes": 1471,
+ "sha256": "44e42ec2ed97f49f20f87985688b6e1be9dd61bbfe9f8a349daac192126e2c55"
+ },
+ {
+ "path": "merges.txt",
+ "bytes": 466391,
+ "sha256": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510"
+ },
+ {
+ "path": "model.safetensors",
+ "bytes": 2869336434,
+ "sha256": "6730581fd366f6d1689728c61637520228385cdfc17c0b24f19aa840b00565fb"
+ },
+ {
+ "path": "special_tokens_map.json",
+ "bytes": 965,
+ "sha256": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685"
+ },
+ {
+ "path": "tokenizer.json",
+ "bytes": 3522644,
+ "sha256": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d"
+ },
+ {
+ "path": "tokenizer_config.json",
+ "bytes": 4392,
+ "sha256": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448"
+ },
+ {
+ "path": "vocab.json",
+ "bytes": 800656,
+ "sha256": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c"
+ }
+ ],
+ "source": "official immutable metadata and official CDN",
+ "task_owned_root": "/root/autodl-tmp/0z5a/flashrlt-20261005/models/ouro-1.4b-thinking",
+ "independent_hash_completed_utc": "2026-10-04T20:59:49Z",
+ "stage_exit_code": 0,
+ "large_weight_inode": "2304:2159281731",
+ "source_reader_released": true,
+ "cleanup_eligible": false,
+ "cleanup_reason": "Required experiments remain unfinished; own read-only hardlinks retained"
+}
diff --git a/benchmarks/results/native-output-recovery/resident_pytest.py b/benchmarks/results/native-output-recovery/resident_pytest.py
new file mode 100644
index 000000000..e18b0b8e3
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/resident_pytest.py
@@ -0,0 +1,64 @@
+"""Run existing local dependencies, failing promptly on iCloud-evicted source.
+
+No package is installed, replaced or stubbed. Evicted bytecode falls back to
+its original source through Python's normal SourceFileLoader behavior.
+"""
+
+import base64
+import csv
+import hashlib
+import importlib.machinery
+import linecache
+import os
+import runpy
+import sys
+
+import pytest
+import torch
+
+original_get_data = importlib.machinery.SourceFileLoader.get_data
+original_getline = linecache.getline
+site = "/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/"
+mirror = "/Users/0z5a/Documents/infra/vime-sm120-initial-20260912/.venv/lib/python3.12/site-packages/"
+with open(site + "setuptools-84.0.0.dist-info/RECORD") as stream:
+ recorded = {row[0]: row[1] for row in csv.reader(stream)}
+
+
+def concise_exception(kind, error, trace):
+ while trace is not None:
+ print(f"{trace.tb_frame.f_code.co_filename}:{trace.tb_lineno}", file=sys.stderr)
+ trace = trace.tb_next
+ print(f"{kind.__name__}: {error}", file=sys.stderr)
+
+
+def resident_line(filename, lineno, module_globals=None):
+ if os.path.exists(filename) and os.stat(filename).st_flags & 0x40000000:
+ return ""
+ return original_getline(filename, lineno, module_globals)
+
+
+def resident_data(loader, path):
+ if os.path.exists(path) and os.stat(path).st_flags & 0x40000000:
+ relative = path.removeprefix(site)
+ other = mirror + relative
+ if relative in recorded and path.endswith(".py") and os.path.isfile(other) and not os.stat(other).st_flags & 0x40000000:
+ data = original_get_data(loader, other)
+ digest = "sha256=" + base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=")
+ assert digest == recorded[relative], relative
+ print(f"resident same-RECORD source: {other}", flush=True)
+ return data
+ raise OSError(61, "iCloud file is not resident", path)
+ return original_get_data(loader, path)
+
+
+importlib.machinery.SourceFileLoader.get_data = resident_data
+linecache.getline = resident_line
+sys.excepthook = concise_exception
+import setuptools
+print(f"torch={torch.__version__} {torch.__file__}", flush=True)
+print(f"setuptools={setuptools.__version__} {setuptools.__file__}", flush=True)
+if sys.argv[1:2] == ["--script"]:
+ sys.argv = sys.argv[2:]
+ runpy.run_path(sys.argv[0], run_name="__main__")
+else:
+ raise SystemExit(pytest.main(sys.argv[1:]))
diff --git a/benchmarks/results/native-output-recovery/validation.json b/benchmarks/results/native-output-recovery/validation.json
new file mode 100644
index 000000000..2ffb9965e
--- /dev/null
+++ b/benchmarks/results/native-output-recovery/validation.json
@@ -0,0 +1,82 @@
+{
+ "parent": "11efa7420172bcf348b28c32bbcd88cae482f94a",
+ "cpu_component_rlt_head": "334f243e1b7b374682e138b641ce9cb8236a9157",
+ "official_qualification_rlt_pin": "fd993ec5512904b68e16f4d541682c076c487b5d",
+ "tests": {
+ "name": "pytest",
+ "errors": "0",
+ "failures": "0",
+ "skipped": "0",
+ "tests": "245",
+ "time": "33.845",
+ "timestamp": "2026-10-05T15:19:16.497705+08:00",
+ "hostname": "192.168.10.10"
+ },
+ "new_output_audit_cases": 20,
+ "expanded_existing_model_cases": 3,
+ "other_existing_cases": 222,
+ "paired_tiny_cpu_outputs": [
+ {
+ "case": "test_evaluation_preserves_updates_and_fresh_resume[ouro]",
+ "samples": 8,
+ "max_score_error": 0.0
+ },
+ {
+ "case": "test_evaluation_preserves_updates_and_fresh_resume[nanbeige]",
+ "samples": 8,
+ "max_score_error": 0.0
+ },
+ {
+ "case": "test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]",
+ "samples": 8,
+ "max_score_error": 0.0
+ }
+ ],
+ "answer_replay_controls": 40,
+ "natural_exit": {
+ "29315": 0,
+ "90984": 0,
+ "18693": 0,
+ "22020": 0,
+ "22814": 0
+ },
+ "scope": "CPU controls; actual tiny sampling/Adam with fresh objects in one process; synthetic Ray/process records; no official model generation",
+ "actual_ray_cuda_e2e": "NOT_RUN",
+ "reward_convergence": "NOT_ESTABLISHED",
+ "existing_python": "/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/bin/python",
+ "test_environment": {
+ "PYTHONDONTWRITEBYTECODE": "1",
+ "FROZENLIST_NO_EXTENSIONS": "1",
+ "MULTIDICT_NO_EXTENSIONS": "1",
+ "AIOHTTP_NO_EXTENSIONS": "1",
+ "YARL_NO_EXTENSIONS": "1",
+ "OMP_NUM_THREADS": "1",
+ "PYTHONPATH": ".:../rlt:tests/plugins:/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron"
+ },
+ "test_files": [
+ "tests/plugins/test_native_heldout_training.py",
+ "tests/rollout_backends/test_native_colocation.py",
+ "tests/rollout_backends/test_native_rlt_contract.py",
+ "tests/rollout_backends/test_native_rlt_evaluation.py",
+ "tests/test_looped_grpo_recipe.py",
+ "tests/test_native_checkpoint_audit.py",
+ "tests/test_native_eval_schedule.py",
+ "tests/test_native_learning_signal_audit.py",
+ "tests/test_native_output_audit.py",
+ "tests/test_native_qualification_recipe.py",
+ "tests/test_native_runtime_audit.py",
+ "tests/test_native_runtime_identity.py",
+ "tests/test_native_runtime_mcore.py"
+ ],
+ "pytest_options": [
+ "-q",
+ "-p",
+ "no:cacheprovider",
+ "--tb=short",
+ "-o",
+ "junit_family=legacy"
+ ],
+ "harness": "../bench/resident_pytest.py",
+ "environment_mutation": false,
+ "process_signals": false
+}
diff --git a/docs/native_output_recovery.md b/docs/native_output_recovery.md
new file mode 100644
index 000000000..313233055
--- /dev/null
+++ b/docs/native_output_recovery.md
@@ -0,0 +1,95 @@
+# Native output and held-out recovery qualification
+
+Checkpoint equality alone cannot establish that a resumed worker generated the
+same samples, used the same publication, or evaluated every held-out example.
+`benchmarks/audit_native_outputs.py` checks those outputs for the frozen
+three-update Ouro Thinking qualification. It builds on the runtime records in
+[draft #20](https://github.com/0z5a/vime/pull/20) and the raw learning-signal audit.
+No training or serving behavior changes in this increment.
+
+For each continuous/resumed run, it reopens all 96 training samples and all
+32 held-out samples: eight development questions at completed updates 0,1,2,3.
+It verifies actual train/development IDs against the frozen selection and token
+audit, includes every development row in order, and checks seeds, R4 traces,
+greedy evaluation settings, policy versions, EOS/truncation and finite scores.
+Saved response text must decode from the saved response tokens; rewards are
+regraded from that text and the fixed label.
+
+Each evaluation has one publication digest. Evaluations 0–2 must match the
+corresponding subsequent training rollouts; the final evaluation must use a
+fourth distinct publication. The first three resumed evaluations belong to the
+split worker, while evaluation 3 belongs to the newly started worker. The raw
+startup and process records are rechecked, not replaced by a detached summary.
+
+Across runs, tokens, answers, rewards, statuses, metadata and semantic traces
+must match. Only `runtime_epoch` and `request_id` are excluded from direct trace
+equality: epoch is separately bound to the phase's worker record, and held-out
+request IDs must be nonempty and unique within their round. Scores, advantages,
+returns, KL, reference/current policy scores and gradient norms use the declared
+FP32 comparison tolerance `atol=1e-5, rtol=3e-5`; maximum absolute differences are
+reported. Masks match exactly. This tolerance is fixed before official model
+execution and is not a BF16 qualification.
+
+An identical pair with no mixed-reward/nonzero-advantage/gradient update remains
+`output_equivalence_pass=true`, but `output_and_signal_pass=false` and the CLI
+returns 1. The report hashes all 39 consumed evidence inputs and the local
+tokenizer files, and preserves both four-point reward curves. It does not turn
+this short qualification into a convergence experiment.
+
+```bash
+python -m benchmarks.audit_native_outputs \
+ --continuous RUNS/rltt/continuous --resumed RUNS/rltt/resumed \
+ --packet PACKET --input-audit INPUT_AUDIT.json \
+ --tokenizer LOCAL_TOKENIZER --algorithm rltt --output output-audit.json
+```
+
+Use `--algorithm grpo` for the matched GRPO run. The tokenizer loads from local
+files with remote code disabled. This command consumes completed, task-owned
+experiment dumps; it does not launch workers. Weight identity, checkpoint/Adam
+state, frozen-source membership and full-framework/GPU execution still require
+their separate evidence. The older/fused Adam format restriction is unchanged.
+
+## Validation
+
+The final suite has **245 distinct CPU passes** in 34.25 seconds, with 42 retained
+MCore/DCP warnings. It includes 20 new output-gate cases, three expanded existing
+native sampling/RLTT/Adam tests, and 222 existing scheduling, runtime, checkpoint,
+signal, recipe and adapter checks. Earlier 18- and 3-case runs overlap it.
+
+The CLI controls use synthetic saved runs and Ray/process records with a real
+WordLevel tokenizer. Sixteen corruption cases cover missing rounds/rows,
+incorrect IDs/prefixes/text/seeds/versions/epochs/EOS, nonfinite scores, wrong or
+stale publications, changed output, changed training tensors, changed gradient
+norm and training text that does not decode from its tokens. Separate controls
+exercise zero learning signal and a small finite score difference.
+
+The three existing model tests generate real tiny native samples, compute
+token-parity training rewards, perform AdamW updates and restore actor/reference/
+optimizer state into fresh objects in the **same process**. Their held-out
+tokenizer and Ray transport are doubles. The new comparator consumes their raw
+held-out sample dictionaries before and after the recovered update:
+
+| Tiny CPU model | Paired held-out samples | Tokens/reward/semantic trace | Maximum score difference | Speedup |
+|---|---:|---|---:|---|
+| Ouro | 8 | Exact | 0 | NOT_MEASURED |
+| Nanbeige | 8 | Exact | 0 | NOT_MEASURED |
+| Huginn | 8 | Exact | 0 | NOT_MEASURED |
+
+The retained official Ouro Thinking tokenizer also passes 40 answer-replay
+controls over the 12 training and eight development inputs. These use known
+labels and invented scores, and verify decoding, reward grading and EOS ID 2;
+they are **not model-generated answers**. Six local configuration/tokenizer files
+match the retained model manifest at `3aaa2224253a92ca45cf2e3d427c360e1ef9c93d`;
+all input prefixes match the retained qualification evidence. No weight file or
+remote node was read for this check. No CUDA initialization or environment
+mutation occurred.
+
+| Required E2E comparison | Baseline throughput | FlashRLT throughput | Speedup | Peak memory reduction | Reward convergence |
+|---|---:|---:|---:|---:|---|
+| Official Ouro Thinking continuous/fresh-process recovery | NOT_RUN | NOT_RUN | NOT_MEASURED | NOT_MEASURED | NOT_ESTABLISHED |
+| RLTT / FlashLoop / slime / Megatron campaign | NOT_RUN | NOT_RUN | NOT_MEASURED | NOT_MEASURED | NOT_ESTABLISHED |
+
+Raw logs/XML, tokenizer-control records, validation receipt and source/artifact
+hashes are in `benchmarks/results/native-output-recovery/`. CPU suite elapsed
+time is not a model speedup. The full experiment matrix and paper's quality and
+system claims remain pending their actual measurements.
diff --git a/tests/plugins/test_native_heldout_training.py b/tests/plugins/test_native_heldout_training.py
index 79369499e..93febcf21 100644
--- a/tests/plugins/test_native_heldout_training.py
+++ b/tests/plugins/test_native_heldout_training.py
@@ -14,11 +14,12 @@
from test_looped_grpo import cpu_engine, publish
from test_rltt_online_cycle import pair, update
+from benchmarks.audit_native_outputs import compare_samples
from vime.rollout import native_eval
from vime.utils.eval_config import EvalDatasetConfig
-def evaluate(engine, data, monkeypatch):
+def evaluate(engine, data, monkeypatch, capture=None):
tokenizer = SimpleNamespace(
encode=lambda prompt, **kwargs: [int(value) for value in prompt.split()],
decode=lambda tokens, **kwargs: r"\boxed{" + str(tokens[-1]) + "}",
@@ -59,6 +60,8 @@ def evaluate(engine, data, monkeypatch):
)
)
output = native_eval.evaluate(args)
+ if capture is not None:
+ capture.append([sample.to_dict() for sample in output.data["heldout"]["samples"]])
return [
{
"tokens": sample.tokens,
@@ -82,7 +85,7 @@ def assert_optimizer_equal(left, right):
def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeypatch, record_property):
data = tmp_path / "heldout.jsonl"
data.write_text('{"prompt":"4 5","label":"2"}\n{"prompt":"7 8","label":"3"}\n')
- evaluations, reference_runs, final_states = [], [], []
+ evaluations, raw_evaluations, reference_runs, final_states = [], [], [], []
for enabled in (False, True):
directory = tmp_path / str(enabled)
directory.mkdir()
@@ -94,7 +97,7 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp
for step in range(3):
records.append(update(actor, reference, optimizer, engine, family, directory, step, "sdpa-reference"))
if enabled:
- evaluations.append(evaluate(engine, data, monkeypatch))
+ evaluations.append(evaluate(engine, data, monkeypatch, raw_evaluations))
if enabled and step == 1:
torch.save(
{
@@ -123,12 +126,19 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp
engine = cpu_engine(native, family)
publish(resumed, engine, family, tmp_path / "restored-policy", 3)
torch.set_rng_state(checkpoint["rng"])
- assert evaluate(engine, data, monkeypatch) == evaluations[1]
+ resumed_outputs = []
+ assert evaluate(engine, data, monkeypatch, resumed_outputs) == evaluations[1]
directory = tmp_path / "fresh"
directory.mkdir()
actual = update(resumed, reference, optimizer, engine, family, directory, 2, "sdpa-reference")
assert actual == reference_runs[1][2]
- assert evaluate(engine, data, monkeypatch) == evaluations[2]
+ assert evaluate(engine, data, monkeypatch, resumed_outputs) == evaluations[2]
+ errors = [
+ compare_samples(left, right)
+ for expected, actual in zip(raw_evaluations[1:], resumed_outputs, strict=True)
+ for left, right in zip(expected, actual, strict=True)
+ ]
+ assert len(errors) == 8
for name, expected in final_states[1][0].items():
assert torch.equal(expected, resumed.state_dict()[name]), name
assert_optimizer_equal(final_states[1][1], optimizer.state_dict())
@@ -136,3 +146,5 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp
record_property("scope", "tiny CPU native/RLTT/Adam recovery; transport and tokenizer doubles; no quality claim")
record_property("training", json.dumps(reference_runs[1]))
record_property("heldout", json.dumps(evaluations))
+ record_property("paired_raw_heldout_samples", len(errors))
+ record_property("paired_raw_score_max_error", max(errors))
diff --git a/tests/test_native_output_audit.py b/tests/test_native_output_audit.py
new file mode 100644
index 000000000..6b391a1f3
--- /dev/null
+++ b/tests/test_native_output_audit.py
@@ -0,0 +1,285 @@
+"""Synthetic saved runs exercise complete-output gates, with a real local tokenizer."""
+
+import copy
+import hashlib
+import json
+import shutil
+import sys
+from pathlib import Path
+
+import pytest
+import torch
+from tokenizers import Tokenizer
+from tokenizers.models import WordLevel
+from transformers import PreTrainedTokenizerFast
+
+from benchmarks.audit_native_outputs import audit, main
+from tests.test_native_learning_signal_audit import evidence
+from vime.rollout.native_eval import evaluation_seed
+from vime.utils.types import RecurrentTrace
+
+pytest_plugins = ["tests.test_native_runtime_audit"]
+
+
+@pytest.fixture
+def runs(tmp_path, records):
+ tokenizer = PreTrainedTokenizerFast(
+ tokenizer_object=Tokenizer(
+ WordLevel(
+ {"[UNK]": 0, "[BOS]": 1, "p": 2, "q": 3, "other": 4, r"\boxed{0}": 5, r"\boxed{1}": 6, "[EOS]": 7},
+ unk_token="[UNK]",
+ )
+ ),
+ unk_token="[UNK]",
+ bos_token="[BOS]",
+ eos_token="[EOS]",
+ )
+ tokenizer_path = tmp_path / "tokenizer"
+ tokenizer.save_pretrained(tokenizer_path)
+ built = []
+ for index, original in enumerate(records[:2]):
+ directory = tmp_path / f"signals-{index}"
+ directory.mkdir()
+ run, packet, inputs = evidence(directory)
+ shutil.copytree(original / "runtime", run / "runtime")
+ for path in original.glob("*-process.json"):
+ shutil.copyfile(path, run / path.name)
+ for step in range(3):
+ rollout_path, train_path = run / f"details/rollout_data/{step}.pt", run / f"details/train_data/{step}.pt"
+ rollout, trained = (torch.load(path, weights_only=False) for path in (rollout_path, train_path))
+ phase = "continuous" if index == 0 else ("split" if step < 2 else "resume")
+ for sample, batch in zip(rollout["samples"], trained["samples"], strict=True):
+ sample["tokens"] = [2, 3, 6 if sample["reward"] else 5, 7]
+ sample["response_length"], sample["rollout_log_probs"] = 2, [-1.0, -1.0]
+ sample["recurrent_trace"].update(runtime_epoch=phase, decode_depths=[4, 4])
+ batch["tokens"], batch["response_lengths"] = torch.tensor(sample["tokens"]), 2
+ batch["recurrent_inputs"] = RecurrentTrace(**sample["recurrent_trace"])
+ batch["loss_masks"] = [1, 1]
+ for key in ("rollout_log_probs", "log_probs", "ref_log_probs", "advantages", "returns", "kl"):
+ batch[key] = batch[key].repeat(2)
+ torch.save(rollout, rollout_path)
+ torch.save(trained, train_path)
+ built.append(run)
+ development = [{"prompt": "p q", "label": "1", "metadata": {"id": f"dev-{i}"}} for i in range(8)]
+ data_path = packet / "development.jsonl"
+ data_path.write_text("".join(json.dumps(row) + "\n" for row in development))
+ profile_path = packet / "qualification.json"
+ profile = json.loads(profile_path.read_text())
+ profile.update(
+ response_limit=2,
+ eval_completions_per_prompt=1,
+ split_stop_after=2,
+ precision="fp32",
+ selected_ids={
+ "train": [str(i) for i in range(12)],
+ "development": [row["metadata"]["id"] for row in development],
+ },
+ )
+ profile["files"]["development.jsonl"] = {"rows": 8, "sha256": hashlib.sha256(data_path.read_bytes()).hexdigest()}
+ profile_path.write_text(json.dumps(profile))
+ profile_sha = hashlib.sha256(profile_path.read_bytes()).hexdigest()
+ input_rows = [{**row, "split": "train"} for row in json.loads(inputs.read_text())["rows"]]
+ input_rows.extend(
+ {
+ "split": "development",
+ "id": row["metadata"]["id"],
+ "token_ids_sha256": hashlib.sha256(json.dumps([2, 3]).encode()).hexdigest(),
+ }
+ for row in development
+ )
+ inputs.write_text(json.dumps({"qualification_sha256": profile_sha, "rows": input_rows}))
+ for index, run in enumerate(built):
+ for path in run.glob("*-process.json"):
+ receipt = json.loads(path.read_text())
+ receipt["qualification_sha256"] = profile_sha
+ path.write_text(json.dumps(receipt))
+ template = torch.load(run / "details/rollout_data/0.pt", weights_only=False)["samples"][0]
+ for step in range(4):
+ samples = []
+ for i, row in enumerate(development):
+ sample = copy.deepcopy(template)
+ reward = int(i % 2 == 0)
+ sample.update(
+ index=i,
+ group_index=i,
+ prompt="p q",
+ tokens=[2, 3, 6 if reward else 5, 7],
+ response=tokenizer.decode([6 if reward else 5, 7], skip_special_tokens=True),
+ reward=reward,
+ metadata={
+ **row["metadata"],
+ "native_eval": {
+ "dataset": "qualification-development",
+ "prompt_index": i,
+ "completion": 0,
+ "seed_profile": "native-heldout-v1",
+ "top_p": 1,
+ "top_k": -1,
+ "max_tokens": 2,
+ "stop_token_ids": [],
+ },
+ },
+ weight_versions=[str(step + 1)],
+ )
+ phase = "continuous" if index == 0 else ("split" if step <= 2 else "resume")
+ sample["recurrent_trace"].update(
+ runtime_epoch=phase,
+ policy_version=step + 1,
+ publication_digest=str(step + 1) * 64,
+ request_id=f"{phase}-{step}-{i}",
+ temperature=0,
+ seed=evaluation_seed(42, "qualification-development", i, 0),
+ )
+ samples.append(sample)
+ torch.save({"rollout_id": step, "samples": samples}, run / f"details/rollout_data/eval_{step}.pt")
+ return *built, packet, inputs, tokenizer_path, tokenizer
+
+
+@pytest.mark.parametrize("algorithm", ["grpo", "rltt"])
+def test_full_cli_reads_all_saved_outputs_with_real_tokenizer(runs, tmp_path, monkeypatch, algorithm):
+ continuous, resumed, packet, inputs, tokenizer_path, _ = runs
+ output = tmp_path / "audit.json"
+ monkeypatch.setattr(
+ sys,
+ "argv",
+ [
+ "audit",
+ "--continuous",
+ str(continuous),
+ "--resumed",
+ str(resumed),
+ "--packet",
+ str(packet),
+ "--input-audit",
+ str(inputs),
+ "--tokenizer",
+ str(tokenizer_path),
+ "--algorithm",
+ algorithm,
+ "--output",
+ str(output),
+ ],
+ )
+ with pytest.raises(SystemExit) as result:
+ main()
+ assert result.value.code == 0
+ report = json.loads(output.read_text())
+ assert report["output_and_signal_pass"] and report["joint_signal_updates"] == [0, 1, 2]
+ assert report["training_samples_per_run"] == 96 and report["heldout_samples_per_run"] == 32
+ assert report["continuous_curve"] == report["resumed_curve"]
+ assert all(value == 0 for value in report["max_absolute_errors"].values())
+ assert report["reward_convergence"] == "NOT_ESTABLISHED" and len(report["consumed_sha256"]) == 39
+ for path, digest in report["consumed_sha256"].items():
+ assert hashlib.sha256(Path(path).read_bytes()).hexdigest() == digest
+ for name, digest in report["tokenizer_sha256"].items():
+ assert hashlib.sha256((tokenizer_path / name).read_bytes()).hexdigest() == digest
+
+
+@pytest.mark.parametrize(
+ "corruption",
+ [
+ "missing_round",
+ "missing_row",
+ "reordered_id",
+ "prefix",
+ "decoded_text",
+ "seed",
+ "version",
+ "epoch",
+ "eos",
+ "nonfinite",
+ "publication",
+ "stale_final",
+ "changed_output",
+ "training_tensor",
+ "gradient",
+ "training_text",
+ ],
+)
+def test_rejects_incomplete_or_changed_outputs(runs, corruption):
+ continuous, resumed, packet, inputs, _, tokenizer = runs
+ path = resumed / "details/rollout_data/eval_3.pt"
+ data = torch.load(path, weights_only=False)
+ sample = data["samples"][1]
+ if corruption == "missing_round":
+ path.unlink()
+ elif corruption == "missing_row":
+ data["samples"].pop()
+ elif corruption == "reordered_id":
+ sample["metadata"]["id"] = "dev-0"
+ elif corruption == "prefix":
+ sample["tokens"][0] = 4
+ elif corruption == "decoded_text":
+ sample.update(response=r"\boxed{1}", reward=1)
+ elif corruption == "seed":
+ sample["recurrent_trace"]["seed"] += 1
+ elif corruption == "version":
+ sample["recurrent_trace"]["policy_version"] = 3
+ elif corruption == "epoch":
+ sample["recurrent_trace"]["runtime_epoch"] = "split"
+ elif corruption == "eos":
+ sample["tokens"][-1] = 4
+ elif corruption == "nonfinite":
+ sample["rollout_log_probs"][0] = float("nan")
+ elif corruption in ("publication", "stale_final"):
+ if corruption == "publication":
+ path = resumed / "details/rollout_data/eval_1.pt"
+ data = torch.load(path, weights_only=False)
+ for row in data["samples"]:
+ row["recurrent_trace"]["publication_digest"] = ("f" if corruption == "publication" else "3") * 64
+ elif corruption == "changed_output":
+ sample["tokens"][-2] = 6
+ sample.update(response=r"\boxed{1}", reward=1)
+ elif corruption == "training_tensor":
+ target = resumed / "details/train_data/2.pt"
+ training = torch.load(target, weights_only=False)
+ training["samples"][0]["kl"].add_(0.1)
+ torch.save(training, target)
+ elif corruption == "gradient":
+ torch.save(2.0, resumed / "grad-actor-2-0.pt")
+ elif corruption == "training_text":
+ target = resumed / "details/rollout_data/2.pt"
+ rollout = torch.load(target, weights_only=False)
+ rollout["samples"][1].update(response=r"\boxed{1}", reward=1)
+ torch.save(rollout, target)
+ target = resumed / "details/train_data/2.pt"
+ training = torch.load(target, weights_only=False)
+ training["samples"][1]["local_raw_reward"] = 1
+ torch.save(training, target)
+ if corruption != "missing_round":
+ torch.save(data, path)
+ with pytest.raises((AssertionError, FileNotFoundError)):
+ audit(continuous, resumed, packet, inputs, "rltt", tokenizer)
+
+
+def test_identical_outputs_with_zero_learning_signal_do_not_qualify(runs):
+ continuous, resumed, packet, inputs, _, tokenizer = runs
+ for run in (continuous, resumed):
+ for step in range(3):
+ rollout_path, train_path = run / f"details/rollout_data/{step}.pt", run / f"details/train_data/{step}.pt"
+ rollout, trained = (torch.load(path, weights_only=False) for path in (rollout_path, train_path))
+ for sample, batch in zip(rollout["samples"], trained["samples"], strict=True):
+ sample.update(reward=0, response=r"\boxed{0}")
+ sample["tokens"][-2] = 5
+ batch["tokens"] = torch.tensor(sample["tokens"])
+ batch["local_raw_reward"] = 0
+ batch["advantages"].zero_()
+ batch["returns"].zero_()
+ torch.save(rollout, rollout_path)
+ torch.save(trained, train_path)
+ torch.save(0.0, run / f"grad-actor-{step}-0.pt")
+ report = audit(continuous, resumed, packet, inputs, "rltt", tokenizer)
+ assert report["output_equivalence_pass"] and not report["output_and_signal_pass"]
+ assert report["joint_signal_updates"] == [] and report["reward_convergence"] == "NOT_ESTABLISHED"
+
+
+def test_predeclared_score_tolerance_reports_small_finite_difference(runs):
+ continuous, resumed, packet, inputs, _, tokenizer = runs
+ path = resumed / "details/rollout_data/eval_3.pt"
+ data = torch.load(path, weights_only=False)
+ data["samples"][0]["rollout_log_probs"][0] += 1e-6
+ torch.save(data, path)
+ report = audit(continuous, resumed, packet, inputs, "rltt", tokenizer)
+ assert report["output_and_signal_pass"]
+ assert 0 < report["max_absolute_errors"]["heldout_scores"] < 2e-6
+ assert report["numeric_tolerance"] == {"atol": 1e-5, "rtol": 3e-5}