Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5832fd3
Add RL package and dependency scaffolding
kmccleary3301 Jul 1, 2026
6bcab5c
Define RL environment package contracts
kmccleary3301 Jul 1, 2026
e1db2e8
Test RL environment package validation
kmccleary3301 Jul 2, 2026
505f85d
Add VeRL export and adapter reports
kmccleary3301 Jul 2, 2026
ebda96d
Test export adapters and docs
kmccleary3301 Jul 2, 2026
1157b33
Add RL renderer record contracts
kmccleary3301 Jul 3, 2026
0a5255d
Test renderer message contracts
kmccleary3301 Jul 3, 2026
e041b1a
Add runtime session state tracing
kmccleary3301 Jul 3, 2026
f22fe9f
Test runtime session state tracing
kmccleary3301 Jul 4, 2026
a49c991
Add replay and security hardening probes
kmccleary3301 Jul 4, 2026
e63f767
Test replay security and E2E probes
kmccleary3301 Jul 4, 2026
5fecacf
Add Phase 2 RL control modules
kmccleary3301 Jul 5, 2026
0f06421
Test Phase 2 control paths
kmccleary3301 Jul 5, 2026
3357258
Add M12 transfer and promotion tooling
kmccleary3301 Jul 6, 2026
4432c16
Add M12 scripts and RL docs
kmccleary3301 Jul 6, 2026
9997660
Test M12 evidence gates
kmccleary3301 Jul 7, 2026
150de68
Add Phase 3 live RL services
kmccleary3301 Jul 7, 2026
7e33130
Add Phase 3 target runner scripts
kmccleary3301 Jul 7, 2026
4e5ff93
Test Phase 3 live target flows
kmccleary3301 Jul 8, 2026
07c3dc1
Add Phase 4 native inference lane
kmccleary3301 Jul 8, 2026
6447c52
Test Phase 4 native inference lane
kmccleary3301 Jul 8, 2026
cba0bcc
Expose RL routes through CLI bridge
kmccleary3301 Jul 8, 2026
1376082
Make M12 transfer tests worktree independent
kmccleary3301 Jul 8, 2026
e16ef5a
Fix Phase 3 promotion guardrails
kmccleary3301 Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ jobs:
missing=1
fi
done
if [ "$missing" -eq 0 ]; then
echo "ready=true" >> "$GITHUB_OUTPUT"
else
echo "ready=false" >> "$GITHUB_OUTPUT"
if [ "$missing" -ne 0 ]; then
echo "Danger-zone ACR guard prerequisites are missing; failing closed."
exit 1
fi
echo "ready=true" >> "$GITHUB_OUTPUT"

- uses: actions/setup-python@v5
if: steps.danger_zone_prereqs.outputs.ready == 'true'
Expand Down Expand Up @@ -170,9 +170,9 @@ jobs:
--repo-root . \
--json-out artifacts/kernel_contract_pack_report.json

- name: Danger-zone ACR guard skipped (missing prerequisites)
if: steps.danger_zone_prereqs.outputs.ready != 'true'
run: echo "Danger-zone ACR guard skipped on this branch."
- name: Danger-zone ACR guard failed closed (missing prerequisites)
if: failure() && steps.danger_zone_prereqs.outputs.ready != 'true'
run: echo "Danger-zone ACR guard prerequisites were missing; the prerequisite step failed closed."

- name: Upload danger-zone ACR report
if: ${{ always() && steps.danger_zone_prereqs.outputs.ready == 'true' }}
Expand Down
7 changes: 7 additions & 0 deletions agentic_coder_prototype/api/cli_bridge/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
SessionSummary,
)
from .service import SessionService
from breadboard.rl.phase3.api_router import create_phase3_rl_router
from breadboard.rl.phase3.service_live import LiveRLRunService

