Skip to content

feat(fixtures): seat alphabet_soup on flat_stove burner plate (un-exclude from grate)#34

Merged
KE7 merged 1 commit into
mainfrom
ws/alphabet-soup-stove
Jun 16, 2026
Merged

feat(fixtures): seat alphabet_soup on flat_stove burner plate (un-exclude from grate)#34
KE7 merged 1 commit into
mainfrom
ws/alphabet-soup-stove

Conversation

@KE7

@KE7 KE7 commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Goal

Actually seat alphabet_soup stably on the flat_stove burner instead of the PR #32 exclusion (which routed it to the table via unstable_distractors). Prefer seating over exclusion (as done for the wine_rack / shelf cradles).

RCA — why the can tipped (and why the "grate" was a red herring)

  • The flat_stove burner "grate" is a VISUAL-ONLY mesh (burnerplate, contype=0/conaffinity=0 — non-colliding). The real collision is a flat plate (collision top z=0.9305 world) + a base box, plus the stove KNOB raised to z≈0.955 off to one side (world x ∈ [-0.28, -0.155]).
  • The burner flat plate sits +0.15 m in x from the fixture body; the knob occupies the body-centred region. The renderer centres distractor placement on the fixture body → the placement region straddles the knob and the burner-left edge.
  • The tall alphabet_soup can (r≈0.029 / h≈0.075) lands partly over the knob, tips off it and tumbles off the stove entirely (measured long-settle drift 846–4635 mm; 3/7 region points fail the 50-step gate). Shorter classes survive the 50-step gate by luck. So it tips because of placement over the knob, not grate bars.

Fix — seat, don't exclude

The burner plate is a clean flat surface. Add a per-(class, fixture) distractor SEAT that relocates alphabet_soup onto the burner-plate centre at the MEASURED flat-plate rest:

  • dx=0.15, dy=0.0, dz=0.1489, x_half=0.05, y_half=0.05, upright (default x90 — no tilt).
  • dz=0.1489 is the measured flat-plate rest and supersedes the stale knob-contaminated variant clearance (0.1691).
  • distractor_fixture_seat() / is_distractor_fixture_seated() in asset_metadata; spawn_clearance returns the seat dz first for a seated (class, fixture) distractor (renderer + simulator resolve the same z, lockstep).
  • Renderer: a flat-top fixture slot with ≥1 seated pool class emits per-class correlated (xc, yc, xh, yh); the seated class lands at the seat region, every other class is distribution-identical (c + h*Range(-1,1) ≡ Uniform(c-h, c+h)).
  • Data: flat_stove gains distractor_seats{alphabet_soup}, drops unstable_distractors. footprint / offset / height / top_z BYTE-IDENTICAL; 7 fixtures preserved.

Evidence

Deterministic on-burner seat (primary proof): placed via the production renderer→Scenic→sim pipeline, alphabet_soup now seats on the burner (on_burner=True), injected==settled to 0.12–0.24 mm at the 50-step production settle and 0.25 mm at a >1500-step settle, 0.00 mm inject-at-rest — reproducible across 3 tasks × seeds × a ±0.05 box (27+ trials).

Deterministic before/after (renderer's actual placement region):

  • BEFORE (body/knob-centred): 3/7 region points fail @50-step; long-settle drift 846–4635 mm (tumbles off the stove).
  • AFTER (burner-plate seat): all points 0.26 mm @50-step / 0.25 mm long; 0 fails.

Aggregate smoke (smoke_clearance_fix.py --seeds 8, fresh main 4fe683e vs branch):

  • distractor: MAIN 182/194 = 93.8% vs BRANCH 192/209 = 91.9% (−1.9 pp). Branch places + passes MORE distractors in absolute terms (192 > 182); the rate dip is the scene-resampling confound (alphabet_soup now enters the flat_stove pool → RNG shift → +15 more distractor placements).
  • task objects: 87.6% → 87.3% (flat).
  • Matched-scene comparison (886 identical keys): overall pass IDENTICAL — main 788/886 vs branch 788/886 = 88.9%. The 16 pass/fail flips are symmetric borderline jitter (8 each way, 3–8 mm), net zero, none involving alphabet_soup-on-flat_stove. → no quality regression.

Scope / safety

  • Distractor-only. flat_stove top_z / footprint / offset / height byte-identical (only the distractor_seats key added). Task seating untouched. Other fixtures untouched. place_half for other flat_stove distractors is byte-identical (cookies, not alphabet_soup, is the worst-case driver).
  • Local CI green: ruff check + ruff format + black clean; Tier-1 (6-file) 174 passed; validation-smoke G0–G3 6/6 pass.

🤖 Generated with Claude Code

…or seat)

