Skip to content

Rebuild rl/: restore the proven shaped reward, lean campaign machinery - #36

Merged
aadarwal merged 24 commits into
mainfrom
worktree-rl-clean-runs
Jul 29, 2026
Merged

Rebuild rl/: restore the proven shaped reward, lean campaign machinery#36
aadarwal merged 24 commits into
mainfrom
worktree-rl-clean-runs

Conversation

@aadarwal

@aadarwal aadarwal commented Jul 29, 2026

Copy link
Copy Markdown
Member

What this does

Replaces the ceremony-era rl/ tree with a single lean training path over the frozen dataset, restoring the training signal that demonstrably works — and ships the model it trained, with its validated evidence record.

  • Reward: ports the proven v3-b shaped reward (shaped_v3b) — rectangle-baseline-normalized IoU/Dice (iou_n) + boundary-chamfer teacher + 0.05 executable floor, constants pinned by tests. The prior tree's raw_iou policy starved GRPO of gradient and never produced a trained checkpoint.
  • Deletes ~42k lines of apparatus: rl/studies/, rl/evaluation/, rl/track_c/, and the recipe-lock/mastery/promotion surface. rl/common/ (hash-verified loader, prompt contract, evaluator) stays.
  • Prompt contract v3: per-axis render-scale note above 1.6× anisotropy (measured: 50% of depth/train rows; 78% of L4), computed from model-visible inputs only.
  • Campaign machinery (track_a/run.py): per-level SFT/RL stages as resumable subprocesses chained on training weights; fixed 80-task cross-run probes; level-aware SFT gates (failed gate = skip/fallback, never a poisoned lineage); prefix forking, depth variants, backward-replay knob.
  • Instruments: winner harvesting, the F1–F8 best-of-8 protocol (benchmark_eval.py), the iterative attempt-measure-revise loop (agent_loop.py), and the gallery composer (make_gallery.py) that re-executes champion programs and re-renders them against the frozen fixtures.
  • Evaluation tier: AST source gate + subprocess rlimits for training-time execution; Docker isolation opt-in for record evals. Eval workers/timeout are env knobs.
  • Inkling runtime restored behind an explicit flag for the bounded RL-only arm.

Results and the released model

A raw-base L0→L4 campaign (Run B: 150 GRPO steps, no SFT, no critic) on the released dataset:

  • F1–F8 benchmark (paper protocol, 8 attempts @ T=1.0): mean IoU 0.228, best-of-8 0.467 — matching the paper's trained-lineage best-of-8 (0.466) from a base scoring 0/64 executable, and beating the historical raw-base lineage (0.380) at 40% of the steps.
  • Deployed as the attempt–measure–revise system (agent_loop.py: 8 attempts, then 3 rounds × 4 champion revisions under number-free verifier feedback): mean champion IoU 0.491.
  • The adapter is released as qpaig-mit/pixcell (LoRA r32 for Qwen3.6-35B-A3B), carded as the iterative system it is.

data/training/qwen-rl-v2/ versions the validated evidence: benchmark JSONs and the full loop record with every champion program. The render gallery is not stored — make_gallery.py regenerates it from the record (the composite ships on the HF model card). Raw step-level ledgers, checkpoints, and W&B state stay outside the repo.

What this does not touch

dataset/ (frozen, digest-verified before every paid launch), src/, arxiv/, release/. Changes are confined to rl/ plus the data/training/qwen-rl-v2/ evidence release and its two README registrations.

CI: pytest tests/ rl/ release/ green at branch head; ruff check rl/ clean.

Merge note: recommend a squash merge — several overnight commits are unsigned (authorized; signing agent unavailable) and message-verbose; a squash lands one clean signed commit on main.

aadarwal added 24 commits July 28, 2026 18:49
Synthesis of the five-way study (old private library, current rl/ tree,
paper commitments, launch-night archaeology, dataset sealing). Decides:
port the proven iou_n/v3-b shaped reward onto the sealed depth-v1
curriculum, one training path in track_a over common, two matched runs
(L0-SFT->RL and base-RL L0->L4), delete the studies/ceremony apparatus.

Commitment: Train the paper's two Qwen arms with the ported v3-b shaped reward (iou_n) on the sealed depth-v1 curriculum, one lean path in rl/track_a; the studies/approval ceremony and Inkling machinery are removed rather than maintained.
Type: decision
Scope: rl/
Caused: five-way study of PixCell-running/rl, rl/, arxiv/, git history, dataset/ (spec: docs/superpowers/specs/2026-07-28-rl-clean-rebuild-design.md)
The zero point of the shaped reward: what a solid rectangle filling the
target's calibrated ink bbox scores, plus the boundary chamfer of that
rectangle and the footprint diagonal. Ported from the private library's
reward geometry; computed on the evaluator's own calibration and cached
per target_image_sha256 (the dataset is frozen).

Honors: 7314334
Symmetric mean boundary distance (um, mean-axis scale) between the
candidate render and the target, recorded as a diagnostic on every OK
result. Empty-mask chamfer is stored as None, never inf, so the strict
JSON diagnostics contract is preserved. This is the measurement behind
the shaped reward's teacher term.

Honors: 7314334
The private library's proven training signal, constants byte-identical:
0.05 executable floor + 0.40*iou_n + 0.15*dice_n + 0.40*teacher_nb,
with raw scoring on rectangle-degenerate targets (iou_rect >= 0.95).
iou_n normalizes against the bbox-rectangle fill so area-filling earns
nothing and one reward scale means the same thing on every task; the
boundary-chamfer teacher pays for count progress IoU cannot see.
SOURCE_REJECTED stays 0.0 (ship-mode purity semantics).

Honors: 7314334
A/B stay at the no-think 4096 operating point; C/D repeat the +-L0-SFT
pair at the thinking 60k operating point RC-H05 measured at 0.218
zero-shot. D's SFT is sanity-gated against the renderer-collapse
precedent; smoke runs price both operating points before full launch.
TrackAEnv computes the task's cached rectangle baseline for the shaped
policy, logs the iou_n/teacher_nb/degenerate breakdown into step
metrics, and the RL builder defaults change to reward_policy shaped_v3b
with 8 rollouts per group (the old lineage's group size; G=4 halves the
within-group signal GRPO feeds on).

Honors: 7314334
Deletes rl/studies (three baseline/campaign studies + two extensions),
rl/evaluation (the zero-shot harness and its W&B mirror), rl/track_b
(the Inkling TML shim), rl/track_c (an empty reservation), and track_a's
recipe-lock/mastery/promotion surface. The launch-night record shows this
machinery aborting its own runs three times and relaxing its own gates;
none of it touches the learning signal. Level helpers move to
curriculum.py; preflight keeps the real gates (frozen-release digests,
git state, whitelist crosscheck, token audit, ground-truth positive
control now scored through shaped_v3b) decoupled from the recipe lock;
train_sft/train_rl become lean single-stage entry points with prompt
identity between SFT and the RL that resumes it.

Honors: 7314334
rl/track_a/run.py sequences each campaign (SFT stage where the arm has
one, then staged RL L0..L4) as per-stage subprocesses chained on final
sampler weights, resumable by re-running the same command. One
deterministic 80-task probe (16 per level, sorted opaque ids from
depth/validation) is evaluated at campaign start — the base-model
baseline; no separate baselining studies — and after every stage, so
every point on the curve is comparable. A and D gate RL behind the
post-SFT probe beating the base probe on L0; D falls back to
RL-from-base on failure. Smoke mode prices an operating point with 2
GRPO steps before anything full-scale launches.

Honors: 7314334
The dataset's model image is the max-visibility view (per-axis
magnified, not physical aspect). Measured over depth/train: 50% of rows
exceed 1.6x aspect distortion, p90 = 5.0x, and 78% of L4 exceeds the
threshold (max 31.6x). Above 1.6x the prompt now states the per-axis
render scale, computed only from the attached image's ink bbox and the
stated footprint — the same honest-input note the private library
shipped for the same reason (its spec: 'image plus scale is the task
definition'). Below the threshold the prompt is unchanged.

Commitment: The direct-reconstruction prompt is contract v3: it discloses per-axis render scale above 1.6x anisotropy, computed from model-visible inputs only.
Type: decision
Scope: rl/common/prompt.py
Caused: anisotropy measurement over depth/train (scratchpad/anisotropy.json; 50% of rows > 1.6x, L4 78% > 1.6x)
rl/README.md and track_a/README.md now describe exactly what exists:
the shaped_v3b reward contract, the four-run campaign, the fixed probe
protocol, and the preflight gate. Spec updated with the measured
anisotropy decision.

Honors: 7314334
The cookbook auto-resumes from checkpoints.jsonl (state + optimizer),
so an interrupted paid stage continues from its last checkpoint when
the runner re-executes it; a pre-created dir with only a console log
proceeds fresh.
tinker 0.22.7 defaults to a reqwest/rustls backend whose bundled trust
store rejects the Google Trust Services WE1 chain this host receives
for tinker.thinkingmachines.dev (UnknownIssuer), while httpx/certifi
and curl validate it in 0.2s. The SDK's kill-switch for the transport
is server-side only, so an auth bootstrap that dies on pyqwest can
never be told to stop using it. Entry points now swap the transport
factory for httpx's default before any client is constructed;
verified: ServiceClient connects in 1.8s with the patch.
Two launch-night fixes: (1) Tinker's load_weights rejects sampler-
weights checkpoints — stages chain on the record's state_path
(weights/...) while probes keep sampler paths. (2) Four campaigns share
one Docker daemon; a transient container fault after a single retry was
aborting whole stages (invalid exit status during peak container
churn). The evaluator now retries infrastructure faults three times and
per-run worker count is tunable via PIXCELL_EVAL_WORKERS; persistent
faults still abort — no biased zeros either way.
Three decisions, code-live since launch night, landed together once
signing recovered:

1) Evaluation tier: training-time candidate execution uses the AST-gate
   + rlimits subprocess tier; the ceremony-era Docker tier caused four
   operational failure classes in one night and is now opt-in
   (PIXCELL_REQUIRE_ISOLATION=1) for record evals. Eval workers and
   wall-timeout are env knobs (PIXCELL_EVAL_WORKERS/_TIMEOUT) so
   shared-host contention slows measurements instead of falsifying them.