logger = logging.getLogger(__name__)
ENGINE_STARTED_AT = time.time()
Expand Down Expand Up @@ -177,6 +179,11 @@ def create_app(service: SessionService | None = None, include_atp_routes: bool |
engine_version = (os.environ.get("BREADBOARD_ENGINE_VERSION") or "0.1.0").strip() or "0.1.0"
app = FastAPI(title="BreadBoard CLI Bridge", version=engine_version)
_service = service or SessionService()
store_path = os.environ.get("BREADBOARD_RL_RUN_STORE")
rl_service = LiveRLRunService(Path(store_path) if store_path else ":memory:")
rl_router = create_phase3_rl_router(rl_service)
app.include_router(rl_router, prefix="/v1/rl", tags=["rl"])
app.include_router(rl_router, prefix="/rl", tags=["rl"])
chaos_config = _load_chaos_config()
required_token = (os.environ.get("BREADBOARD_API_TOKEN") or "").strip()
extension_config = None
Expand Down
10 changes: 10 additions & 0 deletions breadboard/rl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""BreadBoard RL rollout substrate primitives.

This namespace contains the production-oriented RL environment, rollout,
trace/replay, runtime, security, and export primitives introduced by the
BreadBoard x Zyphra RL Phase 1 plan. Existing
``agentic_coder_prototype.rl`` APIs remain intact and can be bridged into this
namespace as the substrate matures.
"""

__all__: list[str] = []
8 changes: 8 additions & 0 deletions breadboard/rl/adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""External adapter probe report primitives."""

from breadboard.rl.adapters.probe import AdapterProbeReport, validate_adapter_probe_report

__all__ = [
"AdapterProbeReport",
"validate_adapter_probe_report",
]
3 changes: 3 additions & 0 deletions breadboard/rl/adapters/benchflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from breadboard.rl.adapters.benchflow.importer import build_benchflow_fixture_probe_report

__all__ = ["build_benchflow_fixture_probe_report"]
44 changes: 44 additions & 0 deletions breadboard/rl/adapters/benchflow/importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

from breadboard.rl.adapters.probe import AdapterProbeReport


def build_benchflow_fixture_probe_report() -> AdapterProbeReport:
return AdapterProbeReport(
adapter_id="benchflow.fixture.v1",
adapter_kind="benchflow_import_fixture",
support_level="fixture_probe",
workload_family="swe",
preserved_fields=[
"env_package_id",
"task_id",
"runtime_backend",
"hardening_policy",
"verifier_command_shape",
],
field_mapping={
"env_package_id": "EnvPackage.metadata.id",
"task_id": "EnvPackage.tasks[].id",
"runtime_backend": "EnvPackage.runtime.backend",
"hardening_policy": "EnvPackage.security.hardening_policy",
"verifier_command_shape": "EnvPackage.evaluation.verifier.command",
},
lost_fields=[
"real_benchflow_harbor_runtime",
"live_benchflow_sandbox_attestation",
],
unsupported_fields=["production_benchflow_execution"],
source_artifacts=["examples/rl_env_packages/swe_toy_patch/env_package.yaml"],
fidelity_notes=[
"This probe checks whether BreadBoard EnvPackage fields can be represented in a BenchFlow-shaped fixture.",
"It does not invoke Harbor or BenchFlow sandbox execution, so sandbox attestation remains intentionally absent.",
],
promotion_requirements=[
"Run an actual BenchFlow/Harbor task using this mapping and capture sandbox identity plus verifier evidence.",
"Compare BreadBoard replay/admission results against BenchFlow task completion semantics on at least one real SWE task.",
],
metadata={
"fixture_scope": "static_env_package_mapping",
"minimum_real_promotion_level": "live_probe",
},
)
3 changes: 3 additions & 0 deletions breadboard/rl/adapters/ors/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from breadboard.rl.adapters.ors.client import build_ors_fixture_probe_report

__all__ = ["build_ors_fixture_probe_report"]
41 changes: 41 additions & 0 deletions breadboard/rl/adapters/ors/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import annotations

from breadboard.rl.adapters.probe import AdapterProbeReport


def build_ors_fixture_probe_report() -> AdapterProbeReport:
return AdapterProbeReport(
adapter_id="ors.fixture.v1",
adapter_kind="ors_openreward_fixture",
support_level="fixture_probe",
workload_family="swe",
preserved_fields=[
"task_id",
"prompt_fields",
"reward_scalar",
"verifier_evidence_ref",
"split_id",
],
field_mapping={
"task_id": "M6 run_summary.rows[].task_id",
"prompt_fields": "M6 run_summary.rows[].prompt_preview",
"reward_scalar": "M6 run_summary.rows[].reward_scalar",
"verifier_evidence_ref": "M6 run_summary.rows[].verifier_evidence_ref",
"split_id": "M6 run_summary.rows[].split_id",
},
lost_fields=["live_ors_server_route", "remote_reward_model_metadata"],
unsupported_fields=["production_ors_execution"],
source_artifacts=["docs_tmp/ZYPHRA/RL_PHASE_1/runs/m6_controlled_swe_toy/run_summary.json"],
fidelity_notes=[
"This probe treats ORS/OpenReward as a reward-record exchange shape over the M6 controlled SWE toy run.",
"It preserves local reward and verifier references but does not contact an ORS service or refresh remote reward metadata.",
],
promotion_requirements=[
"Submit a BreadBoard-generated rollout row to a real ORS/OpenReward endpoint and record route/version metadata.",
"Verify reward parity between the local verifier scalar and the returned ORS/OpenReward result on accepted and quarantined rows.",
],
metadata={
"fixture_scope": "local_reward_record_projection",
"minimum_real_promotion_level": "live_probe",
},
)
3 changes: 3 additions & 0 deletions breadboard/rl/adapters/prime_verifiers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from breadboard.rl.adapters.prime_verifiers.importer import build_prime_verifiers_fixture_probe_report

__all__ = ["build_prime_verifiers_fixture_probe_report"]
41 changes: 41 additions & 0 deletions breadboard/rl/adapters/prime_verifiers/importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import annotations

from breadboard.rl.adapters.probe import AdapterProbeReport


def build_prime_verifiers_fixture_probe_report() -> AdapterProbeReport:
return AdapterProbeReport(
adapter_id="prime_verifiers.fixture.v1",
adapter_kind="prime_verifiers_fixture",
support_level="fixture_probe",
workload_family="verifier",
preserved_fields=[
"verifier_id",
"verifier_kind",
"evidence_sha256",
"rerun_agreement",
"reward_scalar",
],
field_mapping={
"verifier_id": "M6 row_evidence.verifier.id",
"verifier_kind": "M6 row_evidence.verifier.kind",
"evidence_sha256": "M6 row_evidence.sha256",
"rerun_agreement": "M6 row_evidence.rerun_agreement",
"reward_scalar": "M6 row_evidence.reward_scalar",
},
lost_fields=["remote_prime_registry_identity", "live_verifier_service_attestation"],
unsupported_fields=["production_prime_verifiers_execution"],
source_artifacts=["docs_tmp/ZYPHRA/RL_PHASE_1/runs/m6_controlled_swe_toy/row_evidence/"],
fidelity_notes=[
"This probe records verifier identity/evidence semantics from local M6 row evidence only.",
"It does not register a verifier with Prime Verifiers or prove service-side execution/attestation.",
],
promotion_requirements=[
"Wrap one BreadBoard verifier in the real Prime Verifiers interface and capture registry identity plus service attestation.",
"Confirm local rerun agreement and remote verifier result agreement on accepted, rejected, and quarantined examples.",
],
metadata={
"fixture_scope": "local_verifier_evidence_mapping",
"minimum_real_promotion_level": "live_probe",
},
)
96 changes: 96 additions & 0 deletions breadboard/rl/adapters/probe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Mapping


SUPPORT_LEVELS = {"not_started", "fixture_probe", "jsonl_probe", "live_probe", "supported"}


@dataclass(frozen=True)
class AdapterProbeReport:
adapter_id: str
adapter_kind: str
support_level: str
workload_family: str
preserved_fields: list[str]
lost_fields: list[str] = field(default_factory=list)
unsupported_fields: list[str] = field(default_factory=list)
source_artifacts: list[str] = field(default_factory=list)
claim_boundary: str = "adapter_probe_not_production_integration"
data_boundary: str = "fixture_or_probe_only"
field_mapping: dict[str, str] = field(default_factory=dict)
fidelity_notes: list[str] = field(default_factory=list)
promotion_requirements: list[str] = field(default_factory=list)
metadata: dict[str, Any] = field(default_factory=dict)

def to_dict(self) -> dict[str, Any]:
return {
"adapter_id": self.adapter_id,
"adapter_kind": self.adapter_kind,
"support_level": self.support_level,
"workload_family": self.workload_family,
"preserved_fields": list(self.preserved_fields),
"lost_fields": list(self.lost_fields),
"unsupported_fields": list(self.unsupported_fields),
"source_artifacts": list(self.source_artifacts),
"claim_boundary": self.claim_boundary,
"data_boundary": self.data_boundary,
"field_mapping": dict(self.field_mapping),
"fidelity_notes": list(self.fidelity_notes),
"promotion_requirements": list(self.promotion_requirements),
"metadata": dict(self.metadata),
}

@staticmethod
def from_dict(data: Mapping[str, Any]) -> "AdapterProbeReport":
return AdapterProbeReport(
adapter_id=str(data.get("adapter_id") or ""),
adapter_kind=str(data.get("adapter_kind") or ""),
support_level=str(data.get("support_level") or ""),
workload_family=str(data.get("workload_family") or ""),
preserved_fields=[str(item) for item in data.get("preserved_fields") or []],
lost_fields=[str(item) for item in data.get("lost_fields") or []],
unsupported_fields=[str(item) for item in data.get("unsupported_fields") or []],
source_artifacts=[str(item) for item in data.get("source_artifacts") or []],
claim_boundary=str(data.get("claim_boundary") or "adapter_probe_not_production_integration"),
data_boundary=str(data.get("data_boundary") or "fixture_or_probe_only"),
field_mapping={str(key): str(value) for key, value in dict(data.get("field_mapping") or {}).items()},
fidelity_notes=[str(item) for item in data.get("fidelity_notes") or []],
promotion_requirements=[str(item) for item in data.get("promotion_requirements") or []],
metadata=dict(data.get("metadata") or {}),
)


def validate_adapter_probe_report(report: AdapterProbeReport) -> list[str]:
errors: list[str] = []
for field_name in ["adapter_id", "adapter_kind", "support_level", "workload_family"]:
if not str(getattr(report, field_name) or "").strip():
errors.append(f"{field_name} must be non-empty")
if report.support_level not in SUPPORT_LEVELS:
errors.append(f"support_level must be one of {sorted(SUPPORT_LEVELS)}")
if not report.preserved_fields:
errors.append("preserved_fields must be non-empty")
if not report.source_artifacts:
errors.append("source_artifacts must be non-empty")
if not report.data_boundary.strip():
errors.append("data_boundary must be non-empty")
if not report.field_mapping:
errors.append("field_mapping must be non-empty")
for preserved_field in report.preserved_fields:
if preserved_field not in report.field_mapping:
errors.append(f"field_mapping missing preserved field: {preserved_field}")
if report.support_level == "supported" and (report.lost_fields or report.unsupported_fields):
errors.append("support_level=supported requires no lost_fields or unsupported_fields")
if report.support_level == "supported" and report.claim_boundary != "production_supported":
errors.append("support_level=supported requires production_supported claim_boundary")
if report.support_level != "supported" and report.claim_boundary == "production_supported":
errors.append("production_supported claim_boundary requires support_level=supported")
if report.support_level != "supported":
if not (report.lost_fields or report.unsupported_fields):
errors.append("non-supported reports must name lost_fields or unsupported_fields")
if not report.fidelity_notes:
errors.append("non-supported reports must include fidelity_notes")
if not report.promotion_requirements:
errors.append("non-supported reports must include promotion_requirements")
return errors
3 changes: 3 additions & 0 deletions breadboard/rl/adapters/verl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from breadboard.rl.adapters.verl.report import build_verl_jsonl_probe_report

__all__ = ["build_verl_jsonl_probe_report"]
45 changes: 45 additions & 0 deletions breadboard/rl/adapters/verl/report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations

from breadboard.rl.adapters.probe import AdapterProbeReport


def build_verl_jsonl_probe_report() -> AdapterProbeReport:
return AdapterProbeReport(
adapter_id="verl.jsonl_probe.v1",
adapter_kind="verl_jsonl_probe_export",
support_level="jsonl_probe",
workload_family="swe",
preserved_fields=[
"input_ids",
"attention_mask",
"loss_mask",
"completion_logprobs",
"reward_scalar",
"policy_id",
"env_package_hash",
],
field_mapping={
"input_ids": "VeRLProbeRow.input_ids",
"attention_mask": "VeRLProbeRow.attention_mask",
"loss_mask": "VeRLProbeRow.loss_mask",
"completion_logprobs": "VeRLProbeRow.completion_logprobs",
"reward_scalar": "VeRLProbeRow.reward_scalar",
"policy_id": "VeRLProbeRow.policy_id",
"env_package_hash": "VeRLProbeRow.env_package_hash",
},
lost_fields=["verl_DataProto_object", "trainer_execution_state"],
unsupported_fields=["ppo_grpo_trainer_execution", "distributed_actor_logprob_refresh"],
source_artifacts=["docs_tmp/ZYPHRA/RL_PHASE_1/runs/m7_verl_probe/verl_probe_rows.jsonl"],
fidelity_notes=[
"This report covers BreadBoard's token-native JSONL/Parquet projection, not VeRL's in-process DataProto object.",
"Completion logprobs are explicit nullable fields with status metadata; they are not proof of actor-side logprob refresh.",
],
promotion_requirements=[
"Load the exported rows into a real VeRL DataProto or documented ingestion shim and validate tensor dtypes/shapes.",
"Run a no-op or tiny trainer smoke that consumes BreadBoard rows without treating quarantined rows as trainable.",
],
metadata={
"fixture_scope": "jsonl_parquet_export_projection",
"minimum_real_promotion_level": "live_probe",
},
)
13 changes: 13 additions & 0 deletions breadboard/rl/e2e/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""End-to-end RL Phase 1 probe runners."""

from breadboard.rl.e2e.swe_probe import (
ControlledSweProbeRun,
ControlledSweProbeRow,
run_controlled_swe_probe,
)

__all__ = [
"ControlledSweProbeRow",
"ControlledSweProbeRun",
"run_controlled_swe_probe",
]
Loading
Loading