Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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_moundterrain_landscaping (general)
Purposeone deterministic, fixed problem — the first training and deployment-test environmenta second deterministic baseline, added because the crater task’s grading metric is not reachable by this hardwarethe full task: an arbitrary hashed mission per episode
Targetthe checked-in analytic flat-bed manifest crater_target_manifest.json, hash-pinnedthe checked-in mound_target_manifest.json — the same flat analytic bed, its own reset layout mound_pile_v1a per-episode mass-balanced deformation of the flat reset bed, hashed per mission
Episode300 steps (30 s)300 steps (30 s)600 steps (60 s)
Grading cells239823986237
Resetone fixed crater + one loose pile, fixed rover poseone 0.24 m conical pile on a flat bed, no crater, fixed rover pose on the pile centrelineflat particle bed, mission drawn from a deterministic seed stream
Gate metricobservable grading MAE, margin 2.0 mmexcess volume above target, margin 1.75 Lobservable 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

GateSubjectStatus
G0IO contract, manifests, four hashes, no curriculumpassed
G1particle physics/readback (6.0.1 baseline)passed at 6.0.1; target rerun required
G2simple-task reachabilityblocked — actuation
G3external-heightmap seampassed
G4Dreamer integration/config/checkpointspassed
G5simple-task Dreamer learnabilityblocked — model misses margin
G6one-environment trainingblocked — G5 and independent memory clause
G6-Mbatched (num_envs > 1) trainingblocked — fail-closed refusal
G7TD-MPC2blocked by design
G8real-Raph sim-to-realblocked — no hardware evidence
G9general-task reachabilityblocked — no learner evidence
G2-MOUNDmound reachability by volumepassed with a caveat — 1-in-9 per-seed flake
G4-MOUNDmound Dreamer integrationpassed — scope caveat
G5-MOUNDmound Dreamer learnabilityblocked — model misses margin
G6-MOUNDmound one-environment trainingblocked — 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:

StatisticValueRequired
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:

StatisticValueRequired
trained / zero / random / scripted median excess0.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:

Statistic10,000100,000Required
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:

SliceLeafShapePhysical 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 ExternalHeightmapReadinessError with 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 (ExternalHeightmapStaleError in simulation; sensor_stale session 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:

ProfileBehaviourProfile hash
ideal (default)zero delay, dropout, elevation noise, registration error and pose jitter9c67bdce…2283398
randomizeddelay 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 boundsa008c11d…f94870fe
failure_staleat least six held updates; stale-path proof only192fbd06…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:

HashIdentityCrater value
io_schema_fingerprintaction/observation schema74bfe641…60ff16
target_map_sha256desired elevation fieldf20f228f…f305bc8a
reset_layout_sha256deterministic particle spawn layout6e809eb1…fd6769d4a
manifest_sha256whole manifest document08e66df6…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

OperationRestoresDoes not restore
Same-logdir training-state resume (--continue)step, agent parameters and optimizer/update counters, replay buffer, in fresh processsimulator/environment state, partial episodes, driver/RSSM carries, process RNG
Agent import / transferagent state in a new logdir, step 0all else; never a resume
Evaluation / policy loadagent state for inferenceall 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:

  1. 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.
  2. Particle clone frames. ParticleSystem reads 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:

ItemValue
upstream base8bbc14ebabdb32ea7ada5c801dc525d0dc73bafe
backport appliede9f59321933cbc8e11a002b842adc7d4ffae8ff1 (fix Q-ensemble weight init)
resulting pinned SHAbfb0029669f7242c33b1400950f97518ba46a5d8
deliberately rejected75212c3a090115df212402ac911df446ccc2047f — 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> on train is 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=True fails immediately with a NotImplementedError explaining 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:

TagClaimed by shipped code?
landscaping.observable_task_evaluatoryes — LandscapingRealEvaluator
raph.drive_velocityno
raph.shovel_prismatic_velocityno
landscaping.external_heightmap_batchno

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.