← ForgeCalc

Changelog

every correction, with a number you can reproduce · newest first

v2026.07b — Accessibility & Shareability Release (10 changes)

Screen-reader and keyboard support, shareable calculation links, home search, cross-page navigation, and high-DPI plots. No formulas changed in this release.

site/home — All 26 calculators — programmatic labels (WCAG 1.3.1/4.1.2)High

Error: ~578 inputs and selects had visually adjacent but programmatically unassociated labels — screen readers announced unlabeled spinbuttons.

Fix: Every static

Worked example: thermal/ R-ladder: 'spinbutton' → 'resistance value, kelvin per watt, spinbutton'.

Reference: WCAG 2.2 SC 1.3.1, 4.1.2

site/home — All calculators — live result regions (WCAG 4.1.3)High

Error: Results updated via innerHTML swaps that screen readers never announced.

Fix: 137 result containers now carry aria-live="polite".

Reference: WCAG 2.2 SC 4.1.3

site/home — All plots — canvas text alternatives (WCAG 1.1.1)High

Error: All 28 canvases were bare elements with no accessible name.

Fix: Each canvas now has role="img" and a descriptive aria-label (e.g. 'Nozzle contour with Mach, pressure and temperature distributions').

Reference: WCAG 2.2 SC 1.1.1

site/home — Row controls — target size (WCAG 2.5.8)Medium

Error: Delete '×' and direction-flip cells were ~15–21 px targets.

Fix: td.del/td.dirbtn now enforce ≥24×24 CSS px on the five pages with editable tables.

Reference: WCAG 2.2 SC 2.5.8

site/home — Unit & mode toggles — state exposureMedium

Error: mm/inch (and rotor thrust/mass) toggle buttons exposed no pressed state.

Fix: aria-pressed added to the markup and kept in sync by setUnit()/setMode() on 11 pages.

Reference: WAI-ARIA button pattern

/assets/ — Shareable calculation links (/assets/forge-ui.js)High

Error: No way to link, bookmark or cite a calculation — every visit started from defaults.

Fix: URL-state permalinks: a '🔗 Copy link' header button serializes every changed input/select to #in=id:value;… and loading such a link restores the values and recomputes via native input events (page code untouched). Known limit: dynamically added table rows (stack-up contributors, PSD breakpoints, R-ladder rows) are not yet serialized.

Worked example: thermal/#in=fa_cfm:40 reopens forced-air cooling with 40 CFM → ṁ = 22.66 g/s. Locked by self-tests on vacuum, thermal, gdt.

site/home — Home — search / filterMedium

Error: 26 cards with no findability — a user looking for 'Paschen' had no way to know it lives in Vacuum.

Fix: Filter box above the grid matching card text plus curated per-card keywords (data-kw), e.g. 'paschen', 'buckling', 'grms', 'geneva', 'die per wafer'.

Worked example: Typing 'paschen' leaves exactly one card visible (Vacuum System Designer).

/assets/ — Cross-page jump navigation (/assets/forge-ui.js)Medium

Error: The only navigation from a calculator was '← ForgeCalc' back to home.

Fix: A compact 'Jump to…' select (styled to match the header) is injected on every calculator page, listing all 26 tools.

/assets/ — High-DPI plots (/assets/canvas-dpr.js)Medium

