Rough Logic
roughlogic
Field math for the trades. A calm, fast, ad-free, account-free, ever-free reference site.
roughlogic.com is a single-page static web application that helps electricians, plumbers, HVAC technicians, water-damage and mold-restoration techs, carpenters and general contractors, fire-ground engineers, and a widening set of allied professions do the math they actually do during a workday. Everything runs in the browser. No server, no account, no analytics, no telemetry, no AI inference, no API key, no ongoing operating cost beyond domain renewal.
942 deterministic tools across 21 trade groups. 0 dependencies. 0 trackers. 0 LLM calls. 5,235 unit tests. Works offline.
The problem
Tradespeople do quick math constantly: voltage drop, friction loss, conduit fill, duct sizing, refrigerant superheat, psychrometric drying goals, stair geometry, fire-ground pump pressure. The reference material lives behind paywalled code books, in licensed apps that nag the user constantly, or in cluttered websites that lard the page with advertisements and trackers. The trades deserve better.
Related MCP server: headless-oracle
The solution
One static page with 942 small calculators and reference tools, organized into 21 categories. Each tool does one thing. The home page is scannable in five seconds. Every formula is computed from public physics or public-domain data. Every reference value is sourced and dated. The user can save the page and use it offline forever.
The design constraints are the product:
Constraint | What it means |
No accounts | Nothing to sign up for. No email is ever requested. |
No telemetry | No analytics SDK, no pixel, no beacon. CSP |
No AI | Every output is a deterministic function of input and bundled data. No model, no inference, no probabilistic step. |
No runtime dependencies | The app ships zero third-party JavaScript. |
Offline-first | A service worker pre-caches the shell; the page works with the network off. |
Cited | Every answer carries a source stamp with the publication and edition it derives from. |
Quick start
Open https://roughlogic.com in any browser. Type a tool's name in the center search bar; it filters the catalog as you type and shows a results dropdown. Click a result, or press Enter, to open that calculator. Focus the empty search bar to browse the whole catalog. Type in your numbers. Read the answer (it renders live, there is no submit button). Copy to clipboard. Go back to work. The header toggle (top right) switches between dark and light; the choice persists across reloads.
Calculator state is encoded in the URL hash, so you can bookmark or share a calculator with its inputs preloaded (for example, https://roughlogic.com/#voltage-drop).
Use it from an AI agent (MCP server)
The whole catalog is also available to AI agents through a local Model Context Protocol server in mcp/. It is zero-dependency and runs entirely on your machine over stdio: no hosting, no network, no install step. An agent (Claude Code, Claude Desktop, Cursor, and the like) can search the catalog, read a calculator's inputs and worked example, and run it with real numbers.
Rather than register all 942 calculators as separate tools (which would swamp a client's tool list), the server exposes three meta-tools over the catalog:
Tool | Purpose |
| Find calculators by keyword and/or trade. No arguments returns a trade overview with counts. |
| Input fields (with defaults), a publisher-verified worked example, and the cited source for one calculator. |
| Evaluate a calculator with your own inputs. With no inputs, the worked example is run. |
The server reads the same data the site does (tools-data.js, the tile-to-compute wiring in test/fixtures/compute-map.js, and the verified examples in test/fixtures/worked-examples.json) and calls the real calc-*.js compute functions, so the agent surface can never drift from the site.
Run it directly:
node mcp/server.mjsWire it into a client by pointing at the script with an absolute path. For Claude Code:
claude mcp add roughlogic -- node /absolute/path/to/roughlogic.com/mcp/server.mjsFor a config-file client (Claude Desktop, Cursor):
{
"mcpServers": {
"roughlogic": {
"command": "node",
"args": ["/absolute/path/to/roughlogic.com/mcp/server.mjs"]
}
}
}Because it is all local, anyone can use it by cloning this repo and pointing their MCP client at mcp/server.mjs. See mcp/README.md for client setup, the tool reference, and a smoke test.
How it works
The home view is a single centered hero: an elevator-pitch headline, a one-paragraph description, one search bar, and a static "browse by trade" index of the 21 group hubs. The search bar is a combobox: free text filters the catalog by tool name, description, or industry-term alias, and a results dropdown shows matches with their category; focusing the empty field lists every tool. Selecting a result routes to that calculator.
flowchart LR
U([User]) -->|types in search| S[Search combobox]
S -->|click / Enter| R[Router\nhash-state.js]
R -->|#tile-id| V[Calculator view]
V --> I[Labeled numeric inputs]
I -->|input event, debounced| C[compute function\ncalc-*.js / pure-math.js]
C --> O[Live output + Copy button]
C -.reads.-> D[(Bundled JSON shard\ndata/*)]
V --> CITE[Source stamp + citation]
V --> NOTICE[Inline limitation notice]
style C fill:#1a3a5a,color:#fff
style D fill:#2a2a2a,color:#fffEach calculator has labeled numeric inputs (with inputmode set so phones surface the right keypad), a "Test with example" button that fills a known reference case, an inline citation, a live-rendered output that updates as you type, a per-output Copy button, and a limitation notice stating what the tool is not. There is no submit button anywhere on the site.
System design and architecture
The runtime is a single index.html, a single styles.css, a single entry app.js, a lazy-loaded catalog registry (tools-data.js), a set of per-group calculator modules (calc-*.js), a shared math kernel (pure-math.js), a citations module, a service worker, and a data/ folder of sharded JSON. The architecture follows the same principles as encryptalotta.com and sophiewell.com: same-origin static assets, a strict Content Security Policy, no runtime dependencies, no telemetry.
flowchart TB
subgraph Browser
direction TB
HTML[index.html\nCSP + viewport + JSON-LD]
CSS[styles.css\ndark/light, 48px touch, mobile sweep]
subgraph App["app.js (SPA entry)"]
ROUTE[hash router]
RENDER[per-tile renderers]
ENSURE[ensureTools lazy loader]
end
TOOLS[tools-data.js\nTOOLS registry\nlazy: first search/tile route]
subgraph Calc["Calculator kernel"]
PM[pure-math.js\nphysics primitives]
CALC[calc-*.js\n56 group modules]
CIT[citations.js\nsource stamps]
end
SW[sw.js\nservice worker\nstale-while-revalidate]
WORKER[manual-j-worker.js\nWeb Worker]
end
subgraph Data["data/ (sharded, hashed)"]
SHARDS[(per-group JSON shards)]
INTEG[(integrity.json\nSHA-256 manifest)]
end
CDN[(Cloudflare Pages\nstatic edge)]
CDN --> HTML
HTML --> CSS
HTML --> App
App -.lazy import on first search/tile route.-> TOOLS
App --> Calc
CALC -.->|heavy Manual J / duct| WORKER
CALC -.->|lookup| SHARDS
SW -.precache.-> HTML
SW -.cache-on-access.-> SHARDS
INTEG -.startup verify.-> App
style Calc fill:#13293d,color:#fff
style Data fill:#1f1f1f,color:#fffDesign decisions worth calling out:
Computation on the main thread, with two exceptions. Most tools compute in well under a millisecond, so a worker would only add latency. The simplified Manual J load estimators and the duct-sizing calculator (nested bisection + Colebrook iteration) run in
manual-j-worker.jsto keep the main thread responsive.Sharded data, hashed at build. Reference datasets are split per group so a tool loads only what it needs. A startup integrity check (
integrity.js) verifies the SHA-256 of each per-folder manifest againstdata/integrity.json; a mismatch surfaces a non-blocking banner naming the affected dataset.Hash-based state. Per-tile inputs live in the URL hash (
hash-state.js), which makes every calculation bookmarkable and shareable with zero server state. The grammar and its back-compat policy are documented in docs/hash-state.md.Catalog metadata is lazy (spec-v10 §H.2). The 942-entry
TOOLSregistry -- every tile's id, name, group, trades, and description -- lives intools-data.jsand is dynamic-imported only on the first search keystroke or tile-route navigation (viaensureTools(), mirroring the alias loader). The bare home view is static HTML that the router only unhides, so first paint loads neither the catalog nor the search aliases. This keeps the home-view JS sub-budget well under its ceiling (~30.4 KB gz; total home payload 43.2% of the 100 KB budget) instead of ~99% with the array inlined; the bytes are deferred, not eliminated, so the gate measures honestly.One brand accent in an otherwise monochrome palette. Links, the focus ring, the "Run the calculator" CTA, and the copy-success pulse share a single accent that clears WCAG AA on every surface in both themes.
The component diagram above shows what loads; the sequence below shows when. Opening a tile is a chain of cached dynamic imports behind a crash-safe boundary, so the bytes a given calculator needs arrive only on first use and the home view ships none of them:
sequenceDiagram
participant U as User / browser
participant RT as route() in app.js
participant TD as tools-data.js
participant RV as renderToolView
participant MOD as calc-*.js + citations + support libs
participant SW as service worker
U->>RT: navigate to #tile-id (click result or deep link)
Note over RT: home / empty / b= routes are synchronous (no TOOLS needed)
RT->>TD: ensureTools() dynamic import (once; cached in _toolsPromise)
TD-->>RT: TOOLS registry
RT->>RV: applyRoute -> renderToolView(id, params)
RV->>RV: build static view shell synchronously, move focus to h1
par citation block
RV->>MOD: import citations.js
and calculator module
RV->>MOD: loadRenderer(id) -> import calc-group.js (moduleCache)
and support libs
RV->>MOD: loadSupportLibs() (Promise.all, supportLibsPromise)
end
MOD-->>RV: renderer fn + hash-state / clipboard / validity helpers
Note over RV: crash-safe boundary: try { render, applyHashState, example, stamp, copy-all, validity } catch -> recovery panel
RV-->>U: live calculator, recomputes on each input (no submit button)
SW-->>MOD: warm revisit: every module served from cache (0 network)Each dynamic import is memoized (_toolsPromise, moduleCache, supportLibsPromise), so the registry and a given group module load at most once per session; the service worker then serves them with zero network on every later visit. The try/catch around the renderer is Crash-Safe Resume (v3 utility 187): a calculator that throws paints a recovery panel without clearing the URL hash, so the input state survives a reload.
For the full runtime walkthrough and the ASCII diagram, see docs/architecture.md.
Data integrity: two hash chains, two trust boundaries
The component diagram above draws the integrity check as a single edge for clarity, but "hashed at build" is really two independent SHA-256 chains generated by the same pass of scripts/build-data.mjs and checked at two different boundaries. They exist because a bundled dataset can drift in two unrelated ways -- an edit in the repo that never went through the data pipeline (a build problem) and a corrupted or tampered file delivered to a browser (a runtime problem) -- and each chain catches exactly one of them.
flowchart TB
subgraph BUILD["Build time: scripts/build-data.mjs (one pass)"]
SRC[in-tree dataset constants]
SRC --> MAN["per-folder manifest.json\nversion, edition, refresh cadence,\nper-shard SHA-256"]
SRC --> EXP[("scripts/expected-hashes.json\n117 shard + manifest hashes")]
MAN --> SIDE[("data/integrity.json\n17 per-folder manifest hashes")]
end
subgraph CI["Boundary 1: build / CI tripwire (Node)"]
VER["npm run data:verify\nverify-integrity.mjs\nrehashes all 117 shards"]
FAIL["exit 1: build fails,\nnothing ships"]
EXP --> VER
VER -->|any mismatch| FAIL
end
subgraph RUNTIME["Boundary 2: runtime tripwire (the browser)"]
IJS["integrity.js on startup\nSubtleCrypto SHA-256\nof each delivered manifest"]
BAN["non-blocking banner\nnaming the dataset"]
SKIP[no SubtleCrypto:\nskip, fail-open]
SIDE --> IJS
IJS -->|manifest hash drift| BAN
IJS -.insecure context.-> SKIP
end
style BUILD fill:#13293d,color:#fff
style RUNTIME fill:#1f1f1f,color:#fffThe split is deliberate. expected-hashes.json covers every shard (117 files, the full data surface) and is the strict gate -- a single byte changed in any data/**.json without re-running the pipeline turns data:verify red in CI, so unreviewed data never reaches main. data/integrity.json covers only the 17 per-folder manifests (each of which already pins its own shards' hashes; the search/ manifest is a build-time index artifact, not a data source, so it is excluded from the runtime chain), keeping the runtime fetch tiny; the browser recomputes those 17 over SubtleCrypto and shows a banner on any mismatch, but fails open -- an insecure context with no SubtleCrypto skips the check rather than blocking the calculators -- because a missing crypto API is the user's environment, not a data-trust failure. The build boundary fails closed; the runtime boundary fails open.
Repository map
roughlogic.com/
index.html SPA shell: CSP, viewport, JSON-LD, theme pre-paint
styles.css single stylesheet (dark + light, mobile sweep, print)
app.js SPA entry: hash router, renderers, lazy loaders (~86 KB raw / ~28 KB gz)
tools-data.js catalog registry (TOOLS, 942 tiles); lazy-loaded (~355 KB raw / ~123 KB gz)
pure-math.js physics/math primitives shared across groups
calc-<group>.js 56 per-group calculator modules (electrical, hvac, ...,
calc-fab.js is the pipe & conduit fabrication bench split
out of calc-cross.js, holding the v39-relocated conduit
tiles (group A); calc-layout.js the v56 layout & shop-
geometry bench split out of calc-fab.js (bolt-circle,
sine-bar, arc, polygon-miter, ...); calc-shop.js the v40
machine-shop & fab bench (mixed groups K/G/E);
calc-earthwork.js the v70 earthwork/excavation bench
split out of calc-construction.js (group E);
calc-survey.js the v71 coordinate/traverse surveying
bench split out of calc-field.js (group P);
calc-feeder.js the v72 feeder & transformer-conductor
overcurrent bench split out of calc-electrical.js
(group A); calc-drainage.js the v73 storm-drainage
bench (roof-drain, sump-basin) split out of
calc-plumbing.js (group B); calc-velocity.js the v74
velocity bench (duct-velocity-pressure, refrigerant-
velocity) split out of calc-hvac.js (group C);
calc-treatment.js the v75 water-treatment bench
(weir-flow, langelier-index, chemical-feed-pump) split
out of calc-water.js (group M); calc-machining.js the
v76 machining bench (cutting-speed-rpm, drill-point-
depth) split out of calc-mechanic.js (group K);
calc-demo.js the v77 demolition/abatement take-off bench
(moisture-dry-goal, flood-cut-quantity, abatement-
containment) split out of calc-restoration.js (group D);
calc-service.js the v78 post-rough-in service bench
(gas-appliance-demand, tpr-discharge, pipe-support-
spacing, softener-sizing) split out of calc-plumbing.js
(group B); calc-powerquality.js the v79 advanced AC
analysis bench (parallel-conductor-derate, neutral-
current-3ph, motor-vd-starting) split out of
calc-electrical.js (group A); calc-civil.js the v80
site-civil / roadway-geometry bench (horizontal-curve,
vertical-curve, earthwork-end-area, slope-stake-cut-
fill) split out of calc-construction.js (group E);
calc-septic.js the v86 onsite-wastewater / septic bench
(septic-tank, septic-drainfield, septic-dose-tank,
septic-pumpout-interval, septic-lpp-orifice) split out
of calc-plumbing.js (group B); calc-lowvoltage.js the
v28 cabling tiles; calc-motor.js the v129 motor bench
(motor-synchronous-speed-slip, motor-shaft-torque,
motor-operating-cost, multi-motor-feeder) split out of
calc-electrical.js when the v121-v128 batch pushed it
over its gzip cap (group A))
citations.js per-tile source-stamp strings
theme.js dark/light toggle (pre-paint, no flash)
hash-state.js URL-hash state grammar + router
integrity.js startup SHA-256 manifest verification
sw.js service worker (offline + stale-while-revalidate)
manual-j-worker.js Web Worker for Manual J + duct sizing
data/ sharded, hashed reference JSON (per group)
specs/ spec.md .. spec-v478.md (inheriting build specs)
docs/ architecture, correctness, data-sources, a11y, ...
scripts/ build + 28 lint/audit gates + data pipeline
test/ unit (Node test runner) + integration (Playwright)
dist/ build output: prerendered shells + sitemap (generated)The catalog (cheat sheet)
942 tiles across 21 active group letters. The letters are stable identifiers; new groups append, retired groups (S / U / V / W, retired in spec-v107) leave a gap rather than renumbering, and retired tiles keep their IDs.
Letter | Group | Tiles | Representative tools |
A | Electrical | 115 | voltage drop (with reactance), power triangle, EV charger load, service load (220.82), PV interconnection busbar, conduit offset / saddle / 90-stub bending, motor-feeder sizing (430.24/430.62), transformer conductor/protection (450.3(B)), fiber loss budget, cable-tray fill (392.22), CCTV/NVR storage, 70 V speaker line, fire-alarm standby battery (NFPA 72), coax attenuation, NEC pull / junction box sizing (314.28), lumen-method luminaire count (IES), grounding electrode conductor (250.66), bonding jumper (250.28/250.102), min conductor for voltage-drop target (inverse VD), motor synchronous speed / slip, motor shaft torque (5252), motor operating cost, conductor short-circuit withstand (Onderdonk), conduit thermal expansion (352.44), EGC upsize proportional (250.122(B)), delta-wye line / phase, feeder tap conductor 10-ft / 25-ft rule (240.21(B)), buck-boost transformer sizing (Art. 450), wireway / gutter 20% fill (376.22), rooftop sunlight ambient adder (310.15(B)(2)), working-space clearance (110.26), range demand (Table 220.55 Col. C), dryer demand (220.54), feeder/service neutral demand (220.61), motor derating for voltage unbalance (NEMA MG-1), point-method illuminance (inverse-square + cosine), underground burial cover depth (Table 300.5), raceway / cable support spacing (Ch. 3 .30), motor branch-circuit protection + disconnect (430.52/430.110), commercial general-lighting + receptacle load (220.12/220.44), noncoincident loads (220.60), PV circuit ampacity (690.8, the 156% rule), transformer K-factor (UL 1561), max motor-terminal capacitor (self-excitation), bends between pull points (360-degree rule), shock approach boundaries (NFPA 70E 130.4), swimming-pool equipotential bonding (680.26), PV annual energy yield / specific yield (PVWatts), PV inter-row spacing / GCR, PV inverter loading ratio (DC:AC), VFD energy savings (affinity cube law), LED retrofit energy + demand payback, power-factor billing savings (kVAR), battery TOU arbitrage (round-trip haircut), battery demand peak-shaving, battery C-rate deliverable power, motor running overload (NEC 430.32), dwelling service conductor at 83% (310.12), continuous-load OCPD at 125% (210.20), PV cell temperature / power derate (NOCT), PV performance ratio (loss stack), PV source-circuit fuse (NEC 690.9), lighting light-loss factor (maintained lumens), illuminance uniformity ratio, egress lighting compliance (NFPA 101/IBC), conduit jam ratio (three conductors, NEC Ch. 9), motor efficiency-upgrade savings, transformer loading efficiency (core + copper losses), economic conductor sizing (I^2R payback) |
B | Plumbing and Gas | 85 | friction loss, pipe sizing, water hammer, water-heater recovery, sanitary DFU, Spitzglass gas pressure drop, mixing-valve blend temp (ASSE), well pressure-tank drawdown, pipe velocity / copper erosion, WSFU probable demand (Hunter), supply pressure budget, roof drain / leader sizing (IPC 1106), sump / ejector basin cycle (IPC 712), gas appliance demand / CFH (IFGC 402), T&P relief discharge (IPC 504), pipe hanger spacing (IPC 308.5), water softener sizing (NSF 44), septic pump / dose tank cycle (EPA 625), septic pump-out interval, low-pressure-pipe orifice flow / squirt height, new-main chlorination dose (AWWA C651), well shock-chlorination dose, high-altitude appliance derate (NFPA 54 / IFGC), natural-gas / propane conversion (orifice), storage water-heater first-hour rating (FHR / peak-hour demand), flash steam % across a pressure drop, steam main velocity sizing, steam trap load / capacity, pipe pressure rating (ASME B31.1), filled pipe support load per hanger, hanger rod sizing (MSS SP-58), drainage invert / fall / cover (IPC 704), hydronic radiant floor loop sizing, condensate return line sizing (flash steam), branch saddle cutback template, reducer centerline offset / invert continuity, flange pressure-temperature rating (ASME B16.5), medical-gas station demand (NFPA 99), branch-connection reinforcement / area replacement (ASME B31.1), expansion joint / loop guide spacing (EJMA 4D/14D), time of concentration (Kirpich), orifice discharge, open-channel Froude regime, velocity head / dynamic pressure, flow continuity at a size change, Bernoulli total head |
C | HVAC | 102 | duct sizing, Manual J (simplified), refrigerant P-T, chiller tonnage, LMTD/NTU, superheat/subcool charge verdict, economizer free-cooling hours, round-to-rectangular duct equivalent (ASHRAE), total external static pressure (Manual D), refrigeration compression ratio (ASHRAE), framed-wall assembly R-value (parallel path), blown insulation coverage, condensate drain rate / size / slope (IMC 307.2), recovery-cylinder 80% fill (EPA 608), HVAC equipment circuit MCA / MOCP (NEC 440.33 / 440.22), run-capacitor microfarad check (2652 x A / V), vacuum decay / blank-off test (ACCA Std 4), nitrogen pressure test (Gay-Lussac), gas-meter clocking (firing rate), furnace temperature rise / derived airflow, blower-door air-tightness (ACH50, IECC R402.4.1.2), ASHRAE 62.2 whole-house ventilation, infiltration heating / cooling load (sensible + latent), window solar heat gain (Manual J fenestration), internal heat gains (people / lighting / equipment), opaque-envelope conduction (sol-air CLTD), heat-pump seasonal energy vs gas / resistance (HSPF), dual-fuel economic balance point, heat-pump cold-capacity + aux heat (AHRI 47/17), compressed-air leak cost (DOE load/unload), single-stage air-compressor power (isentropic), air discharge-pressure setpoint savings, ERV/HRV sensible recovery (ASHRAE 84 / AHRI 1060), makeup-air tempering load (IMC 508), CO2 demand-controlled ventilation (ASHRAE 62.1), pipe Reynolds number / regime, hydronic GPM from load & delta-T, pump specific speed / impeller type, refrigerant mass flow (P-h), refrigeration COP / Carnot limit, condenser heat of rejection, whole-building heat-loss UA, degree-day annual energy / fuel cost, wall condensation-plane vs dew point, duct heat gain through unconditioned space, grille face velocity / free-area sizing, air density correction (ACFM/SCFM), psychrometric coil leaving-air state, fan affinity laws, walk-in cooler / pull-down load, duct leakage CFM25 (IECC R403.3.5) |
D | Water Damage and Mold Restoration | 51 | air movers, dehumidifier sizing, drying log, circuit-capacity check, drying-chamber CO2, grain-depression water removal, evaporation load / dehu demand, mold remediation scope (EPA / NYC DOHMH), IICRC S520 Condition reference, antimicrobial mix / coverage, spore-trap air sample volume, dry-standard verdict, flood-cut take-off, asbestos / lead abatement containment (EPA NESHAP / OSHA), wood equilibrium moisture content (EMC), ceiling water load / drain-before-entry, dehumidifier field derate, IICRC S500 class-of-loss screen, desiccant airflow sizing, drying-system balance (installed dehu vs evaporation load), bound water in wet materials, disinfectant contact / dwell time (EPA), carpet / cushion restore-vs-replace (S500), water-category deterioration over time (S500), hydroxyl generator sizing (S700), wall-cavity / injection drying system, drying completion projection (days to goal), drying-equipment sensible heat load, fire-char depth + residual capacity (AWC NDS), dry-sponge soot cleaning takeoff, ozone deodorization sizing + lockout (S700), smoke-residue method screen, thermal / ULV fog deodorizer dosage, contents pack-out inventory, surface condensation risk / dew-point margin (S500), indoor/outdoor spore ratio clearance screen (S520), hardwood floor drying-mat sizing (S500 Class 4), mold surface remediation labor / HEPA vacuuming (S520) |
E | Carpentry and Construction | 204 | joist/beam spans, header sizing (R602.7), deck beam/post (R507), wind/snow load, wall bracing, column buckling (Cp), welding heat input, metal weight, 3-4-5 layout squaring, horizontal / vertical curve layout, earthwork end-area volume, slope-stake cut/fill, fillet-weld strength (AWS D1.1 / AISC J2), groove-weld strength (CJP/PJP), press-brake air-bend tonnage, welder duty cycle (NEMA EW-1), carbon equivalent / preheat screen (AWS D1.1), compound miter for crown molding, soil swell / shrinkage (bank-loose-compacted), haul-cycle production / fleet match (CAT), excavation dewatering pump rate, trench spoil setback (OSHA 1926.651), pipe bedding / embedment / backfill (ASTM D2321), industrial coating coverage / DFT (SSPC PA 2), abrasive blast air / abrasive (SSPC SP), shielding-gas cylinder runtime / cost, oxy-fuel cutting gas consumption, weld preheat fuel to temperature, all-in welding cost per foot, weld deposit weight / filler / passes, wire-feed deposition rate, transverse weld shrinkage (Blodgett), eccentric fillet weld group (AISC elastic), minimum plate bend radius, fence material take-off, concrete per post hole, concrete control-joint spacing (ACI 302), rebar tension lap-splice length (ACI 318), thin-set mortar coverage by trowel, resilient / LVP flooring take-off, paver patio take-off (ICPI), segmental retaining wall take-off, attic net-free vent area (IRC R806), residential gutter / downspout sizing, guard / handrail code check (IRC R312), roof rain load / ponding (ASCE 7 Ch. 8), ASCE 7 ASD load combinations / net uplift, seismic base shear (ASCE 7 §12.8), steel beam LTB (AISC F2), steel block shear (AISC J4.3), steel tension member / shear lag (AISC D2/D3), RC tied column (ACI 22.4), slab punching shear (ACI 22.6), rebar hook development (ACI 25.4.3), elastic footing settlement, alpha-method pile capacity (FHWA), infinite-slope stability (NAVFAC), wood bearing perp to grain (NDS 3.10), wood tension member (NDS 3.8), wood beam-column interaction (NDS 3.9.2), web yielding / crippling (AISC J10), slip-critical bolts (AISC J3.8), fillet-weld size limits (AISC J2.4), wind components & cladding (ASCE 7 Ch. 30), snow drift surcharge (ASCE 7 Ch. 7), MWFRS wall pressure (ASCE 7 Ch. 27), RC slab min thickness (ACI 7.3.1), doubly-reinforced beam (ACI), shear friction (ACI 22.9), consolidation settlement (Terzaghi), eccentric footing pressure / kern, surcharge lateral pressure (Boussinesq / NAVFAC), steel beam-column interaction (AISC H1), effective-length factor K (alignment chart), bolt combined tension+shear (AISC J3.7), relative compaction (Proctor QC), soil phase relations (e/n/S), Atterberg indices / A-line, cantilever beam moment/shear/deflection, cross-section properties (A/I/S/r), combined axial + bending stress (P/A +/- Mc/I), weld dilution ratio, weld passes / arc time to fill a groove, weld travel speed for a target heat input, shaft torsional shear / angle of twist, restrained thermal stress / force, thin-wall pressure vessel hoop stress, masonry wall dead load (NCMA), brick veneer anchor spacing (TMS 402/IBC), masonry lintel arching load, seismic spectral acceleration / story drift / P-delta (ASCE 7 §11.4 / §12.8), rain-on-snow / sliding / minimum roof snow (ASCE 7 Ch. 7), ADA ramp layout (multi-run + landings) |
F | Fire-Ground Engineering | 31 | pump discharge pressure, standpipe PDP (NFPA 14), needed fire flow, nozzle reaction, sprinkler K-factor, elevation pressure loss/gain, water-supply duration, smooth-bore nozzle flow (GPM from NP) |
G | Cross-Trade Utilities | 54 | unit conversion, mileage cost, NIOSH lifting, heat stress, haversine, rolling offset (pipefitting), fitting take-out cut length, multi-piece miter elbow, pipe wraparound template, flange bolt-up torque (ASME PCC-1), interference shrink-fit temperature, center of gravity from two scales, bolt-circle hole layout, decimal to fraction / feet-inches, sine bar angle setup, thread pitch and lead, three-wire thread measurement, punch / shear force, rolled plate blank length, tank volume from dipstick, circular arc layout (chord & rise), circle through three points, linear interpolation, regular polygon miter / layout, equal spacing (baluster / picket) |
H | Knowledge References | 15 | color codes, knot reference, wire gauge tables |
J | Trucking and Logistics | 21 | bridge formula, HOS math, cargo securement WLL, IFTA fuel tax, operating cost per mile, deadhead percentage, axle-load tandem slide, per-load profitability / profit-per-mile, fuel surcharge per mile (pegged base), maintenance reserve per mile, GCWR combination weight check, tire load-rating check |
K | Mechanic (Auto, Marine, Aviation) | 36 | fuel range, valve Cv, screw conveyor, HP from torque/RPM (5252), volumetric efficiency, gear-ratio MPH from RPM, machining speed and feed (SFM to RPM, feed IPM), drill point depth (tip allowance), cut time per pass, material removal rate (MRR), theoretical surface finish (Ra/Rt), taper per foot and angle, dividing-head simple indexing, tap drill size, 2K paint mix ratio, cutting-fluid concentration (refractometer), cutting power / spindle torque from MRR, radial chip thinning (RCTF), boring-bar / overhang deflection (L/d), ballnose scallop height, fuel injector sizing (BSFC), mean piston speed / rpm limit, trap-speed horsepower (Hale), prop pitch selection, engine fuel burn (BSFC), alternator charging load, hydraulic pump horsepower |
L | Agriculture and Forestry | 39 | sprayer calibration, irrigation requirement, NPK blend, pesticide REI/PHI, growing degree days, Pearson-square feed ration, livestock water requirement, two-stroke fuel mix (chainsaw / trimmer), green log / limb weight (FPL), tree rigging shock load (ANSI Z133), felling notch / hinge geometry, porta-wrap friction by wraps (capstan), brush chip volume / haul loads, nozzle flow vs pressure / tip selection, downwind spray drift buffer, sprayer field capacity / spray time, hay dry-matter / safe-storage weight, sprinkler precipitation rate, irrigation zone runtime (cycle-and-soak), drip zone flow vs valve capacity, plant spacing count (square / triangular), sod takeoff (slabs / pallets), grain drying shrink / net bushels, livestock dry-matter intake / as-fed ration, nutrient-based manure application rate (NRCS 590) |
M | Water and Wastewater Operations | 28 | pounds formula, detention time, disinfection CT, well drawdown, backflow test, weir/flume open-channel flow, Langelier index, chemical metering-pump setting, pool total-alkalinity adjust, pool cyanuric-acid dose, pool salt dose (SWG), chlorine demand / breakpoint, UV disinfection dose, pool free-chlorine dose by product, pool heater sizing / heat-up time, breakpoint chlorination dose |
N | Stage and Live Production | 15 | DMX addressing, SPL distance, rigging pulley MA, power distro per-leg loading, speaker impedance network, decibel converter, amp power / SPL, stage lighting beam and throw, LED video-wall build (resolution / power / weight), projector brightness and throw, room acoustics (RT60 / axial modes) |
O | Kitchen and Food Service | 11 | recipe scaling, food cost, tip-out split, brine / cure concentration, baker's percentage / dough hydration, period food-cost % and variance, restaurant prime cost, beverage pour cost |
P | Field, Backcountry, and SAR | 15 | backcountry needs, ramp slope, rainwater capture, search probability of detection, area by coordinates (shoelace), traverse closure (Bowditch), hiking time (Naismith's rule), differential leveling (HI method), stadia tacheometry, steel-tape distance corrections |
Q | Historical Reference Data | 1 | historical reference lookup |
R | Accounting, Tax, and Small-Business | 25 | loan amortization, MACRS, breakeven, payroll withholding, declining-balance depreciation, markup vs. margin, employer payroll tax, fully-burdened labor rate, equipment owning & operating hourly rate, overhead recovery rate, WIP percent-complete billing, retainage tracker, surety bond premium, workers-comp EMR premium |
T | Bench Science and Laboratory Math | 14 | Beer-Lambert, dilution, Henderson-Hasselbalch, OD600, gel %, primer melting temperature (Tm), CFU/mL plate count |
X | Real Estate | 30 | LTV, DTI, PITI, cap rate/DSCR, depreciation recapture, gross rent multiplier, PMI cancellation/termination, seller net proceeds sheet, debt yield (loan sizing), break-even occupancy, fix-and-flip max offer (70% rule) |
Y | Educators and K-12 | 22 | readability scores, bell-curve CDF, Pearson correlation, chi-square GOF, linear regression, final-exam grade needed, weighted category grade, two-sample t-test |
Z | Rigging and Heavy Lift | 15 | center of gravity / pick-point load share, crane net capacity after deductions (OSHA 1926.1417), outrigger ground bearing / mat size, wire-rope sling D/d bend efficiency (WRTB), wind force / swing on a suspended load, tag-line pull and handler count, tandem two-crane lift share, shackle / eye-bolt angular derate (ASME B30.26), spreader bar vs lifting beam (ASME BTH-1), forklift load-center derate (ASME B56.1), roller / skate / jacking push force, chain / lever hoist effort (ASME B30.16/21), rigging block redirect resultant, multi-leg sling load distribution, wire-rope breaking strength (IWRC) |
The full inventory is in the specs. Each spec inherits all prior specs by reference: spec.md is the v1 source of truth; v2 through v4 expanded the catalog; v5 added Accounting / Legal / Lab; v6 set citation discipline; v7 through v9 added tiles; v10 was a platform-only maintenance pass; v11 retired Recents and Big Buttons; v12 added five allied-profession groups (U/V/W/X/Y) plus a mobile-responsive sweep, a wiring-correctness lint, and a tiered data-refresh; v13 added the prerendered discoverable surface; v14 is the correctness pass (below). Specs v15 through v17 draft a 385 to 485 tile expansion; landing is incremental against the live catalog (much of v15 was already in place). Spec-v15 is now fully closed (all 35 tiles, catalog at 400; package version stamped 0.15.0). Group A (Electrical) added voltage drop with reactance (NEC Chapter 9 Table 9), the power-triangle solver (IEEE 1459), EV charger continuous load (NEC Article 625), conductor ambient + fill ampacity adjustment (NEC 310.15), the service-load optional method (NEC 220.82), PV interconnection 120% busbar (NEC 705.12), and off-grid battery sizing (IEEE 1013). Group E (Carpentry) added window/door header sizing (IRC R602.7 + AWC NDS, with C_D / C_F factors and a jack-stud count) and deck beam/post sizing (IRC R507 + an NDS column check, footing, and ledger schedule). Group F (Fire-Ground) added standpipe pump discharge pressure (NFPA 14) and smoke-ejector / negative-pressure ventilation CFM (NFPA 1500 / IFSTA). Group G (Cross-Trade) added pump total dynamic head (Hazen-Williams / Crane TP-410), hydraulic cylinder force and speed (NFPA T2.13.7), V-belt sheave and drive sizing (ANSI/RMA IP-20 / IP-22), and the gear ratio / RPM cascade (AGMA 2000). All landed with full v14 discipline. The §H.6 per-group reviewer signoffs remain open and gate the "audited" announcement, not the landing.
Where the catalog stands today (landed through spec-v483; the v275-v374 and v375-v474 expansion campaigns are both complete, package 0.170.0): 942 tiles, 21 groups, 56 calc-* modules. Two inflections separate the current catalog from the v15-era origin above, and the dated entries below predate both -- read this paragraph first. (1) The spec-v106/v107 trades-only refocus (package 0.72.0). After the v101-v120 breadth pass peaked the catalog at 688 tiles across 25 groups, the v106 charter ruled four liability-bearing non-trade groups out of scope and v107 subtractively retired them -- S (Legal), U (Veterinary), V (EMS and Pre-hospital), and W (Pilots and General Aviation), plus one stray aircraft weight-and-balance tile filed under Group K -- each failing the inclusion test on gate 1 (not a trade) and gate 4 (failure mode is patient / animal harm, safety-of-life, or unauthorized practice of law). That removed 88 tiles (688 -> 600), deleted the four calc-legal/vet/ems/aviation.js modules, and dropped 44 tracked sources; retired letters leave gaps in A..Z rather than renumbering (spec-v106 §5), and 88 tile deep-links plus 4 group hubs stopped resolving (a deliberate breaking change to public URLs -- the SPA router lands an unknown #id on home). (2) The v121-v206 trades-only second pass (0.73.0 -> 0.83.0). Depth was rebuilt inside the surviving trades, taking the catalog 600 -> 664: the electrician second pass on motors / feeders / fault / grounding / three-phase (v121-v128, v164-v187), which split the motor bench into calc-motor.js for the catalog's 50th module; the metal-trades weld-estimating / plate-forming / shrink-fit bench (v129-v135); the steamfitting and process-piping / med-gas deepening (v157-v162, v204-v206); a hydronic + pipefitting batch (v199-v203); and the water-damage restoration second / third pass (v136-v140, v189-v198), which spec-v198 §6 notes leaves the IICRC S500 / S520 / S700 trade effectively saturated. Two post-batch QA patches close the line: 0.83.1 makes the OSHA trench-slope tile honor its surcharge input (defer to a PE rather than display a possibly-unsafe simple-slope number), and 0.83.2 retires five dead input controls a full-tree sweep found (a control the user can set that the math silently ignores) and adds a check-dead-inputs.mjs lint gate so the class cannot recur. (3) The v207-v214 landscape and masonry/finish pass (0.84.0). Two adjacent install benches the trades-only catalog had never carried take it 664 -> 672: the landscape-irrigation and planting install cluster in calc-agriculture.js Group L (v207 sprinkler-precip-rate, the in/hr a valve zone applies via PR = 96.3 x gpm / area, the number that sets the runtime and the reason sprays and rotors never share a valve; v208 irrigation-zone-runtime, net-over-rate, gross-over-distribution-uniformity, and a cycle-and-soak split to beat runoff; v209 drip-zone-flow, total emitter flow vs valve capacity with inline or point-source emitter counts; v210 plant-spacing-count, square and triangular (~15% denser staggered) plant counts from bed area and on-center spacing; v211 sod-takeoff, slabs and pallets from a lawn area plus a cut/edge waste allowance); and the masonry/finish takeoffs the two-tile masonry shelf left open in calc-construction.js Group E (v212 cmu-grout-volume, grouted-core plus bond-beam grout in cubic yards for a reinforced CMU wall; v213 masonry-coursing, courses to a height and the course-out check that flags a height off the 8 in CMU / three-course-brick module; v214 wallpaper-rolls, the strip-method roll takeoff where one pattern repeat is wasted per strip, so a large repeat can nearly double the order for the same wall area). (4) The fire & smoke restoration batch (0.85.0). Seven long-specified water-and-fire restoration tiles (spec-v141, v146-v148, v152-v154) that the v189-v198 water pass had left on the shelf land together, opening a fire-damage assessment family the catalog never carried and taking it 672 -> 679, all in calc-restoration.js Group D: v141 equipment-heat-load (the sensible heat a drying chamber's equipment dumps, 3.412 BTU/hr per watt, and the makeup ventilation to hold the efficient-evaporation band); v146 char-depth-capacity (the AWC/NDS one-dimensional char depth and the residual bending-capacity fraction that drives a charred beam's keep-or-replace call); v147 soot-cleaning-takeoff (dry-sponge count, labor, and odor-seal primer for dry smoke); v148 ozone-shock-treatment (volume-based ozone generator sizing with the unoccupied-sealed-aerate-below-0.1-ppm OSHA lockout front and center); v152 smoke-residue-method (the residue-type to cleaning-method screen, the decision every fire job turns on before a sponge or solvent is chosen); v153 thermal-fog-deodorization (label-rate fog deodorant dosage, the penetrating counterpart to ozone); and v154 contents-packout-inventory (boxes, climate storage, and truck loads for the contents side of the loss). Each is the bending section, a quantity, or a safety screen with the IICRC S700 / OSHA / AWC NDS authority that governs named in the citation; the remaining nine deferred restoration specs stay unbuilt as conceptually adjacent to live water tiles. (5) The roofing material-takeoff batch (0.86.0). Three install-side roofing tiles (spec-v215-v217) close the gaps the shingle-only roofing-squares left, taking the catalog 679 -> 682, all in calc-construction.js Group E: v215 ice-barrier-coverage (the eave ice-and-water membrane courses and rolls, where the slope factor sqrt(rise^2 + 144)/12 runs the IRC R905.1.2 coverage 24 in inside the wall line up the slope, so a deep overhang or low pitch quietly adds a course a one-roll-per-eave guess misses); v216 metal-roof-panels (panels, linear feet, and through-fasteners for one plane from the product's net coverage width, where a 36 in exposed-fastener panel and a 16 in standing-seam panel over the same plane differ by nearly a factor of two in panel count); and v217 ridge-cap-fasteners (hip/ridge cap bundles by the linear foot and roofing nails by the pound, where IRC R905.2.6 steps the field pattern from four nails to six in the high-wind rows and moves the order by half again). Each is a material takeoff, not an installation detail, with the IRC / ASTM D1970 / MCA-MRA authority that governs named in the citation. (6) The energy / structural / solar building-science batch (0.87.0). Twelve tiles in four trios take the catalog 682 -> 694, deepening the residential-energy, structural-load, PV-design, and cooling-load corners with no new module, group, or dependency: the air-tightness and ventilation trio in calc-hvacservice.js Group C (v218 blower-door-ach50, ACH50 = CFM50 x 60 / volume against the IECC R402.4.1.2 limit plus the LBL natural-infiltration the next two tiles consume; v219 ashrae-622-ventilation, the 62.2 whole-house Qtot and the continuous fan a tightened house then needs; v220 infiltration-load, the sensible 1.08 x cfm x dT and latent 0.68 x cfm x grains the leakage drives); the PV system-design trio in calc-solar.js Group A (v221 pv-energy-yield, the PVWatts annual kWh, specific yield, and capacity factor; v222 pv-row-spacing, the inter-row pitch and ground-coverage ratio from tilt and the winter-sun profile angle; v223 pv-inverter-ratio, the DC:AC loading ratio and clipping onset against the 1.1-1.3 band); the ASCE 7 structural design-loads trio in calc-construction.js Group E (v224 rain-load-ponding, the 5.2 psf/in rain load at the blocked-primary case plus the IPC secondary-drainage flow; v225 asce7-load-combinations, the seven §2.4.1 ASD combinations reduced to the governing gravity demand and the net uplift; v226 seismic-base-shear, the §12.8 equivalent-lateral-force Cs and base shear with the period cap and code minimum); and the cooling-load-components trio in calc-hvacsystems.js Group C (v227 window-solar-heat-gain, the fenestration solar A x SHGC x PSF and conduction A x U x CLTD; v228 internal-heat-gains, the people / lighting / equipment sensible-latent split; v229 envelope-conduction-load, the opaque sol-air U x A x CLTD that makes the cool-roof case). Each compute matches its pinned worked example to the digit and carries the v14 dims annotation, the v18/v21 {error} contract, and v19/v22 citation discipline naming the ASHRAE 62.2 / IECC / NREL PVWatts / ASCE 7 / Manual J authority that governs. (7) The energy-cost-savings and equipment-sizing batch (0.88.0). Twelve tiles in four trios take the catalog 694 -> 706, turning physics the catalog already carried into the retrofit and operating-cost numbers a trade actually quotes, again with no new module, group, or dependency: the electrical energy-cost-savings trio in calc-service.js Group A (v230 vfd-energy-savings, the annual kWh and dollars a variable-frequency drive saves on a centrifugal load, integrating the affinity cube law over a three-bin duty cycle so the load profile, not the horsepower, is the business case; v231 lighting-retrofit-savings, the energy plus demand-charge savings and simple payback of an LED fixture swap; v232 power-factor-billing-savings, the kVA demand a capacitor bank frees and the payback against a $/kVA-month tariff); the heat-pump heating-mode trio in calc-hvac.js Group C (v233 heat-pump-seasonal-energy, the seasonal operating cost of a heat pump set beside gas and resistance at the local rates via the AHRI 210/240 HSPF; v234 dual-fuel-balance-point, the economic switchover COP where a dual-fuel thermostat should hand off to gas; v235 heat-pump-cold-capacity, the AHRI-47/17 capacity interpolation to the design day and the auxiliary strip heat a cold-climate conversion needs); the grid-tied battery-economics trio in calc-solar.js Group A (v236 battery-tou-arbitrage, the time-of-use spread value net of the round-trip loss and its break-even ratio; v237 battery-peak-shaving, the demand-charge savings and the energy-limited actual shave a battery can hold across a peak; v238 battery-c-rate, the deliverable power bounded by the C-rate and the inverter, and the discharge duration); and the compressed-air energy trio in calc-hvac.js Group C (v239 air-leak-cost, the DOE load/unload leak-test flow and annual cost; v240 compressed-air-power, the single-stage isentropic compression horsepower and running cost; v241 air-pressure-setpoint-savings, the isentropic power-ratio savings from dropping the discharge pressure, reproducing the DOE ~0.5% per-psi rule). Each compute matches its pinned worked example to the digit and carries the v14 dims annotation, the v18/v21 {error} contract, and v19/v22 citation discipline naming the US DOE / AHRI 210/240 / NREL / power-triangle authority that governs. (8) The restoration novelty backfill (0.89.0). Four of the nine deferred water/mold specs (spec-v143, v150, v155, v156) that the fire & smoke batch (4) had left on the shelf, re-vetted one last time against the now-42-tile Group D catalog and landed only where they answer a question no live tile already does, taking it 706 -> 710, all in calc-restoration.js Group D: v143 surface-condensation-risk (the Magnus dew point of the chamber air compared to the coldest IR-read surface, flagging where drying air will condense and make secondary water -- the surface screen psychrometric never made); v150 spore-io-ratio (the indoor/outdoor airborne-spore ratio and the water-damage marker-genera check, the clearance read no tile computed); v155 hardwood-floor-drying-mat (the Class 4 mat-and-suction-unit count for saving a wet wood floor in place, the specialty equipment the class screen routes to but never sized); and v156 mold-cleaning-labor (the multi-pass HEPA-vacuum-and-damp-wipe labor hours and crew calendar time, the S520 source-removal cost driver between the scope tier and the chemistry). The other five deferred specs stayed unbuilt as genuine near-duplicates: v145 (antimicrobial-coverage) duplicates the live antimicrobial-dilution (which already sizes coverage), v151 (dry-standard-mc) duplicates moisture-dry-goal, and v142 / v144 / v149 overlap evaporation-load / flood-cut-quantity / air-sample-volume. Each landed tile matches its pinned worked example to the digit and carries the v14 dims annotation, the v18/v21 {error} contract, and v19/v22 citation discipline naming the ANSI/IICRC S500 / S520 authority that governs. (9) The building-code batch (0.90.0). Nine tiles in three code trios take the catalog 710 -> 719, all in calc-construction.js Group E with no new module, group, or dependency: the IBC/IPC occupancy trio (v242 occupant-load, the summed ceil(area / occupant-load factor) the whole life-safety chain hangs on, where the use, not the area, sets the factor; v243 egress-capacity, the exit count from the 49/500/1000 thresholds and the required width from the 0.15/0.2/0.3 in-per-occupant capacity factors, floored at the 32 in door leaf; v244 plumbing-fixture-count, the minimum water closets, lavatories, fountains, and service sink from the per-sex two-tier ratios of Table 2902.1); the cast-in-place placing-and-curing trio (v245 shore-post-load, the ACI 347 max(slab + form + live, 100 psf) design pressure times the shore tributary area, the vertical companion to formwork-pressure; v246 concrete-evaporation-rate, the ACI 305 / Menzel plastic-shrinkage go/no-go where the concrete temperature, not the air, drives the vapor term; v247 concrete-strength-gain, the ACI 209R t/(a+bt) developed fraction and the inverse solve for the age to a strip/shore-removal target); and the IBC plan-review trio (v251 allowable-area, the Chapter 5 Aa = At + NS x If with the frontage increase and the sprinkler-column choice that can triple the area; v252 egress-travel-distance, the Chapter 10 travel / common-path / dead-end three-check where a single fail fails the floor; v253 exterior-opening-protection, the Table 705.8 opening-area limit banded by fire separation distance and protection status). Each compute matches its pinned worked example to the digit (the v244 restaurant cross-check corrects a ceil(80/75) arithmetic slip in the spec prose to the code-correct four water closets) and carries the v14 dims annotation, the v18/v21 {error} contract, and v19/v22 citation discipline naming the IBC 2021 / IPC / ACI 347 / ACI 305 / ACI 209R authority that governs. The two new-module trios the same batch proposed -- the NFPA 20/13 fire-sprinkler system-design trio (spec-v248-v250, calc-firesprinkler.js) and the AISC 360 steel-member trio (spec-v254-v256, calc-steel.js) -- stay PROPOSED, each requiring a new lazy module. (10) The NDS sawn-lumber design batch (0.91.0). Three tiles in one trio take the catalog 719 -> 722, all in calc-construction.js Group E beside the existing column-buckling-wood (compression) tile, with no new module, group, or dependency -- they add wood as the fourth structural material in Group E beside steel, reinforced concrete, and geotechnics: the sawn-lumber design trio (v263 wood-beam-bending, the NDS 3.3.3 beam stability factor CL from the beam slenderness RB = sqrt(le d / b^2) and the critical FbE = 1.20 Emin' / RB^2, then the adjusted bending value Fb' = Fb* CL and allowable moment M' = Fb' S -- the flexural twin the catalog had been missing since it shipped the wood column, where a stocky, nearly-braced 4x12 holds CL near 1.0 and the same beam left tall and unbraced drops it off a cliff; v264 wood-beam-shear, the rectangular fv = 3V / (2 b d) (NDS 3.4.2) and the tension-side end-notch reduction V' = (2/3) Fv' b dn (dn/d)^2 (NDS 3.4.3.2), where a single 2 in notch in a 4x12 cuts the allowable end reaction nearly in half through the squared depth ratio; v265 wood-bolt-connection, the full six-mode single-shear NDS European yield model Z from the dowel bearing strengths Fe|| = 11,200 G / Fe_perp = 6,100 G^1.45 / sqrt(D) Hankinson-blended to the angle to grain, the bolt bending yield, and the geometry, with the governing value the smallest of the six modes -- a 1/2 in bolt into a thin side member governs in mode IIIs). Each compute matches its pinned worked example to the digit (v263 CL 0.985 / Fb' 1,329 psi / M' 8,179 ft-lb, v264 Vr 4,725 lb / Vr' 2,626 lb / dcr 0.76, v265 governing Z 615 lb in mode IIIs) and carries the v14 dims annotation, the v18/v21 {error} contract (including the RB > 50 slenderness and dn > d notch-depth seams), and v19/v22 citation discipline naming the NDS 3.3.3 / 3.4 / Chapter 12 authority that governs. With this trio the four member-level limit states -- bending, shear, compression, and connection -- are all covered for sawn lumber. (11) The AISC 360 structural-steel batch (0.92.0). Six tiles in two trios take the catalog 722 -> 728 in a new lazy Group E module, calc-steel.js -- the catalog's 51st calc-* module and the first to check the steel member itself (it already sized steel welds in fillet-weld-strength / groove-weld-strength, and wood members in beam-loading / column-buckling-wood, but never the rolled shape). The steel-member trio (v254 steel-beam-flexure, the AISC 360 Ch. F plastic-moment plateau Mn = Mp = Fy Zx with the ASD Mn/1.67 and LRFD 0.90 Mn, matching Manual Table 3-2 for a W18x50 to 252 / 379 kip-ft; v255 steel-beam-shear, the Ch. G web shear Vn = 0.6 Fy Aw Cv1 with the paired Omega_v = 1.50 / phi_v = 1.00 rolled-I-shape factors, the end check a moment-passing beam can still fail; v256 steel-column-capacity, the Ch. E flexural-buckling Fcr from KL/r, the elastic Fe = pi^2 E/(KL/r)^2, and the 4.71 sqrt(E/Fy) inelastic-elastic transition, where stretching a W10x45 from 14 to 24 ft drops it from 239 to 97 kips on slenderness alone) and the bolted-connection trio (v266 bolt-group-eccentric, the elastic vector method that superposes the direct shear P/n with the torsional M r / Ip on the worst corner bolt of a bracket group, the bolted counterpart to the existing weld-group-eccentric; v267 bolt-shear-bearing, the AISC J3.6 shear rupture Fnv Ab against the J3.10 bearing/tearout min(1.2 lc t Fu, 2.4 d t Fu), catching the flip from bolt-shear- to tearout-governed when the plate thins; v268 column-base-plate, the Design Guide 1 bearing area A1_req, the m/n/n' cantilevers, and the thickness tp = l sqrt(2 Pu/(0.90 Fy B N)), flagging an undersized plate in bearing). Each compute matches its pinned worked example to the digit (v254 Mn 421 / Ma 252 kip-ft, v256 Pa 239 kips inelastic then 97 kips elastic, v266 R 15.1 kip on the corner bolt, v267 the 17.9 -> 14.3 kip tearout flip, v268 tp 1.06 in) and carries the v14 dims annotation, the v18/v21 {error} contract, and v19/v22 citation discipline naming the AISC 360-22 Ch. E/F/G/J and Design Guide 1 authority that governs. With steel joining wood, reinforced concrete, and geotechnics, the module registration (a new app.js declare, sw.js precache, build.mjs FILES entry, and check-module-sizes cap) is the new-module scaffolding the prior in-module batches did not need. The remaining new-module trios followed and are all landed: fire-sprinkler (spec-v248-v250, 0.93.0, calc-firesprinkler.js), ACI 318-19 reinforced concrete (v257-v259, 0.94.0, calc-concrete.js), geotechnical foundation-and-earth-retaining (v260-v262, 0.95.0, calc-geotech.js), TMS 402-16 reinforced masonry (v269-v271, 0.96.0, calc-masonry.js), and SDPWS wood lateral (v272-v274, 0.97.0, calc-lateral.js) -- landing the tree through v274. (12) The v275-v374 expansion campaign (0.98.0 through 0.116.0). One hundred proposed trade tiles (specs v275-v374) landed in trio batches (taking the catalog to 800), opening with the HVAC ventilation-and-recovery trio in calc-hvac.js Group C (v275 erv-sensible-recovery, the ASHRAE 84 / AHRI 1060 sensible effectiveness and the load the core takes off the plant; v276 mua-tempering-load, the sensible/latent/total makeup-air tempering load and burner input behind an IMC 508 exhaust hood; v277 dcv-co2-ventilation, the steady-state CO2 mass balance behind a demand-controlled ventilation setpoint), followed by the NEC conductor-and-overcurrent-sizing trio across the Group A electrical modules (v278 motor-overload-sizing, the 430.32 running overload on the nameplate FLA that motor-branch-protection defers; v279 service-conductor-sizing, the 310.12 dwelling 83% service-entrance conductor from the Table 310.16 75 degC column; v280 continuous-load-ocpd, the 210.20/215.3 continuous-load device and conductor at 125% with the 240.6(A) round-up), and the steel members-and-connections depth trio in calc-steel.js Group E (v281 steel-beam-ltb, the F2 lateral-torsional buckling moment the braced flexure tile defers, with the F2-6 Lr and the three-zone Mp/interpolated/elastic-Fcr grading; v282 steel-block-shear, the J4.3 tension-plus-shear tear-out at a bolted or coped end; v283 steel-tension-member, the D2/D3 gross-yield vs net-rupture pair with the U = 1 - xbar/L shear-lag penalty), and the reinforced-concrete member depth trio in calc-concrete.js Group E (v284 rc-column-axial, the 22.4 tied-column Po with the 0.80 phi accidental-eccentricity cap; v285 rc-punching-shear, the 22.6 two-way d/2-perimeter punch that sets flat-plate thickness; v286 rc-hook-development, the 25.4.3 db^1.5 standard-hook length beside the straight-bar tile), and the geotechnical foundation depth trio in calc-geotech.js Group E (v287 soil-settlement-elastic, the immediate settlement soil-bearing-capacity calls separate; v288 pile-axial-capacity, the alpha-method skin-plus-tip pile capacity beside the helical torque correlation; v289 slope-stability-infinite, the translational cut-slope factor of safety with the tan phi/tan beta cohesionless identity), and the NDS wood-member depth trio in calc-construction.js Group E (v290 wood-bearing-perpendicular, the 3.10 crushing check with the Cb bearing-area factor; v291 wood-tension-member, the 3.8 net-section tie beside the strut; v292 wood-combined-bending-axial, the 3.9.2 beam-column interaction with the P-delta amplifier), and the steel connection/detailing depth trio in calc-steel.js Group E (v293 steel-web-local-strength, the J10 web yielding/crippling pair that decides a bearing stiffener; v294 steel-bolt-slip-critical, the J3.8 friction resistance beside the bearing-type bolt; v295 steel-fillet-weld-size, the Table J2.4 / J2.2b leg window, throat, and minimum length a WPS is written to), and the ASCE 7 wind-and-snow load depth trio in calc-construction.js Group E (v296 wind-cc-pressure, the Ch. 30 components-and-cladding corner suction; v297 snow-drift-load, the Ch. 7 leeward-drift surcharge at a step; v298 wind-mwfrs-pressure, the Ch. 27 windward/leeward wall pressures and the internal-cancelling net), and the reinforced-concrete depth-2 trio in calc-concrete.js Group E (v299 rc-slab-min-thickness, the Table 7.3.1.1 deflection-waiving depth; v300 rc-doubly-reinforced, the compression-steel second couple; v301 rc-shear-friction, the 22.9 mu Avf fy interface transfer with its concrete cap), and the site-hydraulics depth trio in calc-plumbing.js Group B (v302 time-of-concentration, the Kirpich storm duration the rational method needs; v303 orifice-flow, the detention-outlet discharge Cd A sqrt(2gh); v304 channel-froude-number, the open-channel subcritical/supercritical regime and critical depth), and the pump-and-fluid fundamentals trio in calc-hvac.js Group C (v305 reynolds-number-pipe, the Re = VD/nu laminar/turbulent regime the friction tiles use implicitly; v306 hydronic-gpm-deltat, the GPM = Q/(500 dT) system flow; v307 pump-specific-speed, the Ns = N sqrt(Q)/H^(3/4) impeller-type index), and the geotechnical depth-2 trio in calc-geotech.js Group E (v308 soil-consolidation-settlement, the Terzaghi primary consolidation of clay; v309 footing-eccentric-pressure, the kern-check trapezoidal/triangular bearing pressure; v310 boussinesq-surcharge-wall, the NAVFAC line-load lateral pressure on a rigid wall), and the field-surveying depth trio in calc-survey.js Group P (v311 differential-leveling, the HI-method vertical control and loop misclosure; v312 stadia-distance, the stadia tacheometry distance and elevation; v313 taping-corrections, the temperature/slope/tension/sag steel-tape corrections), and the steel beam-column-and-connection depth trio in calc-steel.js Group E (v314 steel-h1-interaction, the H1.1 combined axial-plus-flexure unity check; v315 steel-effective-length-k, the alignment-chart K from the G factors; v316 steel-bolt-tension-shear, the J3.7 reduced bolt tension), and the machining depth trio in calc-machining.js Group K (v317 radial-chip-thinning, the RCTF feed compensation at light radial engagement; v318 boring-bar-deflection, the cantilever tool deflection and L/d chatter limit; v319 ballnose-scallop-height, the 3D-finish scallop from stepover), and the refrigeration-cycle trio in calc-refrigerant.js Group C (v320 refrigerant-mass-flow, the m_dot = Q/(h1 - h4) circulation rate; v321 refrigeration-cop, the cycle COP and Carnot ceiling; v322 condenser-heat-rejection, the THR = Q(1 + 1/COP) condenser load), and the engine-build performance trio in calc-mechanic.js Group K (v323 injector-size, the fuel injector flow from horsepower and BSFC; v324 mean-piston-speed, the reciprocating-stress rpm-limit read; v325 trap-speed-horsepower, the Hale quarter-mile power estimate), and the soil characterization / QC trio in calc-earthwork.js Group E (v326 relative-compaction, the Proctor field-density QC grade; v327 soil-phase-relations, the void-ratio/porosity/saturation three-phase makeup; v328 atterberg-indices, the plasticity indices and A-line USCS classification), and the building-energy trio in calc-hvac.js Group C (v329 building-ua, the whole-envelope heat-loss coefficient; v330 degree-day-energy, the annual heating energy and fuel cost; v331 wall-condensation-gradient, the through-wall condensation-plane screen). (13) The v375-v474 expansion campaign (0.117.0 through 0.162.0). A second hundred-spec campaign (specs v375-v474, all proposed 2026-07-03) landed the same way, trio by trio: roughly 86 of the 100 proposed tiles were genuinely new and landed, and the rest were cut as concept-duplicates of live tiles (each cut recorded in its spec's Status line), taking the catalog 800 -> 929 across the existing 21 groups and 56 modules with no new module or dependency. The batches deepened HVAC psychrometrics and coil performance, low-voltage AV/security/data, marine and engine mechanics, roofing ventilation, ASCE 7 snow provisions, and electrical energy economics, closing with the ADA ramp-layout tile (spec-v474). Spec-v475 is a copy-only follow-up recording the deliberate removal of the home-page offline/PWA + MCP note. Every gate is green at the current state: lint (all 28 checks agreeing at 942 tiles / 56 modules / 964 sitemap URLs), 5,235 unit tests, build (942 tile + 21 group shells), data:verify, the 942-tile render-no-nan sweep, the 320px shell-mobile audit, and the responsive-stress sweep on Chromium and WebKit. The dated entries below are the historical landing record (newest-curated, not exhaustive); the CHANGELOG is the complete per-release log. See specs/spec-v106.md and specs/spec-v107.md.
Spec-v24 (Trade-Floor Deepening) and spec-v25 (Surveying and Civil Layout) are closed; package version stamps 0.26.0. These two landed together on 2026-06-09: 16 new tiles plus 3 additive enhancements, taking the catalog 515 -> 531 with no new group letters (every tile deepens an existing group). The headline is conduit bending, the single most-performed piece of field math an electrician does in a day and a gap the catalog had exactly where its first user reaches first. Group A gained the three-tile bending suite (conduit-offset, conduit-saddle, conduit-90-stub): the cosecant offset multiplier, the three- and four-point saddle marks, and the 90-degree stub deduct plus segmented bends, all first-principles trigonometry with the bender deduct/shoe figures user-supplied and flagged confirm-against-your-tool. Group E gained welding heat input (weld-heat-input, the AWS D1.1 / ASME BPVC Section IX HI = (60 x V x I) / TS definition with the arc-efficiency factor by process), metal weight by shape and alloy (metal-weight), and 3-4-5 layout squaring (layout-squaring), then the v25 civil set: horizontal (circular) and vertical (parabolic) curve layout (horizontal-curve, vertical-curve, AASHTO Green Book + FM 5-233), average-end-area and prismoidal earthwork volume (earthwork-end-area, FHWA / FM 5-233), and slope-stake cut/fill with the catch-point offset (slope-stake-cut-fill, FM 5-233). Group G gained the rolling offset (rolling-offset, the Pythagorean true offset and cosecant travel of NCCER pipefitting). Group N gained the day-of-show speaker electronics (speaker-impedance, decibel-converter, amp-power-spl, Ohm's-law networks + the ANSI S1.1 decibel basis). Group P gained the surveyor's tailgate math: area by coordinates (area-by-coordinates, the shoelace method) and traverse closure with the Compass/Bowditch adjustment (traverse-closure). The three enhancements are additive with backward-compatible defaults: tire-gearing now reports the speedometer/odometer error from a tire swap (EN.1), spl-distance adds incoherent N-source summation at +3 dB per doubling with N=1 reproducing the prior output exactly (EN.2), and bend-allowance exposes the bend deduction BD = 2 x OSSB - BA beside the existing flat-pattern length (EN.3). Every new tile carries the full v14 discipline and is born into the v18/v21 output contract (the tile-contract sweep reports 0 Tier-1 and 0 Tier-2 across 536 swept tiles; the angle-to-zero cosecant, zero travel speed, zero radius/length, and zero perimeter/misclosure divisor seams are all guarded per RC-1/RC-2) and the v19/v22 citation discipline. A count reconciliation is recorded honestly: the spec-v24 draft summary stated a 12-tile delta with a "K +2" line, but the spec body specifies only the 10 tiles above and no Group K new-tile section exists; rather than fabricate two uncited tiles to hit a number, the build landed exactly what the body specifies. See specs/spec-v24.md, specs/spec-v25.md, and the 2026-06-09 stanza in docs/audit-trail.md.
Spec-v26 through v30 are closed; package version stamps 0.31.0. Five deepening specs landed on 2026-06-09, taking the catalog 531 -> 555 (24 net-new tiles, no new group letters): the founding trades, the adjacent metal/air/rigging benches, the low-voltage cabling trade, and the pipe/raceway and metal/air/refrigerant roadmap benches. v26 (531 -> 540) finished the founding trades: Group A gained the feeder for a bank of motors (motor-feeder-multiple, NEC 430.24/430.62) and the transformer's two-sided conductor/protection sizing (transformer-conductor-protection, NEC 450.3(B)/240.21(C)); Group B gained the tempering-valve blend temperature (mixed-water-temp, ASSE scald limits), the well pressure-tank drawdown by Boyle's law (pressure-tank-drawdown), and the copper erosion-corrosion velocity check (pipe-velocity); and Group G gained the pipefitter's everyday bench: the fitting take-out cut length (pipe-fitting-takeout), the lobster-back miter (pipe-miter-cut), the wraparound template ordinates (pipe-template-wrap), and the flange bolt-up torque with the ASME PCC-1 cross sequence (flange-bolt-torque). v27 (540 -> 543) added the fillet-weld strength/size tile (fillet-weld-strength, AWS D1.1 / AISC 360 §J2), the ASHRAE round-to-rectangular duct equivalent (round-to-rect-duct), and the rigger's two-scale center of gravity (center-of-gravity-2point, ASME B30.9). A concept-overlap reconciliation is recorded honestly here, in the v24 tradition: the v27 draft proposed six tiles, but three of them (duct-sizing-friction, superheat-subcooling, sling-load-tension) duplicated existing tiles (duct-sizing, superheat-subcool, sling-angle) by concept; rather than ship near-duplicates to hit the number, those three were dropped-not-renamed and their genuinely net-new deltas (the trunk/branch velocity ceiling, the TXV/EEV target-subcool verdict, and the D/d bend efficiency + minimum rated-capacity + sub-30-degree hazard flag) landed as additive, backward-compatible enhancements to the existing tiles. v28 (543 -> 549) opens the structured-cabling trade in a new calc-lowvoltage.js module: the fiber loss budget (fiber-loss-budget, TIA-568/526 + IEEE 802.3), cable-tray fill (cable-tray-fill, NEC 392.22), CCTV/NVR storage (cctv-storage), the 70 V distributed-audio line (speaker-70v-line, NEC 640/725), the fire-alarm standby battery (standby-battery-sizing, NFPA 72 §10.6), and coax attenuation (coax-rg-loss), plus an additive NAC end-of-line voltage check on lv-dc-drop. The spec-v28 §1.1 decision to open a dedicated Group Z is gated on maintainer signoff; pending it, the six tiles land in Group A as a low-voltage sub-cluster via the spec's documented fallback (the group letter is the only thing that changes if Z is later approved). v29 (549 -> 552) lands the first batch off the spec-v28 §7 long-term trades roadmap -- three first-principles, hand-verifiable thermal-movement / field-layout tiles deepening existing groups: pipe cold spring (pipe-cold-spring, the cut-short gap and residual movement, ASME B31.1 §119), the PVC raceway expansion fitting (raceway-expansion-fitting, the NEC Table 352.44 coefficient and the 0.25 in threshold), and insulated pipe-rack spacing (pipe-spacing-rack, center-to-center and bundle width, ASTM C585). The batch is deliberately scoped to math that is hand-verifiable to the last digit -- the gates check finiteness and dimensions, not absolute formula correctness, so the table-method tiles (arc-flash PPE, GEC Table 250.66) stay on the roadmap for a reviewed change. The three live in a new calc-pipefit.js module since calc-electrical.js and calc-plumbing.js are at their size caps. v30 (552 -> 555) lands the §7.4-7.6 metal/air/refrigerant block, same discipline: the groove-weld shear capacity (groove-weld-strength, the AISC Table J2.5 0.60*FEXX throat case, AWS D1.1 / AISC 360 §J2, complementing the v27 fillet tile), the total external static pressure roll-up (duct-static-pressure-total, ACCA Manual D, a component-drop sum against the blower rating), and the refrigeration compression ratio (compression-ratio-refrig, absolute discharge over absolute suction with an altitude correction and a high-ratio flag, ASHRAE) -- in a new calc-metalair.js module since calc-construction.js and calc-hvac.js are at their caps. Every new tile carries the full v14 discipline and the v18/v21 contract (tile-contract sweep: 0 Tier-1 / 0 Tier-2 across 560 swept tiles); the new divisor seams are all RC-1/RC-2 guarded. See specs/spec-v26.md, specs/spec-v27.md, specs/spec-v28.md, specs/spec-v29.md, specs/spec-v30.md, and the 2026-06-09 stanzas in docs/audit-trail.md.
Spec-v31 (Machinist Bench) is closed; package version stamps 0.32.0. A single first-principles tile deepening Group K (Mechanic), taking the catalog 555 -> 556: cutting-speed-rpm (Machining Speed and Feed). It answers the question every machinist and metal fabricator asks before every cut -- the spindle speed RPM = 12 x SFM / (pi x diameter) from a surface speed and the cutter or work diameter, plus the feed rate IPM = RPM x flutes x chip load per tooth -- and is hand-verifiable to the last digit (100 SFM on a 0.5 in 2-flute cutter at 0.002 in/tooth -> 763.94 RPM, 3.056 IPM). Like the conduit-bender and POH figures elsewhere in the catalog, the recommended surface speed and chip load are user-supplied from the tool/material chart (no paywalled table is transcribed); the formula is pure cutting geometry (Machinery's Handbook speeds-and-feeds method, by name). It lands in calc-mechanic.js (cap bumped 18.5 -> 19.5 KB) with the full v14 discipline and the v18/v21 output contract. See specs/spec-v31.md.
Spec-v32 (Layout-Geometry Bench) is closed; package version stamps 0.33.0. A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 556 -> 557: bolt-circle (Bolt Circle Layout). It gives the hole coordinates x = cx + R x cos(angle), y = cy + R x sin(angle) for a circle of N evenly spaced holes from a bolt-circle diameter, start angle, and center, plus the angular spacing 360/N and the adjacent center-to-center chord 2 x R x sin(180/N) -- the layout a fabricator, millwright, or machinist does for every flange and bolt pattern, and a companion to the existing flange-bolt-torque. Pure trigonometry, hand-verifiable to the last digit (an 8 in bolt circle of 6 holes -> R 4 in, 60 deg spacing, chord 4.000 in, first hole at (4.000, 0.000)). A concept-check against the 556 live tiles found no bolt-circle / circle-of-holes / hole-pattern tile. It lands in calc-cross.js (cap bumped 40 -> 41 KB) with the full v14 discipline and the v18/v21 contract. See specs/spec-v32.md.
Spec-v33 (Shop-Math Bench) is closed; package version stamps 0.34.0. A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 557 -> 558: decimal-to-fraction (Decimal to Fraction). It is tape-measure math every trade does daily and unit-converter does not cover -- round a decimal inches value to the nearest 1/8, 1/16, 1/32, or 1/64 tick, reduce the fraction to lowest terms by GCD, break it into feet-inches, and report the rounding error (rounded minus exact). Pure arithmetic, hand-verifiable to the last digit (2.375 in to the nearest 1/16 -> 2-3/8 in = 0' 2-3/8", error 0; 0.4375 -> 7/16; 27.625 in -> 2' 3-5/8"). A concept-check against the 557 live tiles found no fraction / feet-inch / decimal-inch / tape-measure tile. It lands in calc-cross.js (cap holds at 41 KB) with the full v14 discipline and the v18/v21 contract. See specs/spec-v33.md.
Spec-v34 (Drilling Bench) is closed; package version stamps 0.35.0. A single first-principles tile deepening Group K (Mechanic), taking the catalog 558 -> 559: drill-point-depth (Drill Point Depth). A twist drill's conical point makes the full-diameter shoulder shallower than the tip; this tile gives the point length (tip allowance) (diameter / 2) / tan(point angle / 2) and the tip depth to reach a desired full-diameter depth, for 118 / 135 degree and custom points. Pure drill-point geometry, hand-verifiable to the last digit (a 0.5 in drill at 118 degrees -> 0.1502 in point, about 0.3 x diameter, the well-known rule of thumb; to reach 1.0 in full depth, drill the tip to 1.1502 in). A concept-check against the 558 live tiles found no drill / point-length / tip-allowance tile. It lands in calc-mechanic.js (cap holds at 19.5 KB) with the full v14 discipline and the v18/v21 contract. (The tools-data.js registry cap was bumped 44 -> 46 KB; it grows one row per tile and is lazy-loaded, not in the home-view payload.) See specs/spec-v34.md.
Spec-v35 (Small-Engine Bench) is closed; package version stamps 0.36.0. A single first-principles tile deepening Group L (Agriculture and Forestry), taking the catalog 559 -> 560: two-stroke-mix (Two-Stroke Fuel Mix). It answers the everyday question for chainsaw, trimmer, blower, and outboard operators -- how much oil to add for a gas:oil mix -- as oil volume = fuel volume / ratio (the ratio is by volume), reported in fl oz and mL with the per-gallon and per-liter dose. Pure volume arithmetic (1 US gallon = 128 fl oz; 1 fl oz = 29.5735 mL), hand-verifiable to the last digit (50:1 at 1 US gallon -> 2.56 fl oz / 75.71 mL of oil; 40:1 -> 3.2 oz/gal). glycol-mix covers coolant blends but no tile covered the two-stroke fuel ratio. It lands in calc-agriculture.js with the full v14 discipline and the v18/v21 contract. See specs/spec-v35.md.
Spec-v36 (calc-cross.js Module Split) is closed; package version stamps 0.36.1 (a patch). A platform-only / housekeeping spec in the spirit of spec-v10: it adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 560 tiles; only the on-disk module layout changes. calc-cross.js had grown to ~39.6 KB gzipped (96.6% of its 41 KB cap) after the v26-v33 additions, and continued cap-bumping was deferring the real fix its own cap comment had flagged since v26. The spec-v26+ block of cohesive fabrication / layout tiles -- pipe-fitting-takeout, pipe-miter-cut, pipe-template-wrap, flange-bolt-torque (the v26 pipefitter's bench), center-of-gravity-2point (v27), bolt-circle (v32), and decimal-to-fraction (v33) -- is extracted into a new module calc-fab.js (Fabrication & Layout bench) with their renderers and local helpers, populating a new FAB_RENDERERS map. All remain Group G tiles (a tile's group letter is independent of its module, the spec-v28 precedent); their ids, citations, worked examples, and behavior are byte-for-byte unchanged. After the split calc-cross.js is ~31 KB (86% of a lowered 36 KB cap, headroom restored) and calc-fab.js is ~9.8 KB (62% of a 16 KB cap). Every reference is repointed and gated: the app.js declare list, scripts/build.mjs FILES, sw.js SHELL_ASSETS, the module-size caps, the test fixtures (compute-map.js, the bounds fuzzer, the v26/v27 suites), and the v14 corpus + tile-index were all regenerated, with the wiring lint reporting 28 renderer modules / 560 tile-id entries. The remaining near-cap modules (calc-mechanic.js, calc-agriculture.js) and the tools-data.js registry stay on the watch list for the same treatment as the catalog grows. See specs/spec-v36.md.
Spec-v61 (Water-Supply Demand and Pressure Budget) is closed; package version stamps 0.55.0 (a minor). Two tiles at the head of every domestic water-supply design, deepening Group B (Plumbing and Gas) and taking the catalog 590 -> 592: wsfu-demand (Probable Peak Demand from Fixture Units) and supply-pressure-budget (Available Pressure at the Critical Fixture). The first is Hunter's-curve interpolation -- total water-supply fixture units (WSFU) to the probable simultaneous peak flow in GPM, with separate flush-tank and flush-valve curves (a flushometer system peaks higher for the same WSFU): 120 WSFU on a flush-valve system between the (100 WSFU, 55 GPM) and (150, 66) breakpoints interpolates to 59.4 GPM, while the flush-tank curve gives 46.2 GPM for the same count. The curve ships as editable breakpoints (an approximation of IPC 2021 Appendix E Table E103.3(2) / NBS BMS65), not a transcribed table, and a non-monotonic curve errors. The second sums every loss between the main and the worst-case fixture against the required residual: elevation_loss = height x 0.433 psi/ft, available = street - elevation - meter - backflow - friction, headroom = available - fixture_min, with a go / no-go verdict (street 60 psi, 30 ft up, 8 psi meter, 12 psi friction, 8 psi minimum -> 13.0 psi elevation loss, 27.0 psi available, 19.0 psi headroom, adequate; a flushometer's 25 psi minimum leaves only 2.0 psi). Both use GOVERNANCE.general and name Hunter's curve, IPC 2021 Appendix E / Section 604, and the ASPE PEDH without reproducing them; both land in calc-plumbing.js. See specs/spec-v61.md.
Spec-v62 through v69 (the dirty-jobs expansion) are closed; package version stamps 0.63.0 (a minor). A five-spec arc that takes the catalog 592 -> 624 (+32 tiles) and opens the first new group letter since v12. v62-v64 finish the residential water-supply bench in Group B / calc-plumbing.js: roof-drain-sizing (storm GPM and leader / horizontal-drain size per IPC 1106) and sump-basin-sizing (basin drawdown, cycle time, and short-cycle verdict per IPC 712); gas-appliance-demand (connected load to CFH, IFGC 402 / NFPA 54) and tpr-discharge (water-heater T&P relief rating and IPC 504.6 discharge); pipe-support-spacing (hanger spacing and count per IPC 308.5) and softener-sizing (grain load, regeneration interval, and salt per NSF/ANSI 44). v65-v66 stand up the new Group Z (Rigging and Heavy Lift) in a new calc-rigging.js module (13 tiles, all GOVERNANCE.rigging): the lift-planning core -- cg-load-share, crane-net-capacity (OSHA 1926.1417 deduction stack), crane-ground-bearing, sling-d-d-efficiency (WRTB curve), wind-on-load, tagline-force, tandem-lift-share -- and the hook-to-load iron -- shackle-eyebolt-wll (ASME B30.26 angular derate), spreader-beam (ASME BTH-1), forklift-capacity-derate (ASME B56.1), roller-jack-force, chain-lever-hoist (ASME B30.16/21), and block-redirect-load. v67 deepens Group E earthwork in calc-construction.js: soil-swell-shrink, haul-cycle-production, dewatering-rate, spoil-setback (OSHA 1926.651), and pipe-bedding-backfill (ASTM D2321). v68 equips the production tree crew in Group L / calc-agriculture.js (new arboriculture trade): log-limb-weight, tree-rigging-shock (ANSI Z133 dynamic load, GOVERNANCE.worker_safety), felling-notch-hinge, porta-wrap-friction (capstan equation), and chipper-debris. v69 closes the run with surface prep, coatings, and abatement across Groups E and D: coating-coverage-dft (SSPC/AMPP PA 2, the 1604 constant) and abrasive-blast (SSPC SP) in calc-construction.js, and abatement-containment (EPA NESHAP / OSHA 1926.1101 containment take-off) in calc-restoration.js. Every tile carries the full v14 dimensional-analysis annotation, a pinned worked example verified to the digit, a bounds-fuzzer block, and the v18/v21 output contract; the new group and module are wired through GROUPS / GROUP_NAMES / GROUP_SLUG, the build, the service worker, and the home browse-by-trade index, and every gate (lint, 5,534 unit tests, build, data:verify, render-no-nan, a11y, and the 320 px shell-mobile sweep on both Chromium and WebKit) is green. See specs v62 - v69.
Spec-v70 (calc-construction.js cap-relief split) is closed; package version stamps 0.63.1 (a patch). A platform-only / housekeeping spec in the spirit of v10 / v36 / v39: it adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (32 -> 33 calc-* modules). After the v62-v69 expansion, calc-construction.js sat at 97.6% of its 70 KB gzip cap (the most cap-pressured calculator module, one of eight over 95%), and continued cap-bumping was deferring the per-tile split its own cap comment had flagged since v30. The cohesive spec-v67 earthwork / excavation bench -- five contiguous, self-contained tiles (soil-swell-shrink, haul-cycle-production, dewatering-rate, spoil-setback, pipe-bedding-backfill) -- is extracted into a new module calc-earthwork.js (EARTHWORK_RENDERERS). All five keep group: "E" (a tile's group letter is independent of its module, the v28/v30/v36/v39 precedent); their ids, citations, worked examples, and behavior are byte-for-byte unchanged. After the split calc-construction.js is 62.7 KB (cap lowered 70000 -> 66000 to lock in the headroom) and calc-earthwork.js is ~7.0 KB (cap 8500, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size caps, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 33 renderer modules / 624 tile-id entries and the README count gate agreeing at 33 modules. The next-tightest watch-list items are the flat per-tile registries (tile-meta.js, citations.js, tools-data.js, relieved by documented cap bumps when a tile lands) and the next calc-module split candidates (calc-field.js, calc-electrical.js, calc-plumbing.js, calc-hvac.js). See specs/spec-v70.md.
Spec-v71 (calc-field.js cap-relief split) is closed; package version stamps 0.63.2 (a patch). The second cut on the v70 watch-list, same shape as v70: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (33 -> 34 calc-* modules). calc-field.js was the tightest renderer module after v70 at 96.8% of its 22 KB gzip cap (21304 B). The cohesive spec-v25 surveying coordinate-geometry bench -- two contiguous, self-contained tiles, area-by-coordinates (shoelace parcel area, FM 5-233) and traverse-closure (latitude/departure misclosure and compass-rule / Bowditch adjustment) -- is extracted into a new module calc-survey.js (SURVEY_RENDERERS). Both keep group: "P" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v70 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are byte-for-byte unchanged. After the split calc-field.js is 18.8 KB (cap lowered 22000 -> 20000 to lock in ~94% headroom) and calc-survey.js is 3.8 KB (cap 5000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-v24-v25 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 34 renderer modules / 624 tile-id entries and the README count gate agreeing at 34 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-electrical.js, calc-plumbing.js, calc-hvac.js). See specs/spec-v71.md.
Spec-v72 (calc-electrical.js cap-relief split) is closed; package version stamps 0.63.3 (a patch). The third consecutive cut on the v70/v71 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (34 -> 35 calc-* modules). calc-electrical.js was the named next renderer-split candidate and the tightest at 96.7% of its 64.5 KB gzip cap (62418 B). The cohesive spec-v26 feeder / transformer-conductor overcurrent bench -- two contiguous, self-contained tiles, motor-feeder-multiple (NEC 430.24 feeder conductor / 430.62 feeder protection for several motors on one feeder) and transformer-conductor-protection (NEC 450.3(B) / 240.21(C) primary-and-secondary protection) -- is extracted into a new module calc-feeder.js (FEEDER_RENDERERS). The cut was clean: the bench owns its NEC 240.6(A) standard-OCPD table and helpers and reaches nothing above it but the per-module _finiteGuard. Both keep group: "A" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v70/v71 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are byte-for-byte unchanged. After the split calc-electrical.js is 59.0 KB (cap lowered 64500 -> 62000 to lock in ~95% headroom) and calc-feeder.js is 4.5 KB (cap 6000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the multiline-input attribution comment, the test fixtures (compute-map.js, the bounds fuzzer, the calc-v26 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 35 renderer modules / 624 tile-id entries and the README count gate agreeing at 35 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-plumbing.js, calc-hvac.js). See specs/spec-v72.md.
Spec-v73 (calc-plumbing.js cap-relief split) is closed; package version stamps 0.63.4 (a patch). The fourth consecutive cut on the v70/v71/v72 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (35 -> 36 calc-* modules). After v72 relieved calc-electrical.js, calc-plumbing.js was the tightest remaining calculator module at 96.2% of its 60 KB gzip cap (57728 B) -- the named next renderer-split candidate. The cohesive spec-v62 storm-drainage bench -- two contiguous, self-contained tiles, roof-drain-sizing (roof area to storm GPM and leader / horizontal-drain size per IPC 1106) and sump-basin-sizing (basin drawdown, cycle time, and short-cycle verdict per IPC 712) -- is extracted into a new module calc-drainage.js (DRAINAGE_RENDERERS). The cut is clean: the bench owns its IPC capacity tables and _roof* helpers and reaches nothing outside it but the per-module _finiteGuard and the shared ui-fields.js helpers. Both keep group: "B" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70/v71/v72 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are byte-for-byte unchanged. After the split calc-plumbing.js is 54.5 KB (cap lowered 60000 -> 57500 to lock in ~95% headroom) and calc-drainage.js is 4.5 KB (cap 6000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 36 renderer modules / 624 tile-id entries and the README count gate agreeing at 36 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidate (calc-hvac.js). See specs/spec-v73.md.
Spec-v74 (calc-hvac.js cap-relief split) is closed; package version stamps 0.63.5 (a patch). The fifth consecutive cut on the v70/v71/v72/v73 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (36 -> 37 calc-* modules). After v73 relieved calc-plumbing.js, calc-hvac.js was the named next renderer-split candidate and the tightest calculator module at 95.9% of its 61 KB gzip cap (59041 B). The cohesive spec-v23 velocity bench -- two contiguous, self-contained tiles, duct-velocity-pressure (the ACCA Manual D / ASHRAE relation V = 4005 x sqrt(VP) for standard air, either direction) and refrigerant-velocity (line velocity and oil-return window per the ASHRAE Refrigeration Handbook) -- is extracted into a new module calc-velocity.js (VELOCITY_RENDERERS). The cut is exceptionally clean: the bench already carried its own scoped ui-fields.js imports and reaches nothing outside it (no _finiteGuard, no shared tables), so the moved code is byte-for-byte unchanged. Both keep group: "C" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70/v71/v72/v73 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-hvac.js is 56.9 KB (cap lowered 61000 -> 60000 to lock in ~95% headroom) and calc-velocity.js is 2.7 KB (cap 4000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-v23 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 37 renderer modules / 624 tile-id entries and the README count gate agreeing at 37 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-water.js, calc-mechanic.js, calc-restoration.js). See specs/spec-v74.md.
Spec-v75 (calc-water.js cap-relief split) is closed; package version stamps 0.63.6 (a patch). The sixth consecutive cut on the v70/v71/v72/v73/v74 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (37 -> 38 calc-* modules). After v74 relieved calc-hvac.js, calc-water.js was the named next renderer-split candidate and the tightest calculator module at 95.8% of its 23.5 KB gzip cap (22522 B). The cohesive spec-v20 Phase M bench -- three contiguous, self-contained tiles, weir-flow (USBR Water Measurement Manual V-notch / Francis open-channel flow), langelier-index (the Standard Methods LSI water-stabilization index), and chemical-feed-pump (the AWWA pounds-formula metering-pump setting) -- is extracted into a new module calc-treatment.js (TREATMENT_RENDERERS). The cut is clean: the bench reaches nothing outside its own scoped ui-fields.js imports and never calls calc-water.js's _finiteGuard (each compute fn does its own positive/finite guards inline), so the moved code is byte-for-byte unchanged and no guard helper is copied. All three keep group: "M" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70/v71/v72/v73/v74 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-water.js is 19.0 KB (cap lowered 23500 -> 21000 to lock in the freed space and clear the WARN) and calc-treatment.js is 4.6 KB (cap 6000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-v20 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 38 renderer modules / 624 tile-id entries and the README count gate agreeing at 38 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-mechanic.js, calc-restoration.js, calc-stage.js). See specs/spec-v75.md.
Spec-v76 (calc-mechanic.js cap-relief split) is closed; package version stamps 0.63.7 (a patch). The seventh consecutive cut on the v70/v71/v72/v73/v74/v75 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (38 -> 39 calc-* modules). After v75 relieved calc-water.js, calc-mechanic.js was the named next renderer-split candidate and the tightest calculator module at 95.6% of its 19.5 KB gzip cap (18633 B). The cohesive machining bench -- two contiguous, self-contained tiles at the end of the file, cutting-speed-rpm (the speeds-and-feeds spindle relation RPM = 12 x SFM / (pi x diameter) and feed IPM = RPM x flutes x chip load, spec-v31 K.4) and drill-point-depth (the drill-point tip-allowance geometry (diameter / 2) / tan(point angle / 2), spec-v34 K.5) -- is extracted into a new module calc-machining.js (MACHINING_RENDERERS). The cut is clean: the bench reaches nothing outside its own scoped ui-fields.js imports and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged. Both keep group: "K" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v75 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-mechanic.js is 16.8 KB (cap lowered 19500 -> 18000 to lock in the freed space) and calc-machining.js is 3.1 KB (cap 4000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-mechanic unit suite), and the regenerated v14 corpus, with the wiring lint reporting 39 renderer modules / 624 tile-id entries and the README count gate agreeing at 39 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-restoration.js, calc-plumbing.js, calc-electrical.js). See specs/spec-v76.md.
Spec-v77 (calc-restoration.js cap-relief split) is closed; package version stamps 0.63.8 (a patch). The eighth consecutive cut on the v70/v71/v72/v73/v74/v75/v76 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (39 -> 40 calc-* modules). After v76 relieved calc-mechanic.js, calc-restoration.js was the named next renderer-split candidate and tied for the tightest calculator module at 95.2% of its 29 KB gzip cap (27605 B). The cohesive demolition / abatement bench -- three contiguous, self-contained tiles at the end of the file, moisture-dry-goal (the IICRC S500 dry-standard verdict: a material is dry when its moisture content matches similar unaffected material, spec-v60), flood-cut-quantity (the flood-cut demolition take-off -- drywall area, 4x8 sheet count, baseboard LF, and batt area, spec-v60), and abatement-containment (the asbestos / lead containment take-off -- poly sheeting, negative-air-machine count, required exhaust CFM, and regulated-waste bags, spec-v69) -- is extracted into a new module calc-demo.js (DEMO_RENDERERS). The cut is clean: the bench reaches nothing outside its own scoped ui-fields.js import block (makeNumber, makeCheckbox, makeOutputLine, attachExampleButton, fmt, debounce, DEBOUNCE_MS) and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged. All three keep group: "D" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v76 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-restoration.js is 24.4 KB (cap lowered 29000 -> 26000 to lock in the freed space) and calc-demo.js is 4.8 KB (cap 5500, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 40 renderer modules / 624 tile-id entries and the README count gate agreeing at 40 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-plumbing.js, calc-electrical.js, calc-construction.js). See specs/spec-v77.md.
Spec-v78 (calc-plumbing.js cap-relief split) is closed; package version stamps 0.63.9 (a patch). The ninth consecutive cut on the v70/v71/v72/v73/v74/v75/v76/v77 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (40 -> 41 calc-* modules). After v77 relieved calc-restoration.js, calc-plumbing.js was the named next renderer-split candidate and the tightest calculator module at 95.2% of its 57.5 KB gzip cap (54735 B). The cohesive spec-v63 + spec-v64 service bench -- four contiguous, self-contained tiles at the end of the file, the post-rough-in decisions a plumber makes at appliance hookup and final tie-in rather than at supply/DWV rough-in: gas-appliance-demand (IFGC 402 / NFPA 54 connected-load to CFH, spec-v63), tpr-discharge (the IPC 504 water-heater T&P relief rating check and 504.6 discharge checklist, spec-v63), pipe-support-spacing (IPC Table 308.5 / MSS SP-58 hanger spacing and count, spec-v64), and softener-sizing (the NSF/ANSI 44 / WQA grain-load, regeneration-interval, and salt budget, spec-v64) -- is extracted into a new module calc-service.js (SERVICE_RENDERERS). The cut is clean: the bench reaches nothing outside its own scoped ui-fields.js import block (makeNumber, makeTextarea, makeSelect, makeOutputLine, attachExampleButton, fmt, debounce, DEBOUNCE_MS) and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged; the now-orphaned makeTextarea import is dropped from calc-plumbing.js. All four keep group: "B" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v77 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-plumbing.js is 49.5 KB (cap lowered 57500 -> 53000 to lock in the freed space, ~93.4%) and calc-service.js is 6.9 KB (cap 8000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 41 renderer modules / 624 tile-id entries and the README count gate agreeing at 41 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-electrical.js, calc-construction.js, calc-hvac.js). See specs/spec-v78.md.
Spec-v79 (calc-electrical.js cap-relief split) is closed; package version stamps 0.63.10 (a patch). The tenth consecutive cut on the v70/v71/v72/v73/v74/v75/v76/v77/v78 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (41 -> 42 calc-* modules). After v78 relieved calc-plumbing.js, calc-electrical.js was the named next renderer-split candidate and the tightest calculator module at 95.1% of its 62 KB gzip cap (58989 B). The cohesive spec-v20 §A advanced-analysis trio -- three contiguous, self-contained tiles at the end of the file, parallel-conductor-derate (paralleled-set ampacity with the NEC 310.15(C)(1) more-than-three current-carrying-conductor adjustment and the 1/0-AWG-minimum parallel rule), neutral-current-3ph (the phasor-sum neutral of three 120-degree-displaced phase currents, and the harmonic-dominated case where triplens make the neutral a current-carrying conductor per NEC 310.15(E) / IEEE 519), and motor-vd-starting (the Ohm's-law motor-starting voltage dip against a contactor-dropout limit, distinct from the steady-state voltage-drop tile) -- is extracted into a new module calc-powerquality.js (POWERQUALITY_RENDERERS). The cut is clean: the bench owns its PARALLEL_* tables and cccAdjustmentFactor helper and reaches nothing outside its own scoped ui-fields.js import block (DEBOUNCE_MS, debounce, makeNumber, makeSelect, makeOutputLine, attachExampleButton, fmt); each compute fn does its own positive/finite guards inline, so no _finiteGuard copy is needed and the moved code is byte-for-byte unchanged. All three keep group: "A" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v78 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-electrical.js is 54.9 KB (cap lowered 62000 -> 58000 to lock in the freed space, ~94.7%) and calc-powerquality.js is 5.2 KB (cap 6500, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 42 renderer modules / 624 tile-id entries and the README count gate agreeing at 42 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-construction.js, calc-hvac.js, calc-fire.js). See specs/spec-v79.md.
Spec-v80 (calc-construction.js cap-relief split) is closed; package version stamps 0.63.11 (a patch). The eleventh consecutive cut on the v70/v71/v72/v73/v74/v75/v76/v77/v78/v79 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (42 -> 43 calc-* modules). After v79 relieved calc-electrical.js, calc-construction.js was the named next renderer-split candidate and the tightest calculator module at 95.0% of its 66 KB gzip cap (62728 B). The cohesive spec-v25 site-civil / roadway-geometry quartet -- four contiguous, self-contained tiles, horizontal-curve (the AASHTO/FM 5-233 circular-curve geometry with the arc definition D = 5729.58 / R: tangent, curve length, external, middle ordinate, long chord, and PC/PT stations), vertical-curve (the equal-tangent parabola measured from the BVC: BVC/EVC stations and elevations, crest/sag turning point, and elevation at any station), earthwork-end-area (the average-end-area volume V = (interval/2)(A_i + A_{i+1}) with the optional prismoidal pair and swell/shrink factor), and slope-stake-cut-fill (the cut/fill and planar catch-offset from the hinge) -- is extracted into a new module calc-civil.js (CIVIL_RENDERERS). These are roadway and site-grading decisions, distinct from the building-construction core (framing, concrete, rebar, beams). The cut is clean: the bench reaches nothing outside its own scoped ui-fields.js import block (DEBOUNCE_MS, debounce, makeNumber, makeSelect, makeOutputLine, attachExampleButton, fmt) and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged. All four keep group: "E" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v79 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-construction.js is 57.9 KB (cap lowered 66000 -> 62000 to lock in the freed space, ~93.3%) and calc-civil.js is 6.6 KB (cap 8000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-v24-v25 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 43 renderer modules / 624 tile-id entries and the README count gate agreeing at 43 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-hvac.js, calc-fire.js, calc-cross.js). See specs/spec-v80.md.
Spec-v81 (calc-hvac.js cap-relief split) is closed; package version stamps 0.63.12 (a patch). The twelfth consecutive cut on the v70..v80 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (43 -> 44 calc-* modules). After v80 relieved calc-construction.js, calc-hvac.js was the named next renderer-split candidate and the tightest calculator module at 94.9% of its 60 KB gzip cap (56914 B). The cohesive spec-v16 "Group C expansion" batch -- seven contiguous, self-contained first-principles HVAC engineering tiles, chiller-tons (cooling tonnage from chilled-water flow and the entering/leaving split, water and propylene-glycol factors per ASHRAE Fundamentals Ch. 31), hx-lmtd-ntu (counter/parallel-flow log-mean temperature difference, heat duty, required UA, and effectiveness-NTU per TEMA / Incropera), air-changes-hour (ACH = CFM*60/volume with pressurization and the ASHRAE 62.1 / 170 occupancy bands), boiler-pipe-sizing (hydronic GPM, the velocity-limited copper/steel/PEX size, and Hazen-Williams head per ASHRAE Systems Ch. 13), compressor-short-cycle (the ASHRAE/AHRI part-load cycling parabola and minimum oil-return runtime per Copeland AE 17-1226), humidifier-capacity (moisture addition and latent load from the entering-to-target RH rise with altitude-corrected humidity ratios), and filter-pressure-drop (velocity-scaled clean/change-out drop by MERV/HEPA class and the annual fan-energy penalty per ASHRAE 52.2) -- is extracted into a new module calc-hvacsystems.js (HVACSYSTEMS_RENDERERS). These are engineered building-systems decisions (central plant, hydronics, air handling), distinct from the residential split-system core that stays in calc-hvac.js (Manual J loads, duct sizing, refrigerant charging and superheat/subcool service). The cut is clean: the bench owns its module-local _v16h_* helpers and reaches nothing outside its own scoped ui-fields.js import block (DEBOUNCE_MS, debounce, makeNumber, makeSelect, makeOutputLine, attachExampleButton, fmt), one pure-math.js import (hazenWilliamsFrictionLoss), the per-module _finiteGuard, and two shared spec-v9 psychrometric helpers (_v9_satPressure_kPa, _v9_pressureAtAltitude_kPa) -- all four copied verbatim (non-exported, so they add no corpus row), so the moved compute functions are byte-for-byte unchanged. All seven keep group: "C" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v80 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-hvac.js is 44.0 KB (cap lowered 60000 -> 47000 to lock in the freed space, ~93.6%) and calc-hvacsystems.js is 14.7 KB (cap 16500, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-hvac-v16 unit suite), and the regenerated v14 corpus, with the wiring lint reporting 44 renderer modules / 624 tile-id entries and the README count gate agreeing at 44 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-fire.js, calc-cross.js, calc-agriculture.js). See specs/spec-v81.md.
Spec-v82 (calc-fire.js cap-relief split) is closed; package version stamps 0.63.13 (a patch). The thirteenth consecutive cut on the v70..v81 watch-list, same shape: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 624 tiles across 25 groups; only the on-disk module layout changes (44 -> 45 calc-* modules). After v81 relieved calc-hvac.js, calc-fire.js was the named next renderer-split candidate and the tightest calculator module at 94.9% of its 27 KB gzip cap (25622 B). The cohesive spec-v3 technical-rescue bench -- three contiguous, self-contained tiles, confined-space-purge (the air-change purge time t = V*N/CFM for a confined space per OSHA 1910.146), rope-ma (the rope-rescue mechanical advantage across rig types, theoretical and actual after pulley losses, per NFA/NFPA training literature), and sling-angle (the per-leg tension load multiplier L = W/(n*sin(theta/2)) with the choker derate and the spec-v27 D/d bend-efficiency curve, per ASME B30.9) -- is extracted into a new module calc-rescue.js (RESCUE_RENDERERS). These are life-safety / rescue-rigging decisions, distinct from the fire-suppression hydraulics that stay in calc-fire.js (hose friction, pump discharge, hydrant flow, required fire flow, master stream, foam, sprinkler/standpipe). The cut is clean: the bench carries its own scoped ui-fields.js import block (the aliased _DF/_mnF/_msF/_moF/_aeF/_fmtF set, used by nothing else in calc-fire.js) and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), and its only tables (ROPE_RIGS, the _V27_DD_EFFICIENCY curve) are local to the moved tiles, so the moved compute functions are byte-for-byte unchanged and no cross-module import is created. All three keep group: "F" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v81 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-fire.js is 22.8 KB (cap lowered 27000 -> 24500 to lock in the freed space, ~93.1%) and calc-rescue.js is ~4.4 KB (cap 5500, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-fire-v3 and calc-v27 unit suites, the cross-tile-invariants imports), and the regenerated v14 corpus, with the wiring lint reporting 45 renderer modules / 624 tile-id entries and the README count gate agreeing at 45 modules. The standing module-cap watch continues on the registries (tile-meta.js, citations.js, tools-data.js) and the next renderer-split candidates (calc-cross.js, calc-agriculture.js, calc-kitchen.js). See specs/spec-v82.md.
Spec-v83 through v85 (the field-trades depth pass) are closed and landed together; package version stamps 0.64.0 (a minor). Three evidence-driven specs that take the catalog 624 -> 634 (+10 tiles) by finishing three benches the catalog named but only half-equipped. The thirteen-spec v70-v82 cap-relief run had left every calculator module with headroom, so the expansion lands without a single new module: each tile drops into the cohesive home its siblings already occupy. v83 finishes the onsite-septic trade in Group B / calc-plumbing.js (+3): septic-dose-tank (the timed-dose working volume and daily cycle count for a pressure-distribution field -- net dose, pumped-per-cycle including drainback, and the dose-to-void ratio with a sub-5 flag), septic-pumpout-interval (years between pump-outs from the tank volume, household size, and a per-capita sludge/scum accumulation rate, loud that a sludge-judge measurement governs), and septic-lpp-orifice (the orifice-discharge Q = 19.63 x Cd x d^2 x sqrt(h) per-orifice flow, total orifice count, and system flow for a low-pressure-pipe or mound lateral); sources named, not reproduced -- the USEPA Onsite Wastewater Treatment Systems Manual (EPA/625/R-00/008), university onsite-wastewater extension guidance, and the orifice-discharge equation. v84 closes the sprayer-applicator loop in Group L / calc-agriculture.js (+3, new landscaping cross-trade): nozzle-flow-pressure (the square-root flow law Q proportional to sqrt(pressure) with a target-flow solve that flags the out-of-band pressure proving you change tips, not pressure, to change the rate), spray-drift-buffer (a relative downwind buffer scaling an editable droplet-class base by wind and release height, explicit that the label's mandatory buffer is the law under FIFRA), and sprayer-field-capacity (theoretical and effective acres-per-hour, spray time, and tank count from boom width, speed, and the field efficiency that overlap and turns eat up). v85 finishes the welding bench on the business side in Group E / calc-fab.js (+4, keeping the rest of the group's modules from growing): shielding-gas-runtime (cylinder runtime, bottle count, and prorated gas cost from a flow setting and arc-on time), oxyfuel-cutting-gas (oxygen and fuel consumed and runtime per cylinder for an oxy-fuel cut), weld-preheat-fuel (the sensible-heat fuel mass x specific heat x rise / efficiency to reach the preheat temperature carbon-equivalent recommends), and weld-cost-per-foot (the all-in filler + labor + gas cost per foot, where the operating factor moves the number more than the filler). Every tile carries the full v14 dimensional annotation, a pinned worked example verified to the digit with cross-checks, a bounds-fuzzer block, and the v18/v21 output contract (a non-finite or out-of-domain input returns {error}; the dose-to-void ratio is null not infinity when drainback is zero; the optional cost outputs are null when their rate is left at zero). All gates are green: lint, 5,537 unit tests, build (634 tile + 25 group shells, 661 sitemap URLs), data:verify, the worked-examples runner (+10 fixtures), render-no-nan, a11y, and the 320 px shell-mobile sweep on both Chromium and WebKit. The three specs targeted 0.64.0 / 0.65.0 / 0.66.0 individually; landed in one commit they stamp a single minor, 0.64.0. See specs v83 - v85.
Spec-v86 (calc-plumbing.js cap-relief split) is closed; package version stamps 0.64.1 (a patch). The fourteenth cap-relief cut in the v70-v82 lineage, resumed after the v83-v85 expansion pushed calc-plumbing.js back to the front of the watch-list: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 634 tiles across 25 groups; only the on-disk module layout changes (45 -> 46 calc-* modules). When v83 added the three onsite-septic pressure-distribution tiles to calc-plumbing.js, that module became the tightest calculator module in the repo at 98.9% of its 53 KB gzip cap (52412 B) -- the next Group B tile would have broken the build. The cohesive onsite-wastewater / septic bench -- five tiles spanning three eras, septic-tank (the EPA 150-gpd-per-bedroom static-tank rule with a 1000-gal floor), septic-drainfield (soil-absorption area and trench length from the design flow and the code application rate), and the v83 pressure-distribution trio septic-dose-tank / septic-pumpout-interval / septic-lpp-orifice -- is extracted into a new module calc-septic.js (SEPTIC_RENDERERS). The septic side of a building's plumbing is a distinct domain from the supply, DWV, drainage, and hydronic tiles that stay in calc-plumbing.js. The cut is clean: the bench reaches nothing outside the ui-fields.js helpers it imports (the four standard renderers use the plain names; the v7-era septic-drainfield renderer keeps its aliased _v7p_ set verbatim) and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged; the now-orphaned limitation-banner.js import (used only by the drainfield renderer) is dropped from calc-plumbing.js. All five keep group: "B" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v82 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-plumbing.js is 48.6 KB (cap lowered 53000 -> 52000 to lock in the freed space, ~93.5%) and calc-septic.js is 5.7 KB (cap 7000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-plumbing-v2 and calc-plumbing-v7 unit suites, the cross-tile-invariants imports), and the regenerated v14 corpus, with the wiring lint reporting 46 renderer modules / 634 tile-id entries and the README count gate agreeing at 46 modules. The standing module-cap watch continues on the registries (tile-meta.js, tools-data.js, citations.js) and the next renderer-split candidates (calc-agriculture.js, calc-electrical.js, calc-construction.js). See specs/spec-v87.md.
Spec-v87 (calc-agriculture.js cap-relief split) is closed; package version stamps 0.64.2 (a patch). The fifteenth cap-relief cut in the v70-v86 lineage, taking the next-named candidate: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 634 tiles across 25 groups; only the on-disk module layout changes (46 -> 47 calc-* modules). After the v83-v85 expansion and the v86 plumbing split, calc-agriculture.js was the tightest remaining calculator module at 95.1% of its 37 KB gzip cap (35200 B). The cohesive spec-v68 tree-care / arborist-rigging bench -- five contiguous tiles, log-limb-weight (green frustum weight from a USDA FPL species density), tree-rigging-shock (the dynamic shock-load peak static x (1 + sqrt(1 + 2 x drop / rope stretch))), felling-notch-hinge (open-face notch and hinge geometry per ANSI Z133-2017), porta-wrap-friction (the capstan / Euler-Eytelwein hold force load x exp(-mu x wraps x 2pi)), and chipper-debris (brush chip loose volume and haul-load count) -- is extracted into a new module calc-arborist.js (ARBORIST_RENDERERS). The tree-removal-and-rigging side of the trade is a distinct domain from the crop, soil, irrigation, livestock, forestry-cruise, and sprayer tiles that stay in calc-agriculture.js. The cut is clean: the bench reaches nothing outside the ui-fields.js helpers it imports, its own module-local GREEN_DENSITY species table, and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged. All five keep group: "L" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v86 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-agriculture.js is 30.0 KB (cap lowered 37000 -> 32000 to lock in the freed space, ~93.8%) and calc-arborist.js is 6.7 KB (cap 8000, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer), and the regenerated v14 corpus, with the wiring lint reporting 47 renderer modules / 634 tile-id entries and the README count gate agreeing at 47 modules. The standing module-cap watch continues on the registries (citations.js, tools-data.js) and the next renderer-split candidates (calc-construction.js, calc-cross.js, calc-electrical.js). See specs/spec-v87.md.
Spec-v89 (calc-hvac.js cap-relief split) is closed; package version stamps 0.64.4 (a patch). The seventeenth cap-relief cut in the v70-v88 lineage, taking the next-named candidate: a platform-only / housekeeping spec that adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 634 tiles across 25 groups; only the on-disk module layout changes (48 -> 49 calc-* modules). After the v81 building-systems split, calc-hvac.js had climbed back to the front of the watch-list as the tightest renderer module at 94.3% of its 47 KB gzip cap (44302 B) -- the named next renderer-split candidate in the spec-v88 §5 roadmap. The cohesive refrigerant-circuit bench -- five tiles spanning two eras, refrigerant-pt (the manufacturer P-T saturation lookup with the engineering-practice target-superheat band), superheat-subcool (the line-temperature diagnostic with fixed-orifice and TXV/EEV charge verdicts), compare-refrigerants (the side-by-side P-T view with manufacturer attribution), refrigerant-charge (the line-set charge estimator in oz per foot per diameter), and refrigerant-charging (the full suction/liquid superheat-and-subcool diagnostic with a psig/psia toggle) -- is extracted into a new module calc-refrigerant.js (REFRIGERANT_RENDERERS). The refrigerant-circuit side of the trade (charge, P-T state, and superheat/subcool diagnostics) is a distinct domain from the load-calc, duct, psychrometric, and rotating-equipment tiles that stay in calc-hvac.js. The cut is clean: the bench reaches nothing outside the ui-fields.js helpers it imports, the single interpolateRefrigerant primitive from pure-math.js (the P-T linear interpolation), its own module-local REFRIGERANTS / CHARGE_OZ_PER_FT / REFRIGERANT_OAT_PRESETS / REFRIGERANT_PT_TABLES_v7 tables (which move with it), and the per-module _finiteGuard (copied verbatim, non-exported so it adds no corpus row), so the moved compute functions are byte-for-byte unchanged and no cross-module import is created. All five keep group: "C" (a tile's group letter is independent of its module, the v28/v30/v36/v39/v42/v70..v88 precedent); their ids, citations, worked examples, dimensional annotations, and behavior are unchanged. After the split calc-hvac.js is 38.2 KB (cap lowered 47000 -> 41000 to lock in the freed space, ~93.1%) and calc-refrigerant.js is 8.2 KB (cap 9800, lazy-loaded, not in the home-view payload). Every reference is repointed and gated: the app.js declare lists, scripts/build.mjs FILES, sw.js precache, the module-size and dimension-graduation lists, the test fixtures (compute-map.js, the bounds fuzzer, the calc-hvac / calc-hvac-v2 / calc-hvac-v7 / v23 / v27 unit suites, the renderer-wiring and citation-phase source checks, and the first-principles and cross-tile-invariants imports), and the regenerated v14 corpus, with the wiring lint reporting 49 renderer modules / 634 tile-id entries and the README count gate agreeing at 49 modules. The standing module-cap watch continues on the registries (citations.js, tools-data.js) and the next renderer-split candidates (calc-construction.js, calc-cross.js). See specs/spec-v89.md. The prior cut (spec-v88) extracted the solar-PV / battery-storage / EV-charging electrification bench out of calc-electrical.js into calc-solar.js; see specs/spec-v88.md.
Spec-v90 through v100 (the field-trades depth pass) are closed and landed together; package version stamps 0.65.0 (a minor). Eleven evidence-driven growth specs that take the catalog 634 -> 659 (+25 tiles) by finishing benches the catalog named but only half-equipped, each gap web-validated against the existing free tools and each formula machine-verified to the digit. One new module is opened (49 -> 50 calc-* modules): calc-finish.js, the finish-and-site-carpentry take-off bench the spec-v94 module note named, which relieves the standing calc-construction.js cap watch instead of bumping that module again. The benches: v90 opens food-service cost control in Group O / calc-kitchen.js (food-cost-percentage actual period cost and theoretical variance from the inventory count, prime-cost COGS-plus-labor and the three P&L ratios, pour-cost pours-per-bottle and the menu price at a target pour cost); v91 turns Group J / calc-trucking.js's average numbers into per-load decisions (load-profitability net and profit-per-loaded-mile after loaded-plus-deadhead costs, fuel-surcharge the pegged-base DOE/EIA method, maintenance-reserve the tire/PM/major-component cents per mile); v92 opens the video side of Group N / calc-stage.js (led-video-wall resolution / size / power / weight / viewing distance, projector-brightness required ANSI lumens and throw); v93 closes the pool-chemistry loop in Group M / calc-treatment.js (pool-alkalinity-adjust bicarbonate or muriatic acid, pool-cya-dose stabilizer or dilution, pool-salt-dose the SWG mass balance in 40-lb bags); v94 adds fencing to Group E / calc-construction.js (fence-estimate sections / posts / rails / pickets, post-hole-concrete cylinder-less-post bags); v95 opens calc-finish.js with the two most-requested interior-finish take-offs (thinset-coverage bags by trowel notch, flooring-takeoff boxes by pattern waste with the last-row rip balance); v96 details the concrete and steel back in calc-construction.js (control-joint-spacing ACI 302/360 joint layout and panel grid, rebar-lap-splice the ACI 318 tension lap in bar diameters); v97 lands hardscape in calc-finish.js (paver-patio pavers / base / bedding sand per ICPI, retaining-wall-block segmental blocks / courses / gravel with the over-4-ft engineered-design advisory); v98 adds roofing trim-out to calc-finish.js (attic-ventilation the IRC R806 net-free-area and vent count, gutter-downspout the SMACNA adjusted-area gutter and downspout sizing); v99 opens the opaque envelope in Group C / calc-hvac.js (assembly-r-value the ASHRAE parallel-path whole-wall R below the center-of-cavity R, blown-insulation-coverage bags and settled thickness at a target R); and v100 adds two shop-fluid mixes to Group K (paint-mix-ratio the 2K by-volume ratio in calc-mechanic.js, cutting-fluid-concentration the refractometer Brix-times-factor sump top-up in calc-machining.js). Every tile carries the full v14 dimensional annotation, a pinned worked example verified to the digit with cross-checks, a bounds-fuzzer block, and the v18/v21 output contract (a non-finite or out-of-domain input returns {error}; optional outputs are null when their trigger input is left at zero; the three-way pool and cutting-fluid action branches return an exact zero dose at target, not an error). All gates are green: lint (every gate, including the module-size, wiring, sw-precache, dimensions, corpus, tile-contract, and README-count gates agreeing at 659 tiles / 50 modules / 686 sitemap URLs), 5,546 unit tests, build (659 tile + 25 group shells, 686 sitemap URLs), data:verify, the worked-examples runner (+25 fixtures), render-no-nan, and the 320 px shell-mobile sweep. Module caps were bumped with dated comments (kitchen 13000->16000, trucking 19500->22500, stage 18500->21500, treatment 6000->8500, construction 62000->65000, hvac 41000->43500, mechanic 18000->19500, machining 4000->5000, the new calc-finish.js at 8500, plus tools-data 54000->58000 and citations 190400->192000). See specs v90 - v100.
Spec-v101 through v103 (the field-service design bench pass) are closed and landed together; package version stamps 0.66.0 (a minor). Three evidence-driven growth specs that take the catalog 659 -> 665 (+6 tiles, two per spec) by adding the everyday design and field-service numbers each trade reaches for off the print or at the unit -- numbers the deep rough-in benches did not cover. Each gap was concept-checked against the post-v100 live ids and each formula machine-verified to the digit with a pinned worked example and cross-checks. Three new modules are opened (50 -> 53 calc-* modules), each relieving a brushing cap rather than bumping the source module: calc-elecdesign.js (the electrician design/layout bench off calc-electrical.js's ~93.7% cap), calc-hvacservice.js (the HVAC field-service bench off calc-hvac.js's ~93% cap), and calc-disinfect.js (the pipe/well disinfection bench off calc-plumbing.js's ~93.5% cap). The benches: v101 opens calc-elecdesign.js in Group A (pull-box-sizing the NEC 314.28 pull/junction box minimum -- 8x the largest raceway for a straight pull, 6x plus the same-row others for an angle/U pull, and the 6x between-entries rule, distinct from the 314.16 box-fill conductor-volume; lumen-method the IES luminaire count to hit a target maintained footcandle, ceil(target_fc x area / (lumens x CU x LLF)) with the achieved footcandles at that integer count, the inverse of lux-to-footcandle's forward illuminance); v102 opens calc-hvacservice.js in Group C (condensate-drain the gallons-per-hour a coil sheds, the IMC 307.2.2 minimum drain size by tonnage, and the fall over a run at the 1/8-in-per-foot code slope, with the per-ton rate an editable field estimate since condensate tracks the latent load; recovery-cylinder the maximum net refrigerant under the DOT/EPA-608 80% fill rule from the stamped water capacity and the refrigerant liquid density, plus the headroom and the fill / do-not-fill action); and v103 opens calc-disinfect.js in Group B (main-disinfection-chlorine the AWWA C651 new-main chlorination -- pipe volume 0.0408 x dia^2 x length, pounds of available chlorine for the dose, and the product weight at its strength; well-shock-chlorination the household-bleach shock for a private well from the casing diameter and standing water column, with a quart/ounce echo for small amounts). All six carry GOVERNANCE.general design/dosing governance (the code, the standard, and the AHJ govern; sources named, never reproduced), the full v14 dimensional annotation, and the v18/v21 output contract (a non-finite or out-of-domain input returns {error}; the do-not-fill branch returns an exact zero headroom, not an error). All gates are green: lint (every gate, including the module-size, wiring, sw-precache, dimensions, corpus, tile-contract, and README-count gates agreeing at 665 tiles / 53 modules / 692 sitemap URLs), 5,549 unit tests, build (665 tile + 25 group shells, 692 sitemap URLs), data:verify, the worked-examples runner (+13 fixtures), render-no-nan, and the 320 px shell-mobile sweep. The three new modules register caps in scripts/check-module-sizes.mjs (elecdesign 5000, hvacservice 4000, disinfect 4000) and graduate into the dimensions fail-on-missing set. See specs v101 - v103.
Spec-v112 through v119 (the field-trade breadth pass) are closed and landed together; package version stamps 0.70.0 (a minor). Eight evidence-driven, in-scope growth specs under the spec-v106 trades-only charter take the catalog 676 -> 687 (+11 tiles), each added to an existing module with no new module, group, or dependency. Each closes a daily-math gap a concept-check of the live group surfaced: v112 (Group B / calc-plumbing.js) water-heater-storage-sizing sizes a storage tank by the DOE/AHRI first-hour rating (usable storage + one hour of recovery) against the peak-hour draw (50 gal / 40k / 80% / 90 F rise -> 42.7 gph recovery, 77.7 gph FHR, short of an 80 gph peak by 2.3); v113 (Group E / calc-construction.js) guard-handrail-check runs the IRC R312 / R311.7.8 / IBC 1015 dimensional checks (guard required over 30 in; 36 in residential / 42 in commercial; 4 in sphere infill, 4-3/8 in on the stair triangle; 34-38 in handrail) and always renders the 200 lb load note; v114 (Group F / calc-fire.js) smooth-bore-flow gives smooth-bore nozzle flow gpm = 29.7 x d^2 x sqrt(NP) with the companion reaction (1-1/8 in tip at 50 psi -> 266 gpm); v115 (Group J / calc-trucking.js) adds gcwr-check (combined weight vs the binding of the GCWR and the 80,000 lb federal cap) and tire-load-check (axle weight vs tires x marked load); v116 (Group M / calc-water.js) adds chlorine-demand (applied minus residual, dose for a target, breakpoint flag) and uv-dose (intensity x time vs a 40 mJ/cm^2 validated target); v117 (Group Z / calc-rigging.js) adds multi-leg-sling (ASME B30.9 conservative tension over 2 legs / sin angle -- 8,000 lb on 4 legs at 60 deg -> 4,619 lb/leg) and wire-rope-strength (MBS = 46 x d^2, WLL at 5:1, estimate only); v118 (Group L / calc-agriculture.js) hay-dry-matter (dry matter, weight restated at a target moisture, safe-storage flag); and v119 (Group D / calc-restoration.js) wood-emc (the USDA FPL Hailwood-Horrobin equilibrium-moisture-content sorption equation -- 70 F / 50% RH -> ~9.2%). All carry the full v14 dimensional annotation, the v18/v21 output contract (every non-finite or non-positive input returns {error}), and the v19/v22 citation discipline (each cites its standard by section/name with the AHJ / manufacturer / primacy agency named as the governing authority; no licensed table is reproduced). All gates are green: lint (the README-count gate now agreeing at 687 tiles / 53 modules / 714 sitemap URLs), 5,562 unit tests (+22 worked-example fixtures across eight bounds-fuzzer blocks), build, data:verify, the worked-examples runner (743 tiles), render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. Standing per-module gzip caps in scripts/check-module-sizes.mjs ticked up with dated comments where a new tile brushed cap (all still lazy-loaded, none in the home-view payload). See specs/spec-v112.md through specs/spec-v119.md.
Spec-v120 (Room Acoustics) is closed; package version stamps 0.71.0 (a minor -- one new in-scope tile, no cap or dependency change). One evidence-driven, in-scope tile under the spec-v106 trades-only charter takes the catalog 687 -> 688 (+1 tile), added to Group N / calc-stage.js with no new module, group, or dependency. The gap a concept-check of the live group surfaced: Group N covered SPL, inverse-square, atmospheric absorption, speaker alignment, and impedance, but never the room itself -- the reverberation time that decides intelligibility and the axial room modes that predict bass buildup and nulls, both everyday load-in math for a sound tech walking an unknown venue. room-acoustics returns the Sabine reverberation time RT60 = 0.049 x V / A (volume in cubic feet over total absorption in sabins) and the three first axial room modes c / (2 x dimension) with c = 1130 ft/s (pinned example: a 5,000 ft^3 room with 500 sabins, 20 x 15 x 10 ft -> RT60 0.49 s; modes 28.3 / 37.7 / 56.5 Hz; cross-check: 250 sabins -> RT60 0.98 s, modes unchanged because they depend on geometry, not absorption). The 0.049 Sabine coefficient and the 1130 ft/s speed of sound are bundled as editable annotated fields. It carries the full v14 dimensional annotation (volume L^3, sabins L^2, RT60 T, modes T^-1), the v18/v21 output contract (any non-finite input, or a non-positive volume, absorption, or dimension, returns {error}), and the v19/v22 citation discipline (GOVERNANCE.general over the public-domain Sabine equation and the f = c/(2L) axial-mode relation; the acoustician and the venue govern). All gates are green: lint (the README-count gate agreeing at 688 tiles / 53 modules / 715 sitemap URLs), 5,563 unit tests (+2 worked-example fixtures, one new bounds-fuzzer block), build (688 tile + 25 group shells, 715 sitemap URLs), data:verify, the worked-examples runner (745 fixtures), render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. No module cap moved (calc-stage.js had headroom). See specs/spec-v120.md.
Spec-v107 (retire four non-trade groups: the CUT) is closed; package version stamps 0.72.0 (a minor that is a breaking change to public URLs). The first subtractive landing under the spec-v106 trades-only charter: it removes the four liability-bearing non-trade groups recorded as NOT DOING in spec-v106 -- S (Legal Plain-English and Statutory Math), U (Veterinary), V (EMS and Pre-hospital), and W (Pilots and General Aviation) -- plus one stray flight-ops tile, weight-balance (Aircraft Weight and Balance), that had been filed under Group K (Mechanic). Each fails the spec-v106 inclusion test on gate 1 (not a trade) and gate 4 (the failure mode is patient / animal harm, safety-of-life, or unauthorized practice of law, not a failed inspection). The cut takes the catalog 688 -> 600 (-88 tiles: 87 group tiles + the one stray), 25 -> 21 groups, and 53 -> 49 modules (the four modules calc-legal.js, calc-vet.js, calc-ems.js, and calc-aviation.js are deleted; calc-mechanic.js survives with weight-balance removed tile-level). It adds nothing and changes no surviving tile's output. The retired group letters leave gaps in the A..Z sequence (spec-v106 §5: letters are stable identifiers, never renumbered); aircraft maintenance content stays under Group K. Every touchpoint was cleared and gated: the tools-data.js rows, the four declare() blocks and GROUPS / GROUP_NAMES entries in app.js, the tile-meta.js rows plus the 44 SIMPLIFIED entries and their limitation-banner.js copy, the 88 citations.js entries, the data/search/aliases.json blocks, the scripts/related-tiles.mjs keys (and seven inbound references from surviving tiles, repointed), the sw.js precache (cache version bumped so old clients drop the retired modules), the scripts/build.mjs file list, every test fixture and bounds-fuzzer / numerical-stability / cross-tile-invariant block, and the regenerated v14 corpus, tile-index, and citation strings. This breaks public URLs: 88 tile deep-links and 4 group-hub URLs stop resolving. They drop out of sitemap.xml on rebuild so crawlers de-index over time, and the SPA router already lands an unknown #<id> hash on the home view rather than a dead end. All gates are green: lint (every gate, including the README-count gate now agreeing at 600 tiles / 49 modules / 623 sitemap URLs), 4,926 unit tests (down from 5,563 with the removed tiles' fixtures and fuzzer cases), build (600 tile + 21 group shells, 623 sitemap URLs), data:verify, the worked-examples runner (657 fixtures), render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. The source-coverage map drops from 206 to 162 tracked sources with the four groups' authorities retired. The FREEZE / SALVAGE pass for the off-brand-but-not-liable groups (O, P, T, X, Y) is a separate design, spec-v108, not executed here. See specs/spec-v107.md.
Spec-v121 through v128 (the electrician second-pass: motors, feeders, fault, raceway, grounding, three-phase) are closed and landed together; package version stamps 0.73.0 (a minor). Eight evidence-driven, in-scope growth specs under the spec-v106 trades-only charter take the catalog 600 -> 608 (+8 tiles), all added to Group A / calc-electrical.js with no new module, group, or dependency. Each closes a daily-math gap a concept-check of the live electrical group surfaced. The motor-performance family: v121 motor-synchronous-speed-slip (the synchronous speed Ns = 120 f / P, the slip from the nameplate full-load speed, and the rotor/slip frequency -- 60 Hz / 4-pole / 1750 rpm -> 1800 rpm sync, 2.78% slip, 1.67 Hz rotor); v122 motor-shaft-torque (the two-way T = 5252 x HP / RPM solver -- 10 HP at 1750 rpm -> 30.0 lb-ft, and the inverse 30 lb-ft at 3500 rpm -> 20.0 HP); v123 motor-operating-cost (input kW at the motor's efficiency, annual kWh, and energy dollars -- 25 HP / 93% / 4000 hr / $0.12 -> 20.05 kW, 80,215 kWh, $9,626, with the premium-motor delta that justifies a retrofit). The NEC numeric-method tiles (no copyrighted table reproduced): v124 multi-motor-feeder (NEC 430.24 feeder ampacity = 1.25 x largest FLC + sum of the others, and the 430.62 feeder-OCPD ceiling rounded down to a standard size -- 28 / 26 / 70 -> 61 A conductor, 90 A OCPD); v126 conduit-thermal-expansion (the NEC 352.44 PVC length change delta_L = coefficient x length x temperature swing against the 1/4-inch expansion-fitting trigger -- 100 ft / 50 F -> 2.03 in, fitting required); v127 egc-upsize-proportional (the NEC 250.122(B) circular-mil proportion when ungrounded conductors are upsized -- base 26,240 cmil EGC, phase 167,800 -> 250,000 cmil -> ratio 1.49, 39,094 cmil, next size #4 Cu, clamped so the EGC never drops below its table size). The first-principles engineering tiles: v125 conductor-short-circuit-withstand (the public-domain ICEA P-32-382 / Onderdonk adiabatic withstand (I/A)^2 t = K log10((T2+B)/(T1+B)) -- Cu #6 at 0.1 s -> 6,313 A withstand, inadequate vs a 10,000 A fault, 41,560 cmil minimum; a screen, not an engineered study); and v128 delta-wye-line-phase (the wye and delta line-to-phase voltage/current relations and the connection-independent S = root-3 x V_line x I_line -- 208 V wye -> 120.1 V phase, 3,602 VA; 240 V delta / 30 A -> 17.3 A winding current). All eight carry the full v14 dimensional annotation, a pinned worked example verified to the digit with a cross-check, a bounds-fuzzer block exercising the error seams, and the v18/v21 output contract (a non-finite or out-of-domain input returns {error}; the only divisions are by guarded-positive denominators). Citation discipline (v19/v22): the three NEC tiles cite NEC 2023 by section with the NEC_DISCLOSURE edition note and free read-only at nfpa.org/freeaccess; the Onderdonk tile cites ICEA P-32-382 as a public-domain relation; the four first-principles tiles carry single-edition notes (the 120, 5252, 0.800, and root-3 constants are documented unit bridges). All gates are green: lint (every gate, including the README-count gate now agreeing at 608 tiles / 50 modules / 631 sitemap URLs), 4,900 unit tests (+8 bounds-fuzzer blocks, +16 worked-example fixtures), build (608 tile + 21 group shells, 631 sitemap URLs), data:verify, the worked-examples runner, render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. The eight tiles took calc-electrical.js to 60031 B gz against its 60000 B cap (100.1%, over); the follow-on spec-v129 split relocated the four-tile motor bench (motor-synchronous-speed-slip, motor-shaft-torque, motor-operating-cost, multi-motor-feeder) into a new calc-motor.js (MOTOR_RENDERERS), lowering calc-electrical.js to ~56.9 KB gz (94.8%) and giving the catalog its 50th calc-* module -- the same per-bench cap-relief that produced calc-feeder/powerquality/solar/elecdesign. The four keep group A; ids, citations, and rendered DOM are byte-for-byte unchanged. (tools-data.js ~52.5 KB gz, 85% of 62 KB.) See specs/spec-v121.md through specs/spec-v128.md.
Spec-v109, v110, and v111 (the field-service grounding / gas-heat pass) are closed and landed together; package version stamps 0.69.0 (a minor). Three evidence-driven, in-scope growth specs under the spec-v106 trades-only charter take the catalog 669 -> 676 (+7 tiles), each added to an existing module with no new module, group, or dependency. v109 closes the service-grounding gap in Group A / calc-electrical.js with three tiles: grounding-electrode-conductor sizes the GEC from NEC Table 250.66 with the 250.66(A)-(C) electrode caps (250 kcmil Cu service to a ground rod -> Table base 2 AWG, rod cap 6 AWG -> 6 AWG; to a Ufer -> 4 AWG; to a water pipe / steel electrode, no cap -> 2 AWG); bonding-jumper sizes the supply-side jumper from Table 250.66 (with the 12.5% rule above 1100 kcmil copper -- 1500 kcmil phase -> 0.125 x 1500 = 187.5 kcmil -> 4/0) and the equipment jumper from Table 250.122 (400 A OCPD -> 3 AWG, one per parallel raceway); and min-conductor-for-vd inverts the voltage-drop tile -- the smallest copper and aluminum conductor that holds the drop at or below a target percent, reusing the existing voltageDrop K-factor helper. (The spec's worked example for that last tile omitted the single-phase factor of 2 the helper applies; the landed tile and its pinned fixtures use the physically correct value -- 20 A, 150 ft, 120 V, 3% -> 6 AWG Cu, ~2.46%, not the spec prose's 8 AWG.) v110 opens the gas-heat side of the Group C / calc-hvacservice.js field-service bench: gas-meter-clock computes the actual firing rate from the meter (1 cf dial, 37 s/rev, 1030 BTU/cf -> 97.30 cfh, ~100,216 BTU/hr, firing on rate vs a 100k nameplate) and furnace-temp-rise checks the supply-minus-return rise against the rating-plate range and derives airflow from Qs = 1.08 x CFM x delta-T (70->120 F at 100k/80% -> 50 F rise, 1,481 CFM, in range). v111 adds the install-time fuel-gas tiles to Group B / calc-gas.js: gas-altitude-derate (NFPA 54 / IFGC high-altitude derate -- 100k at 6,000 ft, 4%/1000 ft above 2,000 -> 0.84 factor, 84,000 BTU/hr, kit flag) and gas-fuel-conversion (NG/LP conversion via first-principles orifice flow Q ~ A x sqrt(P / SG) -- 100k NG->LP -> 97.09 / 40.00 cfh, area ratio 0.370). All carry the full v14 dimensional annotation, the v18/v21 output contract (every non-finite or non-positive input returns {error}), and the v19/v22 citation discipline (NEC 250.66 / 250.102 by section with free read-only at nfpa.org/freeaccess for v109; GOVERNANCE.general first-principles for the gas tiles). All gates are green: lint (the README-count gate now agreeing at 676 tiles / 53 modules / 703 sitemap URLs), 5,554 unit tests (+15 worked-example fixtures across three bounds-fuzzer blocks), build (676 tile + 25 group shells, 703 sitemap URLs), data:verify, the worked-examples runner, render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. Four standing per-module gzip caps in scripts/check-module-sizes.mjs ticked up with dated comments (all still lazy-loaded, none in the home-view payload): calc-electrical.js 52000 -> 60000, calc-hvacservice.js 9000 -> 11500, calc-gas.js 5500 -> 8500, and the tools-data.js registry 58000 -> 62000. See specs/spec-v109.md, specs/spec-v110.md, and specs/spec-v111.md.
Spec-v105 (HVAC evacuation and leak-check diagnostics) is closed; package version stamps 0.68.0 (a minor). Two evidence-driven tiles take the catalog 667 -> 669, both added to the existing calc-hvacservice.js bench (no new module, no new group; both keep group: "C") -- the two go/no-go numbers a tech reads off the gauges before charging a system, named in the spec-v104 §5 roadmap. The post-v104 live ids carried no micron decay test and no temperature-corrected pressure test. vacuum-decay-test is the evacuation standing-decay (blank-off) verdict: from the micron level at valve-off, the level after a timed hold, and the hold time, it returns the total rise (end - start) and the rise rate, with a tight-and-dry / moisture / leak reading against an editable 500-micron pass ceiling (the ACCA Standard 4 / AHRI field convention) -- a vacuum that holds at or below the ceiling is dry and tight; one that climbs is residual moisture if it plateaus or a leak if it keeps rising (pull to 300 microns, 450 after 15 min -> 150-micron rise, 10 microns/min, below 500 -> ok to charge). nitrogen-pressure-test separates a real leak from the ambient thermal swing in a standing nitrogen pressure test using Gay-Lussac's law (at fixed volume P/T is constant in absolute units): the temperature-corrected expected gauge pressure is (start_psig + atm) x (T2_R / T1_R) - atm with R = F + 459.67, and any pressure lost below that expected value is the leak (150 psig at 70 F cooling to 50 F is expected to read 143.8 psig with no leak; a gauge reading 144 holds -- the 6 psi drop is purely thermal -- while 138 flags a 5.8 psi leak). Both carry GOVERNANCE.general over public first-principles physics (rise/time arithmetic; the ideal-gas law), the full v14 dimensional annotation (microns and psi as pressure M L^-1 T^-2, temperatures as T), and the v18/v21 output contract (a non-finite, non-positive, or below-absolute-zero input returns {error}). All gates are green: lint (every gate, the README-count gate now agreeing at 669 tiles / 53 modules / 696 sitemap URLs), 5,551 unit tests, build (669 tile + 25 group shells, 696 sitemap URLs), data:verify, the worked-examples runner (+4 fixtures), render-no-nan, and the 320 px shell-mobile + responsive-stress sweeps on Chromium and WebKit. The caps touched are calc-hvacservice.js in scripts/check-module-sizes.mjs (6500 -> 9000 B gz; the bench is now six tiles at ~7.5 KB gz, still lazy-loaded and absent from the home-view payload) and the citations.js registry (192000 -> 200000 B gz for the two new citation entries). See specs/spec-v105.md.
Spec-v104 (HVAC field-service electrical diagnostics) is closed; package version stamps 0.67.0 (a minor). Two evidence-driven tiles take the catalog 665 -> 667, both added to the existing calc-hvacservice.js bench (no new module, no new group; both keep group: "C"). The gap was concept-checked against the post-v103 live ids: a search for mca, mocp, 440, and capacitor returned nothing, yet both are everyday numbers on an HVAC service call. hvac-equipment-circuit is the NEC 440 nameplate math every installer and tech verifies at the condenser: the minimum circuit ampacity MCA = 1.25 x largest-motor RLA + sum of the other loads (NEC 440.33) and the maximum overcurrent device MOCP = 1.75 x largest RLA + others, taken to the next NEC 240.6(A) standard size down because 175% is a ceiling (NEC 440.22(A)), with the 225% start-allowance reported as a separate ceiling and an optional check of the installed breaker against the maximum (the textbook RLA-20 + fan-1.5 nameplate returns MCA 26.5 A, MOCP 35 A, exactly as stamped). run-capacitor-microfarad is the first-principles in-circuit capacitor test: from the capacitive reactance Xc = 1/(2 x pi x f x C), the measured capacitance is C[uF] = 1e6 x I / (2 x pi x 60 x V) ~= 2652 x amps / volts at 60 Hz, compared to the nameplate rating and an editable +/-6% tolerance band with a good / weak / replace verdict (a 45 uF cap drawing 6.2 A at 370 V reads 44.4 uF, within band; the same cap at 3.0 A reads 21.5 uF, replace). hvac-equipment-circuit carries GOVERNANCE.electrical and cites NEC 440.33 / 440.22(A) / 240.6(A); run-capacitor-microfarad carries GOVERNANCE.general over public capacitive-reactance physics. Both carry the full v14 dimensional annotation (current as I, capacitance as M^-1 L^-2 T^4 I^2) and the v18/v21 output contract (a non-finite, non-positive, or out-of-domain input returns {error}). All gates are green: lint (every gate, the README-count gate now agreeing at 667 tiles / 53 modules / 694 sitemap URLs), 5,550 unit tests, build (667 tile + 25 group shells, 694 sitemap URLs), data:verify, the worked-examples runner (+4 fixtures), render-no-nan, and the 320 px shell-mobile sweep. The only cap touched is calc-hvacservice.js in scripts/check-module-sizes.mjs (4000 -> 6500 B gz; the bench is now four tiles at ~5.4 KB gz, still lazy-loaded and absent from the home-view payload). See specs/spec-v104.md.
Spec-v60 (Water-Loss Documentation) is closed; package version stamps 0.54.0 (a minor). Two documentation tiles that book-end a water job, completing the Group D batch and taking the catalog 588 -> 590: moisture-dry-goal (Dry Standard vs Affected Reading) and flood-cut-quantity (Flood-Cut Demolition Take-Off). The first is the IICRC S500 dry-standard check: a material is dry when its moisture content matches similar unaffected material in the same structure, so from the unaffected reference reading, the affected reading, and an acceptable delta it returns the gap, a dry / wet verdict, and the points still to remove (unaffected drywall 12, affected 35, delta-allow 4 -> 23 above standard, continue drying, 19 to go; affected 15 -> 3, at dry standard, 0 to go; wood 11% vs 14% at delta 2 -> 1 point to go). The second is the flood-cut take-off: from the affected wall run and the cut height it returns the drywall area removed, the 4x8 sheet count (ceil(ft2 / 32)), the baseboard linear feet, and the batt-insulation area (60 LF, 24 in cut, one side, insulated -> 120 ft^2 drywall, 4 sheets, 60 LF base, 120 ft^2 batt; two-sided -> 240 ft^2, 8 sheets). Both use GOVERNANCE.general, name IICRC S500-2021 without reproducing it, and note the field judgment they cannot replace (the same meter/material/scale for the dry standard; the highest moisture reading drives the cut height, and pre-1980 structures need a lead / asbestos assessment first). Both land in calc-restoration.js. With this batch Group D spans a water-and-mold job end to end: scope and Condition (v58) -> antimicrobial mix and air sampling (v59) -> the dry-standard verdict and demolition take-off (v60). See specs/spec-v60.md.
Spec-v59 (Remediation Chemistry and Air Sampling) is closed; package version stamps 0.53.0 (a minor). Two field tiles deepening Group D (Water Damage and Mold Restoration), taking the catalog 586 -> 588: antimicrobial-dilution (Antimicrobial Mix and Coverage) and air-sample-volume (Air Sample Run Time and Volume). The first turns an area, the label's coverage rate, the label's dilution (ounces per gallon, or a 1:N ratio where the concentrate is 128/(N+1) oz per finished gallon), and the sprayer tank size into the finished-solution volume, the concentrate / water split, the per-tank dose, and the number of tank fills (400 ft^2 at 200 ft^2/gal and 4 oz/gal in a 1.5 gal tank -> 2.0 gal finished, 8.0 oz concentrate, 1.94 gal water, 2 fills, 6.0 oz per tank; a 1:64 ratio -> 1.97 oz/gal). Its GOVERNANCE.pesticide seam is the key correctness property: read and follow the EPA-registered product label (the label is the law under FIFRA), the defaults are placeholders not a recommendation, and antimicrobials do not substitute for the physical removal of growth (IICRC S520). The second computes spore-trap sampling: run time = target volume / calibrated flow, total sampled volume, and total pump time across an event (15 L/min at 75 L over 3 cassettes -> 5.0 min / 300 s each, 225 L total, 15.0 min pump time; an Andersen N6 at 28.3 L/min / 28.3 L -> 1.0 min), naming ASTM D7391 and AIHA-accredited analysis. Both land in calc-restoration.js. See specs/spec-v59.md.
Spec-v58 (Mold Remediation Scoping) is closed; package version stamps 0.52.0 (a minor). Two tiles deepening Group D (Water Damage and Mold Restoration) at the front of a mold job, taking the catalog 584 -> 586: mold-remediation-level (Remediation Scope by Affected Area) and mold-conditions (IICRC S520 Condition Reference). The first maps affected square footage plus three field flags (porous material, HVAC involvement, vulnerable occupant) to the EPA 402-K-01-001 band (small / medium / large), the NYC DOHMH level (I through IV, with any HVAC involvement overriding to Level V), and the controls each triggers: containment, PPE tier, whether an independent assessor is advised, and whether post-remediation verification is advised. Hand-verifiable as a deterministic five-band lookup (45 ft^2 of moldy drywall, no HVAC, healthy occupant -> medium band, Level III, full containment, half-face P100, optional independent assessor, clearance recommended; 6 ft^2 hard surface -> small / Level I / limited / N95 / optional; 250 ft^2 -> large / Level IV / full-face PAPR / assessor + clearance recommended; any HVAC job -> Level V). The second is a reference page parallel to water-classes: the three S520 Conditions (normal fungal ecology, settled spores, actual growth) in plain English, with remediation defined as returning Condition 2 and 3 areas to Condition 1. Both use GOVERNANCE.general and name EPA 402-K-01-001, the NYC DOHMH guidelines, and IICRC S520-2024 without reproducing them; both land in calc-restoration.js. See specs/spec-v58.md.
Spec-v57 (Equal Spacing Layout) is closed; package version stamps 0.51.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 583 -> 584: equal-spacing (Equal Spacing Layout). It is one of the most-performed layout calculations on a job site -- spacing a row of items evenly in a run (balusters, pickets, studs, shelf pins, fence boards) -- which the catalog did not cover: decimal-to-fraction converts one measurement and deck-ledger-fasteners is a code-table spacing for one connector, but no tile divides a run into equal parts. Two modes: count-from-a-maximum-gap (the railing case, the smallest number of items whose gap stays at or below a limit, N = ceil((run - gmax)/(width + gmax))) and gap-from-a-desired-count (gap = (run - N x width)/(N + 1), N+1 equal gaps at both ends), plus the center-to-center pitch and the item-center positions from one datum; item width 0 lays out division marks. Pure arithmetic, hand-verifiable to the last digit (a 60 in run, 1.5 in balusters, 4 in maximum gap per the IRC R312.1.3 4 in sphere rule -> 11 balusters, 3.625 in gap, 5.125 in pitch; dividing a 100 in run into 6 equal parts -> 16.667 in gap with the middle mark at 50 in; an over-fitting count returns a finite negative gap flagged "does not fit," not an error). It lands in calc-layout.js (the v56 layout & shop-geometry bench) with the full v14 discipline and the v18/v21 contract; the position list is bounded to 200 entries so a large count cannot build an unbounded array. See specs/spec-v57.md.
Spec-v56 (calc-fab.js Module Split) is closed; package version stamps 0.50.1 (a patch). Platform-only housekeeping in the lineage of spec-v36 / v39 / v42: adds no tiles, removes none, changes no calculator output (catalog holds at 583); only the on-disk module layout changes. calc-fab.js had reached 19,260 B gzipped, 96.3% of its 20,000 B cap after the layout family expanded across v32 / v37 / v38 / v44 / v47 / v55 (bolt-circle, sine-bar, thread-pitch, circular-arc, circle-from-3-points, polygon-miter) on top of the v26 pipefitter's bench, the v27 center-of-gravity, the v33 decimal-to-fraction, and the v39 conduit suite -- so the documented per-tile-split remediation came due (at ~96% the precedent is a split, not another cap bump). The eight layout / shop-geometry tiles (pure coordinate, angle, and measurement geometry) move into a new thematic module calc-layout.js; their group letters, ids, citations, worked examples, and behavior are byte-for-byte unchanged. The wiring lint reports 31 renderer modules / 583 tile-id entries. See specs/spec-v56.md.
Spec-v55 (Regular Polygon Miter and Layout) is closed; package version stamps 0.50.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 582 -> 583: polygon-miter (Regular Polygon Miter and Layout). Building any N-sided frame -- an octagon column wrap, a hexagon planter, a picture frame, a segmented turning ring, a gazebo facet -- needs the joint miter angle (180/N degrees off square) and the piece length for a target size, which the catalog only half-covered: geometry gives regular-polygon area and a perimeter from a side list but no miter angle or size conversion, and compound-miter (v54) solves a different problem (sprung crown). The user gives the side count and a target size as one of three dimensions (side length, across-flats width, or across-corners diameter -- a labeled select so a value is never read against the wrong dimension); the tile recovers the side and reports the miter saw setting, the interior angle (N-2)180/N, across-flats s/tan(180/N), across-corners s/sin(180/N), perimeter, and area. Pure polygon geometry, hand-verifiable to the last digit (a hexagon with side 12 in -> 30 deg miter, 120 deg interior, 24 in across-corners, 20.7904 in across-flats, 374.123 in^2 area; an octagon gives the known 22.5 deg miter, a square 45 deg, an equilateral triangle 60 deg). It lands in calc-fab.js with the full v14 discipline and the v18/v21 contract (N < 3, N > 360, a non-positive size, or non-finite inputs error). See specs/spec-v55.md.
Spec-v54 (Compound Miter for Crown Molding) is closed; package version stamps 0.49.0 (a minor). A single first-principles tile deepening Group E (Carpentry and Construction), taking the catalog 581 -> 582: compound-miter (Compound Miter, Crown Molding). Crown installed "sprung" against the wall does not sit flat against a single saw fence; cutting it flat on the table needs a compound cut -- a miter (table swing) AND a bevel (blade tilt) -- and finish carpenters reach for a printed chart that covers exactly two profiles (38 and 45 degree spring) at exactly one corner (90 degrees) and nothing for the out-of-square corners a real house is full of. The catalog had pipe-miter-cut, roof-pitch, and rafter but nothing that turns a spring angle and wall corner into saw settings: the miter = atan(tan(corner/2) x sin(spring)) and the bevel = asin(cos(spring) x cos(corner/2)). Pure trigonometry, hand-verifiable to the last digit (a 38 deg spring at a 90 deg corner -> 31.62 deg miter, 33.86 deg bevel; a 45 deg spring at 90 deg -> 35.26 deg miter, 30.00 deg bevel; both reproduce the standard published compound-miter chart to the digit), and it handles the out-of-square corners the two-row chart cannot. It lands in calc-shop.js (group letter is independent of module per the v28/v36/v39 precedent, and calc-shop.js has the headroom calc-construction.js, at 94% of its cap, does not) with the full v14 discipline and the v18/v21 contract (a spring outside (0, 90) or a corner outside (0, 180) errors). See specs/spec-v54.md.
Spec-v53 (Linear Interpolation) is closed; package version stamps 0.48.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 580 -> 581: linear-interpolation (Linear Interpolation). It is the everyday move when a published chart or table gives the rows above and below your point -- read the value between them: y = y1 + (x - x1) x (y2 - y1) / (x2 - x1), with the slope and an extrapolation flag when the query falls outside the two reference points. The operation appears inside a dozen tiles already (NEMA derate rows, ACI w/c curves, refrigerant tables, livestock-water tables), which is exactly why it earns a standalone cross-trade utility for reading any table by hand (derating, pump-curve, steam, psychrometric, calibration). Pure linear geometry, hand-verifiable to the last digit ((0,10) and (10,30) at x=4 -> y=18, slope 2; querying x=15 flags an extrapolation). It lands in calc-cross.js with the full v14 discipline and the v18/v21 contract; the tools-data.js registry cap was bumped 48 -> 50 KB (it grows one row per tile and is lazy-loaded, not in the home payload). See specs/spec-v53.md.
Spec-v52 (Hiking Time, Naismith's Rule) is closed; package version stamps 0.47.0 (a minor). A single first-principles tile deepening Group P (Field, Backcountry, and SAR), taking the catalog 579 -> 580: hiking-time (Hiking Time, Naismith's Rule). It is the canonical backcountry / SAR trip-time estimate: flat-ground time (horizontal distance / pace) plus an ascent penalty of one hour per 600 m (about 2000 ft) of climb, scaled by a terrain / fatigue factor, reported in hours and h:min with the flat-and-ascent breakdown. Group P already had pace-count distance (pacing-distance), navigation, and SAR detection probability, but no time estimate over distance and terrain. Distinct from pacing-distance (steps to distance, not time); pure arithmetic plus the historical Naismith rate (W. W. Naismith, 1892), hand-verifiable to the last digit (10 km with 600 m of ascent at 5 km/h -> 2 hr flat + 1 hr ascent = 3 h 0 min; a 1.5x factor -> 4 h 30 min). It lands in calc-field.js with the full v14 discipline and the v18/v21 contract. See specs/spec-v52.md.
Spec-v51 (Stage Lighting Beam and Throw) is closed; package version stamps 0.46.0 (a minor). A single first-principles tile deepening Group N (Stage and Live Production), taking the catalog 578 -> 579: lighting-beam (Stage Lighting Beam and Throw). Group N already covered the audio (SPL / dB / impedance / amp / time-alignment), rigging (truss / rigging-check), power (distro / neutral-imbalance), and control (DMX) pillars of live production -- but not lighting, the fourth. This tile is the theatrical fixture photometry a lighting designer runs: the beam (pool) diameter at a throw distance, D = 2 x throw x tan(beam angle / 2), and the center-beam illuminance by the inverse-square law, E = candela / distance^2 (or candela estimated from a fixture's total lumens spread over the beam cone), reported in footcandles and lux. It is distinct from the existing architectural lux-to-footcandle lumen-method tile (a room area-average from a flux budget); this is a single aimed fixture, the model manufacturers publish their photometric cut sheets in. Pure point-source photometry, hand-verifiable to the last digit (a 20-degree fixture at 30 ft throw with 100,000 cd -> a 10.58 ft pool at 111.1 fc / 1196 lux; double the throw and the illuminance quarters). It lands in calc-stage.js (cap bumped 17 -> 18.5 KB) with the full v14 discipline and the v18/v21 contract. See specs/spec-v51.md.
Spec-v50 (Baker's Percentage) is closed; package version stamps 0.45.0 (a minor). A single first-principles tile deepening Group O (Kitchen and Food Service), the most under-served substantive group, taking the catalog 577 -> 578: bakers-percentage (Baker's Percentage / Dough Hydration). It is the bakery / pizzeria formulation method every bread and dough recipe is written in -- flour is 100%, every ingredient is its weight as a percent of flour, and hydration is water as a percent of flour. From the flour weight and the percentages it gives each ingredient weight, the total dough weight, the total formula percent, and the per-piece weight. A concept-check against the 577 live tiles found this is the one common kitchen formulation recipe-scale explicitly does not handle (its renderer warns "bakers' percentages do not scale linearly"); it is distinct from recipe-scale (factor scaling) and yield-ep (AP/EP yield). Pure arithmetic, hand-verifiable to the last digit (1000 g flour at 65% hydration, 2% salt, 1% yeast over 4 pieces -> 650 g water, 1680 g dough, 168% total formula, 420 g per piece). It lands in calc-kitchen.js with the full v14 discipline and the v18/v21 contract. See specs/spec-v50.md.
Spec-v47 (Circle Through Three Points) is closed; package version stamps 0.44.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 576 -> 577: circle-from-3-points (Circle Through Three Points). It is the inverse of bolt-circle -- recover a circle's center and radius from three measured points on its arc (the triangle's circumcircle), for when you cannot measure the chord and a midspan rise directly but can take three points off the curve. The center is the circumcenter (D = 2(x1(y2-y3)+x2(y3-y1)+x3(y1-y2)), then the standard circumcenter coordinates), the radius the distance from the center to any point; diameter and circumference follow. First-principles coordinate geometry, hand-verified to the last digit (points (0,0), (4,0), (0,3) -> center (2, 1.5), radius 2.5, since a right triangle's hypotenuse is the diameter). Collinear or coincident points return an error (zero determinant). A concept-check against the 576 live tiles found bolt-circle lays out holes on a known circle but no tile recovers the circle from three points. Lands in calc-fab.js (the Group G fabrication & layout bench, alongside bolt-circle / circular-arc). See specs/spec-v47.md.
Spec-v46 (dist/ integrity gate activation) is closed; the close rides the 0.44.0 stamp. Housekeeping in the spirit of spec-v45: no tiles, no calculator changes. A dormant-gate audit (diff scripts/check-*.mjs against the gates referenced in .github/workflows/ci.yml and the npm run lint chain) found that check-dist (the spec-v12 §G.3 dist/-vs-runtime cross-check -- every same-origin reference in a shipped dist/ file must resolve to a file actually present in dist/, catching a dangling fetch or data-shard reference the build did not copy) was never invoked by CI. It is a deterministic, offline gate with no flakiness risk, so v46 wires npm run check:dist into the integration job (after npm run build, beside check:shells / check:shell-mobile). It currently resolves 2,011 same-origin references across 790 dist/ files with zero dangling, so wiring it is safe and locks that in. See specs/spec-v46.md.
Spec-v44 (Circular Arc Layout) is closed; package version stamps 0.42.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 575 -> 576: circular-arc (Circular Arc Layout). It answers the everyday field-layout question for an arch, curved trim, sheet-metal radius, or road curve -- recover the radius, arc length, and central angle of a circular arc from a measured chord (span) and rise (the sagitta / middle ordinate) at midspan. R = (chord^2/4 + rise^2) / (2 x rise); central angle = 2 x acos((R - rise)/R) (valid for minor and major arcs); arc length = R x angle. First-principles circle geometry, hand-verified to the last digit (chord 24 in, rise 4 in -> radius 20 in, central angle 73.7398 deg, arc 25.7400 in; a rise equal to the radius is a semicircle, a rise greater than the radius is a major arc). A concept-check against the 575 live tiles found bolt-circle lays out hole positions but no tile recovers a curve's radius from a chord and rise. Lands in calc-fab.js (the Group G fabrication & layout bench, alongside bolt-circle / sine-bar / pipe-template-wrap) with the full v14 discipline and the v18/v21 contract; tools-data.js fit the new row within its current cap. See specs/spec-v44.md.
Spec-v43 (Tank Volume from Dipstick) is closed; package version stamps 0.41.0 (a minor). A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 574 -> 575: tank-volume (Tank Volume from Dipstick). It answers the everyday question for anyone gauging a fuel, water, chemical, or feed tank -- how many gallons are in a partially-filled cylindrical tank from a single depth (dipstick) reading. The horizontal cylinder is the non-trivial closed form: the liquid is a circular segment of area A = R^2 x acos((R-h)/R) - (R-h) x sqrt(2Rh-h^2), volume = A x length; the vertical cylinder is the trivial V = pi x R^2 x depth. Reported in US gallons, liters, and cubic feet with percent full; dimensions in inches or feet. First-principles circular-segment geometry (flat ends; dished heads need a head-type correction), hand-verified to the last digit (24 in dia x 48 in horizontal, depth 12 in = half full -> 47.00 gal of a 94.00 gal tank, 50.0%; vertical same dims at depth 12 in -> 25.0%). A concept-check against the 574 live tiles found pipe-volume covers only the full cylinder and the existing "tank" tiles are expansion / septic / pressure tanks -- no partial-volume gauging tile existed. Lands in calc-cross.js (the Group G home, which had headroom after the v36 fab split) with the full v14 discipline and the v18/v21 contract; the tools-data.js registry crossed its cap so its gzip cap was bumped 47000 -> 48000 B (lazy-loaded, not in the home payload). See specs/spec-v43.md.
Spec-v42 (calc-gas.js Module Split) is closed; package version stamps 0.40.1 (a patch). Platform-only housekeeping in the spirit of spec-v36 / spec-v39: adds no tiles, removes none, changes no calculator output (catalog stays 574). calc-plumbing.js had reached 98.9% of its 50 KB gzip cap -- the tightest module in the catalog, one citation reword from breaking the build -- so the documented per-tile-split remediation came due. The three self-contained fuel-gas tiles relocated out of calc-plumbing.js into a new thematic module calc-gas.js (Fuel-Gas Piping bench): gas-pipe-sizing (IFGC 2021 Table 402.4 / NFPA 54 sizing via the Spitzglass formula), gas-leak-rate (orifice leak estimate), and gas-pipe-pressure-drop (longhand Spitzglass drop). They keep group: "B" (Plumbing and Gas; the group letter is independent of the module, the v28/v36/v39 precedent); ids, citations, worked examples, and behavior are byte-for-byte unchanged. The shared GAS_PROPERTIES table and the Spitzglass helper move with them; the small, stable Schedule 40 inside-diameter table is duplicated in calc-gas.js (it stays in calc-plumbing.js for the water tiles that also use it). Result: calc-plumbing.js 49.5 KB -> 46.9 KB gz (cap lowered 50000 -> 49000 B to lock in the relief; now 95.7%), new calc-gas.js 4.4 KB (cap 5500 B, 80.2%); module count 29 -> 30, catalog stays 574. The wiring lint reports 30 renderer modules / 574 tile-id entries; all three moved tiles verified clean in a real browser (identical outputs) plus the full lint / 5,511-test / build / shell-mobile bar. See specs/spec-v42.md.
Spec-v41 (Machine Shop & Fab Bench, Batch 2) is closed; package version stamps 0.40.0 (a minor). Two first-principles tiles extending the existing calc-shop.js module from spec-v40's own §5 roadmap, taking the catalog 572 -> 574 (distribution K +1, G +1; group count holds at 24, no new module, no new group). Group K: tap-drill-size (tap drill for a target percent of full thread on a 60-degree thread, D_drill = D_major - % / (76.98 x TPI), with the nearest 1/64 in fraction -- the named letter / number drill is a chart lookup, never transcribed). Group G: rolled-blank (developed flat blank length to roll plate into a cylinder / ring at the neutral axis, L = pi x (OD - 2T(1-k)) = pi x (ID + 2kT), default k = 0.5 mid-thickness). Both are first-principles geometry (public domain), hand-verified to the last digit (1/4-20 UNC at 75% -> 0.201286 in, the standard #7 drill, nearest 13/64 in = 72.17%; M8x1.25 at 75% -> 6.78 mm vs the standard 6.8 mm; OD 12 in / T 0.25 in / k 0.5 -> developed length pi x 11.75 = 36.913714 in). Two further spec-v40 §5 candidates were deferred on a live concept-check: gas-cylinder-duration (overlaps the existing o2-cylinder-duration by concept -- cylinder gas content / flow = time) and weld-cost-per-foot (overlaps weld-usage + time-and-materials). calc-shop.js sits at 83.7% of its 16 KB cap (no bump) and is lazy-loaded, so the home-view payload is unaffected. Full v14 discipline and the v18/v21 contract; the wiring lint reports 29 renderer modules / 574 tile-id entries, and both tiles verified clean across the render-no-nan, a11y, and 320 px responsive (Chromium + WebKit) gates. See specs/spec-v41.md.
Spec-v40 (Machine Shop & Fab Bench) is closed; package version stamps 0.39.0 (a minor). Ten first-principles tiles standing up a new calc-shop.js module -- the everyday math a working machinist, fabricator, and welder runs at the bench but the catalog did not yet cover -- taking the catalog 562 -> 572 (distribution K +5, G +2, E +3; the group count holds at 24, each tile keeping its natural group letter while living in the new module behind SHOP_RENDERERS, the v28/v36/v39 group-letter-independent-of-module precedent). Group K (machinist): machining-time (cut time per pass, t = L / feed_IPM with feed_IPM = RPM x IPR), material-removal-rate (MRR for milling / turning / drilling), turning-surface-finish (theoretical Rt = f^2 / 8r, Ra ~= Rt/4), taper-calc (taper per foot and angle, TPF = 12(D-d)/L), dividing-head (simple indexing, turns = ratio/N plus the full-turns-plus-holes plate setting). Group G (cross-trade): thread-measure-wire (three-wire 60-degree measurement, M = E + 3W - 1.51553 P), punch-force (F = perimeter x T x shear strength). Group E (welding / sheet-metal): press-brake-tonnage (air-bend tons/ft = 575 x (UTS/60) x T^2 / V), weld-duty-cycle (DC2 = DC1 (A1/A2)^2, NEMA EW-1), carbon-equivalent (IIW CE = C + Mn/6 + (Cr+Mo+V)/5 + (Ni+Cu)/15 with a preheat band, AWS D1.1). Eight tiles are first-principles geometry / algebra (public domain); two cite a published empirical / material constant the user can override (press-brake-tonnage the 575 air-bend constant, carbon-equivalent the IIW formula), and one (punch-force) is first-principles shear with a user-supplied shear strength -- zero table transcription (no thread chart, tap-drill table, or speeds-and-feeds book). Every tile is hand-verified to the last digit (e.g. punching a 0.5 in round hole in 0.25 in steel at 50,000 psi -> 19,634.95 lb / 9.8175 tons; 250 A at 60% duty -> 41.67% at 300 A and 193.6 A continuous; A36-type C 0.25 / Mn 0.80 -> CE 0.38333, "preheat advised"). The new module starts at a 16 KB cap (fits with headroom) and is lazy-loaded, so the home-view payload is unaffected. Full v14 discipline and the v18/v21 contract; the wiring lint reports 29 renderer modules / 572 tile-id entries, and all ten verified clean across the render-no-nan, a11y, and 320 px responsive (Chromium + WebKit) gates. See specs/spec-v40.md.
Spec-v39 (calc-electrical.js Cap Relief) is closed; package version stamps 0.38.1 (a patch). A platform-only / housekeeping spec in the spirit of spec-v10 and spec-v36: it adds no tiles, removes no tiles, and changes no calculator output -- the catalog holds at 562 tiles; only the on-disk module layout changes. calc-electrical.js (Group A, the founding electrical trade and the largest module) had reached ~65.5 KB gzipped, 99.3% of its 66 KB cap -- the most-pressed module after calc-plumbing.js (98.9%) -- so the next electrical tile, or even a citation reword, would have broken the build, and continued cap-bumping was deferring the documented per-tile-split fix. The spec-v24 conduit-bending suite -- three cohesive, self-contained, first-principles bend/layout geometry tiles, conduit-offset, conduit-saddle, and conduit-90-stub -- is relocated into the existing calc-fab.js (the cross-trade Fabrication & Layout bench), the conduit analog of the pipe-miter-cut / pipe-template-wrap tiles already there. All three keep group: "A" (a tile's group letter is independent of its module, the spec-v28 / spec-v36 precedent); their ids, citations, worked examples, and behavior are byte-for-byte unchanged. The cleavage was confirmed clean by the v36 self-containment test (the moved block references no symbol defined above the cut, only ui-fields helpers and the module-local _finiteGuard calc-fab already has). After the move calc-electrical.js is ~62.4 KB (96.7% of a lowered 64500 B cap, relief locked in) and calc-fab.js is ~15.3 KB (78% of a raised 20000 B cap, grown into its bend/layout role; lazy-loaded, so the home-view payload is unaffected). Every reference is repointed and gated: the app.js declare list, test/fixtures/compute-map.js, the conduit imports in the bounds fuzzer and the v24/v25 suite, the module-size caps, and the v14 corpus were all updated, with the wiring lint reporting 28 renderer modules / 562 tile-id entries and a browser smoke-test confirming the moved + a kept electrical tile. The next near-cap modules (calc-plumbing.js, tools-data.js, calc-agriculture.js, calc-hvac.js) stay on the watch list for the same treatment as the catalog grows. See specs/spec-v39.md.
Spec-v38 (Thread-Pitch Bench) is closed; package version stamps 0.38.0. A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 561 -> 562: thread-pitch (Thread Pitch and Lead). It is the everyday machinist / fabricator setup question -- read the thread pitch off a TPI count or a metric designation, and the lead of a single- or multi-start thread. Unified (UN/UNC/UNF) inch threads and ISO metric threads share a 60-degree included angle, so the tile is exact closed-form geometry: inch pitch P = 1 / TPI; metric pitch is the millimetre value with TPI = 25.4 / P; the lead (axial advance per turn) is P x starts; and the 60-degree sharp-V fundamental height is H = P x sqrt(3) / 2. Pure arithmetic and 60-degree geometry, hand-verifiable to the last digit (1/4-20 UNC at 20 TPI -> 0.050000 in / 1.2700 mm pitch and a 0.0433013 in sharp-V height; metric M8x1.25 -> 20.32 TPI and 0.0492126 in pitch; a 2-start 8 TPI thread -> 0.125 in pitch, 0.250 in lead), with zero table transcription -- the user supplies the TPI or the metric pitch, so there is no thread-chart lookup. A concept-check against the 561 live tiles found no thread-pitch / threads-per-inch / lead tile (roof-pitch is roofing slope; flange-bolt-torque reads a thread series for a tensile-area constant but computes no pitch; fastener-pullout, deck-ledger-fasteners, screw-conveyor are unrelated). It lands in the calc-fab.js module (~64% -> ~66% of its 16 KB cap; no cap bump) alongside sine-bar and bolt-circle. Full v14 discipline and the v18/v21 contract; non-positive TPI/pitch, fewer than one start, and non-finite inputs are guarded, and the truncated working depth and tap-drill size (thread-form/class-specific) are noted as out of scope. See specs/spec-v38.md.
Spec-v37 (Sine-Bar Bench) is closed; package version stamps 0.37.0. A single first-principles tile deepening Group G (Cross-Trade Utilities), taking the catalog 560 -> 561: sine-bar (Sine Bar Angle Setup). It is the precision-angle setup every machinist, toolmaker, and QC inspector reaches for at the surface plate: a sine bar of length L (the roll-center distance, commonly 5 in or 10 in) set on a gauge-block stack of height H tilts to angle theta where sin(theta) = H / L, so the tile solves both directions -- the angle from a stack (theta = arcsin(H/L)) and the stack height for a target angle (H = L x sin(theta)). Pure trigonometry, hand-verifiable to the last digit (a 5 in sine bar on a 2.5 in stack -> arcsin(0.5) = 30.0000 deg; reversing, 30 deg -> 2.5000 in; a 10 in bar at 10 deg -> 1.7365 in), with a note that above ~45 deg a sine plate or angle blocks are preferred because the stack height changes little per degree. A concept-check against the 560 live tiles found no sine-bar / sine-plate / gauge-block angle tile (the existing "angle" tiles -- power triangle, sling angle, ladder angle, wind triangle -- are unrelated). It is the first tile to land in the new calc-fab.js module (62% -> ~64% of its 16 KB cap), the headroom the v36 split was for, and a companion to the existing bolt-circle layout tile. Full v14 discipline and the v18/v21 contract; the arcsin domain seam (H > L) and the 0..90 deg range are both guarded. See specs/spec-v37.md.
The v24/v25 field formulas, as a one-screen cheat sheet (all first-principles, all ASCII):
Tile | Formula | Worked check |
| mark spacing = offset / sin(theta); shrink = offset x tan(theta/2) | 6 in @ 30 deg -> 12 in spacing, multiplier 2.0 |
| 3-point: center bend = 2 x outer; field multiplier 2.5x (45/22.5) or 2.0x (60/30) | 3 in @ 45/22.5 -> 7.5 in marks, 9/16 in shrink |
| stub mark = height - deduct; segment shots = ceil(90 / per-shot) | 8 in stub, 6 in deduct -> 2 in mark; 5 deg shots -> 18 |
| true offset = sqrt(rise^2 + roll^2); travel = true offset / sin(theta) | rise 12, roll 9 -> 15 true offset; 21.21 in travel @ 45 deg |
| HI = (60 x V x I) / TS x efficiency | 25 V, 200 A, 8 in/min, eta 0.8 -> 30 kJ/in |
| weight = area x length x density x qty | 1x12x120 in A36 plate -> 408.4 lb |
| diagonal = sqrt(a^2 + b^2); out-of-square = abs(d1 - d2) | sides 3, 4 -> diagonal 5 exactly |
| T = R tan(d/2); L = R d_rad; LC = 2R sin(d/2); D = 5729.58/R | R 1000 ft, d 30 deg -> T 267.95, L 523.60, LC 517.64 |
| y = y_BVC + g1 x + ((g2-g1)/2L) x^2; turning x = -g1 L/(g2-g1) | g1 +3, g2 -2, L 400 -> crest 97.60 at sta 5040 |
| V = (L/2)(A1 + A2); prismoidal (L/6)(A1 + 4Am + A2); yd3 = ft3/27 | two 100 ft^2 @ 100 ft -> 10000 ft3 (370.4 yd3) |
| cut/fill = existing - design; catch = offset + ratio x abs(cut/fill) | existing 104.5, design 100, 2:1 -> 4.5 ft cut, 9 ft catch |
| A = 1/2 abs(sum(E_i N_{i+1} - E_{i+1} N_i)); acres = ft2/43560 | 100x100 square -> 10000 ft2 (0.2296 ac) |
| lat = d cos(az), dep = d sin(az); misclosure = sqrt(sumLat^2 + sumDep^2); Bowditch correction = -(d/perimeter) x sum | rectangle -> perfect closure (0 misclosure) |
| series Z = sum Z_i; parallel Z = Z/N (equal drivers) | four 8-ohm parallel -> 2 ohm |
| power 10 log10(P2/P1); field 20 log10(V2/V1); combine 10 log10(sum 10^(Li/10)) | P2/P1 = 2 -> 3.01 dB; two 90 dB -> 93.01 dB |
| SPL = sensitivity + 10 log10(P) - 20 log10(d) | 90 dB, 100 W, 1 m -> 110 dB; doubling power -> +3 dB |
Spec-v16 is now closed (Part II of III); package version stamped 0.16.0. The Group B (Plumbing), Group M (Water / Wastewater), Group C (HVAC), and the Group D / C.4 loose-ends batches landed 16 genuinely-new tiles plus 2 output extensions, taking the catalog 400 -> 417. Group B added water-heater recovery rate (DOE 10 CFR 430 / AHRI 1300), potable thermal-expansion-tank sizing (ASPE Plumbing Engineering Design Handbook + ASME B40.1 steam tables, with the IPC 607.8 PRV note), sanitary-drain DFU sizing (IPC 2021 Tables 709.1 / 710.1 for horizontal branch, stack, and building drain), and trap-primer sizing (IPC 1002.4 occupied-space compliance). Group C now ships the full first-principles mechanical set: chiller tonnage from delta-T and GPM (Q = GPM x 500 x delta-T, with property-derived glycol factors per ASHRAE Fundamentals 2021 Ch. 31), heat-exchanger LMTD and effectiveness-NTU (TEMA / Incropera, counter- and parallel-flow, with thermodynamic-limit rejections), air changes per hour (CFM x 60 / volume, net ACH and pressurization, against ASHRAE 62.1 / 170 occupancy bands), hot-water boiler distribution pipe sizing (GPM = Q / (500 x delta-T) then the smallest copper / steel / PEX size at or below the material velocity ceiling, with Hazen-Williams head loss; ASHRAE Systems and Equipment 2020 Ch. 13), compressor short-cycle protection (the ASHRAE/AHRI part-load cycling parabola against the minimum oil-return runtime; Copeland AE Bulletin 17-1226), and humidifier capacity from an RH target (60 x CFM x rho x delta-W with altitude-corrected humidity ratios; ASHRAE Fundamentals 2021 Ch. 1). Group M added the small-system-water-operator math: pool turnover rate and chlorine demand (NSPF CPO Handbook / ANSI-APSP-ICC 11), well drawdown and specific capacity (AWWA A100 / USGS), cooling water makeup from cycles of concentration (CTI / ASHRAE), and first-order chlorine residual decay (EPA 815-R-02-020 / AWWA M14). The Group D / C.4 batch added D.5 equipment power draw vs available circuit capacity (NEC 210.20(A) 80%-continuous check over the drying-equipment fleet) and the C.4 cooling-tower efficiency ratio (range / (range + approach), added to the existing cooling-tower tile rather than duplicated). Then C.7 filter pressure-drop (clean and change-out drop by MERV / HEPA class, the brake-HP fan power at each, and the annual fan energy and loading penalty over a clean filter; ASHRAE 52.2 + first-principles fan power) landed as a first-principles tile -- the site's "compute the physics, never reproduce the licensed table" rule is exactly what lets it use representative cut-sheet defaults inline rather than bundle a paywalled curve. B.3 recirculation heat-loss landed its net-new annual-cost output as an extension of the existing recirc-loop-sizing tile (standing heat loss x runtime / heater efficiency / per-fuel BTU content x fuel price, gas or electric) rather than shipping a duplicate. And B.8 cross-connection backflow assembly sizing landed as backflow-sizing, reusing the head-loss curves already bundled for backflow-loss (so no new dataset) and adding the genuinely-net-new screening: a high / health hazard forces a reduced-pressure principle (RP) assembly per IPC 312 regardless of selection, the downstream residual pressure (upstream minus head loss) is checked against a minimum, and the EPA 40 CFR 141.85 / AWWA M14 annual-test reminder is surfaced. Each shipped with the full v14 discipline: dimensional annotation, bounds fuzzer, a worked example cross-checked against the cited reference, citation + tile-meta + related-tiles + search aliases, and a prerendered shell. With B.3 and B.8 landed, every genuinely-new v16 tile the first-principles / extension / representative-defaults discipline can deliver has shipped. The rest are covered by existing tiles (C.1 duct fittings by duct-friction-static; D.1-D.4 by air-movers / dehumidifier / nam-sizing / drying-times; B.4 storm-drain by computeStormwaterRational + computeManningSlope; N.6 WSFU by the Hunter's-curve pipe-sizing tile), and only the external-dataset tiles (C.2 refrigerant line-set / NIST REFPROP and B.7 LP-gas / NPGA) are deferred to their own reviewed changes (each bundles a genuinely external, in B.7's case safety-sensitive, dataset that lands later as a 0.16.x change). With those documented, v16 closed on 2026-06-05 and the package version stamped 0.16.0; the §Z.4 reviewer signoffs remain open and gate the "audited" announcement, not the close. v17 (Allied-Profession Deepening, Part III of III) is the next frontier; because v18-v23 landed out of spec order and stamped the package through 0.24.2 before v17's bookkeeping close, the v17 close rides 0.24.2 rather than the drafted 0.17.0. See specs/spec-v16.md.
Spec-v17 (Allied-Profession Deepening, Part III of III) is closed; the close rides the 0.24.2 patch stamp. Multiple batches landed incrementally, taking the catalog 417 -> 437. Phase L added the irrigation requirement (ET-based acre-feet from ET_crop = Kc x ET0 x days, net/gross depth after rainfall and efficiency; FAO Irrigation and Drainage Paper 56 + USDA NRCS Irrigation Guide, with reference ET0 user-supplied and FAO 56 Table 12 Kc values inline), the cattle stocking rate (available forage, animal-unit-months, and grazing days; USDA NRCS National Range and Pasture Handbook Ch. 6), and the grain bin capacity (cylinder + cone geometry to bushels via ft^3 x 0.8036, weight by USDA FGIS test weight). The §Z.4 deliverable added shared, lazy-loaded statistical special functions to pure-math.js -- erf, normCdf, gammaln, gammainc, chi2Cdf, betainc, tcdf -- each verified against a published table value (Abramowitz & Stegun for erf; the standard t / chi-square critical-value tables for the CDFs), with zero impact on the home-view payload; the three tiles that consume them complete the Educators statistics set: Y.4 pearson-correlation (Pearson r, R^2, and the t-test from tcdf), Y.3 chi-square-gof (the chi-square goodness-of-fit statistic and p-value from chi2Cdf, expected as counts or proportions with an expected-below-5 flag), and Y.2 linear-regression (the least-squares slope / intercept, R^2, residual standard error, the slope t-test, and an optional prediction). That batch also corrected the home page's stale, inconsistent crawler-facing tool count (index.html read "404", the SPA runtime read "400") to a durable "420+". Each shipped with the full v14 discipline. As in v16, the audit found that much of what v17 drafts is already in the catalog and is documented as covered rather than duplicated: Aviation top-of-descent / weight-balance / pressure-altitude / Mach-in-true-airspeed; EMS anion-gap / nihss / wells-pe / perc-rule; Lab henderson-hasselbalch / molarity-dilution / beer-lambert. The Group L deepening then completed its genuinely-new surface: L.2 npk-blend (a soil-test fertilizer recommendation -- max(0, crop demand - soil credit) for N/P2O5/K2O, solved into a three-straight blend of urea, DAP, and potash with over-application flags) and L.5 tank-mix (acres per tank, product per tank with unit conversions, and tanks / total product / carrier water for a field; the nozzle-output GPA calibration stays the existing gpa-rate tile). The finance / tax / legal deepening then added two more genuinely-new tiles after auditing out the already-covered ones (R.1 estimated tax, R.2 mileage, R.4 Schedule SE, S.2 FRCP deadline, and S.3 prejudgment interest all already exist): R.3 home-office (the simplified $5/ft^2-to-$1,500 method vs the actual office-percent-of-expenses method, reporting the higher; IRS Pub 587 / Form 9049) and S.1 wage-garnishment (the federal CCPA Title III cap -- consumer 25% / student-loan 15% bounded by the 30x-minimum-wage floor, child support 50-65% exempt from the floor -- with an optional stricter state cap; 15 USC 1673). Group V (EMS) deepening then completed, taking the catalog 427 -> 429: V.1 ideal-body-weight (the Devine ideal, Hume lean, and ICU adjusted body weights used as drug-dosing and tidal-volume weights, with a short-stature flag) and V.3 corrected-qt (QTc by Bazett, Fridericia, and Framingham from the measured QT and heart rate, flagging which correction to trust by rate and banding prolongation at 450 / 460 / 500 ms); the rest of Phase V was already covered (V.2 anion-gap, V.4 nihss, V.5 wells-dvt / wells-pe, V.6 perc-rule). Group X (Real Estate) then added three no-shard financing tiles, taking the catalog 429 -> 432: X.1 mortgage-point-breakeven (payment with/without points, monthly savings, point cost, and the break-even month vs the holding period), X.3 per-diem-interest (the CFPB Closing Disclosure prepaid-interest line from the closing date through end of month, Actual/365 / Actual/360 / 30-360), and X.4 mortgage-reserves (required PITI-months vs eligible liquid plus allowable retirement assets). X.5's income-method valuation then landed as a net-new OUTPUT extension on the existing rental-worksheet tile rather than a duplicate (the v16 B.3 / C.4 extension pattern): the gross rent multiplier (GRM = property value / annual gross rent) and the value it implies at a user-entered market GRM, completing the income approach the worksheet's NOI / cap-rate already covered. Group U (Veterinary) then added three first-principles tiles, taking the catalog 432 -> 435: U.1 vet-cri (the AVECCT constant-rate-infusion bag method), U.3 vet-transfusion (transfusion volume from species blood volume and the PCV gap, ACVIM 2021), and U.4 equine-weight (Carroll-Huntington heart-girth body weight); U.2 anesthesia induction and U.5 caloric-with-illness-factor were audited out as covered by vet-weight-based-dose / vet-anesthesia-vitals and vet-energy-requirement. Two genuinely-new no-shard tiles then landed, taking the catalog 435 -> 437: W.5 holding-fuel (the in-hold endurance question the pre-flight fuel-planning tile does not answer -- fuel burned over the hold, fuel remaining at release, endurance left in hr:min, and the maximum hold before busting the 45-min IFR / 30-min VFR reserve floor; 14 CFR 91.151 / 91.167) and X.2 rent-vs-buy (the New York Times rent-vs-buy methodology as a first-principles DCF -- each path a present value of out-of-pocket cost discounted at the investment-return rate, PV_buy = down + PV(P&I + tax + insurance + HOA + maintenance) - PV(net sale) against PV_rent = PV(inflating rent), with the break-even holding year and a buy-vs-rent verdict; tax treatment is out of scope and noted). With those, every genuinely-new v17 tile and tile-output the first-principles / extension discipline can deliver has shipped, and v17 closed on 2026-06-08. The one drafted surface that does not close inside v17 is the §Z.5 state-keyed shards: the R.4 SE wage base and the sales/use-rate reference already ship as data/accounting/se-tax-parameters.json and data/crosswalks/state-tax-rates.json, and the L.1 ET reference is the tile's user-supplied reference ET0; the two genuinely-new 50-state legal datasets (S.1 garnishment maxima, S.3 prejudgment-interest rates) land as their own reviewed change per the v16 deferred-external-dataset precedent, and neither tile is blocked on them (wage-garnishment already computes the federal CCPA Title III cap with an optional stricter state-cap percent, and judgment-interest accepts the statutory rate as an input). The §Z.6 per-group reviewer signoffs remain sought and gate the "audited" label on the release announcement, not the close. Because v18-v23 had already stamped the package through 0.24.2 (out of spec order), re-stamping the drafted 0.17.0 would be a semver regression, so the close rides 0.24.2 and changes no code. Platform note: the spec-v10 §H.2 TOOLS-metadata extraction has landed. The ~30 KB TOOLS array moved out of app.js into a lazy-loaded tools-data.js, dynamic-imported via an ensureTools() that mirrors the existing ensureAliases pattern (the home view is static HTML and routing consults the id list only for a tile hash, so the bare home view excludes the shard), with the ~15 build / lint scripts and tests that parse the { id: ... } shape repointed to the new file. A static import was rejected because it would only shrink app.js on disk without reducing the bytes the browser loads on first paint. The result: the home-view JS sub-budget dropped from 99.3% to 39.9% (and the total home payload to 31.9% of its 100 KB ceiling), restoring headroom for the rest of v17. The full design and rationale are in specs/spec-v17.md.
Spec-v18 (Public-Surface Hardening) is closed; the close rides the 0.24.2 patch stamp. v18 ships no new tiles and changes no correct output -- it is a defect-removal pass that writes the per-tile output contract down (spec-v18 §2) and makes the test suite enforce it. Every registered compute function must return either an all-finite-numeric result or an { error } object; it must never throw, hang, exhaust memory, mutate its input, or return a different result on an identical second call. The first hardening pass added the check-tile-contract gate (a structured input sweep seeded from each tile's worked-example fixture, run inside a worker with a heap cap and wall-clock timeout so a regression that reintroduces an unbounded loop surfaces as a gate failure rather than an infinite CI hang) and removed the seven genuinely-dangerous defects it found -- inputs that previously crashed, hung, or exhausted memory rather than returning a clean error: upgrade-roi and loan-amortization (a non-finite term looped / allocated without bound), serial-dilution and hip-valley-rafter (a non-finite count built an unbounded array), macrs and court-deadline (a NaN/Infinity index threw), and solar-times (a non-finite time-zone offset spun the minute-wrap loop forever). Each landed with a red-then-green regression test. The remaining lower-severity backlog -- a perturbed numeric slot driven to Infinity/NaN that leaks a non-finite output field instead of erroring -- is recorded as a ratcheted baseline (test/fixtures/contract-baseline.json) so no new tile can add one, and is hardened module-by-module per spec-v18 §7. v18 also promoted the temporary 320 px shell auditor to the standing check-shell-mobile gate (wired into CI) and fixed a genuine page-level horizontal-scroll defect it surfaced: the client-rendered changelog overflowed 320 px on long file-path / URL tokens, now wrapped. The §7 per-module Tier-2 campaign is now CLOSED (package 0.24.1, 2026-06-06): the backlog went from 837 to 0 -- every registered compute function honors the output contract under the full sweep (each numeric slot driven to 0 / -1 / NaN / Infinity), the baseline is rewritten to 0 so any new leak hard-fails, and no correct output changed (all 5,425 unit tests pass). The fix is the v21 seam applied module-wide: a generic non-finite input guard (a pasted 1e999 or garbage returns { error } instead of leaking; a non-exported _finiteGuard per module, no corpus row) plus a per-function degenerate-denominator fix on the 16 residual zero/negative cases (a zeroed required input returns { error }; a genuinely-infinite field is null with the other fields preserved). Pinned by test/unit/v18-section7-hardening.test.js. The §5.4 render-assertion layer then closed v18 entirely (package 0.24.2, 2026-06-08): test/integration/render-no-nan.test.js asserts at the real-Chromium DOM that no renderer paints a raw NaN, Infinity, $NaN, or undefined into the user-visible output (the half of the C-7 contract §7's solver sweep does not cover -- a finite value can still leak through a missing field or a bad format string). Every one of the 581 tiles is checked across four input states: a finite result via its "Test with example" button, the empty first render, the degenerate-after-interaction states (each input blanked in turn, each select cycled through every option), and the checkbox / radio toggle states (each box on and off, each radio selected) that switch a renderer onto a mode branch the other states never reach. Result: 581 / 581 pass, 0 leaks, running inside the existing test:e2e job. See specs/spec-v18.md.
Spec-v19 (Citation Integrity Sweep) is closed; the close rides the 0.24.2 patch stamp. v19's guarantee is that every public tile cites inline (in view and in the clipboard export), current (edition checked against the source's publication cycle), and well-formatted (every URL linkifies, nothing overflows a 320px phone). The substance of the sweep landed as spec-v22 (the concrete findings register that "closes the loop opened by v19"): the freshness ledger (docs/citation-freshness-ledger.md) lists every tracked source with a current | disclosed-lag | acknowledged-stale status, the link/constant-hygiene checks live in check-citation-coverage.mjs, 320px wrapping rides on check-shell-mobile.mjs, and prose conventions are guarded by the CF-09 regex. The one piece that remained genuinely open -- the §2.1/§2.2 coverage-gate graduation -- closed 2026-06-08: check-citation-coverage.mjs now fails on any tile missing a citation entry, any orphan entry, any entry missing one of the four required fields (formula / edition / freeAccess / governance), and any field carrying a raw http(s):// scheme. Coverage stands at 581 / 581 with all four required fields present, so the gate graduated at its floor (the v14 §16 ratchet). Pinned by test/unit/v19-citation-coverage.test.js. See specs/spec-v19.md.
Spec-v21 (Public-Surface Hardening II) is closed; package version stamps 0.21.0. Where v18 wrote the contract and built the harness, v21 is the defect register: the result of an adversarial stress-read of all 23 solver modules, enumerating every concrete leak and patching each with a red-then-green regression test (test/unit/v21-defect-register.test.js). It ships no new tiles and changes no correct output (all 442 worked-example fixtures still pass). The reassuring headline (spec-v21 §4): the catalog is mostly sound -- six modules came back fully clean, the allied-health dosing unit-toggles are arithmetically correct, and the hardest calendar logic (computeDeadline) is correct. The 28 defects that existed cluster on two named seams: RC-1, a renderer-coerced 0/negative pushed into a solver with no domain guard (the fix is an explicit positivity/finiteness guard returning { error }, e.g. a zero load that drove a lumber span to Infinity ft, or a negative area that put NaN into a needed-fire-flow); and RC-2, a solver that emitted infinite/NaN values and leaned on a renderer guard to hide them (the fix represents the degenerate case as null plus a flag, e.g. solids-retention-time on zero outflow, or the t-statistic of a perfect regression fit). Two non-contract items were resolved by confirming the basis against the cited source: the judgment-interest day-count is now declared Actual/365-Fixed explicitly in the output and notice, and the stage atmospheric-absorption humidity term was re-derived against ANSI S1.26, dropping an extra (p_r/p_a) factor that over-weighted humidity above sea level (unity at sea level, so no fixture changed). The fixes closed enough leaks to ratchet the Tier-2 contract backlog from 926 to 840; the baseline was rewritten to lock the gain. See specs/spec-v21.md.
Spec-v22 (Citation Integrity II) is closed; package version stamps 0.22.0. The citation counterpart to v21: a read of all 437 reference blocks and the cycle table behind them, fixing every concrete way the provenance promise quietly breaks. It ships no new tiles. The headline defect (CF-01): eight non-electrical tiles -- a wastewater operator's sludge index, a pesticide applicator's sprayer calibration, a livestock heat-stress index -- were displaying the NEC ampacity disclosure as their edition note, so a user was told to "verify the NEC edition adopted by your AHJ" on a tile that has nothing to do with the NEC. Each got a domain-appropriate note (OSHA, WEF, EPA-label, USDA, NOAA, NFPA-1142), and a new edition-note-relevance gate in check-citation-coverage.mjs -- a disclosure constant may not attach to a tile that does not cite its standard -- caught four more electrical-group tiles wearing the ampacity note for a quantity they do not compute (battery sizing, power-factor algebra, arc-flash, short-circuit), twelve total. The cycle table had fallen behind its own dates (CF-02/CF-03): NEC, three ASHRAE standards, and the AASHTO Green Book had passed their next_expected release estimates unflagged. NEC advanced to the published 2026 edition (disclosed-lag: bundled values still follow 2023 and the disclosure now says so); the rest re-stamped "verified, monitoring." The freshness gate now fails on a passed date with no re-stamp and on any tracked source missing a row in the new docs/citation-freshness-ledger.md. Two links were repaired (CF-05/CF-06: a .co.uk the linkifier could not render, a defunct AMS-55 host), the worst 320px-overflowing URLs shortened to bare host (CF-08, the .citation-link overflow-wrap guard already catching the rest), and the spelled-out <number> percent / in dollars prose reworded to % / (USD) (CF-09). The raw-URL-scheme (CF-07) and non-ASCII (CF-10) classes were re-confirmed clean. See specs/spec-v22.md.
Spec-v23 (Catalog Enhancement & Expansion VII) is closed; package version stamps 0.23.0. v23 is the value pass after the v21/v22 hardening: twenty enhancements that add the inverse/solve-for mode an existing tile stops one input short of, and twenty-three new tiles a working professional reaches for. Because it lands after the contract and citation gates went green, every new path is born into them -- the fuzzer's Infinity probe immediately drove a finite-guard fix on the new lumen-method denominator, exactly the RC-1 seam v21 named. All 23 of the new tiles have now landed (catalog 437 -> 460 across two batches), each as one formula, one cross-check, one tolerance, one named US authority. The first batch (8 tiles): A.1 lux-to-footcandle (IES lumen method + the exact 10.800 lux/fc identity), C.1 duct-velocity-pressure (ACCA Manual D / ASHRAE V = 4005√VP), C.2 refrigerant-velocity (ASHRAE Refrigeration Handbook line velocity with an oil-return verdict), F.1 fire-stream-reaction (IFSTA smooth/fog nozzle reaction with a staffing note), F.2 sprinkler-k-factor (NFPA 13 Q = K√P solved three ways), K.1 valve-flow-coefficient (ISA-75.01 / Crane TP-410 Q = Cv√(ΔP/SG)), T.2 od600-cell-count (spectrophotometry with a user-supplied strain factor and linear-range flag), and Y.1 curve-grade-scaler (flat / square-root / linear-rescale, clamped to [0, 100]). The second batch (the remaining 15): B.1 trap-seal-loss (IPC/UPC §1002 trap-to-vent), B.2 water-meter-sizing (AWWA M22), D.1 drying-chamber-co2 (ASHRAE 62.1 mass balance), E.1 wall-bracing-length (IRC R602.10), E.2 deck-ledger-fasteners (IRC R507.9), J.1 cargo-securement-wll (FMCSA 49 CFR 393), J.2 fuel-tax-ifta (IFTA Articles of Agreement), K.2 screw-conveyor (CEMA Book No. 350), L.1 pesticide-rei-phi (EPA WPS 40 CFR 170 + label), M.1 backflow-test-psi (USC FCCCHR / AWWA C511), T.1 gel-percent-agarose (Sambrook & Russell), V.1 pediatric-tube-depth (AHA PALS, with the licensed-provider banner), W.1 weight-shift-fuel-burn (FAA-H-8083-1, extending weight-shift-cg into the time domain), X.1 depreciation-recapture (IRS Pub 544 / IRC §1245 / §1250), and X.2 rent-roll-vacancy (Appraisal Institute EGI). Each shipped with the full v14 discipline -- dimensional annotation, bounds-fuzzer row, a worked example cross-checked against the cited source, a citations.js entry with a single-edition note, a tile-meta.js row with related-tiles and aliases, and a 320px-audited prerendered shell. The 20 Part I enhancements also landed -- each additive (an inverse/solve-for mode, an exposed assumption, a cross-check output, or a labeled second method), changing no existing correct output without an opt-in and guarding every new zeroable denominator per the v21 RC-1 seam: SEER2/annual-cost on seer-eer, target-superheat charge verdict on superheat-subcool, strip-kW on balance-point, solve-for inverses on tankless-gpm and fuel-range, peak-demand sizing on water-heater-recovery, burst/freeze on glycol-mix, sloped-roof + drift on snow-load, the Kz/Kzt/Kd/G design factors on wind-pressure, cracked/edge on anchor-embedment, eccentric bearing on footing-area, the Iowa second method on required-fire-flow, nozzle reaction on master-stream/hydrant-flow, per-axle wear on brake-pad-life, the required-t10 inverse on disinfection-ct, overflow-rate loadings on detention-time, Cooper-Jacob transmissivity on well-drawdown, bag-count/kg-ha on npk-blend, tank-batches on sprayer-calibration, and loan-derived debt service + break-even occupancy on cap-rate-dscr. The contract sweep improved as a result (the new guards cleared 3 prior Tier-2 leaks; baseline 840 -> 837). See specs/spec-v23.md.
Spec-v20 (Catalog Expansion VI) is closed; package version stamps 0.24.0. v20 is the catalog-growth member of the v18/v19/v20 set, and it landed after the v21-v23 hardening, citation, and enhancement passes (out of spec order), so every one of its 55 new tiles is born into the hardened v21 contract and the v22 citation discipline rather than retrofitted -- the bounds-fuzzer's Infinity probe drove finite-guard fixes on the new declining-balance, markup, neutral-current, and ISA-correction denominators as they landed, exactly the v21 RC-1 seam. The catalog advances 460 -> 515 across nineteen groups: A +3 (parallel-conductor-derate, neutral-current-3ph, motor-vd-starting), B +3 (thermal-expansion-volume, vent-sizing-stack, gas-pipe-pressure-drop via the Spitzglass low-pressure form), C +3 (economizer-savings-hours, pipe-heat-loss-radial, fan-motor-bhp), D +2 (grains-removed, evaporation-load), E +3 (point-load-bearing, column-buckling-wood, beam-reactions), F +2 (elevation-pressure-loss, water-supply-duration), J +3 (cost-per-mile, deadhead-percent, axle-load-distribution), K +3 (hp-from-torque, volumetric-efficiency, gear-mph-rpm), L +3 (growing-degree-days, pearson-square-ration, livestock-water-requirement), M +3 (weir-flow, langelier-index, chemical-feed-pump), N +1 (power-distro), O +1 (brine-cure), P +1 (search-probability), R +3 (declining-balance-depreciation, markup-vs-margin, employer-payroll-tax), S +2 (federal-post-judgment-interest, lease-rent-proration), T +2 (primer-tm, cfu-plate-count), U +4 (vet-body-surface-area, vet-corrected-reticulocyte, vet-fluid-deficit, vet-anion-gap), V +4 (cockcroft-gault-crcl, winters-expected-pco2, aa-gradient, fena), W +3 (isa-temp-correction, weight-shift-cg, landing-takeoff-da-correction), X +3 (gross-rent-multiplier, pmi-cancellation-date, seller-net-sheet), Y +3 (final-grade-needed, category-weighted-grade, two-sample-t-test, the last reusing the bundled tcdf helper). Each shipped with the full v14 discipline; the four Group U and four Group V tiles additionally carry the spec-v12 §13 licensed-provider banner. A self-audit caught the spec's example PMI months for pmi-cancellation-date ("~70/~82"): standard amortization of a $250k loan at 6.5% over 360 months reaches 80% LTV at month 146 and 78% at month 156, and the implementation uses the correct months. Because 0.21.0-0.23.0 were already stamped, the close stamps 0.24.0 rather than the 0.20.0 the spec named (a downgrade would be a semver regression). See specs/spec-v20.md.
Retired platform affordances: Recents and Big Buttons mode (v11), Project Bundle (the bundle.js module; old #b= hashes still parse and route home). High-contrast theme was folded into the dark/light toggle; a stored high-contrast preference migrates to dark on load.
Discoverable surface (prerendered shells)
The home document renders the SPA, and per-tile state lives in the URL hash. But fragments are not part of URL canonicalization, and most non-Google crawlers do not execute JavaScript, so the cited reference content of 942 tiles would otherwise be invisible to general web search. Spec-v13 fixes this with a build-time prerender step.
flowchart LR
SRC[TOOLS registry\n+ RELATED graph\n+ citations] --> BUILD[scripts/build.mjs]
BUILD --> TILE["/tools/<id>/index.html\n1,010 static shells\n~1.9 KB gz each"]
BUILD --> GROUP["/groups/<slug>/index.html\n21 static shells\n~4.4 KB gz each"]
BUILD --> MAP["sitemap.xml\n1032 URLs"]
BUILD --> COPY[home doc + SPA modules\ncopied into dist/]
TILE -->|Run the calculator| SPA[("/#<id>\ninteractive SPA")]
style BUILD fill:#1a3a5a,color:#fff/tools/<id>/index.htmlis one static, zero-JavaScript shell per tile (1,010). Each carries the tile name as<h1>, a verb-first description, a JSON-LDWebApplication+BreadcrumbListblock, Open Graph + Twitter Card meta, a canonical link, a Formula and source block (the cited formula and the source-stamp, prerendered fromCITATIONSso the actual reference content -- the math and its authority -- is crawlable and readable offline, not just the tile name; spec-v45), an Audience block, a curated related-tiles list, a Posture block, and a "Run the calculator" anchor to the SPA hash route. Thecheck-shellsgate (wired into CI as of spec-v45) fails the build on any tile shell missing the formula/source block, an over-cap title or description, an off-allowlist JSON-LD type, or an over-budget gzip size./groups/<slug>/index.htmlis one shell per active group (21), listing every tile with a one-line description and an internal link, plus JSON-LDCollectionPage+BreadcrumbList+ItemList.sitemap.xmlcarries 1032 URLs (home + 21 groups + 1,010 tiles), regenerated at every build.SPA-side canonical emission: when the SPA opens a tile it sets
<link rel="canonical" href="https://roughlogic.com/tools/<id>/">so a crawler that lands on a hash URL still reads the canonical shell.
Measurement is source-side only (Cloudflare edge metrics, Google Search Console, Bing Webmaster Tools); there is no client telemetry. See docs/seo.md for the shell model, authoring rules, and JSON-LD allowlist.
Correctness posture
The site is a calculator; the unit of value is the answer it returns. Spec-v14 adds an end-to-end correctness audit on top of the source-stamp discipline (v6) and the per-tile unit tests. The audit is a set of build-time gates that ratchet to fail-on-missing as coverage closes, so a regression surfaces at CI rather than in the field.
flowchart TB
F[Exported calculator function] --> A[Phase A: corpus row\n1227 functions extracted]
F --> C[Phase C: dimensional analysis\n1176/1176 annotated, balanced]
F --> D[Phase D: bounds fuzzer\n1227/1227 covered]
F --> E[Phase E: numerical stability\nbit-pattern pins on iterative methods]
F --> Fa[Phase F: cross-tile invariants\n341 tests / 285 monotonicity batches]
F --> I[Phase I: derivation index\n942/942 tiles]
F --> G[Phase G: source-coverage map\n942/942 tiles, 165 sources]
F -.pending.-> B[Phase B: independent worked-example source]
F -.pending.-> H[Phase H: per-group reviewer signoff]
style C fill:#14532d,color:#fff
style D fill:#14532d,color:#fff
style E fill:#14532d,color:#fff
style Fa fill:#14532d,color:#fff
style G fill:#14532d,color:#fff
style I fill:#14532d,color:#fffStatus as of this writing:
Phase | What it guarantees | State |
A | Every exported function has a formula-corpus row in | Complete (1,181 rows) |
B | Every fixture comes from a published worked example independent of the primary citation | Pending the per-group review pass |
C | Every function carries a dimensional-analysis annotation that parses and balances | Complete (1,184/1,184) |
D | Every function passes the bounds-and-edge-case fuzzer | Complete (1,181/1,181 corpus rows) |
E | Every iterative method has a numerical-stability (bit-pattern) pin | Complete |
F | Every shared computation passes cross-tile invariant tests | Complete (5/5 shared-computation classes; round-trip identities; 285 monotonicity batches, 341 tests) |
G | Every tile maps to a classified source: a tracked published authority, or an explicit first-principles / public-domain / author-original class with no edition cycle | Complete (942/942 tiles classified, 100%; 165 tracked sources) |
H | Every active non-exempt group has a current reviewer signoff | Pending external reviewers (H and Q are exempt) |
I | One derivation-index row per tile | Complete (942/942) |
The cross-tile invariant suite is the most distinctive gate. Where an output is monotonic in an input (voltage drop in length, friction loss in flow, fluid plan in patient weight), a sweep asserts strict monotonicity plus a published-rule pin (for example, NEC 430.22 125%, Hazen-Williams Q^1.929, the IRS standard mileage rate against the bundled shard). A sign flip, an exponent swap, or a missing unit conversion fails immediately rather than producing a plausible-but-wrong number. The sweep now covers every catalog compute function whose output is monotonic in an input. See docs/correctness.md.
Building and testing
The site has no command-line interface of its own. The repository ships these npm scripts.
Command | What it does |
| Start a local development server. |
| Produce the static |
| Run the unit suite under Node's built-in test runner (5,235 tests). |
| Run the Playwright integration suite (per-tile smoke, layout, print, CSV, render-leak, perf, responsive-stress). |
| Run the axe-core accessibility loop over every tile. |
| Run the 28-gate lint chain (below). |
| The pre-PR gate: lint, test, build, dist check, data verify. |
| Run the data pipeline (fetch, parse, shard). |
| Verify shard SHA-256 hashes against |
| Audit every prerendered shell (942 tools + 21 groups + home) for zero horizontal scroll: all at the 320px floor, plus a representative sample at 568x320 landscape and 200% text zoom (needs a built |
| Remove |
The lint chain
npm run lint runs 28 gates in sequence. They are the project's executable spec: a violation fails CI.
Gate | Guards |
| Banned tokens: em-dash, emoji, forbidden phrasings (spec §8). |
| Banned n-grams in user-facing copy. |
| Every tile has a source stamp (v6). |
| Data manifests match the shard tree. |
| The inline boot-script sha256 matches the CSP in both |
| Citation editions are current. |
| Generated citation strings are not stale. |
| Search aliases + group/tile counts are consistent. |
| The catalog counts the README states (tile / module / group / sitemap-URL totals, including the Mermaid-diagram nodes that glue the number to |
| Every relative markdown link in the living docs (README, ARCHITECTURE, |
| Every tile has a worked-example fixture. |
| Tile metadata is well-formed. |
| Every tile has a curated related-tiles entry. |
| Renderer imports/exports and dist-vs-runtime parity. |
| A renderer that parses newline-delimited input (one row per line) builds it with |
| No compute function destructures an input it never references in its body -- a control the user can set that the math silently ignores (the static cousin of the trench-slope |
| The service-worker precache list matches shipped files. |
| Per-module gzip caps (tile shell 6 KB, group shell 12 KB). |
| Home-view payload under the 100 KB budget. |
| Formula corpus is not stale (Phase A). |
| Per-tile derivation index is not stale (Phase I). |
| Fixture tolerances under the per-group ceiling (Phase B). |
| Dimensional annotations parse and balance (Phase C). |
| Tile-to-source coverage map (Phase G). |
| Per-group reviewer-signoff table is well-formed (Phase H). |
| Every tile is mentioned in |
| Every corpus row has a bounds-fuzzer row (Phase D). |
| Every registered compute function honors the spec-v18 §2 output contract: no throw, hang, OOM, impurity, input mutation, or |
Continuous integration
.github/workflows/ci.yml runs four jobs on every push and pull request to main/develop:
flowchart LR
PUSH([push / PR]) --> TEST[test\nlint + unit + data:verify]
TEST --> LH[lighthouse\nbuild dist, audit shells + home]
TEST --> A11Y[accessibility\naxe-core over every tile]
TEST --> INT[integration\nPlaywright full suite +\n320px shell-mobile gate]
style TEST fill:#1a3a5a,color:#fffThe integration job also builds dist/ and runs two shell gates. check-shells (the spec-v13 content gate, wired into CI as of spec-v45) asserts every prerendered shell carries a within-cap title and meta description, a canonical link, Open Graph + Twitter blocks, a JSON-LD block whose every @type is on the closed allowlist, the spec-v45 formula/source citation block (tile shells), and a within-budget gzip size (6 KB tile / 12 KB group). check-shell-mobile (spec-v18 §6): every prerendered /tools/ and /groups/ shell plus the SPA home shell is loaded at a 320 px viewport and fails the build if scrollWidth exceeds clientWidth (a page-level horizontal scroll on a phone), with a representative sample re-checked at landscape and 200% text zoom. The Playwright suite additionally runs the spec-v18 §5.4 render-leak gate (render-no-nan.test.js): every tile is loaded at the real-Chromium DOM across its finite-result, empty-first-render, degenerate-after-interaction (each input blanked, each select cycled), and checkbox/radio toggle states, and fails if the user-visible output ever contains a raw NaN, Infinity, $NaN, or undefined; and the responsive-stress.test.js SPA gate re-checks the interactive views at 200% text zoom and across landscape / tablet widths.
The Lighthouse budgets are tiered: the prerendered /tools/ and /groups/ shells carry the strict budget (performance >= 0.95, FCP <= 1 s, LCP <= 1.5 s) because they ship only styles.css; the SPA home view, which loads the ~86 KB app.js (the catalog registry is deferred to tools-data.js, lazy-loaded on first interaction), is gated on the stable paint metrics (FCP, LCP, CLS) and the accessibility / best-practices / SEO scores rather than the high-variance total-blocking-time the shared 2-core runner produces under CPU throttle.
Accessibility and mobile
The site targets WCAG 2.2 Level AA and is verified by an axe-core loop over every tile under both themes. The interaction contract: a single <h1> per view, a 48 px touch-target floor on every control (the per-tile example button and checkbox rows included), an aria-live output region, visible focus rings, full keyboard operation, and prefers-reduced-motion honored (entry animations are transform-only so text never composites at sub-full opacity). Every input carries a persistent accessible name (an aria-label or an associated <label>, never a placeholder alone), and every numeric input sets inputmode so phones raise the right keypad; a catalog-wide integration sweep (a11y.test.js) asserts both on every live tile, so an ad-hoc grid input that ships placeholder-only or without inputmode fails the build.
Keyboard cheat sheet
Press a leader key G, then a single letter within 1.5 s. ? opens an in-app overlay listing the same bindings (theme-aware, legible in both themes); Esc closes it.
Keys | Action | Keys | Action | |
| Home |
| Duct Sizing | |
| Focus search |
| Refrigerant P-T | |
| Unit Converter |
| Lumber Spans | |
| Ohm's Law |
| Concrete Volume | |
| Wire Ampacity |
| Static Pressure | |
| Voltage Drop |
| Toggle shortcut overlay | |
| Friction Loss |
| Close overlay |
In the search box, Up / Down move the result highlight, Enter opens it, Esc dismisses the dropdown. Shortcuts are suppressed while typing in any input, textarea, or select.
The mobile sweep guarantees zero page-level horizontal scroll at any viewport width >= 320 px on every view. The layout is single-column and fluid: every input and output is a full-width block that stacks vertically, so narrowing the viewport never forces a sideways scroll -- only a longer vertical one.
The responsive design model
Three overflow sources can push a page wider than the viewport. Each has a structural defense, so the guarantee holds by construction rather than by per-tile tuning:
Overflow source | Example | Defense |
A long unbreakable string | a |
|
A wide multi-column table | the 5-column loan-amortization / MACRS schedule (~440 px intrinsic) | the table lives in a |
A rigid intrinsic-width element | an SVG phasor diagram, a wide form row |
|
The table case is the subtle one. The CSS protects the wrapper class, not the table -- a <table> dropped into a bare <div> re-introduces the bug one tile at a time. A 2026-06-08 full-catalog audit (route to all live tile ids at 320 px, populate via the example button, assert no page-level scroll) caught exactly one such escapee, macrs-depreciation, whose schedule <div> had been built without the .tabular-tool class; adding the class fixed it. That one-off audit is now a standing CI gate -- the responsive-stress.test.js "every live tile view" case drives all 942 live tile views (input grid + populated example output) at the 320 px floor on every push, so a new tile that ships a bare-<div> table fails the build rather than escaping to production. Current run: 942 / 942 tiles clean.
flowchart TB
P[".view-region (page)\nno child exceeds the column → no page scroll"] --> OUT["output line\nflex, min-width: 0"]
P --> TBLW[".tabular-tool\noverflow-x: auto"]
OUT --> STR["long token\noverflow-wrap: anywhere → wraps"]
TBLW --> TBL["wide <table>\nscrolls INSIDE the wrapper"]
P --> SVG["media / SVG\nmax-width: 100% → never exceeds column"]
style TBLW fill:#14532d,color:#fff
style TBL fill:#1f1f1f,color:#fffVerified viewports. The sweep targets four widths -- 320 px (iPhone SE 1st gen, the floor), 375 px (modern SE / 12 mini), 414 px (Plus), and 760 px (the layout breakpoint) -- plus the 48 px touch-target floor, inputmode on every numeric field so the soft keyboard surfaces the right pad, and input-event compute (not change) so voice dictation updates the result without a trailing keystroke. A Playwright guard asserts documentElement.scrollWidth <= clientWidth + 1 at 320 px. Two layers run the assertion: the a11y.test.js block spot-checks the highest-risk routes (home, both wide-table tiles loan-amortization / macrs-depreciation, the longest reference list color-codes, and the longest-output finance tile rent-vs-buy), and the responsive-stress.test.js "every live tile view" case sweeps the full catalog -- all 942 live tile views, each with its example output populated -- so the guarantee holds for every tile, not just the representative sample. The interactive SPA is one surface; the prerendered static shells (/tools/<id>/, /groups/<slug>/) plus the SPA home are another, and npm run check:shell-mobile audits all 964 routes (942 tools + 21 groups + home) at 320 px (last run: 964/964 clean).
Because a single-viewport sweep covers only one of the three responsive axes, two standing gates extend the no-horizontal-scroll guarantee to the other two -- WCAG 1.4.4 resize text (200% text-only zoom, emulated by doubling the root font-size so every rem-based size grows the way Firefox text-zoom does) and landscape phones + tablet portraits (568x320, 667x375, 822, 834, and both sides of the 760 px breakpoint) -- each over the surface it can actually reach. The responsive-stress.test.js integration test drives the interactive SPA (the integration server serves the repo root, so it asserts a 2xx before measuring and never touches the prerendered shells, which live only in dist/). It carries three checks: the full-catalog 320 px portrait sweep (all 942 live tile views), the 200% text-zoom sweep over a diverse route sample, and the landscape/tablet-width sweep. The check:shell-mobile auditor serves dist/ and covers the prerendered shells on the same three axes (every shell at the 320 px floor; a representative tool sample plus every group hub and the home shell at landscape + text-zoom). (WCAG 1.4.10 reflow at 400% page zoom is already covered: it resolves to the 320 px viewport both gates test.) The whole sweep runs on two browser engines: Chromium drives the full integration suite, and WebKit (the iOS Safari engine, where flexbox min-width and sub-pixel rounding diverge from Chromium and where roughly half of US mobile traffic lives) re-runs responsive-stress via a dedicated webkit-responsive Playwright project, so the no-horizontal-scroll guarantee is CI-enforced on the engine behind every iOS browser, not just Chromium. See docs/accessibility.md and docs/mobile-responsive.md.
Safety guarantees
Read-only by default. No cookies, no sessionStorage, no IndexedDB. localStorage holds exactly one key (
rl-theme, value"dark"or"light"). No calculator inputs are persisted. The service-worker cache holds only same-origin static assets.No outbound network calls at runtime. CSP
connect-src 'self'is enforced at the browser and the Cloudflare edge, and thecheck-csplint gate (spec-v48) fails the build if either copy of the CSP drifts -- if the inline boot-script sha256 stops matching, or if any directive admits an external origin -- so the policy cannot silently weaken.All inputs are typed. No HTML rendering of user-supplied text.
Startup integrity check.
integrity.jsverifies each per-folder data manifest againstdata/integrity.json; a mismatch surfaces a non-blocking banner.Honest framing. An inline limitation notice on every calculator and a footer disclaimer state that the site is a math aid, not a code authority.
Limitations
The site is honest about what it is and is not.
It is not a code authority and does not interpret code requirements. The authority having jurisdiction governs all installations and inspections.
It does not reproduce any licensed code text or table. NEC, IPC, IRC, ASHRAE Fundamentals, ACCA Manual J, NFPA standards, and AWC span tables are not bundled. Where a first-principles calculator matches a code table for the same inputs, it is because both compute the same physics, not because the table was copied.
The Manual J cooling and heating estimators are simplified; a code-compliant load calculation requires full Manual J, and every Manual J view says so.
The site does not generate code-compliant designs. The user is the judgment.
Stability commitments
No A/B testing, ever. No user-visible feature flags. No tracking, no email capture, no notifications.
Public changelog at CHANGELOG.md (developer-facing in-repo; the public
/changelog.htmlpage was retired in the search-first home refactor).A 90-day deprecation notice for any tool removed or any formula changed.
Semantic versioning.
Determinism, not AI
roughlogic uses zero LLM and zero AI. Every output is the result of a deterministic function over user input and bundled data. There is no inference, no model, no probabilistic step. The same inputs produce the same outputs, every time, on any device, with or without a network connection.
Documentation
specs/ - the inheriting build specifications (
spec.mdthroughspec-v478.md); each carries an implementation-status banner.docs/architecture.md - runtime architecture and ASCII diagram.
docs/correctness.md - the spec-v14 correctness pass (corpus, cross-check, dimensions, bounds, stability, invariants, signoffs).
docs/data-sources.md - every dataset with source, license, cadence, and shard layout.
docs/derivations.md - first-principles derivation per calculator, plus the per-tile index.
docs/legal.md - legal posture, dataset attributions, first-principles approach.
docs/accessibility.md - WCAG 2.2 AA conformance checklist.
docs/mobile-responsive.md - the per-tile mobile sweep and no-horizontal-scroll guard.
docs/threat-model.md - threats and controls.
docs/performance.md - performance budget and enforcement.
docs/seo.md - prerendered shell model, authoring rules, JSON-LD allowlist.
docs/deployment.md - Cloudflare Pages configuration.
docs/launch-checklist.md - per-release launch gates and the live status snapshot.
docs/citation-discipline.md - per-tile source-stamp strings and edition table.
docs/citation-freshness-ledger.md - per-source edition / asOf ledger with a current / disclosed-lag / acknowledged-stale status (spec-v19 §3.3, spec-v22).
docs/hash-state.md - URL-hash grammar and back-compat policy.
docs/edition-rollover.md / docs/edition-amendment.md - code-edition runbooks.
docs/maintainer-quickstart.md / docs/contributor-checklist.md - maintenance and per-PR checklists.
docs/audit-trail.md - append-only record of external reviews.
CHANGELOG.md - public changelog.
License
MIT. See LICENSE.
This server cannot be installed
Maintenance
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/clay-good/roughlogic.com'
If you have feedback or need assistance with the MCP directory API, please join our Discord server