Skip to content

feat(campaign): experiment-campaign loop — controller skill, worker agents, kill-rule core#18

Open
sumtopmus wants to merge 17 commits into
developfrom
feature/experiment-campaign
Open

feat(campaign): experiment-campaign loop — controller skill, worker agents, kill-rule core#18
sumtopmus wants to merge 17 commits into
developfrom
feature/experiment-campaign

Conversation

@sumtopmus

Copy link
Copy Markdown
Owner

What this adds

A Claude Code experiment-campaign loop for RL runs: a durable controller skill plus worker subagents that launch training, monitor W&B telemetry, early-stop bad runs, analyze results, design the next experiment, and continue — backed by one deterministic, unit-tested telemetry/kill-rule helper exposed as a read-only CLI command.

Implements docs/superpowers/plans/2026-06-08-experiment-campaign.md.

Components

Deterministic core (pure, unit-tested):

  • core/campaign/killrules.pyevaluate(rows, rules, baselines) → KillVerdict; rule types nan / floor_at_step / collapse_vs_baseline / budget.
  • core/campaign/telemetry.py — W&B history reader via an injectable api_factory (tests never touch the network). Fetches each metric key independently and merges by _step so an absent or step-disjoint metric can't zero out the fetch.

CLI:

  • dsim campaign-status <run> [--rules f.json] — read-only telemetry + kill-rule verdict as JSON; the deterministic monitor tick. Invoked as python -m dsim … (repo sets package = false).

Agent layer (.claude/):

  • run-campaign controller skill + experiment-analyst, experiment-monitor, experiment-coder worker agents.

Scaffolding & docs:

  • docs/campaigns/TEMPLATE/{goal,ledger,frontier}.md, the smoke validation campaign (+ runbook), conf/experiment/smoke_canary.yaml, and a campaign-status entry in the README CLI surface.

Validation

Driven end-to-end on real W&B telemetry as the smoke campaign (interactive gate → launch → healthy monitor tick kill:false → forced abort kill:true/floor_at_step → analyst report card → ledger/frontier written). The smoke surfaced and fixed two real monitor-path defects, each with a regression test:

  1. Objective metric never logged — the single-agent env emitted info['scored'] but SB3's EvalCallback keys on info['is_success'], so eval/success_rate (the campaign objective) was absent. Mirrored scored → is_success in envs/quidditch/simple_env.py.
  2. Monitor was blindtelemetry.py requested a never-logged key in a single history(keys=…) call; wandb returns zero rows if any requested key is absent, silently neutering every kill-rule (kill:false). Fixed with the per-key fetch + merge described above.

Tests

  • New: tests/core/campaign/*, tests/dsim/test_campaign_status_cli.py, tests/test_agent_assets.py, plus regression tests for both defects (test_simple_env_is_success.py, the absent-key telemetry test).
  • Full fast suite + slow scoring-canary green on the author's machine. In a headless CI without an OpenGL/X11 display, the pre-existing test_render_smoke.py / test_video_callback_team.py abort on GL context creation — environmental, unrelated to this change.

Notes for reviewers

  • The smoke trained but did not learn (success_rate ≡ 0.0 at lr 5e-5 / 200k steps) — expected; the smoke validated loop mechanics, not training quality. An lr-bump follow-up is queued in docs/campaigns/smoke/frontier.md.
  • Clean fast-forward of the campaign work onto feature/experiment-campaign; the merge into develop was verified conflict-free via an in-memory trial merge.

https://claude.ai/code/session_018gE4JxQZ9dQSjuZJQGcm7R


Generated by Claude Code

sumtopmus and others added 17 commits June 8, 2026 14:59
Controller skill + worker subagents that run RL experiments, monitor
W&B telemetry, early-stop bad runs (hard rules + model judgment),
analyze results, design the next experiment, and continue. Interactive
and autonomous modes; ledger + brain rollup; config + guarded code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 tasks: kill-rule evaluator + telemetry reader + dsim campaign-status
(TDD), campaign templates, controller skill + three worker agents,
asset-validation test, docs, and verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The repo sets package=false, so there is no bare dsim console script;
the campaign-status monitor tick and obs-preflight must run via
python -m dsim (matching the Makefile). Also clarify obs-preflight is
skipped for scratch inits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scaffold docs/campaigns/smoke/ (goal/ledger/frontier), a tiny real
single-agent experiment (conf/experiment/smoke_canary.yaml, 200k steps,
video off), realistic + force-kill rules files, and a step-by-step
runbook for manual end-to-end validation of the run-campaign loop on a
W&B-authed machine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two defects surfaced by the smoke validation campaign that together made the
run-campaign kill-rule loop silently inoperative on single-agent runs:

1. envs/quidditch/simple_env.py emitted info['scored'] but not
   info['is_success']. SB3's EvalCallback only records eval/success_rate when
   episode info carries 'is_success', so the campaign's objective metric was
   never logged. Mirror scored -> is_success.

2. core/campaign/telemetry.py fetched all keys in one run.history(keys=...)
   call. wandb returns ZERO rows if ANY requested key was never logged (e.g.
   rollout/ep_rew_mean, which these runs don't emit) or if requested metrics
   never co-occur at a step. That blinded every kill-rule -> vacuous kill:false.
   Fetch each metric key independently and merge by _step.

Validated live: healthy kill:false pre-150k -> kill:true (floor_at_step +
budget) once eval/success_rate data crosses the gate. Regression tests added
for both; scripts/callbacks.py docstring updated (single-agent env now logs
honest success rates).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the first (and only) smoke iteration: single-agent smoke_canary ran to
200k with eval/success_rate identically 0.0 (verdict null; n_eval_episodes=20 is
noise, not a real judgement). The campaign's real value was validating the
run-campaign loop end-to-end and surfacing the two monitor-path defects fixed in
the preceding commit. Frontier records loop-validation status and queues the
lr-bump follow-up; no iteration 2 run (smoke purpose met).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants