Skip to content

Per-island task lists and per-island placement - #255

Merged
michaellchung merged 8 commits into
mainfrom
s23-pr-14-per-island
Oct 14, 2026
Merged

michaellchung merged 8 commits into
mainfrom
s23-pr-14-per-island

Conversation

@michaellchung

@michaellchung michaellchung commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements rl-per-island-tasks (--rl-island-tasks) and rl-mixed-island-placement (--rl-island-placement ISLAND:KEY=VALUE), with one full-parameter training contract v6, and syncs the English OpenSpec changes.

Motivation

P3-Q1..Q6 and P4-Q1..Q6.

What changed

  • yeto/rl/island_tasks.py: launcher filters --data JSONL by task id on the launching machine, writes one prompt file per island, mounts it and sends --data-sha256; island checks it and records task ids in rl_driver_start; plan computed once and recomputed identically on the head.
  • yeto/rl/engine/island_placement.py: per-island placement / standby GPUs / GPUs per node under inter-island elastic scheduling; launcher derives every island-side value from the per-island args copy; driver emits rl_round_wall.
  • Run manifest and dry run record per-island tasks, placement and AlgorithmSpec hash.

Behavior changes / compatibility

  • P4-Q6: full-parameter training contract schema yeto-dense-full-training-contract-v6, one bump for two changes: eval settings are island-local; with --rl-island-placement the placement flags leave the contract (recorded as per_island_placement). --rollout-num-gpus-per-engine always stays in. Old test runs cannot resume (P0-D5).
  • Refused before any cloud call: non-local or non-JSONL --data, external learners (P3-Q6), training-island eval (P3-Q3), mixed placement under strict scheduling, --rl-elastic / --rl-overlap-eval in a mixed run. Unequal task counts only warn (P3-Q2).
  • P4-Q5: inter-island elastic "capacity weighting" currently advances by island count (islands report capacity 1.0); real capacity is a follow-up.
  • Fake-engine tape golden gains rl_round_wall events.

Tests

Local CPU tests: every test file this PR adds or changes: 288 passed in 10.55s. The tree of this branch equals s23-final; the full suite with cargo on s23-final: 11 failed (expected set below).

Known expected failures until the ports image is rebuilt for the new Miles pin (P0-1.11 GPU run): test_rl_ports_image (2), test_rl_backend_identity::test_golden_samples_keep_both_old_hashes_and_carry_the_identity, and 8 test_decoupling_golden samples (golden is regenerated after the rebuild).

Depends on

#254. Tree of this branch equals s23-final (a9dce1e7). #256 (image pins) follows and removes the expected failures.

Not verified on GPU

None of this PR has run on GPU yet. The regression GPU run for the S23 stack is P0-1.11 GPU run (in progress at the time of writing); results will be linked here before merge.

🤖 Generated with Claude Code

@michaellchung
michaellchung force-pushed the s23-pr-13-remove-unreachable branch from 702c83f to 29d87ca Compare October 14, 2026 11:32
@michaellchung
michaellchung changed the base branch from s23-pr-13-remove-unreachable to main October 14, 2026 11:32
chowhsu and others added 8 commits October 14, 2026 11:32
`yeto launch --rl-island-tasks 'l0=web1-10,pwn1-10;l1=web11-20,pwn11-20'`
(or a JSON file) gives every training island its own subset of the
tasks in --data. The launcher filters the --data JSONL by each row's
metadata.task_id on the launching machine, writes one prompt file per
island under the run directory, mounts it in place of --data and sends
the island its SHA256 (--data-sha256). The island checks the file
before training and records task ids and SHA256 in rl_driver_start;
the run manifest and dry-run plan carry the same record.

Before any cloud call the launcher refuses: --data that is not one
local JSONL, external learners, island ids out of range, islands without
a list, unknown or repeated task ids, rows without a task id, and
training-island eval (P3-Q3: eval runs on the eval island). Unequal
task counts only warn (P3-Q2). A JSON spec is rewritten inline so the
head's second hop rebuilds the same bytes from its staged --data.

The full-parameter training contract moves to v6: evaluation settings
and the Miles eval flags are island-local, so islands with different
(or no) eval settings are not refused by the syncer. All full-parameter
contract values change (old test runs cannot resume, as in P0-D5).

