0

Bimanual Chore Scheduling

Fresh

Bimanual household-robot chore scheduling RL environment: a two-arm robot must finish a chore set (laundry chain, dish batches, fillers) in minimum...

Type
RL Env
Publisher
Jwilksbooth
Runtime
single-turn
License
mit
Size
v0.1.0
Published
Jul 2026

Cite

Notes

Only stored in your browser.

bimanual-chore-scheduling

Minimum-makespan chore orchestration for a two-arm household robot — the second rung of a robotics vertical built with the same validation discipline as its siblings (robot-cycle-time, economic-dispatch, dcopf-grid-verifiers, multiperiod-dispatch, n1-contingency-dispatch, nodal-pricing-lmp). Rung 1 asks how fast can the arm move; this rung asks what should the robot do next. A bimanual robot (two arms with different end-effectors, hence different per-arm task times) faces a chore set — a laundry chain whose washer/dryer cycles run unattended, batches of dishes contending for the sink and dishwasher, filler chores, bimanual tasks needing both arms — under precedence and exclusive stations, on an integer-minute grid, in minimum total time. The mathematics is industrial machine tending (arms serving long autonomous machine cycles, work packed into cycle windows) wearing a household skin; the isomorphism is documented, not hidden.

The naive answer this environment defeats is greedy longest-first list scheduling (LPT, the standard dispatching heuristic): it starves the short chain-head tasks that gate the machine cycles and takes long both-arm bait first. On a measured 100% of instances the greedy schedule is suboptimal — a structural property of the task class (any root chore baits LPT away from a chain head; measured across a 14-config sweep and reported the same way the sibling reports its structural sync-failure rate) — by a median 36.5% makespan premium (N=200; the calibrated dial, see CALIBRATION.md).

Task

Given the task table (types: arm — choose an arm, per-arm durations; bimanual — both arms; machine — no arm, runs alone), station lists, precedence, and the start cap: output {"schedule": [["<task>", "<arm>", <start>], ...]} — every task exactly once. Rewards: format (0.10), feasibility (0.40 — positive-proof check of arm/station occupancy incl. one dual-station task, precedence at chosen-arm durations, label/type consistency), and makespan (0.50 — exp(−5·(M−M*)/M*), hard-gated on feasibility, fail-closed below M*).

Ground truth validation

Two independently implemented solvers in different paradigms must agree on the minimum makespan M* for every dataset instance:

  • Primary: time-indexed MILP (scipy/HiGHS dual bounds closed to optimality; decoded schedule re-graded by the reward function itself).
  • Cross-check: CP-SAT interval model (ortools; constraint propagation — different vendor, different algorithm class, different encoding), written from the spec text only, by an implementer who never read the primary.
Metric (200 instances, seeds 0–199)Result
M* disagreements between paradigms0 / 200
M*−1 refutation certificates (both solvers, exact INFEASIBLE status)0 failures / 400
Anti-vacuity controls (M ≤ M* attained at exactly M*)0 failures / 400
Greedy schedule grader-feasible (validates horizon + grader semantics)200 / 200
Greedy suboptimal (premium rate)100% (structural)
Median premium36.5%
Raw-draw rejection rate (survivor-bias indicator)0.0%

Exact-certificate property: scheduling on an integer-minute grid means there are NO tolerances anywhere — the grader, both solvers, and the certificates share exact integer semantics, so M*−1 is proven infeasible under the grader's own rules and no numerical slack can buy a shorter certified schedule. (The first cross-check implementation — a disjunctive big-M MILP — agreed on every M* but needed up to 22 minutes per refutation certificate; it was replaced by CP-SAT, ~50,000× faster on the worst case, and the dead end is documented with its measurements in CALIBRATION.md.)

Anti-reward-hacking (18 regression-tested attack gates)