Error: Canvases rendered at fixed 640-px backing stores — blurry on retina/high-DPI displays (the audit's top visual-quality finding).

Fix: A transparent getContext wrapper scales every 2D backing store by devicePixelRatio (≤3×) while keeping the page's logical coordinate space, so all 28 plots stay pixel-identical in layout but render sharp. Draw code untouched. Note: backing resolution is set at load; window resizes still display via CSS scaling, now from a 2–3× sharper buffer.

Worked example: On a 2× display the PSD editor renders from a 1280×640 buffer instead of 640×320.

site/home — Site — version bumpLow

Error:

Fix: Footers bumped v2026.07 → v2026.07b; roadmap statuses updated (items 19, 20, 23, 26 shipped; embed/PDF export explicitly reserved for the monetization phase).

v2026.07 — Correctness Release (57 changes)

A full independent audit of every calculator (formulas recomputed from first principles) found the defects below. All are fixed in this release. Each entry shows the error, the fix, and a before → after number you can reproduce on the page.

vacuum/ — Paschen Breakdown (air)Critical

Error: Townsend constants were 10× too high (A=112.5, B=2737.5 per Pa·m) — a cm→m conversion applied without the Torr→Pa division. Breakdown voltage was overestimated ~3–7× away from the curve minimum (non-conservative for HV design).

Fix: A = 11.25 (Pa·m)⁻¹, B = 273.8 V/(Pa·m) — the standard air values A=15 (cm·Torr)⁻¹, B=365 V/(cm·Torr) converted correctly.

Worked example: p·d = 10 Pa·m: V_b 4,981 V → 857 V. p·d = 1 Pa·m: 857 V → 307 V. Curve minimum ≈305 V now sits at p·d ≈ 1.1 Pa·m (literature: ~0.7–1 Pa·m), not 0.11.

Reference: Townsend/Paschen air coefficients (A=15 /cm·Torr, B=365 V/cm·Torr, γ≈0.01)

vacuum/ — Conductance & Pumping Network — orificeHigh

Error: Orifice conductance used C = 11.6·D², i.e. 11.6 L/(s·cm²) applied to D² instead of the area — the π/4 was missing, making every network with an orifice ~27% optimistic.

Fix: C = 11.6·A = 11.6·(π/4)·D² ≈ 9.11·D² (D in cm, air 20 °C, molecular flow).

Worked example: 63 mm orifice: 460 L/s → 362 L/s.

Reference: Molecular-flow aperture conductance, C = 11.6·A[cm²] L/s (air, 20 °C)

structural/ — Flat Plate DeflectionCritical

Error: The boundary-condition coefficients were beam/strip values, not plate values: 'SS square C≈76.8' is the simply-supported strip constant (384/5); 'Clamped square C≈220' likewise. Deflection was over-predicted 3.2–3.6×.

Fix: SS square C = 246 (α = 0.00406), clamped square C = 794 (α = 0.00126) in δ = q·a⁴/(D·C).

Worked example: Defaults (E=70 GPa, t=3 mm, ν=0.33, a=200 mm, q=20 kPa, SS): δ 2.357 mm → 0.735 mm.

Reference: Timoshenko & Woinowsky-Krieger, Theory of Plates and Shells, Table 8

mechanisms/ — Geneva DriveHigh

Error: Motion/dwell used motion = 720/n — the wrong geometry, coincidentally correct only at n=6. A 4-slot Geneva read 180°/180°.

Fix: External-Geneva geometry: β = 90°−180°/n; crank motion during indexing = 2β = 180°−360°/n; dwell = 180°+360°/n. Added center distance = R/sin(180°/n) with a crank-radius input.

Worked example: n=4: motion/dwell 180°/180° → 90°/270°. n=6: 120°/240° (unchanged — the one coincidence). Center distance (n=4, R=25 mm) = 35.36 mm.

Reference: Standard external Geneva kinematics

vibration/ — Narrow-Band Fatigue LifeHigh

Error: Time-to-exceedance used the Gaussian fraction-of-time P(|x|>nσ) as if it were a crossing rate — 2–5× optimistic (non-conservative): at fₙ=300 Hz, 3σ it gave 1.23 s.

Fix: Rice narrow-band upcrossing rate ν = fₙ·e^(−n²/2); T = 1/ν. Card relabeled 'mean rate of upcrossings of ±nσ'.

Worked example: fₙ=300 Hz, 3σ: T 1.23 s → 0.30 s (ν=3.33 s⁻¹, e^(−4.5)=0.0111). 4σ: 52.6 s → 9.9 s.

Reference: Rice (1954) narrow-band crossing statistics

vibration/ — SRS Estimate & Qual MarginHigh

Error: The qual uplift multiplied Grms by √2 but labeled it '+6 dB'. ×√2 Grms = +3 dB (PSD ×2); a true +6 dB qual is ×2 Grms / ×4 PSD. A user could under-test by 3 dB.

Fix: Existing line relabeled '+3 dB, ×√2 (PSD ×2)'; added an explicit '+6 dB, ×2 Grms (PSD ×4)' output.

Worked example: Acceptance 6.1 Grms: +3 dB → 8.6 Grms (PSD ×2); +6 dB → 12.2 Grms (PSD ×4).

Reference: SMC-S-016 / NASA GEVS qualification-margin practice

vibration/ — Natural Frequency Library — unit toggleMed-High

Error: Toggling mm↔inch re-rendered the card from its default template, silently discarding user inputs and reinterpreting the defaults in the new unit (L=50 mm became L=50 in).

Fix: Fields now convert in place with the correct power of 25.4 (lengths ×f, area ×f², I ×f⁴); user values survive the toggle.

Worked example: Cantilever L=50 mm, I=100 mm⁴ toggled to inch now reads L=1.9685 in, I=0.000240 in⁴ — same physical fₙ.

cte/ — Stoney Thin-Film StressHigh

Error: Curvature used the film's (1−ν_f) where Stoney's relation needs the substrate's (1−ν_s); κ and wafer bow read ~28% high for Si.

Fix: κ = 6·E_f·h_f·Δα·ΔT·(1−ν_s)/(E_s·h_s²·(1−ν_f)) — i.e. κ = 6σ_f·h_f(1−ν_s)/(E_s·h_s²) with σ_f = [E_f/(1−ν_f)]·Δα·ΔT. New ν_s input (default 0.22, Si).

Worked example: Defaults: κ 0.0143 → 0.0112 m⁻¹; wafer bow 40.3 → 31.5 µm.

Reference: Stoney (1909); standard thin-film form with substrate biaxial modulus

cte/ — Solder Joint Shear Strain & Coffin-MansonMed-High

Error: Shear strain used γ = Δα·ΔT·D/(2h) while labeling D as the distance to neutral point — strain 2× low, predicted life ~3.7× optimistic at k=1.9.

Fix: Engelmaier DNP convention: γ = Δα·ΔT·D/h. C default changed from 1.0 to 0.2 and tagged 'illustrative' (calibrate to test data).

Worked example: Defaults (Δα=14.4 ppm/K, ΔT=165 K, D=15 mm, h=0.3 mm): γ 5.94% → 11.88%; N_f (C=1) 214 → 57. With the new illustrative C=0.2: N_f ≈ 11.

Reference: Engelmaier solder-joint fatigue model

gdt/ — ① True Position + ② Bonus / Virtual ConditionHigh

Error: Bonus tolerance used |actual − MMC|, which granted bonus to size-nonconforming features (a ⌀10.00-MMC hole measured 9.95 got 0.05 bonus), and Module ①'s Feature-type select was read but never used.

Fix: Directional bonus (internal: max(0, actual−MMC); external: max(0, MMC−actual); mirrored for LMC), hard 'OUT OF SIZE LIMITS — no bonus' flag when actual is outside [MMC, LMC], and the feature-type select is now wired into both modules.

Worked example: Internal ⌀10.00 MMC / 10.10 LMC, actual 9.95: bonus 0.0500 → 0.0000 + size-fail flag.

Reference: ASME Y14.5-2018 material-condition modifiers

pcb/ — Microstrip / Stripline — propagation delayMed-High

Error: Delay was computed in ps/mm but printed as 'ps/cm' — read 10× low.

Fix: Constant 3.335 → 33.35 so the ps/cm label is correct.

Worked example: εr_eff = 3.0: displayed 5.8 → 57.8 ps/cm.

pcb/ — Critical Length & ReflectionMed-High

Error: The page defines 'transmission line if t_r < 2·t_prop' (⇒ l_crit = v·t_r/2) but the code computed v·t_r/4 — self-contradictory (conservative by 2×).

Fix: Code now matches its own definition: l_crit = v·t_r/2.

Worked example: t_r=1 ns, εr=4 (v=1.5×10⁸ m/s): 37.5 mm → 75.0 mm.

thermal/ — TIM & Thermal Via Array — unit toggleMed-High

Error: Toggling mm↔inch flipped the TIM area label to in² without converting the value or re-running the card — stale output, and the next edit reinterpreted the number as in² (645× area error).

Fix: tim_A is now converted (×/÷ 25.4²) with the other fields and tim() re-runs on toggle.

Worked example: A=100 mm² toggled to inch now reads 0.1550 in² and R_TIM is unchanged (0.217 K/W at defaults).

sealing/ — Groove cross-section canvasMed-High

Error: Canvas dimension annotations hardcoded 'mm' even with the inch toggle active.

Fix: Annotations now print the value converted to the active unit.

Worked example: w = 2.62 mm displays as w = 0.1032 in when toggled.

tolerances/ — Methods — BenderizedMedium

Error: 'Benderized' computed 1.5·t_max + RSS(others) — a hybrid that is not Bender's published method.

Fix: True Bender: T = 1.5·√(Σtᵢ²).

Worked example: Default 5-contributor loop: ±0.0447 → ±0.0402 (RSS ±0.0268, WC ±0.0570).

Reference: Bender (1962), 'Statistical Tolerancing as it Relates to Quality Control and the Designer'

tolerances/ — Monte CarloMedium

Error: MC sampled σ = tol/3 regardless of each row's Cpk, so the histogram silently disagreed with the Cpk-corrected column.

Fix: MC now samples σᵢ = tolᵢ/(3·Cpkᵢ).

Worked example: With all Cpk=1.33 the MC yield now exceeds the plain-RSS yield, consistent with the Cpk column.

tolerances/ — Results — yield pillsLow

Error: Defect rate (dppm) was computed but never displayed.

Fix: Each statistical method's pill now shows yield % · dppm.

Worked example: RSS at defaults: '99.92%' → '99.92% · 796 ppm'.

tolerances/ — Method notes — Cpk wordingLow

Error: Note claimed the Cpk correction 'accounts for off-center processes' — the math is a symmetric spread inflation.

Fix: Reworded: 'widens the effective spread for low-capability processes (symmetric approximation; a true mean shift is not modeled).'

tolerances/ — Contributor tableLow

Error: Feature names were interpolated raw into innerHTML; typing a double-quote broke the row.

Fix: Names are HTML-escaped on render.

Worked example: Name `6" boss` no longer breaks the table.

structural/ — Euler BucklingMedium

Error: I was always b·h³/12; a column entered with b

Fix: I = min(b·h³, h·b³)/12 — weak-axis buckling.

Worked example: b=10, h=20 mm: I 6,667 → 1,667 mm⁴ (P_cr ÷4).

Reference: Euler column buckling, weak-axis governs

structural/ — Pressure Vessel — Hoop StressLow

Error: No thin-wall validity check.

Fix: Warning shown when r/t < 10.

Worked example: r=15 mm, t=3 mm (r/t=5) now flags 'thin-wall assumption violated'.

cycles/ — Carnot Limit / COPMedium

Error: T_L ≥ T_H produced negative efficiency or raw Infinity COP with no comment.

Fix: Guard: both cards now require T_H > T_L (absolute) and say so instead of printing nonsense.

Worked example: T_H=20 °C, T_L=40 °C: '−6.8%' → 'requires T_H > T_L'.

cycles/ — Refrigerator / Heat Pump COPLow

Error: One '2nd-law efficiency' scalar applied to both modes without comment.

Fix: Label now notes η_II differs by mode.

thermoelectric/ — All cardsLow

Error: R=0 or K=0 produced Infinity in I_opt/Z/P_max paths.

Fix: Explicit R>0 / K>0 guards with a message.

thermoelectric/ — Formula referenceLow

Error: The thermal suite's TEC card implements the same model with no cross-reference — a future divergence risk.

Fix: Added a cross-link to the Thermal Management Suite TEC card.

nozzle/ — De Laval Designer — defaultsMedium

Error: Defaults mixed air properties (γ=1.4, R=287) with a 3,200 K / 50 bar rocket chamber — a plausible-looking but incoherent rocket (Isp≈170 s).

Fix: Defaults now use the rocket-gas preset (γ=1.2, R=380), select preselected.

Worked example: Defaults: M_e 5.00 → 3.91, V_e 2,315 → 2,971 m/s, F 16.9 → 18.9 kN, Isp 170 → 232 s.

nozzle/ — De Laval Designer — regimeMedium

Error: Severely over-expanded flow (where the quasi-1-D thrust equation is invalid) was labeled the same as mild over-expansion.

Fix: When p_e < 0.35·p_a the regime pill now reads 'flow separation likely (Summerfield); thrust model invalid'.

Worked example: Defaults at sea level: p_e/p_a = 0.19 → separation warning shown.

Reference: Summerfield separation criterion (p_e ≲ 0.25–0.4·p_a)

nozzle/ — InputsLow

Error: γ ≤ 1 cascaded into NaN.

Fix: γ > 1 validation on the designer and thrust-sizing cards.

rotor/ — Hover calculatorLow

Error: r ≤ 0 or ρ ≤ 0 produced Infinity.

Fix: Explicit guard with message.

aero/ — Flow Parameters — water presetMedium

Error: The water preset ran Mach and Knudsen through gas formulas (a=√(γRT) → Mach vs 343 m/s instead of ~1,480; λ meaningless for liquids).

Fix: Liquid presets suppress Mach/Knudsen with an explanatory note.

Worked example: Water, v=3 m/s: 'Ma 0.009 incompressible' → '— (liquid: a=√(γRT) is gas-only)'.

aero/ — Wing Lift & DragLow

Error: Stall warning keyed on α>15° only.

Fix: Also flags C_L > 1.4.

rf/ — Antenna Gain ↔ ApertureLow

Error: HPBW ≈ 57.3·λ/D shown without qualification (real feeds run 65–70·λ/D).

Fix: Relabeled 'uniform-aperture ideal'.

rf/ — Phased ArrayLow

Error: Grating-lobe pill triggered at d>λ/2 without saying that is the endfire worst case.

Fix: Pill relabeled 'risk (d>λ/2 — endfire worst case)'.

rf/ — Link BudgetLow

Error: No polarization or pointing loss line items.

Fix: Two optional dB inputs added (default 0), included in P_r, waterfall and range sweep.

Worked example: 3 dB polarization loss drops the default link margin 17.0 → 14.0 dB.

magnetics/ — Field cardLow

Error: B²/2μ₀ labeled 'MPa' in one card and 'MJ/m³' in another (same number).

Fix: Unified: 'MJ/m³ (≡ MPa)'.

magnetics/ — Larmor / CyclotronLow

Error: Non-relativistic formulas with no validity note.

Fix: Card notes 'Non-relativistic (valid v ≲ 0.1c)'.

optics/ — Thin LensMedium

Error: Sign convention (1/s' = 1/f + 1/s with negative real-object distances) was unlabeled — typing +100 silently gave a virtual-image answer.

Fix: Label now reads 's < 0 = real object (Cartesian)'.

optics/ — FMCW / LiDARMedium

Error: Chirp slope labeled 'THz/ms' — 1,000× off as labeled (the computed number was already in MHz/µs).

Fix: Relabeled MHz/µs.

Worked example: B=4 GHz, T=10 µs: '400 THz/ms' → '400 MHz/µs' (=0.4 THz/ms).

fab/ — Deal-Grove OxidationLow

Error: Silicon consumed used 0.46·x_ox.

Fix: 0.44·x_ox (N_ox/N_Si = 2.25×10²²/5.0×10²²).

Worked example: x_ox=0.4633 µm: Si consumed 0.2131 → 0.2039 µm.

Reference: Deal & Grove (1965); standard 44% consumption ratio

devices/ — p-n JunctionMedium

Error: n_i was fixed at 10¹⁰ cm⁻³ while T was an input, so V_bi rose with temperature instead of falling ~2 mV/K.

Fix: n_i(T) = 5.29×10¹⁹·(T/300)^2.54·e^(−6726/T) (Si).

Worked example: Na=Nd=10¹⁷, T=300 K: V_bi = 0.835 V; T=350 K: 0.758 V (falls, as physics requires — previously it rose).

Reference: Standard Si n_i(T) empirical fit

devices/ — Interconnect RCLow

Error: Only the lumped 0.69RC delay was shown; on-chip distributed lines follow ~0.38RC.

Fix: Added a 'Distributed line (0.38RC)' output.

radiation/ — Attenuation & ShieldingMedium

Error: μ presets are 1 MeV values but nothing near the result said so — using them at other energies is wrong by up to an order of magnitude.

Fix: Validity line added to the result block: 'μ presets are 1 MeV values — μ varies strongly with energy'.

Reference: NIST XCOM attenuation data (energy-dependent)

radiation/ — Decay cardLow

Error: Elapsed time was forced to use the half-life's unit selector.

Fix: Elapsed time now has its own unit selector (dk_ut).

Worked example: HL = 5.27 yr (Co-60), t = 5.27 d → activity 99.81 GBq (was only expressible in years).

mechanisms/ — Four-Bar GrashofLow

Error: Loop-closure test contained an always-true first clause (L₀ < s+l+p+q).

Fix: Clause removed; the real check (2·max < Σ) remains.

thermal/ — Fin PerformanceLow

Error: Description said η = tanh(mL)/mL while the code (correctly) uses the corrected length L_c = L + t/2.

Fix: Text now states η = tanh(mL_c)/mL_c, L_c = L + t/2.

Reference: Incropera, corrected fin length

thermal/ — Dimensionless GroupsLow

Error: β's film-temperature reference (20 °C + ΔT/2) and Bi's use of L as the conduction length were silent assumptions.

Fix: Both stated in the formula reference.

thermal/ — R-ladder tableLow

Error: Row names interpolated raw into innerHTML; a double-quote broke the row.

Fix: Names HTML-escaped on render.

thermal/ — Constants (g₀)Medium

Error: g varied across the site: 9.81 in thermal (Grashof), vibration (shock), sealing (hydrostatic), nozzle (Isp) vs 9.80665 in rotor.

Fix: All five pages now use FORGE.G0 = 9.80665 from the new shared /assets/constants.js (with a documented rounding policy).

Worked example: Nozzle Isp = F/(ṁ·9.80665); ≤0.1% shifts elsewhere.

Reference: ISO 80000-3 standard gravity (exact)

site/home — Home page — vault/live reconciliationMedium

Error: The vault (deploy source) home page had diverged from the live site — it was missing the Aerodynamics, Rotor & Propeller and GD&T cards, still carried tier groupings and 'SOON' placeholders, and the file itself was truncated mid-footer.

Fix: Vault index.html rebuilt to match the live 26-card discipline-grouped layout (existing CSS preserved byte-for-byte). The repo is the single source of truth again — no more hand-edits to the deployed site.

Worked example: Card count in the deploy source: 21 (truncated) → 26; live layout order preserved.

site/home — Home page — typos & titleMedium

Error: Footer said 'Accesible'; the GD&T card said 'Vitrual Conditions'; the was just 'ForgeCalc'.</p> <p><b>Fix:</b> 'Accessible', 'Virtual', and <title> 'ForgeCalc — Free Engineering Calculators'.</p> </div> <div class="entry"> <div class="where"><a href='/'>site/home</a> — Home page — orphaned calculators<span class="pill warn">Medium</span></div> <p><b>Error:</b> Acoustics & Ultrasonics and Corrosion & Cathodic Protection were live but linked from nowhere (invisible to users and crawlers).</p> <p><b>Fix:</b> Both now have home-page cards in matching markup (Acoustics after DSP; Corrosion after Structural).</p> <p><b>Worked example:</b> Linked calculators: 24 → 26.</p> </div> <div class="entry"> <div class="where">/assets/ — Shared constants (/assets/constants.js)<span class="pill warn">Medium</span></div> <p><b>Error:</b> Physical constants were per-page literals and drifted (g₀ 9.81 vs 9.80665).</p> <p><b>Fix:</b> New static /assets/constants.js (no build step) with FORGE.G0 = 9.80665 and a documented rounding policy; included by thermal, vibration, sealing, nozzle, rotor.</p> <p><b>Reference:</b> ISO 80000-3</p> </div> <div class="entry"> <div class="where">/assets/ — Self-test harness (/assets/selftest.js)<span class="pill bad">High</span></div> <p><b>Error:</b> No regression protection existed — the class of every defect in this release could silently recur.</p> <p><b>Fix:</b> Each corrected page now carries a TESTS array of golden cases (seeded from the audit's worked numbers) and paints a pass/fail banner when opened with ?selftest. 21 pages, 40 golden cases.</p> <p><b>Worked example:</b> e.g. /vacuum/?selftest asserts V_b(10 Pa·m)=857 V and C_orifice(63 mm)=361.6 L/s.</p> </div> <div class="entry"> <div class="where">/changelog/ — New page + version tag<span class="pill warn">Medium</span></div> <p><b>Error:</b> No changelog or visible version existed; corrections would ship silently.</p> <p><b>Fix:</b> New /changelog/ page (this one) mirrored to the vault as CHANGELOG.md; v2026.07 tag and Changelog/Roadmap links added to every page footer.</p> </div> <div class="entry"> <div class="where">/roadmap/ — New page<span class="pill warn">Medium</span></div> <p><b>Error:</b> No public status board for shipped vs planned work.</p> <p><b>Fix:</b> New /roadmap/ page from the audit's §12 master table (shipped / next up / under consideration), mirrored as ROADMAP.md.</p> </div> <div class="entry"> <div class="where"><a href='/'>site/home</a> — SEO/discoverability heads (all pages)<span class="pill bad">High</span></div> <p><b>Error:</b> 0 of 29 pages had a meta description, Open Graph/Twitter tags, or a canonical URL; no sitemap.xml or robots.txt existed. Shared links rendered as bare URLs and crawl coverage was luck-based.</p> <p><b>Fix:</b> Per-page meta description (from each page's own subtitle), og:*/twitter tags, canonical link on all 28 content pages + home; sitemap.xml (30 URLs) and robots.txt at the root. No visible layout change.</p> </div> <div class="entry"> <div class="where"><a href='/pcb/'>pcb/</a> — Microstrip / Stripline Impedance<span class="pill warn">Medium</span></div> <p><b>Error:</b> The Z₀ formula was labeled 'Hammerstad' but is the IPC-D-317A closed form (87/√(εr+1.41)·ln(5.98h/(0.8w+t))), which degrades outside 0.1<w/h<2.</p> <p><b>Fix:</b> Relabeled 'IPC-D-317A microstrip (best 0.1<w/h<2, εr≈4–5)' with the validity window stated.</p> <p><b>Reference:</b> IPC-D-317A; Hammerstad-Jensen is a different, more accurate model</p> </div> </div> </div> <footer> v2026.07b · <a href='/changelog/'>Changelog</a> · <a href='/roadmap/'>Roadmap</a> · <a href='/submit/'>Submit an idea</a> </footer> </body> </html>