# NativeCAD 0.12.3 "Marriner" — refusals name themselves

**126 tools, nothing added, removed or renamed.** This number was bumped on 2026-09-19 and never cut; the build carries the boolean-pair work of that day and everything landed on the 20th.

## Refusals carry a structured reason (CADSB-1071)
786 of the 1,202 previously unnamed refusals now arrive with `error.details.reasonCode` (65.4 %). 418 of them were a **leak, not a missing vocabulary**: `ops/blend.js`, `shell.js`, `boolean.js` and `chamfer.js` already stamped `.reasonCode` at every throw and `commands/executor.js` put it on the failed entry — the `E_GEOMETRY` envelope in `tools/modeling` was rebuilt from the prose and dropped it. No message text changed. `cad_server_info` publishes the vocabulary under `reasonCodes`; `tools/refusal_reason_census.js` keeps the figure re-measurable (`--check` matches the committed census). 416 sites remain unnamed and are listed there; this is not yet a hard gate.

## Every kernel-worker death is named (CADSB-1126)
`E_KERNEL_CRASHED` now always carries one of five codes — `kernel-worker-module-missing` (with `details.missingModule`), `kernel-worker-exited`, `kernel-worker-shutdown-in-flight`, `kernel-worker-killed`, `kernel-worker-threw`. Measured split of the 111 unnamed deaths in the census: 44 module-missing (40 `Assembly`, 4 `SketchDof`), 27 exited, 24 shutdown-in-flight, 16 killed. Module-missing and shutdown-in-flight are `recoverable:false` with their own hint; four tool layers that used to overwrite the host's details bag with `recoverable:true` now merge into it. The `Assembly` resolution itself is triaged, not fixed (CADSB-1135): both specifiers resolve on a checkout, so the open question is the bundle.

## The diagnostics ceiling moves to 64 KiB (CADSB-1129)
`cad_server_info` at `section:"all"` with an open contest scope measured 54,987 B against a 48 KiB frame budget once the reason-code vocabulary was published — and deleting the new field outright still landed at ~49.4 KB, so the ceiling, not the field, was binding. Now 64 KiB, measurement recorded in `packages/mcp/src/budgets.js` and `docs/PAYLOAD_BUDGETS.md`. The published-shape matrix workflow also installs the repo root's deps so its `npm pack` can build `dist/server.min.js` at all — it had been dying in prepack on every Node line before a single assertion.

## Thresholds are literal (CADSB-1066)
Six angular comparison thresholds (sin/cos of 15°, 35°, 5°, 1°) in DFM off-axis faces, crease splitting, coplanar-edge and ruled-along tests and smooth clustering were computed from a transcendental at run time and differed by ULPs between V8 and JavaScriptCore. They are constants now; the same body classifies identically in both.

## Carried from the 2026-09-19 bump: four more boolean pairs exact (CADSB-1010, 1011, 1012, 1014, 1015, 1017)
The countersink (a seated CONE pocket, 8 faces instead of 200), the O-ring groove (torus − cylinder, 8 analytic faces, removed volume to 1e-9 against a quadrature oracle), the ball end (sphere ∪ cylinder, 7 faces instead of 3,503) — and two silent lies now refuse by name: a subtract whose tool never touched the base (pass `allowNoOp:true` for the old behaviour) and a boolean that emptied the body (`EMPTY_RESULT`). New refusal codes on the exact rungs: `torusgroove_breaks_out`, `sphbox_multi_axis_clip`.

## Kernel
- The lattice builds; the rounded cube reaches the general engine inside its `meshFallback` budget (CADSB-1057/1045/1013/1044/1048).
- A lathe-turned body whose wall is authored as a line-swept `SURFACE_OF_REVOLUTION` is the cylinder or cone it is, so it is a solid of revolution to `blendRevolved` again — recovery exact at 785.398 mm³ (CADSB-1093; the fillet itself still waits on the tessellator, CADSB-1131).
- A multi-turn helical ribbon is no longer mistaken for a trimmed full-turn band: the thumb-screw thread's repair skin drops from 33,016 mm² to 160 mm², open edges 5,958 → 1,967 (CADSB-1101; the flank holes are CADSB-1133).
- Fillet corner ends where one wall is a cylinder get a construction instead of "a wall is not a PLANE"; they now stop at the next named clause (CADSB-1110 → CADSB-1132).

## Gates
bundle-smoke over stdio on the shipped `.mcpb` (initialize, tools/list 126, cad_server_info, licence gate) · contest 108/108 · cadsb-1129 11/11 · cadsb-1126 81/81 · cadsb-1071 234 · schema-sync 481/481 (review lane, same day) · `dist/server.min.js` sha256 `06a61cea…` identical in the tgz and the `.mcpb`. Known red carried from 0.12.2, unchanged: `license.test.js` (CADSB-1134 — a description trimmed by CADSB-1038's byte cap).

**Downloads are served from featureboard.ai** (see `latest.json` for bytes + sha256):
https://featureboard.ai/nativecad/releases/nativecad-mcp-0.12.3.mcpb
Staged kernel: git 52df4c37, tree 9cd98aaf646f, 356 files. Built with `SOURCE_DATE_EPOCH` pinned from a clean `git archive` export of 52df4c37, esbuild 0.28.1.
