# NativeCAD 0.11.2 "Jochum" — two crossing cylinders union analytically, whichever is named first and at equal radii

**125 tools, nothing added, removed or renamed.** A patch release for the two crossing-cylinder unions 0.11.1 (CADSB-1005) left on the general engine — both hit live on featureboard.ai within minutes of that release (CADSB-1009).

## 1. The thicker rod named as the tool
Cylinder 1 r10 × 200, Cylinder 2 r5 × 200 rotated across it, `Union — f1 + f0`: the web app passes the r5 rod as the base and the r10 rod as the tool. The cylinder/cylinder rung (`ops/cylCylEdge.js`) reads "a thinner tool through a thicker wall" (r_tool < R_base) and refused `cylcyl_tool_radius_too_large`, so the pair fell to the general engine — 500+ PLANE faces on the thick rod and several seconds — while the very same rods named the other way round were analytic in 0.11.1.

Union is commutative. `ops/boolean.js` now asks the same rung the other way round before giving up on it (`_tryCylCylSwapped`), gated on `checkLocal` exactly like the swapped pierce (CADSF-1027 / CADSB-975); the result carries `operandsSwapped: true`. Subtract is not commutative and is untouched.

## 2. Equal radii — the Steinmetz cross
Two Ø2 × 20 rods crossed into a plus sign (New Cylinder r1 h20 at (0,10,10), rotate X 90°, unioned with the default r1 h20): r = R, which the rung refuses by name because its space quartics degenerate there. The general engine answered 1410 faces — or, at 200 mm long, refused with 148 validity findings.

At r = R the intersection is two exact planar **ellipses**, E1(t) = C + R cos t·e2 + R sin t·(e1 + e3) and E2 with (e3 − e1), crossing at the two pinch points C ± R·e2 where both cylinders share a tangent plane. New `ops/cylCylEqual.js` builds exactly that body: both walls re-authored with their seams through the pinch points, the eight kept wall pieces bounded by the four elliptic arcs, caps rebuilt on the re-cut rims.
- **12 faces, 20 edges, 10 vertices** (V − E + F = 2); `checkFull` clean, the two valence-8 pinch vertices included.
- Volume within **0.02 %** of πR²(H + L) − 16R³/3 at chord 1e-4·R (the tessellator's own deficit).
- Every edge an exact conic, measured against the wall(s) it lies on and recorded (worst 2e-16).
- Round-trips through STEP unchanged (`tests/test_cadsb-1009.js` §C).
- `regime: 'cyl-cyl-equal-analytic'`, union only; refuses by name (`cyleq_*`) for unequal radii, offset or skew axes, a rod that stops inside the cross. Plain cylinders only in this release.

## Performance
Both cases were also "pretty unperformant": each click was paying for a general classify-and-stitch boolean whose answer nobody could use. Both are now sub-second analytic constructions.

## Known — filed, not hidden
- **Filleting the saddle edges still refuses by name** (`blend-sel-non-planar-support`) — CADSB-1006; the equal-radius cross adds the elliptic-crease variant to that ticket's scope.
- `tool-list-budget.test.js` red on master before and after (tools/list 413 KB against the 400 KB ceiling); no tool description changed here.
- `packages/mcp/CHANGELOG.md`'s 0.11.2 entry landed one commit after the release (10bdfb7b, with CADSF-1595's own entry above it) rather than in e60920e2 itself.

## Gates
schema-sync 481/481 · mcp-smoke `dist/server.min.js` 125 tools · bundle-smoke on the shipped `.mcpb` (unlicensed host) · `dist/server.min.js` sha256 `03213093…` identical in the tgz and the `.mcpb` · `tests/test_cadsb-1009.js` 36/36, `test_cadsb-1005.js` 22/22.

**Downloads are served from featureboard.ai** (see `latest.json` for bytes + sha256):
https://featureboard.ai/nativecad/releases/nativecad-mcp-0.11.2.mcpb
Staged kernel: git 2c8775a8, tree f5ed0b84abc3 (348 files). Built with `SOURCE_DATE_EPOCH` pinned to 2c8775a8 from a clean `git archive` export, esbuild 0.28.1.