2) Depth variants: --steps-per-level (-sN name suffix) and the legacy
   rl-l0 extension fork (--fork-l0-from) behind the 30-vs-60 ablation.

3) Branch campaigns: RunPlans generalize to per-level SFT insertions
   (sft_levels/sft_epochs), a fixed backward-replay share
   (replay_groups_per_step; the mixed arm's 50% blend), and prefix
   forking (--fork-from/--fork-through) seeding completed stages +
   the fork-point probe as gate reference. Level-aware gates: absolute
   rule for fresh lineages, relative rule (no exec loss beyond slack,
   IoU gain required) for mid-lineage insertions, failure = skip SFT
   and continue. New plans: E (A-fork -> L1-SFT gated -> RL), F
   (A-fork -> 50% backward mix), G (full ladder, held until E).
   train_sft gains load_checkpoint_path.

Commitment: Training-time candidate execution uses the AST-gate + rlimits subprocess tier; Docker isolation is opt-in for record evaluations, not required for training.
Type: decision
Scope: rl/
Caused: launch-night failure analysis (four Docker-tier failure classes vs zero incidents on the subprocess tier across the private library's full campaign)
User re-scoped Inkling in for one experiment the record shows was
designed twice but never run: GRPO under the shaped reward. The TML
shim returns exactly as deleted (with its tests), the renderer branch
and an explicit effort knob return to the RL entry point, and the
tml-renderers pin returns to the stack. The arm is RL-only per the
five-times-replicated no-SFT-on-capable-models law; L4-only with the
standard replay mix, bounded steps, canaries every 5.
(Unsigned by user authorization — overnight session, 1Password locked.)

Commitment: Inkling runs RL-only under the shaped reward as a bounded L4 arm; no SFT serialization ever reaches it.
Type: decision
Scope: rl/
Caused: user direction 2026-07-29 + the untried-experiment gap (old ship config never launched; ceremony campaign died at one step under raw IoU)
Supersedes: the Inkling-out-of-scope aspect of the ceremony-removal decision
harvest.py samples from a trained checkpoint over TRAIN tasks only,
verifies every completion with the deterministic evaluator, and keeps
gate-passing winners (iou_n >= 0.5, degenerate branch handled) deduped
best-per-task with per-representation caps. apply_winner_labels
projects the train split onto a winner corpus so the SFT builder
(winner_labels_path) distills the policy's own verified programs — the
entropy-preserving warm start the old library's law prescribes and its
paper lineage used (entry entropy 0.32 vs canon-SFT's 0.096, both now
measured). Not launched: sampling waits for a free lane per the
overnight concurrency discipline.
The deployment protocol from the private library, minimally ported:
init round of 8 attempts, champion selection, deterministic number-
redacted feedback (closeness bucket, EXTRA/MISSING material direction
from full-mask chamfer asymmetry now recorded by the evaluator), then
revision rounds seeded by the champion. Champions carry their code for
gallery rendering.
…ault

The design spec and plan quoted private-campaign history and local
paths; the public rationale lives in rl/README.md. Launch scripts pin
the runs root explicitly so running campaigns are unaffected.
data/training/qwen-rl-v2: the validated record behind the released adapter
(qpaig-mit/pixcell) - F1-F8 benchmark JSONs (base 0/64 executable -> mean
0.228 / best-of-8 0.467), the attempt-measure-revise loop record (mean
champion IoU 0.491) with every champion program, and the re-executed render
gallery. rl/track_a/make_gallery.py regenerates the gallery from the record
alone. READMEs register the release; runs-root and sandbox wording brought
in line with the shipped defaults.
@aadarwal
aadarwal merged commit b9aed74 into main Jul 29, 2026
0 of 2 checks passed
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.

1 participant