# UT collision labels and partial-assembly frame audit

Inspection only. No runtime source, settings, firmware, running process, or robot command was changed. All generated analysis files are under `/tmp`.

## Evidence snapshot

- Deployed source: `baf3caf6e01fa854cb6b782cf06c8b2d87e3a75b`.
- Remote run: `/home/floatarm/Downloads/ut-ik-overlap-recovery-20261002/user-run-035455` on `floatarm@100.64.152.89`.
- Captured stalled event: **2026-10-02 12:56:29.608 JST**, before the operator returned the robot to its folded pose.
- Assembly: EE + U1–U4 + U7 + U8 + BASE. Selected motion group U1–U4.
- Snapshot: `/tmp/ut-pair-label-live-20261002.json`.

## Labels trace correctly within the software

The held command recomputes to exactly the recorded constraint 268, capsule indices 14 and 23. Their source scene objects are `/Unit3_link` and `/Unit1_link`.

| Shape | Parent scene joint | Zero-based wire slot | Protocol motor identity | Profile CAN node |
|---|---|---|---|---|
| `/Unit3_link` | `/FA_joint10` | 9 | UNIT_3 / PITCH | 5 |
| `/Unit1_link` | `/FA_joint14` | 13 | UNIT_1 / PITCH | 1 |

Incoming yaws are also consistent: U4 yaw moves U3's body; U2 yaw moves U1's body. Missing U5/U6 do not compact the wire slots. The bridge binds UT slots by protocol unit and motor identities.

This verifies the software name/index mapping, not the physical placement of each shape.

## EE–U1 coverage

EE–U1 is excluded from volumetric capsule checks because the bodies are adjacent. It uses two angular rules in `simulator/ut_ik_self_collision.py:323`:

1. U1 pitch has a yaw-dependent minimum, between −20° and −12°. In the captured command U1 pitch is +1.195°, and the applicable minimum is −20°, leaving 21.195° slack.
2. The EE throat rule uses the distance of U1 yaw from its ±180° configuration, called phi. It accepts either phi ≤ 93° **or** sufficient combined EE/U1 pitch clearance. At this pose, U1 yaw is −151.709° and phi is 28.291°. The yaw branch therefore passes regardless of EE pitch for this particular constraint. EE pitch is −89.902°; its separate motor bounds still apply.

These rules are also checked over the commanded joint segment. They are angular approximations, not full distance tests of EE housings, links, wrist, and gripper against U1. Passing them does not establish that every EE/U1 surface clears.

## Confirmed motion/collision frame disagreement

An independent recursive evaluator rebuilt scene transforms directly from the exported object hierarchy, including passive-joint dependencies. It matched collision geometry transforms to approximately 5e−16 at the recorded pose.

For the same joint angles, the first installed arm link has these differences in horizontal bearing, collision model minus motion model:

| Assembly, always with U7/U8 | First arm link bearing difference |
|---|---:|
| U1 only, zero pose | −89.9985° |
| U1–U2, zero pose | −89.9985° |
| U1–U3, zero pose | −89.9985° |
| **U1–U4, zero pose** | **−89.9985°** |
| U1–U5, zero pose | −89.9985° |
| Full U1–U6, zero pose | +0.0015° |
| **U1–U4, recorded stalled pose** | **−89.9985°** |

U7/U8 bearings agree within 0.005° in all those comparisons. This is therefore an internal assembly-frame disagreement, not a uniform world-coordinate rotation. Base origins were aligned only for the comparison figure.

The collision `assembly_source()` implementation reparents `/Unit4` directly under U7's yaw while retaining the original `/Unit4` local matrix, originally relative to U5's yaw. That matrix has a different zero orientation from the original U7-to-U6 attachment. The independent motion model omits absent modules in its own chain. The two constructions do not agree for this partial assembly.

This demonstrates a software model inconsistency. It does not, by itself, qualify which mounting orientation matches the physical hardware. The operator's observation that EE is close to U7 is consistent with the motion-model drawing and inconsistent with the collision model's 57 cm estimate.

## Clearance values and what they establish

| Pair | Held-command capsule clearance | Feedback at held event |
|---|---:|---:|
| U3 link–U1 link | 10.000085 mm | 14.874539 mm |
| EE–U7, nearest represented shapes | 570.855616 mm | 573.519640 mm |

The command/feedback difference does not explain the EE–U7 discrepancy: both collision-model evaluations put it more than half a metre away.

The earlier deadline diagnosis remains a faithful account of what software rejected. It was not sufficient evidence of which physical bodies actually limited the robot. A rigid reorientation of the entire distal arm would preserve U3–U1 relative separation, so reconciling its U7 attachment alone should not be assumed to cure the numerical U3–U1 boundary stall. The capsule envelopes also extend beyond their enclosed scene meshes; their gap is not a measured surface gap on the robot.

## Verification and artifacts

Three existing focused tests pass: scene export hash, zero-pose scene-frame agreement, and all 19 UT targets through the real local gRPC boundary with a fake service. They check different aspects; they do not cover agreement between motion and collision models for shortened chains.

- `/tmp/ut_compare_attachment_frames.py`: repeatable independent frame comparison with assertions.
- `/tmp/ut-attachment-frame-audit.json`: numerical bearing results.
- `/tmp/ut-pair-label-analysis-20261002.json`: nearest body pairs and mechanical-rule slack at command and feedback poses.
- `/tmp/ut-frame-comparison.png`: same measured joint angles rendered with collision meshes versus motion-model centerlines.
- `/tmp/ut-label-audit-pose.png`: collision mesh labels and reported pair.

Before deploying a correction, the motion/collision attachment frames need to be reconciled and checked against the physical mounting, and EE–U1 coverage needs a deliberate treatment of attachment regions versus parts that can collide. No correction was implemented during this inspection.