Parsing and filtering live in the backend-neutral yeto/rl/island_tasks.py;
--rl-island-tasks is a neutral CLI flag, --data-sha256 sits next to
--data in the Miles island flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review fixes for rl-per-island-tasks:
- _check_island_tasks computes the plan once and caches it on args;
  island tasks, the run manifest and the dry run read the cache. The
  cache is not replayed to the head, which plans again from its staged
  --data; a test checks both hops give the same per-island SHA256.
- Islands are built only for --gpu entries (elastic adds none); a learner
  id outside the plan is refused with the planned ids listed.
- The SFT learner and diffusion sample paths refuse --rl-island-tasks.
- island_tasks.py takes the flag name from its caller for error messages.
- The help says a JSON spec file path must not contain '='.
- Drop a duplicated stale comment in island_entry.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two islands with different placements (P4 mixed island placement) must
hash the same training contract. The trainer shape, GPU split, rollout
engine size, weight transfer path and the colocate/offload switches are
island-local now, like the data and port flags.

Cherry-picked onto the per-island tasks work (P3). Conflicts resolved:
- island_entry.py: the placement flags and switches join P3's island-local
  eval flags and switches in one set each; the contract keeps using P3's
  _dense_shared_miles_argv helper; the docstring names both changes.
- test_rl_launcher.py: kept both P3's eval check and P4's placement check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--rl-island-placement ISLAND:KEY=VALUE (keys placement, standby-gpus,
use-gpus-per-node) gives one island its own placement values; the other
islands keep the run-wide flags. yeto.rl.engine.island_placement parses
and checks the overrides and builds each island's args copy; the launcher
derives every island-side value (shape checks, minimum nodes, learner
command, capability check, ports rejections) from that copy.

Refused before any cloud work: mixed placement under the legacy (strict)
schedule, --rl-elastic or --rl-overlap-eval in a mixed run (the error
names the colocated islands), and per-island standby GPUs on a colocated
island. A colocated island of a mixed run drops the inherited rollout and
standby GPU counts.

The run manifest and dry-run rows record every island's placement and
AlgorithmSpec hash. The island driver emits rl_round_wall (placement,
round and rollout seconds) every round. A static test keeps placement
reads in the launcher on per-island args.

Cherry-picked onto the per-island tasks work (P3) and the 1.7b.4b
algorithm move. Conflict resolved in launcher.py _prepare_rl_args: kept
the per-island require_ports_supported loop and dropped the
_prepare_ports_algorithm call here, since 1.7b.4b already calls it later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fake-engine tape golden gains the rl_round_wall events (volatile
seconds scrubbed); the elastic wire comparison ignores round_seconds; the
provenance source check follows the per-island ports rejection call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ement

Review follow-up for P4:
- The launcher sends --rl-per-island-placement to every island of a
  --rl-island-placement launch; only then do the placement flags leave the
  full-parameter training contract (recorded as per_island_placement). A
  uniform launch keeps them, so islands with different GPU splits are
  still refused. --rollout-num-gpus-per-engine always stays in: it sets
  the engine TP and has no per-island value.
- The launcher static check also covers rollout_num_gpus, and a new check
  keeps island task factory calls inside _island_task.
- island_placement parses and resolves once per call; the dry run builds
  the placement rows once; the dedup key names every placement field.

Cherry-picked onto the per-island tasks work (P3). Conflicts resolved
(P4-Q6: one v6 contract carries both changes):
- island_entry.py: P3's _dense_shared_miles_argv takes a
  per_island_placement keyword and adds the placement flags and switches
  only then; the eval switches stay always island-local. The schema stays
  yeto-dense-full-training-contract-v6, now with per_island_placement.
- launcher.py dry_run_plan: builds both the task plan and the placement
  rows once.
- test_rl_launcher.py: kept P3's eval check and P4's conditional
  placement checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A launch with both --rl-island-tasks and --rl-island-placement gives each
island its own task file and its own placement in the dry run, while both
islands carry the same algorithm hash and the per-island placement marker.
Each feature's refusals (eval on training islands, mixed placement under
legacy scheduling) still apply when both are given. A unit check pins the
v6 dense contract: per-island data and placement leave it, the engine size
stays in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michaellchung
michaellchung marked this pull request as ready for review October 14, 2026 11:32
@michaellchung
michaellchung merged commit 104e62a into main Oct 14, 2026
1 of 3 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.

2 participants