# NativeCAD 0.12.1 "Kertész" — the fillet on a cylinder/cylinder saddle builds

**126 tools, nothing added, removed or renamed.** A patch release for the other half of Chris Wilson's report (2026-09-18): union two crossing cylinders, then fillet the junction. 0.11.1 and 0.11.2 made the union analytic (CADSB-1005, CADSB-1009); the fillet still refused by name — `blend-sel-non-planar-support`, "a corner between TWO CURVED supports … the rolling ball's spine there is the intersection of the two OFFSET surfaces, a general CHANNEL SURFACE with no exact circle/torus answer".

## Why it is buildable (CADSB-1006)
For this pair the offset surfaces are two more coaxial cylinders — R + ρ about the wall's axis, r + ρ about the tool's — on the same perpendicular, intersecting axes, so the ball-centre spine is the **same closed-form Steinmetz family as the union edge**: X(φ) = C ± √(R'² − r'² cos²φ)·e1 + r'(cos φ·e2 + sin φ·e3). One square root per sample, no marcher. The corner is concave (material inside both cylinders), so the ball sits in the air and the fillet **adds** material — a weld fillet at a boss root.

## What `ops/blendSaddleCyl.js` authors
- Contact curves C_A = X + ρn_A, C_B = X + ρn_B fitted as clamped cubic B-splines, refined by sample doubling until the measured worst distance to the exact curve is inside tolerance; the number is recorded on every edge (ops/edgeTolerance.js).
- The band as a bicubic B_SPLINE_SURFACE_WITH_KNOTS interpolating the canal B(φ, ψ) = X + ρ(n_A cos ψω + m sin ψω) on a 65×17 grid — one face per tool half — with exact ρ rim arcs at φ = 0, π.
- The wall's hole loop becomes the contact loop; each tool half swaps its quartic for the contact half and its seams for shorter ones; the quartics and their vertices retire.
- The **equal-radius cross** (CADSB-1009) too: its creases are ellipses meeting at pinch points where the two walls share a tangent plane, so the band closes to a point there — one face per crease bounded by its two contact curves alone.

Measured (`tests/test_cadsb-1006.js`, 38 assertions): Ø10 through Ø20 at ρ 2 → 14 faces, `checkFull` clean, contact curves on their walls to 1.4e-7 mm, band at ρ from its spine to 4e-15, band surface fit 4e-5, added volume within 2.5 % of a Pappus oracle; STEP round-trips; works on both crossings of a through rod, one crossing, one picked half (expanded to its loop and reported), the single boss, the swapped-operand union, a tube's outer wall, and the Ø2 cross (16 faces, scale-invariant). `cad_fillet_edges` returns `method: 'saddle'`.

## Refusals by name (right shape, wrong radius)
`saddle-runs-off-tool-end` (the tool's cap is inside R + ρ) · `saddle-runs-off-wall` (the ±(r + ρ) contact band leaves the wall's end) · `saddle-runs-onto-seam` · `saddle-tool-not-capped` (a bore bridge between two crossings) · `saddle-fit-tolerance`. Every other pick falls through to the route it had before.

## Known — filed, not hidden
- `tool-list-budget.test.js` red on master before and after (tools/list over the 400 KiB ceiling since before 0.11.1); no tool description changed here.
- The band's 65×17 control net fits the canal to ~4e-5 mm on a Ø20 part; a denser net is a knob (NU/NV in blendSaddleCyl.js), not a fix.

## Gates
schema-sync 481/481 · mcp-smoke `dist/server.min.js` 126 tools · bundle-smoke on the shipped `.mcpb` (unlicensed host) · `dist/server.min.js` sha256 `283177e3…` identical in the tgz and the `.mcpb` · `tests/test_cadsb-1006.js` 38/38, `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.12.1.mcpb
Staged kernel: git 7be05353, tree a64fb98dea95. Built with `SOURCE_DATE_EPOCH` pinned to 7be05353 from a clean `git archive` export, esbuild 0.28.1.
