Terrain Landscaping — Training Readiness
Gates remain blocked or unmeasured. No learned policy is claimed. No Raph hardware evidence exists. TD-MPC2 landscaping is disabled. Do not treat this page as approval for a long training run.
No curriculum exists anywhere in this stack.
The target simulator pair is Isaac Sim 6.1.0 with Isaac Lab 3.0.0. The physics and readback results labelled below as Isaac Sim 6.0.1 are historical baseline evidence; each particle, terrain, renderer, and learner gate must be rerun on the target pair before promotion. CPU, fixture, and synthetic runs retain contract value but do not establish GPU or real-terrain fidelity.
1. Three separate tasks, and no curriculum
The three landscaping task IDs have separate readiness claims:
terrain_landscaping_crater (simple) | terrain_landscaping_mound | terrain_landscaping (general) | |
|---|---|---|---|
| Purpose | one deterministic, fixed problem — the first training and deployment-test environment | a second deterministic baseline, added because the crater task’s grading metric is not reachable by this hardware | the full task: an arbitrary hashed mission per episode |
| Target | the checked-in analytic flat-bed manifest crater_target_manifest.json, hash-pinned | the checked-in mound_target_manifest.json — the same flat analytic bed, its own reset layout mound_pile_v1 | a per-episode mass-balanced deformation of the flat reset bed, hashed per mission |
| Episode | 300 steps (30 s) | 300 steps (30 s) | 600 steps (60 s) |
| Grading cells | 2398 | 2398 | 6237 |
| Reset | one fixed crater + one loose pile, fixed rover pose | one 0.24 m conical pile on a flat bed, no crater, fixed rover pose on the pile centreline | flat particle bed, mission drawn from a deterministic seed stream |
| Gate metric | observable grading MAE, margin 2.0 mm | excess volume above target, margin 1.75 L | observable grading MAE, margin 2.0 mm |
There is no curriculum or automatic task switching. Results do not transfer between tasks; an AST test guards the general task from crater-specific identifiers and manifest loaders.
2. What is proven, and what is not
| Gate | Subject | Status |
|---|---|---|
| G0 | IO contract, manifests, four hashes, no curriculum | passed |
| G1 | particle physics/readback (6.0.1 baseline) | passed at 6.0.1; target rerun required |
| G2 | simple-task reachability | blocked — actuation |
| G3 | external-heightmap seam | passed |
| G4 | Dreamer integration/config/checkpoints | passed |
| G5 | simple-task Dreamer learnability | blocked — model misses margin |
| G6 | one-environment training | blocked — G5 and independent memory clause |
| G6-M | batched (num_envs > 1) training | blocked — fail-closed refusal |
| G7 | TD-MPC2 | blocked by design |
| G8 | real-Raph sim-to-real | blocked — no hardware evidence |
| G9 | general-task reachability | blocked — no learner evidence |
| G2-MOUND | mound reachability by volume | passed with a caveat — 1-in-9 per-seed flake |
| G4-MOUND | mound Dreamer integration | passed — scope caveat |
| G5-MOUND | mound Dreamer learnability | blocked — model misses margin |
| G6-MOUND | mound one-environment training | blocked — G5-MOUND and memory |
Dreamer readiness requires G0–G6. G2, G5 and G6 are blocked; G5-MOUND
is also blocked. No training-ready claim or learned policy is made. G6 is
independently blocked on memory: a pre-fix run peaked at 23.33 GiB (97.2 %
of 24 GiB) near 3,300 steps. On fixed containment, six 10,000-step canaries
peaked at 15.9–17.6 GiB, with 24–26 MB replay. Nothing beyond 10,000 steps
has been measured; the 100,000-step extension remains unmeasured while G2 is
blocked, and the memory limit cannot be raised after a failure. Three
randomized-profile smokes do not clear G5.
G2 and G9 — the environment-reachability wall
Both require a deterministic scripted reference to improve final observable grading MAE by 2.0 mm over zero-action and seeded-random baselines. G2’s best of ten controller architectures reached +0.31 mm; the retuned shipped reference is −0.32 to +0.24 mm, within the zero baseline’s ±0.3 mm bed-creep noise. Architectures ran in separate processes; same-seed settled starts vary ~0.23 mm, so their ranking is unresolved, though all missed by ~1.5 mm. Shipped-reference comparisons are within-process. G9’s cut-to-fill reference finishes 0.18–0.37 mm worse than doing nothing on all three missions.
The evaluator responds: teleporting ~10 L into the crater bowl improved
observable MAE from 0.00915 to 0.00436. Actuation is the blocker: top-surface
L1 grading does not reward within-ROI relocation, buried material disappears
from the map, and the front plate shoves but cannot carry. Thresholds and
episode budgets were not weakened. Both full-strength tests are
xfail(strict=False), exposing the deficit. Remedies require an operator
decision: carrying implement, particles much finer than the blade, longer
episodes, volume rather than top-surface grading, or geometry allowing
deposits without bowl transit.
G5 — blocked
On Isaac Sim 6.1.0 / Isaac Lab 3.0.0, three corrected-containment 10,000-step
canaries completed first try without envelope aborts or resource breaches.
The prior abort came from an 8 m × 8 m plane: a half-extent had been supplied
as an edge length. This geometry fix does not relax the external-heightmap
operating envelope. Out-of-envelope frames remain errors, not truncations; the
0.1.0 matrix observed ExternalHeightmapFrameError when crater rollouts left
the mission ROI, with some non-reproducible rollout aborts. See the
modelling envelope.
The corrected-bed 2026-08 median paired gain vs zero was −0.42 mm. The latest full target-pair gate (2026-09-19, not remeasured against current source) used 3 training seeds and 15 paired rollouts:
| Statistic | Value | Required |
|---|---|---|
| median paired difference vs zero | −0.43 mm | ≥ +2.0 mm |
| median paired difference vs random | −0.08 mm | ≥ +2.0 mm |
| scripted-reference gain vs zero | +0.23 mm | ≥ +2.0 mm |
All three trained checkpoints lose to the zero-action baseline. G5 is bounded by G2’s actuation deficit, and its conditional 100,000-step extension remains unspent. No learned policy is claimed.
The mound task — reachable, and still not learned
The crater’s top-surface L1 metric charges ~1 mm/episode of wheel and blade
damage, and no blade push pattern shaves faster than it churns. With the real
RaphRover + RaphShovel fixed, the sibling mound task grades excess volume
above target on a flat bed: crest removal counts, below-target ruts and wheel
churn do not. The crater task, manifest, 2.0 mm margin and hashes are
unchanged. Mound has its own mound_pile_v1 reset layout and manifest hash;
both use the same 1287-float actor layout and IO-schema fingerprint.
The 1.75 L margin was frozen before testing: max(0.5 L floor, 5 × 0.35 L worst within-process zero repeatability). Settling removes 5.5–7.6 L under all policies. Same-seed settled starts vary by up to 3.6 L across processes versus ≤0.6 L within one; therefore each comparison runs all policies in one process from one settled start, grading only within-process differences.
G2-MOUND passes with a recorded flake: three full five-pass runs passed 8 of 9 gate-seed executions (4/4, 3/4, 4/4), including two clean-process passes. The harness retries crashes, never assertion failures; the 1-in-9 failure was not retried away.
G5-MOUND fails its margin. Three first-try 10,000-step canaries (740–771 s, 33 × 301-step episodes) had no retries, breaches or non-finite values. Three checkpoints were evaluated against zero, random and scripted baselines on five predeclared seeds, one process per seed:
| Statistic | Value | Required |
|---|---|---|
| trained / zero / random / scripted median excess | 0.018822 / 0.019368 / 0.019182 / 0.016760 m³ | — |
| median gain vs zero / random | +0.55 / +0.36 L | ≥ +1.75 L |
| median paired gain vs zero / random | +0.58 L / +1.05 L | ≥ +1.75 L |
Per-seed paired gain vs zero was −0.32 / +1.13 / +1.39 L: two checkpoints beat both baselines, one lost to doing nothing; scripted reference led the trained median by 2.06 L. Unlike crater G2, the mound scripted reference clears its margin, establishing reachability; the learner does not. No learned mound policy is claimed.
The 100,000-step extension was spent, and it made things worse
On operator instruction, the same runs resumed in place to 100,000 total steps (332 × 301-step episodes each; 94–103 min; 8.1–8.2 GiB peak/24 GiB; 244–246 MiB replay/2 GiB; no breaches or retries). Under the same protocol and margin:
| Statistic | 10,000 | 100,000 | Required |
|---|---|---|---|
| median gain vs zero / random | +0.55 / +0.36 L | −0.09 / −0.01 L | ≥ +1.75 L |
| median paired gain vs zero / random | +0.58 / +1.05 L | −0.08 L / −0.21 L | ≥ +1.75 L |
| gap to scripted reference | +2.06 L | +3.20 L | — |
Per-seed gain vs zero changed from −0.32 / +1.13 / +1.39 L to −0.00 / −0.30 / +1.38 L. A 10× steps budget erased the lead. The “needs more steps” hypothesis is refuted for this configuration, and no further extension is permitted. The longer runs unexpectedly peaked lower (8.1–8.2 GiB vs 17.5–17.6 GiB single-process); no cause is known.
Steps are not the only budget axis: the replay ratio
Dreamer updates = steps × replay_ratio ÷ (batch_size × batch_length) =
steps × ratio ÷ 256 for batch_size: 8, batch_length: 32. Both mound
attempts used replay ratio 16.0 (half the repository default, 1/32 of
excavation’s 512). They made ~625 and ~6,084 updates.
A learner-budget diagnosis found maximum-entropy actor output and wall time
spent almost entirely in simulation: gates measured an exploration
distribution, not a learned policy.
Both task profiles now declare 512.0, but this changes no gate row or result:
published attempts remain at 16.0, and the new ratio has not passed a canary
gate. Thus “more steps” was tested and refuted, while “more updates” was not;
the attempts do not bound this configuration. The conditional 100,000-step
extension is spent and failed. Three seeded randomized-profile 1,000-step mound smokes were
stable (three full episodes each, no aborts or breaches), but are early and do
not clear G5. Because neither gate passes, no short-canary command is documented on this page.
3. The actor observation contract
Both tasks publish seven leaves and three actions, flattened to exactly 1287 float32 in this order:
| Slice | Leaf | Shape | Physical bound |
|---|---|---|---|
[0:256] | proprio_dyn/heightmap_current_global | (16, 16) | [-0.30, 0.50] m |
[256:512] | proprio_dyn/heightmap_target_global | (16, 16) | [-0.30, 0.50] m |
[512:896] | proprio_dyn/heightmap_current_local | (24, 16) | [-0.30, 0.50] m |
[896:1280] | proprio_dyn/heightmap_target_local | (24, 16) | [-0.30, 0.50] m |
[1280:1283] | proprio/mission_pose | (3,) | x, y ∈ [-2.0, 2.0] m, yaw ∈ [-π, π] |
[1283:1286] | proprio/base_velocity | (3,) | vx, vy ∈ [-1.5, 1.5] m/s, wz ∈ [-4.0, 4.0] rad/s |
[1286:1287] | proprio_dyn/heightmap_age_s | (1,) | [0.0, 0.5] s |
Elevations are metres from the mission datum (containment base plane, z = 0). Global maps area-mean downsample the 4 m ROI. Local maps bilinearly sample native cell centres in body frame (+x forward, +y left), at the frame’s synchronized pose, without extrapolation.
The actor receives no validity mask, shovel extension, previous action, time remaining, particle positions, simulator world pose, or privileged current-minus-target map. Out-of-bound values are contract failures, never clipped.
Actions normalize to [-1, 1]: robot/cmd_vel [0:2] uses linear scale/saturation 0.4 m/s, angular scale radians(60) and saturation 1.0 rad/s; payload/joint_vel [2:3] uses scale/saturation 0.04 m/s.
Canonical configuration is RaphRover + RaphShovel, drive_filtered base and joint_vel payload control; Leo overrides are rejected and deprecated Leo helpers are not an alternate recipe. Task metadata records the effective robot/payload/mode outside the unchanged IO fingerprint. Bridge generation checks the live configuration, task, frozen contract and numerical action settings before writing; matching action dimensions alone do not qualify hardware or replace live generation.
Full coverage is a hard invariant
There is no validity mask, so every delivered frame must be complete. The fixed source is 0.05 m cells: an 80 × 80 target ROI plus a 33-cell (1.65 m) guard per side, totaling 146 × 146. Any non-finite, incomplete, wrongly shaped frame, or one outside the declared elevation/pose/velocity envelope, is rejected whole: no sentinel fill, clipping or partial frame.
Unknown cells are never zero-filled. Unsupported cells use calibrated base-plane elevation because the semantic terrain-work-surface layer is base plane plus regolith and excludes rover, shovel, walls and transient occluders. If a lab mapper cannot cover the area under rover and shovel, reopen this full-coverage decision rather than approximate.
4. The external-heightmap source: timing, freshness, and the target manifest
The rover has no onboard depth camera; the actor uses one external mapper.
- 10 Hz: publish one accepted-or-held frame per policy step. Map, mission pose and body velocity share one provider snapshot and source timestamp; crop at that frame’s pose, never combine stale map with newer pose.
- Source time: simulation uses
monotonic_sim_time(common_step_counter * step_dt), monotonic across resets; producers reject future or non-monotonic timestamps. - Reset readiness: async providers wait up to 2.0 s, polling at 10 Hz, for a complete frame. The synchronous simulator provider captures once with zero timeout because blocked reset cannot advance its snapshot. Failure raises
ExternalHeightmapReadinessErrorwith failing environment ids; selected rows stay unready until retry succeeds. No zero startup frame. - Stale abort: cutoff 0.5 s, matching actor freshness
[0.0, 0.5] s. Older frames are rejected as an out-of-MDP pause/abort (ExternalHeightmapStaleErrorin simulation;sensor_stalesession abort in deployment). - Dropouts: hold the previous complete map and increase freshness; never introduce holes.
Measurement profiles
Select with env.external_heightmap.profile. Canonical JSON/SHA-256 hashes travel in the run manifest:
| Profile | Behaviour | Profile hash |
|---|---|---|
ideal (default) | zero delay, dropout, elevation noise, registration error and pose jitter | 9c67bdce…2283398 |
randomized | delay U[0.0, 0.1] s; drop probability 0.05, max two consecutive; per-cell noise N(0, 0.002 m) clipped ±0.006 m; per-episode SE(2) translation N(0, 0.005 m) clipped ±0.015 m, yaw N(0, 0.25°) clipped ±0.75°; per-frame pose jitter at same bounds | a008c11d…f94870fe |
failure_stale | at least six held updates; stale-path proof only | 192fbd06…3652a8e35 |
Seeded robustness defaults are not lab-error claims or a curriculum. Lab data may change randomized values only with a new versioned profile hash. Across 100 seeded crater grading frames, oracle/observable evaluation: ideal agrees to 1e-9 with identical success classification; randomized p95 disagreement is 0.00189 m (0.01 m bound) with 100 % classification agreement (≥95 % bound). Only ideal has been used for training or the general task.
The target manifest owns the mission identity
The manifest owns mission frame ID, world-to-mission calibration version, datum, source/ROI/guard geometry, surface aggregation, target map, reset layout, physical bounds, grading cells and success parameters. Simulation and deployment reject frame, datum, geometry or hash mismatch before inference.
Direct ExternalHeightmapBatch construction checks finite arrays/timestamps, lossless nonnegative integer IDs/sequences, unique environment IDs, physical bounds and typed nonempty metadata. Actor projection and real evaluation enforce canonical geometry and policy-time freshness; projection also checks the target elevation envelope. Bounds use float32 representation without clipping. The 2026-09-20 admission changes preserve the frozen IO fingerprint; host regressions do not replace a current-source native run or advance readiness.
Four distinct hashes:
| Hash | Identity | Crater value |
|---|---|---|
io_schema_fingerprint | action/observation schema | 74bfe641…60ff16 |
target_map_sha256 | desired elevation field | f20f228f…f305bc8a |
reset_layout_sha256 | deterministic particle spawn layout | 6e809eb1…fd6769d4a |
manifest_sha256 | whole manifest document | 08e66df6…f1ec6f17 |
Crater’s checked-in manifest is fixed; configuration errors if crater/pile/spawner fields no longer reproduce its reset hash. General missions derive from deterministic (env.general_mission_seed, env_id, episode_index): that triple regenerates the mission across processes. Its reset hash (b2b2cdbf…53a95b90) is task-fixed; target and manifest hashes vary per mission.
5. Particles: GPU solver, CPU-facing readback
Landscaping uses PhysX PBD particles. The solver is GPU-only: without GPU dynamics PhysX rejects particles with Particles feature is only supported on GPU. Please enable GPU dynamics flag in Property/Scene of physics scene!, leaving them inert; a CUDA-capable NVIDIA GPU is required. Per-particle readback uses CPU-facing USD UsdGeom.Points. On Isaac Sim 6.0.1, probing found no direct/Fabric particle alternative: omni.physics.tensors.SimulationView exposes only cloth/material/system-level views and isaacsim.core.prims.ParticleSystem is system-level. Isaac Sim 6.1’s omni.physics.tensors 110.3.2 has no particle views.
Both tasks set sim.device = "cpu" on the 6.0.1 baseline; SRB disables Fabric when particles are enabled. Isaac Sim 6.1 must re-prove that its CUDA direct-data pipeline synchronizes PBD particle positions/velocities to USD points consumed by heightmap, reward and renderer.
GPU-setting trap: Kit’s persisted /persistent/physics/overrideGPUSettings = 0 (“Force CPU”) overrides authored physxScene:enableGPUDynamics=true, silently making particles inert while rigid bodies still work. This caused the zero-displacement symptom; neither simulationOwner nor USD readback was responsible. SRB now clears the override at spawn with a warning and authors simulationOwner equal to configured physics_prim_path.
Claims are Isaac Sim/Lab-version specific. The measured baseline is Isaac Sim 6.0.1 / omni.physx 110.0.7; re-prove on Isaac Sim 6.1.0 / Lab 3.0.0 using tests/integration/test_particle_simulation_owner.py and both smoke nodes.
6. Dreamer
DreamerV3 is the only learner wired to this contract, pinned to 4049794d4135e41c691f18da38a9af7541b01553 with elements 3.22.0. Crater config is hyperparams/task/terrain_landscaping_crater/dreamerv3.yaml; strict merge rejects dropped keys and requires all declared keys. A profile not authored against the strict upstream schema falls back to lenient merge with a warning; strict_task_config records which path ran. num_envs > 1 fails at wrapper construction before reset, step or allocation, naming missing selective-reset transport and env.num_envs=1 (see §7).
Checkpoint operations — three of them, named precisely
| Operation | Restores | Does not restore |
|---|---|---|
Same-logdir training-state resume (--continue) | step, agent parameters and optimizer/update counters, replay buffer, in fresh process | simulator/environment state, partial episodes, driver/RSSM carries, process RNG |
| Agent import / transfer | agent state in a new logdir, step 0 | all else; never a resume |
| Evaluation / policy load | agent state for inference | all else |
Resume is not bitwise continuation. Synchronous complete replay chunks are required; ckpt_generation.json records step, replay item count and completed chunk paths. Missing/incomplete chunks fail loudly instead of resuming with empty replay. This operation never uses run.from_checkpoint; logs identify the operation.
A portable Dreamer model is a sanitized directory, not a run snapshot: empty done marker plus exactly one agent form (agent.pkl xor contiguous agent-NNNN.pkl shards). Step/replay payloads, symlinks, nested directories and unknown members are rejected structurally without unpickling. Loading starts a new run.
Checkpoint and policy loads fail closed before inference unless recorded task ID, IO-schema and projection-layout fingerprints, target-manifest and mapper-profile hashes, and normalization policy match the live environment. Layout fingerprint checks packed-vector order even when IO schema matches. allow_unverified=True / SRB_ALLOW_UNVERIFIED_LANDSCAPING_CHECKPOINT permits unverifiable artifacts only, never mismatches.
What Dreamer’s integration does and does not prove
G4 proves the one-environment strict path: projection, config, upstream construct/update, truncation that resets collection but remains non-terminal for bootstrap, 1,000-step smoke (~14 env steps/s), checkpoint/reload/eval, sanitized artifact and mismatch rejection. It proves nothing about learning, the general task or hardware. The 0.1.0 matrix saw ExternalHeightmapFrameError when crater rollouts left the mission ROI; out-of-envelope frames remain errors, not truncations (see modelling envelope).
G6’s projected replay/model memory clause is independently blocked: the 1,000-step smoke ended at 8.28 GB RSS; the 10,000-step canary campaign peaked at 23.33 GiB (97.2 % of 24 GiB) near 3,300 steps. The limit was not breached and cannot be raised after failure. 2026-08-07 canaries re-evidenced the clause at 66–73 % (~15.5 GiB plateau; see §2); nothing beyond 10,000 steps is measured, so G6 remains blocked.
7. Batched training is unsupported
num_envs > 1 is refused fail-closed for Dreamer landscaping, and there are
two independent measured reasons:
- Mixed-reset transport. After one row truncates, the current transport
advances the freshly reset row by one hidden physics step under a masked
action before labelling that frame
is_first=True. The continuing row is otherwise unaffected and no global reset occurs, but the reset row’s first observation is not its true unstepped reset observation. - Particle clone frames.
ParticleSystemreads and writes per-particle state in prim-local coordinates while exposing it as world-frame buffers. With cloned environments carrying non-zero origin transforms, both beds collapse onto the world origin seam and both rover articulations read all-NaN. This is a core particle-transport defect, not a landscaping one.
Rejecting construction is the recorded outcome, deliberately, rather than weakening the mixed-reset requirement.
8. TD-MPC2 — landscaping is blocked
TD-MPC2 cannot be used for any landscaping task, and asking for it fails immediately with:
TD-MPC2 landscaping is disabled: velocity-controlled shovel extension is unobserved and no approved recurrent/history state contract exists.
The reason is observability, not plumbing. The shovel is velocity-controlled
and its extension is not in the actor observation, so the same visible state
can correspond to different shovel extensions. Upstream TD-MPC2 encodes the
current state feed-forward and cannot recover that hidden actuator state
(_prev_mean is planner state, not recurrent observation state). Dreamer is
allowed a belief about extension only because its recurrent carry includes the
previous action, and even that is an accepted partial-observability risk for a
short canary rather than proof that extension is observed.
The block is capability/contract based, not name based — it fires on either
frozen task ID in any spelling, on any environment publishing
landscaping_contract_metadata(), and on any generated RealEnv declaring the
contract’s IO-schema fingerprint. It fires before the log directory is
created, before config.yaml is written, before checkpoint discovery, before
replay allocation, and before the agent is constructed. Unblocking requires
separate approval of one of: measured shovel extension, an approved
observation/action history or recurrent encoder, or another physically grounded
state estimator. Integrating commanded velocity and presenting the estimate as
measured extension is explicitly forbidden.
What TD-MPC2 does work on
The generic dict-flattening path is repaired and usable on ordinary multi-leaf
SRB tasks: every actor-visible numeric non-image leaf (packed vectors and
2-D map leaves) is concatenated into one float32 state vector with physical
bounds, and image-like leaves are rejected at construction with an actionable
message instead of reaching upstream’s encoder after the log directory, config,
replay and model have already been created.
That path is gated on a pinned upstream checkout:
| Item | Value |
|---|---|
| upstream base | 8bbc14ebabdb32ea7ada5c801dc525d0dc73bafe |
| backport applied | e9f59321933cbc8e11a002b842adc7d4ffae8ff1 (fix Q-ensemble weight init) |
| resulting pinned SHA | bfb0029669f7242c33b1400950f97518ba46a5d8 |
| deliberately rejected | 75212c3a090115df212402ac911df446ccc2047f — it pins Torch 2.7.1 / TensorDict 0.8.3 / TorchRL 0.8.1, older than Isaac Sim ships |
The decision was to keep Isaac’s installed Torch/TensorDict/TorchRL matrix
and backport only the Q-ensemble initialization fix. Without the backport the
ensemble silently keeps PyTorch’s kaiming_uniform_ weights and non-zero
biases instead of the intended trunc_normal_(std=0.02) with zeroed biases.
assert_upstream_compatible() runs in both the train and policy-load paths
before anything is allocated and refuses an unpatched checkout with the exact
re-pin commands. The upstream contract test therefore checks the installed
checkout, so its result is environment-dependent: it is green against the
pinned patched checkout and red against an unpatched one, which is the gate
working as designed.
TD-MPC2 checkpoints are weights-only
Upstream’s save() writes {"model": state_dict} and nothing else — no
optimizer, replay, step, or RNG state. Therefore:
--model <ckpt>ontrainis a weights import. Training starts at an explicitly logged step 0 with a fresh replay buffer, fresh optimizers and reset schedules. The step is not parsed out of the file name.--continue/continue_training=Truefails immediately with aNotImplementedErrorexplaining that no versioned full trainer-state checkpoint exists; nothing is allocated first.- an evaluation/policy load is logged as
Evaluation load (weights only).
No TD-MPC2 weights-only load is a training resume, and no output describes one as such. Contrast this with Dreamer, which does have a real same-logdir training-state resume (§6).
9. Real Raph validation is unavailable
No hardware evidence exists. The hardware-free half of the sim-to-real work is complete — the observable task evaluator, the session-abort vocabulary, the horizon-truncation semantics, the model-artifact refusal, and a crater validation spec that resolves its real environment. The live half was never started: no live Raph or mapper contract has been recorded, and there is no lab run.
Constructing the canonical landscaping RealEnv validates four capability tags
before it acquires a ROS node, starts hardware, or lets a caller load a
policy:
| Tag | Claimed by shipped code? |
|---|---|
landscaping.observable_task_evaluator | yes — LandscapingRealEvaluator |
raph.drive_velocity | no |
raph.shovel_prismatic_velocity | no |
landscaping.external_heightmap_batch | no |
A CLI validation run of the crater spec therefore exits 4 with a typed
DeploymentNotReadyError naming the missing tags. That is the intended and
measured state.
What must be recorded from the lab before this can change: the Raph ROS drive/shovel command topics and message types, unit and sign conventions, saturation behaviour, watchdog/timeout semantics, acknowledgement mechanism, measured joint-state feedback, the measured real drive limits (the values in the contract are simulator values, not verified lab facts), the live external mapper and its calibration, live map/pose and map/velocity skew, and the live 10 Hz pacing and latency distribution.
Simulation and fake-adapter results are not hardware proof. Passing every other gate on this page would still not imply G8.
A dry run of the crater spec checks validation wiring only; it cannot provide landscaping hardware evidence. See the dry-run rule.
10. Generating and checking the deployment bridge
Both task IDs generate distinct bridge modules, and the general task must never be relabelled with the crater’s hash:
# Regenerate the checked-in bridge modules (writes in place)
srb real_agent gen --env terrain_landscaping_crater
srb real_agent gen --env terrain_landscaping
# Freshness gate: read-only byte comparison against the checked-in module
srb real_agent gen --env terrain_landscaping_crater --check
srb real_agent gen --env terrain_landscaping --check
Run both without an env.particles_height override. See the
freshness gate
and Sim-to-Real for --check and
the deployment capability gate.
11. Configuration hazard worth knowing
srb.hydra.extract.extract_defaults_from_class serializes an
asset-instance field default as {"name": …} plus a small allow-list
(action_mode and nested sub-asset fields). Any other customization the task
declared on that instance is silently dropped, so a CLI/Hydra-launched run
rebuilds the asset from its class defaults while a directly constructed
TaskCfg(...) gets the declared values.
This was measured on landscaping: direct construction received a
(4.0, 4.0) m containment with 0.3 m walls; the CLI path received Plane’s
class defaults (0.75, 2.0) m with 1.0 m walls. Every CLI-launched
landscaping run before the fix — crater included — trained on a surface a
fraction of the declared size.
The landscaping tasks are repaired locally by declaring the containment as
plain scalars (env.bed_size_m, env.bed_wall_height_m) that survive the
round trip. The underlying allow-list is unchanged, so this remains a
repo-wide hazard for any task that customizes an asset-instance default, and
one cosmetic instance is still live in landscaping (the crater’s plane
visual_material). If you customize an asset instance in a task config,
verify it survives the Hydra round trip rather than assuming it does.