RCA: the flat_stove burner "grate" visual mesh is contype=0/conaffinity=0
(NON-colliding); the real collision is a flat plate (top z=0.9305 world) + base
box, with the stove KNOB raised to the side. The distractor placement region is
centred on the fixture BODY (which sits over the knob) — straddling the knob and
the burner-left edge. The tall alphabet_soup can (r0.029/h0.075) tips off the
knob and tumbles OFF the stove (long-settle drift >800mm). PR #32 excluded it via
unstable_distractors.

Fix (seat, not exclude): the burner plate is a clean flat surface offset +0.15m
in x from the body. Add a per-(class,fixture) distractor SEAT that relocates
alphabet_soup onto the burner-plate centre at the MEASURED flat-plate rest
(dz=0.1489, supersedes the stale knob-contaminated variant clearance 0.1691).
Measured stable fixed point: 0.25mm 50-step AND >1500-step settle, 0.00mm
inject-at-rest, reproducible across 3 tasks x 4 seeds x a +/-0.05 box.

- asset_metadata: distractor_fixture_seat()/is_distractor_fixture_seated();
  spawn_clearance returns the seat dz first for a seated (class,fixture) distractor
  (renderer+simulator lockstep z).
- renderer: a flat-top fixture slot with >=1 seated pool class emits per-class
  correlated (xc,yc,xh,yh); seated classes land at the seat region, every other
  class is distribution-identical (c + h*Range(-1,1) == Uniform(c-h,c+h)).
- data: flat_stove gains distractor_seats{alphabet_soup}, drops unstable_distractors;
  footprint/offset/height/top_z BYTE-IDENTICAL. 7 fixtures preserved.

E2E (production renderer->Scenic->sim): alphabet_soup seats on the burner, 50-step
drift 0.12-0.24mm, long-settle 0.25mm — PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@KE7
KE7 force-pushed the ws/alphabet-soup-stove branch from f53b5e6 to 1def923 Compare June 16, 2026 20:26
@KE7
KE7 merged commit a0c3a08 into main Jun 16, 2026
3 checks passed
@KE7
KE7 deleted the ws/alphabet-soup-stove branch June 16, 2026 20:31
KE7 added a commit that referenced this pull request Jul 1, 2026
…nverged-rest (Option-2); flag genuinely-bimodal cabinet (#39)

RCA g4_remaining_arenas.md §3b: task objects resting on a fixture EXTERIOR
top never reach a stable rest in the 50-step validation settle. The analytic
on-fixture spawn z (rule 2 of spawn_clearance) uses the fixture AABB top
(highest geom), which sits far above the real rest face (flat_stove
cook_region grate is visual-only — #32/#34; microwave/cabinet tops have a
raised lip/rounded shell). The object is injected too high and falls
~48-64 mm per 50-step settle, so no single analytic clearance is a fixed
point → pose_tolerance fails on z.

DIAGNOSIS (scripts/measure_g4_fixture_fixedpoint.py): iterate the settle map
f(z)=settle50(inject at z) to its fixed point z* (|Δz|<1mm). Both objects
fall STRAIGHT DOWN (xy drift <0.15 mm — not a roll-off) to a deterministic
converged rest — diagnosis (a), the record case.

FIXED (additive VARIANT_CLEARANCES rows; rule 1 supersedes rule-2 analytic;
gate stays 5 mm; renderer+simulator resolve the same z* → scenic_z==settled z):
  * white_bowl|microwave       = 0.0794 (z*=0.8994, spread 0.0 mm, n=18/3 tasks)
  * akita_black_bowl|flat_stove = 0.0784 (z*=0.8984, spread 1.5 mm, n=18/3 tasks)
Per-case pose_tolerance (position subset, 3 seeds): white_bowl|microwave
0/9→9/9 (dz 48.8→0.0 mm); akita|flat_stove 0/6→6/6 (dz 64.5→1.2 mm).

FLAGGED, not forced — akita_black_bowl|wooden_cabinet: the cabinet top has a
NON-UNIFORM collision surface — a solid edge region rests at z*≈1.126, visual-gap
regions fall to ≈0.898, and the top_drawer placement is metastable across seeds
(0.898↔1.119, spread 221 mm). No single scalar is a fixed point; forcing the
dominant 0.078 would inject the solid-region bowl inside the cabinet body
(contact-explosion regression risk). Needs an xy-aware rest surface (out of
scope for scalar Option-2).

Corpus :init-block scan confirms these are the ONLY 3 task-object-on-fixture-
exterior pairs (moka_pot/cabinet-bowl/wine/book fixture relations are all :goal;
object starts table-resting).

Guards/no-regression: purely additive (2 rows, 0 changed/removed — proven);
fixture_geometry.json, stack_offsets.json, spawn_clearances.json, asset_metadata.py,
consistency.py (5 mm gate) all byte-identical. Untouched-arena CONTROL (study +
table-center, all classes) 30/30=100%; white_bowl|table byte-identical. Updated
test_fixture_task_residual → asserts measured pairs present at fixed-point value +
cabinet stays flagged. CI Tier-1 182 passed; validation smoke G0-G3 6/6; ruff+black
clean on src/+tests/.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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