Single shared parse gate: format-invalid answers cascade to zero on all three rewards (invariant asserted across the whole attack corpus). Gates cover: the greedy shortcut and blind serialization (honest partial credit, strictly separated); NaN/Infinity literals, >4300-digit integers, bracket bombs, null bytes (all score 0 without crashing); duration-injection killed by fixed arity; duplicate/omitted/phantom tasks (multiset check on the raw list); arm-swap compression (chosen-arm duration used in occupancy AND precedence AND makespan); two-sided one-minute boundary probes at every resource type; dual-station occupancy; label/type mismatches (bimanual labeled "left" frees no arm); sub-M* compression (fail-closed); Arrow round-trip identity on the real dataset rows; determinism. An adversarial pass (100+ crafted payloads, 10,000-schedule parse fuzz, 60,000-schedule feasibility fuzz vs an independent oracle) found zero reward exploits.

Usage

pip install -e .
N_INSTANCES=200 python tests/test_validation.py   # needs: pip install ortools==9.11.4210
python calibration/measure.py --n 200             # difficulty sweep

# give frontier models room to reason; -r 1 matches published baselines
vf-eval bimanual-chore-scheduling -p anthropic -m <model> -n 50 -r 1 --max-tokens 16000

Lower token budgets truncate reasoning mid-derivation and score as format failures — published baselines use exactly the line above.

import verifiers as vf
env = vf.load_environment("bimanual-chore-scheduling", num_examples=300)
# disjoint train/eval: load_environment(1000) + load_environment(200, seed_offset=1000)

Instance generation: median 0.23 s per instance including the M* solve (mean 0.32 s, worst 1.41 s over 12 seeds). Fully deterministic per seed.

Baselines

50 examples, 1 rollout each, --max-tokens 16000 (reproduce with the vf-eval line above; -m claude-haiku-4-5 / -m claude-opus-4-8):

ModelMean rewardFormatFeasibilityOn completed rollouts
Haiku 4.50.2690.980.22fails on feasibility — cannot track the minute-grid packing
Opus 4.80.8200.820.8241/41 non-truncated → exact optimum (reward 1.0)

Read these honestly. The Haiku→Opus gap is large and real: Haiku parses the task (format 0.98) but collapses on feasibility (0.22) — it writes schedules that double-book an arm or violate a minute boundary. Opus, given the tokens, saturates: every one of its 41 non-truncated rollouts is a certified optimum, and its entire 0.180 gap from 1.0 is the 9/50 rollouts that truncated at 16k tokens mid-derivation (mean output 5.8k tokens; the minute-by-minute reasoning is long), scoring 0.0 for want of a final JSON object — not a single feasible-but-suboptimal answer among them. So at the shipped 12–26-task size this environment discriminates sharply between Haiku-class and Opus-class reasoning but does not measure frontier headroom (cf. the vertical's saturated control, economic-dispatch). Larger instances (more tasks, tighter horizons) are the lever for frontier discrimination — tracked as a v0.2 knob, not shipped unmeasured.

Instance generation

12–26 tasks: the laundry chain (always), 2–4 dish batches (p=0.75), fillers and bimanual root tasks sized so greedy's failure is measured, not assumed — the difficulty distribution, the knobs that control it, and the config that shipped are in CALIBRATION.md, along with the stylizations (compressed cycle times, two-arm task abstraction) stated plainly.

Roadmap

  • v0.2 (frontier headroom): capacity-2 stations. A structural analysis plus an Opus 4.8 mini-probe (documented in CALIBRATION.md) established that at this instance size the optimum equals the closed-form arithmetic lower bound on ~93% of instances, so a frontier model that isn't truncated finds it exactly — no config knob moves M* more than +2 above the bound, and the compact regime saturates the same way (7/7 exact on completed rollouts). A shared resource that admits two concurrent occupants turns station timing into genuine cumulative-resource packing that no closed-form bound reads off, breaking the saturation while preserving the exact-MILP + dual-certificate validation spine (a one-line capacity change, unlike stochastic durations or preemption which would rewrite it).
  • v0.3: task durations imported from rung-1 (robot-cycle-time) motion solutions — connecting the vertical's layers with real numbers; stochastic durations; task preemption.