Independent correctness and usability audit of pcb-toolkit v0.1.5.
Date: 2026-09-14 · Toolchain: cargo/rustc 1.98.0 (x86_64-pc-windows-msvc)
Method: every calculator was driven through the CLI and compared against an
independent reimplementation of the published formula (written separately, in Python),
against the reference vectors in docs/notes/17-test-vectors.md, and against physical
invariants. Nothing in this report was taken from the library's own test suite.
The correctness defects below were fixed in a follow-up pass. All Critical, High and Medium findings are resolved; the deferred items were explicitly scoped out and are listed as such.
| ID | Finding | Status |
|---|---|---|
| C1 | microstrip Er_eff/Zo wrong | Resolved — rewritten as true Hammerstad-Jensen 1980 |
| C2 | pi-pad used the T-pad series formula | Resolved — Z·(K²−1)/(2K); tests + source table corrected |
| H1 | --freq silently ignored |
Resolved — Kirschning-Jansen dispersion implemented |
| H2 | stripline negative Zo | Resolved — rejected by a shared post-condition |
| H3 | coplanar Er_eff > Er | Resolved — bounded partial-capacitance form; Zo moved to the matching CBCPW form |
| M1 | formulas misattributed | Resolved — the implementation is now genuinely H-J |
| M2 | two disagreeing microstrip models | Resolved (narrowed) — divergence cut from 5.4% to 0.19%; differential deliberately keeps IPC-2141 (see below) |
| M3 | NaN / impossible Er_eff at high t/h | Resolved — H-J is well-behaved there, and the post-condition backstops it |
| — | embedded microstrip Zo discontinuity | Resolved (found while fixing; Zo now scales as 1/√Er_eff) |
| — | elliptic_ratio had no domain guard |
Resolved — clamped, and degenerate W/h rejected |
| — | thickness unvalidated in stripline/coplanar |
Resolved |
| M4 | STATUS.md overstates completeness | Deferred (doc accuracy, out of scope) |
| L5 | crosstalk diverges from Saturn | Resolved (2026-10-06) — Saturn decompiled; it is wrong by 48×. Docs re-framed, absolute + decomposition tests added |
| L1 | dead COPPER_MELTING_POINT_C holds gold's melting point |
Resolved (2026-10-08) — constant deleted; constants.rs rewritten, 13 constants down to 7 |
| L2 | §7 of the test-vector doc repeats the melting-point error | Resolved (2026-10-08) — corrected, with a note that the PDF prints the wrong figure |
| L3 | fusing reference vector is internally inconsistent | Won't fix — the reference is wrong (10 × 0.70 ≠ 18.79 sq.mils), so no assertion can be built from it. Recorded in the module docs instead |
| L4 | wire_gauge::area_saturn is unexplained public API |
Resolved (2026-10-08) — identified as ampacity at 700 circular mils/A, renamed ampacity_a, documented, and tested against the published current table |
| L6 | hygiene (dead toml dep, dead print_result branch, rustfmt, stale docs) |
Resolved (2026-10-08) — all five items |
Verification: 214 tests pass (up from 192), cargo clippy clean, and every microstrip
result was diffed against an independently written Python implementation of H-J and K-J
across 9 geometries including dispersion — agreement is exact to 0.00000000%.
differential::edge_coupled_external intentionally still uses IPC-2141. It is the one
module matching its reference vector exactly on all 8 outputs, so re-baselining it would
have discarded the repo's only end-to-end validation. The two models now agree to 0.19%.
A second remediation pass closed the findings the audit deferred — L1, L2, L4 and L6 — and re-examined the "Unverified" ratings, several of which were stale at the time they were written. L3 is deliberately left open: the fusing reference vector is self-inconsistent (it states a 10 mil × 0.70 mil trace with an 18.79 sq.mil cross-section, when that product is 7.0 and etching only removes copper), so there is nothing correct to assert against. The Onderdonk core is right; the vector is not. The baseline-health and per-module tables further down this document describe the repo as it was audited in September and are kept as the historical record; the two tables in this section are the current ones.
The goal also changed, which changes what "verified" can mean here. Saturn PCB Toolkit is
now treated as inspiration, not a specification — see CLAUDE.md — so a module whose only
former grading criterion was "matches Saturn" is graded against published literature and
physical invariants instead. crosstalk is the clearest case: it deliberately does not
match Saturn, because Saturn is wrong by 48×.
| Check | Result |
|---|---|
cargo test -p pcb-toolkit -p pcb-toolkit-cli |
330 passed, 0 failed, 1 ignored (306 library + 24 CLI) |
| Non-finite inputs | Rejected everywhere. A CLI sweep over every numeric argument of every command found 313 accepted spellings of nan/inf; CalcError::NotFinite closed all of them, and non_finite_numbers_are_rejected_everywhere keeps them closed |
cargo clippy --workspace --all-targets -- -D warnings |
Clean, including the Tauri crate |
cargo fmt --all -- --check |
Clean (was 103 diffs across 35 files) |
| CLI tests | 24, in crates/pcb-toolkit-cli/tests/cli.rs (was zero) |
| CI | None. The GitHub Actions workflows were removed on 2026-10-09; STATUS.md lists the commands to run by hand. tsc --noEmit and the Tauri crate's tests consequently have no automated coverage — see the note there |
RUSTDOCFLAGS=-D warnings cargo doc --no-deps --workspace --lib |
Clean. The --lib scope avoids a bin/lib output filename collision, since the CLI's bin target is pcb-toolkit and the library pcb_toolkit |
clippy.toml |
Exists, so disallowed_types is no longer inert — bans f32 and HashMap |
The one #[ignore] is differential::edge_coupled_internal_sym's second reference vector,
whose published Zeven is below its Zodd; the vector is internally inconsistent and the
ignore carries that reason inline.
The Tauri entry point carries a scoped #[allow(clippy::disallowed_types)] because
tauri::generate_context! expands to a HashMap; the ban still applies to the rest of that
crate.
Three gradings:
- Verified — at least one assertion against a value computed outside this codebase (a published reference vector, a standard table, or a closed form worked by hand).
- Verified (invariant) — no external vector exists, but the module is pinned by properties that cannot all hold for a wrong implementation (duality, matching conditions, monotonicity, continuity, dimensional reduction to a known case).
- Plausible — implements the cited published formula and is guarded, but nothing independent confirms the numbers.
| Module | Rating | Evidence |
|---|---|---|
impedance::microstrip |
Verified | True Hammerstad-Jensen 1980; diffed against an independent Python H-J/K-J across 9 geometries, exact |
impedance::stripline |
Verified | Downgraded to Plausible and then rewritten on 2026-10-08. It is now genuinely Cohn's two-branch model and asserts the SLINE worksheet's stored result (51.437079595 Ω) to 1e-9 — the module's first absolute assertion. The single-branch IPC-2141 form it replaced was within 0.04% near w/b ≈ 0.3 and −3.8% at w/b = 0.52 |
impedance::offset_stripline |
Verified | Asserts the SLINE2 worksheet's stored result (51.726315928 Ω) to 1e-9. That vector straddles both Cohn branches — Za at w/b = 0.52, Zb at 0.12 — so it pins the branch switch as well. Also asserted to reduce exactly to impedance::stripline when the two heights are equal |
wires::{round_wire, coax, twisted_pair} |
Verified | Twisted pair asserts the TWIST worksheet (101.3 Ω); coax is checked against the 50 Ω PTFE diameter ratio; all three have their derived Lo/Co cross-checked against the worksheets' independently published per-inch coefficients |
signal |
Verified (invariant) | Knee frequency and critical length are checked at the figures the source quotes, and critical length additionally by the property that defines it (flight time = Tr/rule) rather than by its own arithmetic. Γ, VSWR, return loss and mismatch loss are asserted to be recoverable from one another. er_from_delay is asserted to invert propagation_delay exactly |
reactance::reactance_to_edge |
Verified | Asserts the CAPAC worksheet's two figures (15.915 Ω, 62.832 Ω), and that both forms equal the sine-domain reactance at the knee frequency — which is what they are |
inductor::{circular_loop, rectangular_loop} |
Verified | Circular asserts both CIRCULAR worksheet vectors (100.325 nH at 10 mil wire, 53.628 nH at 100 mil); rectangular asserts the RECTANGL expression term by term, plus symmetry in its sides |
resistance |
Verified | Plane spreading resistance asserts the RESIST worksheet (0.91 mΩ), and the Ω·mil resistivity is asserted to be the SI constant converted rather than retyped |
impedance::coplanar |
Plausible | Bounded partial-capacitance form; no reference vector, and no dispersion model exists for CPW |
impedance::embedded |
Plausible | No reference vector; does now apply frequency (H1 resolved) |
differential::edge_coupled_external |
Verified | All 8 outputs match ref p11 to 5+ s.f. |
differential::edge_coupled_internal_{sym,asym} |
Plausible | Coupling coefficient corrected to the published 0.347 (Saturn transposes it to 0.374); denominator is the plane-to-plane span |
differential::edge_coupled_embedded |
Plausible | No reference vector |
differential::broadside_coupled |
Plausible | No reference vector; self-declared low confidence |
via |
Verified | saturn_page36_via_vector — C/L/Z/f_res to 5+ s.f. |
padstack::thru_hole |
Verified | saturn_page23_thru_hole_vector — 56/56/80 exact |
padstack::corner_to_corner |
Verified | 3-4-5 triangle, exact |
inductor |
Verified | saturn_page30_square — Mohan/Wheeler to 0.009% |
ppm |
Verified | Three reference vectors (Hz↔PPM, XTAL load) |
spacing |
Verified | saturn_page20_b1_vector, plus monotonicity in voltage, continuity across the 500 V extrapolation boundary, and imperial/metric agreement |
pdn |
Verified | Reference vector, a hand-computed case, Xc against the closed form, and the magic 0.225 pF/in tied back to ε₀ derived from MU_0 |
thermal |
Verified (invariant) | Hand-computed 25 + 2.5·40 = 125 °C = 257 °F, °F/°C tracking, and zero power ⇒ junction = ambient |
ohms_law (E-I-R, LED, R/C/L) |
Verified | Reference vectors, all exact |
ohms_law::{pi_pad, t_pad} |
Verified (invariant) | C2's bad source table is no longer trusted: both networks are analysed by hand for input match and voltage ratio, and asserted to be duals (T_series · Pi_shunt = Z²) |
reactance |
Verified | Matches the closed form; more precise than the reference's own f_res |
wavelength |
Verified | 59.015 vs ref 59.01426 (the residual is Saturn's c = 11.8 in/ns) |
wire_gauge |
Verified | AWG 4/0, 10, 22, 40 against standard tables |
materials |
Verified | 45 entries, Er correct on spot checks. roughness_factor deleted — it was a repo-local invention, not even a faithful copy of Saturn's fudge |
current |
Verified | IPC-2221A formula known; DC resistance and skin depth correct, the latter over two decades of frequency. IPC-2152 is desktop-only |
fusing |
Verified | Onderdonk; the trace-area path remains unvalidatable against any published vector |
crosstalk |
Verified (microstrip) | Absolute values plus a factor-by-factor decomposition, and a test asserting the exact 45.9317× ratio to Saturn's output so the divergence cannot drift silently (Saturn's two defects alone account for 48.014× of it; the remainder is an Er_eff modelling difference). Stripline mode not implemented |
constants |
Verified (invariant) | η₀ cross-checked via √(µ₀/ε₀); c in/ns asserted not to be the rounded 11.803. the file went from 13 constants to 7, the deletions all being genuinely unreferenced — among them a copper melting point of 1064.62 °C, which is gold's |
Two changes of rating are worth calling out explicitly, because the September table was already behind the code when it was written:
via,inductor,ppmandpadstackwere graded Unverified or absent, but each already asserted a reference vector from the Saturn help PDF.pdn,thermal,spacingand the attenuators were the ones that genuinely lacked independent checks. All four now have them.
What is still Plausible is where to be careful: coplanar, embedded, and four of the five differential topologies have no external vector, and none exists to find — the published sources give formulas, not worked examples.
Stripline is the exception, and it was graded wrong here first. This section originally
called it Verified "exact within validity", which no test in the module supports: its
assertions are all ranges and monotonicity. An external check does exist after all — the
Mathcad worksheets shipped with Johnson & Graham's High-Speed Digital Design carry stored
results for Cohn's centred stripline, and a transcription of them is on this machine at
gerbers2ems/hsddpy. Against that:
| geometry | w/b | pcb-toolkit | Cohn | diff |
|---|---|---|---|---|
| b=20 mil, w=6, t=1.37, Er=4.5 | 0.30 | 51.418 | 51.437 | −0.04% |
| b=64.5 mil, w=8, t=1.5, Er=4.5 | 0.12 | 77.981 | 77.629 | +0.45% |
| b=15.5 mil, w=8, t=1.5, Er=4.5 | 0.52 | 37.217 | 38.677 | −3.8% |
The module's own stated bound (W/(2H − T) < 0.35) was therefore honest, and the formula
was genuinely good inside it. The gap was that 50 Ω stripline on a thin core often lands at
w/b ≈ 0.3–0.5, right where the error starts to matter.
Resolved the same day. Cohn's model has two branches — a skinny-trace log form and a
wide-trace form selected at w > 0.35b — and only the skinny one had been implemented.
impedance::stripline now implements both, with the Canright-corrected K1 shape factor, and
asserts the worksheet's stored 51.437079595 Ω. Two side effects worth recording:
- The wide-trace branch has no logarithm of the geometry to drive negative, so finding H2's negative impedance is no longer possible — the test that used to assert a wide trace is rejected now asserts that it computes, and is physical.
impedance::offset_striplinebecame nearly free, since the offset case is the parallel combination2·Za·Zb/(Za + Zb)of two centred striplines taken about each plane in turn. It could not have been added correctly on the single-branch model: its reference geometry puts one half-line in each regime.
Everything from here down describes the state of the repo as audited, before the fixes. It is kept as the historical record and as the rationale for each change — see the Resolution status table above for what has since been fixed. Present-tense claims below refer to the pre-fix code, and the per-module confidence table likewise predates the repairs.
Usable: yes. Correct: mostly, with two calculators that return materially wrong numbers and three that return unphysical output outside their validity range.
The repo builds clean, has no unsafe, no stubs, no panics on the paths tested, and 192
tests that genuinely pass. Most calculators are right — several match their reference to
5+ significant figures. The CLI works, its help is accurate, and the README examples
reproduce exactly.
But the test suite does not establish correctness, and that gap is not cosmetic. The
flagship calculator — impedance::microstrip — is wrong by ~5% and no test detects it,
because its only impedance assertion is 20.0 < Zo < 80.0. A second defect
(ohms_law::pi_pad) is actively pinned in place by tests that assert the wrong value.
The headline "192 tests passing" in STATUS.md is accurate as a count and misleading as
a claim of validation.
| Count | Items | |
|---|---|---|
| Critical — silently returns wrong numbers for valid, ordinary input | 2 | C1 microstrip, C2 pi-pad |
| High — unphysical output or silently ignored input | 3 | H1 frequency, H2 stripline, H3 coplanar |
| Medium — correctness-adjacent, or misleading documentation | 4 | M1–M4 |
| Low / informational | 5 | L1–L5 |
| Check | Result |
|---|---|
cargo build --workspace |
Clean, zero warnings |
cargo test --workspace --all-targets |
192 passed, 0 failed (matches STATUS.md) |
cargo clippy --workspace --all-targets |
Clean, zero warnings |
cargo fmt --check |
Fails — 103 diffs across 35 files |
cargo doc --no-deps |
Builds; warns of bin/lib output filename collision |
| CLI tests | Zero. No tests/, no benches, no doc tests |
CI (.github/workflows/ci.yml) runs only build + test. It runs neither clippy nor
fmt --check, which is why 103 formatting diffs accumulated unnoticed. The workspace
declares [workspace.lints.clippy] disallowed_types = "deny" (Cargo.toml:25), but that
lint is inert without a clippy.toml listing the disallowed types, and none exists — the
lint configuration currently enforces nothing.
Ratings earned by independent recomputation, not by the presence of tests.
| Module | Rating | Evidence |
|---|---|---|
differential::edge_coupled_external |
Verified | All 8 outputs match ref p11 to 5+ s.f. |
via |
Verified | C/L/Z/f_res match ref p36 to 5+ s.f. |
pdn |
Verified | All 3 outputs match ref p28 exactly |
padstack::thru_hole |
Verified | 56/56/80 exact |
padstack::corner_to_corner |
Verified | √2·100 = 141.421 exact |
reactance |
Verified | Matches closed form; more precise than the doc's f_res |
wavelength |
Verified | 59.015 vs ref 59.01426 |
inductor |
Verified | Matches Mohan/Wheeler to 0.009%; the doc's value is the outlier |
spacing |
Verified | Matches IPC-2221 at 4 spot voltages exactly |
wire_gauge |
Verified | AWG 4/0, 10, 22, 40 match standard tables |
materials |
Verified | 45 entries; Er correct on spot checks |
ohms_law (E-I-R, LED, R/C/L, t-pad) |
Verified | All exact |
ohms_law::pi_pad |
WRONG | C2 — series arm uses the T-pad formula |
impedance::microstrip |
WRONG | C1 — Er_eff +5.8%, Zo −5.4% |
impedance::stripline |
Plausible / unguarded | Exact within validity; H2 negative Zo outside it |
impedance::coplanar |
Plausible / unguarded | H3 Er_eff exceeds Er at large gap |
impedance::embedded |
Unverified | No reference vector; H1 ignores frequency |
differential::* (other 4) |
Unverified | No reference vectors exist |
differential::broadside_coupled |
Unverified | Self-declared "confidence: LOW" |
current |
Partial | DC resistance & skin depth correct; IPC-2152 path unreachable from CLI |
fusing |
Partial | Onderdonk core correct; trace-area path unvalidatable (L3) |
crosstalk |
Verified (microstrip) | Divergence from Saturn fully accounted for; Saturn is wrong by 48× (L5, resolved). Stripline mode not implemented |
Files: impedance/common.rs (er_eff_static, effective_width), applied at microstrip.rs:42-46
The conductor-thickness correction is applied by widening the trace (we = w + Δw) and
feeding u = we/h into er_eff_static. But er_eff_static is monotonically increasing
in u, so finite thickness makes Er_eff go up. Physically it must go down: a
thicker conductor pushes more field into the air above the substrate.
Reference geometry (docs/notes/17-test-vectors.md §1 — W=17, H=10, T=2.10, Er=4.6):
| Quantity | pcb-toolkit | Independent Hammerstad-Jensen | Reference | Error |
|---|---|---|---|---|
| Er_eff | 3.4681 | 3.2772 | 3.2802 | +5.8% |
| Zo (Ω) | 49.1445 | 49.6744 | 50.7426 | −3.1% |
| Tpd (ps/in) | 157.7812 | 153.3784 | 153.4869 | +2.8% |
| Co (pF/in) | 3.2106 | 3.0877 | 3.0248 | +6.1% |
The direction of the error is confirmed by the zero-thickness case: independent HJ gives Er_eff 3.4323 at t=0 falling to 3.2772 at t=2.10, while pcb-toolkit rises from 3.4341 to 3.4681.
The library contradicts itself. For identical single-ended geometry (W=10, H=15, T=2.10, Er=4.6), two modules disagree:
impedance microstrip -> Zo = 73.4951 <-- outlier
differential (its internal Zo) -> Zo = 77.5036
reference (Saturn p11) -> Zo = 77.5040
independent Hammerstad-Jensen -> Zo = 77.6499
differential::edge_coupled_external computes single-ended Zo with the IPC-2141 formula
87/√(er+1.41)·ln(5.98h/(0.8w+t)) (edge_coupled_external.rs:47)
and agrees with all three references. impedance::microstrip uses a different model and
is the sole disagreeing value.
The README's own headline example is affected. impedance microstrip -w 10 --height 5 --er 4.6 is printed in all three READMEs as Zo = 44.3599, Er_eff = 3.5172. Independent
Hammerstad-Jensen for that geometry gives Zo = 44.8322, Er_eff = 3.3075 — the published
example is +6.3% on Er_eff. The example reproduces exactly, so the documentation is
faithful; the number it faithfully documents is wrong.
Failure scenario: a user sizing a 50 Ω trace on 10 mil FR-4 gets a width ~5% off. On a controlled-impedance board that is a real fabrication error, and it is the single most likely thing anyone uses this library for.
Why no test catches it: microstrip.rs has three tests — 20.0 < Zo < 80.0, "narrow
wide", and "negative width errors". Every value in the table above passes all three.
File: ohms_law.rs:325
let r_shunt_ohm = z_ohm * (k + 1.0) / (k - 1.0); // correct for Pi
let r_series_ohm = z_ohm * (k - 1.0) / (k + 1.0); // this is the T-pad series formulaThe Pi-pad series arm should be Z·(K²−1)/(2K). As written, pi_pad and t_pad return
identical series resistance at every attenuation:
| dB | pi_series (ours) | t_series (ours) | correct pi_series | error |
|---|---|---|---|---|
| 1 | 2.8751 | 2.8751 | 5.7692 | 2.0× |
| 6 | 16.6139 | 16.6139 | 37.3519 | 2.2× |
| 20 | 40.9091 | 40.9091 | 247.5000 | 6.0× |
Shunt values are correct for both topologies; only the Pi series arm is wrong.
Failure scenario: anyone building a Pi attenuator from this output gets the wrong series resistor — at 20 dB, 41 Ω instead of 248 Ω. The pad will not attenuate correctly and will not present the design impedance.
This one is worse than C1 in one respect: tests at
ohms_law.rs:413 and
:421 assert the wrong values (2.88, 25.97),
so the bug is locked in. Those expectations trace to the Pi-pad table in
docs/notes/17-test-vectors.md, whose series column is itself a duplicate of the T-pad
column — a bad source faithfully reproduced.
MicrostripInput::frequency is documented "Used for Kirschning-Jansen dispersion
correction" (microstrip.rs:19) but
is destructured away with .. at microstrip.rs:25
and never read. Output is bit-identical from 0 Hz to 50 GHz:
f=0 zo=49.144468 er_eff=3.468128
f=50GHz zo=49.144468 er_eff=3.468128
No dispersion code exists anywhere. KJ_DISPERSION_A/B (constants.rs:35,38) are
declared and never used. Yet common.rs:4 advertises "Kirschning-Jansen frequency
dispersion — used by all topology modules", and CLAUDE.md and STATUS.md both claim
"frequency-dependent Er_eff".
Failure scenario: a user computing impedance at 10 GHz silently gets the DC answer. Dispersion is precisely what matters at that frequency. The CLI accepts the flag, so there is no signal that it did nothing.
stripline correctly omits -f (homogeneous medium — genuinely non-dispersive).
The IPC-2141 formula is valid only for w/(b−t) < 0.35. There is no guard. Sweeping
width at h=20 mil, t=1.4 mil, Er=4.6 (validity limit ≈ 14 mil):
w=10 -> Zo = 59.4311 (valid, matches IPC-2141 to 0.008%)
w=14 -> Zo = 51.2347 (validity limit)
w=50 -> Zo = 17.9560 (well outside validity, no warning)
w=100 -> Zo = -0.9579 <-- negative
Failure scenario: a wide stripline (power distribution, low-impedance trace) silently returns a negative characteristic impedance, and negative Lo. Nothing errors.
Er_eff is a weighted average of the substrate Er and air, so 1 ≤ Er_eff ≤ Er always.
At w=10, h=10, Er=4.6:
gap=10 -> Er_eff = 3.6777 ok
gap=50 -> Er_eff = 5.0643 <-- exceeds Er = 4.6
gap=200 -> Er_eff = 6.4802 <-- exceeds Er = 4.6
Failure scenario: wide-gap CPW returns an impossible Er_eff, and every derived value (Tpd, Lo, Co) inherits the error.
M1 — Formulas are misattributed. impedance::microstrip is documented
"Hammerstad-Jensen 1980" in CLAUDE.md, STATUS.md, and its module header. It actually
implements the Wheeler/IPC-2141 closed form for Zo and the Schneider 1975
(1+12/u)^−0.5 approximation for Er_eff (common.rs:12-18).
Hammerstad-Jensen 1980 is the a(u)/b(εr) formulation, which appears nowhere. A reader
choosing this library for HJ accuracy gets a cruder model than advertised.
M2 — Two inconsistent microstrip models coexist. See C1. Whichever is correct, the library should not return two different answers for one physical structure.
M3 — microstrip produces NaN and impossible Er_eff at high t/h. At h=1 mil:
t=100 -> er_eff = 509.0669, zo = null (NaN serialized as JSON null)
t=500 -> er_eff = 36362.5008, zo = null
Er_eff must be ≤ 4.6. zo reaches consumers as JSON null, which will break
deserialization into f64. Validation bounds each dimension independently but never
their ratio. There is also a discontinuity at u = π/2 where effective_width switches
branches (Zo jumps 14.29 → 52.61 between t=5 and t=20).
M4 — STATUS.md overstates completeness. It marks every CLI command "Complete".
In fact: padstack exposes 2 of the 7 sub-calculators documented in
docs/notes/06-padstack.md; the entire IPC-2152 path (current::calculate_ipc2152,
~230 lines) has no CLI exposure; ohms_law::pi_pad/t_pad support only matched
impedances, not the unmatched case described in docs/notes/ghidra-ohmslaw.md; and the
45-material database is never consumed by any calculator or command.
L1 — Dead pub constant holds gold's melting point. ✅ RESOLVED (2026-10-08)
constants.rs:23 defines
COPPER_MELTING_POINT_C = 1064.62. Copper melts at 1084.62 °C; 1064.18 °C is gold.
The value is unused — fusing.rs correctly uses its own COPPER_MELTING_TEMP_C = 1084.62 —
but it is public API, so a downstream consumer can import the wrong constant and get a
~2% fusing-current error.
L2 — docs/notes/17-test-vectors.md §7 repeats the same error. ✅ RESOLVED (2026-10-08)
It quoted the melting temperature as 1064.62 where every other document in the repo says
1084.62. §7 now carries 1084.62 with a parenthetical noting that the source PDF prints the
wrong figure, so the discrepancy is recorded rather than silently flipped.
L3 — The fusing reference vector is internally inconsistent and cannot validate the
trace path. ⛔ WON'T FIX — the reference is the thing that is wrong. §7 states W=10 mil, thickness 0.70 mil, cross-section 18.79 sq.mils — but
10 × 0.70 = 7.0 sq.mils, and etching only reduces area. The stated area implies a ~26.8
mil trace. The library's own test sidesteps this by feeding area directly
(saturn_fusing_current_from_area), so it passes while fusing_current_trace disagrees
with the vector by 2.7× (1.304 A vs 3.515 A). The Onderdonk core itself is correct.
L4 — wire_gauge::area_saturn is an undocumented magic quantity. ✅ RESOLVED
(2026-10-08) It exported diameter_mils² / 700.0 with no units and no physical
interpretation, as public API.
The quantity was identified rather than deleted: 700 circular mils per ampere is the conservative power-transmission current rule, and dividing the circular-mil area by it reproduces the standard table at every gauge it is published for — AWG 10 → 14.83 A (published 15), 12 → 9.33 (9.3), 14 → 5.87 (5.9), 16 → 3.69 (3.7), 18 → 2.32 (2.3), 22 → 0.92 (0.92). So it is not an area at all; it is ampacity, and a useful output.
Renamed ampacity_a, the divisor named CIRCULAR_MILS_PER_AMPERE, documented including the
caveat that chassis wiring is rated several times higher, relabelled in the CLI and the
desktop schema, and pinned by
ampacity_matches_the_published_power_transmission_table, which asserts each row to within
half of its own last published digit.
L5 — crosstalk diverges from its reference, and that is correct. ✅ RESOLVED
(2026-10-06) Ours: −35.48 dB / 0.084 V. Saturn: −2.23327 dB / 3.86640 V.
This finding originally argued only from implausibility ("77% coupling from a 250 mil run").
Saturn's V8.47 handler has since been decompiled — it had never been analysed before
(PROGRESS.md:83 and NOTES.md:50 both record 0x004bde04 as unanalysed, so our formula
was never a reverse-engineering of Saturn in the first place). TForm12.Button1Click at
0x501780 thunks to 0x501888; the microstrip branch 0x501f05–0x501fb9 is:
er_eff = 0.475*Er + 0.67
t = 1.017 * sqrt(er_eff) // 1.017 is ns per FOOT
ratio = 2*t*L_inches / Trise_ns // clamped at 1.0
coeff = [1/(1 + (S/H)^2)] * ratio // no 1/4 factor
which reproduces Saturn's published vector to all six of its digits. The gap decomposes
exactly: 4.000000 (Saturn omits the 1/4 in the backward-coupling coefficient — the
solver contains no 0.25 and no 4) × 12.003651 (1.017 × 11.803: a per-foot constant
applied to a length converted to inches) × 0.956631 (√(2.855/3.119729), Saturn's
IPC-2141 Er_eff approximation vs our Hammerstad-Jensen) = 45.932276, the observed ratio.
The first two factors are Saturn's bugs and alone come to 48.015× (+33.63 dB).
Actions taken: crosstalk.rs's module docs rewritten (they previously blamed this crate and
carried a // - Match Saturn formula exactly TODO that would have introduced the bug);
absolute test reference_geometry_absolute added, plus
saturn_divergence_is_fully_accounted_for pinning the decomposition above; the §17 vector
had been transcribed in the docs and asserted nowhere. Also fixed in passing: the invented
trace_width_mils input (required by the CLI with no default, silently defaulted to 10 by
the desktop — two users got different dB for the same documented geometry) now has a single
crosstalk::DEFAULT_TRACE_WIDTH_MILS; the unguarded log10; and the kb / kb_db naming
collision with differential::*, which measure different quantities under the same names.
Still open: Saturn offers a stripline mode (branch 0x502794, two plane heights) that this
crate does not implement, and the output is now labelled microstrip to say so.
See docs/notes/18-v847-vs-rust-comparison.md §1.
L6 — Hygiene. ✅ RESOLVED (2026-10-08) All five items:
| Item | Fix |
|---|---|
Unused toml dependency in the CLI |
Removed from the CLI and the workspace manifest |
print_result's non-JSON branch dead (all 34 sites pass true) |
Function is now print_json with no flag; the commands' own titled-block output was always the real text path, and the dead branch would have printed a {:#?} struct dump |
| 103 rustfmt diffs | cargo fmt --all applied. fmt --check is in the manual check list in STATUS.md |
PROGRESS.md listed "Begin Rust implementation" as the next priority |
Replaced with a status note saying the implementation is done and the scope is closed |
NOTES.md's material table self-contradicting |
Er column marked superseded in place, pointing at materials-er-mapping.md, which is what materials.rs implements |
192 tests pass, but they are weighted toward assertions that cannot fail for a plausible
implementation: 159 assert! (largely range and monotonicity) against 122
assert_relative_eq!, and only ~14 tests named for a reference vector.
Three distinct problems, in descending order of importance:
- Absolute assertions sourced from a bad reference actively entrench bugs — C2 is the example. Worse than no test.
- Range assertions on the flagship path (
20.0 < Zo < 80.0) admit a 60 Ω window and cannot detect a 5% error. - Tests that avoid the disputed step —
saturn_fusing_current_from_areavalidates Onderdonk but skips the area derivation that actually disagrees (L3).
docs/notes/17-test-vectors.md contains 18 transcribed reference vectors; roughly half
are never asserted anywhere, including the microstrip vector that would have caught C1 on
day one. The tests/vectors/*.json store planned in
docs/notes/16-rust-design-research.md was never created.
Not executed — this audit made no code changes.
Priority 1 — wrong numbers
- Fix
pi_padseries arm toZ·(K²−1)/(2K); correct the tests atohms_law.rs:413,421and the Pi-pad table in17-test-vectors.md(C2). Smallest fix, unambiguous, highest confidence. - Fix the microstrip thickness correction so Er_eff decreases with thickness (C1).
Decide deliberately whether the target is true Hammerstad-Jensen or the IPC-2141 model
already used by
edge_coupled_external— then use one model library-wide (M1, M2). - Wire the microstrip vector (§1) into a test as an absolute assertion. It is already transcribed and would have caught C1.
Priority 2 — unphysical output
4. Implement Kirschning-Jansen dispersion, or remove --freq and the claims in
CLAUDE.md / STATUS.md / common.rs:4 (H1). Silently ignoring an input is the worst of
the three options.
5. Add validity guards: stripline w/(b−t) < 0.35 (H2), coplanar Er_eff ≤ Er (H3),
microstrip t/h bound (M3). Return CalcError::OutOfRange rather than a wrong number.
6. Add a debug assertion on the universal invariant 1 ≤ Er_eff ≤ Er in every impedance
path — it alone would have caught H3 and M3.
Priority 3 — trust
7. Convert the remaining vectors in 17-test-vectors.md into absolute assertions;
mark unvalidatable ones #[ignore] with a reason rather than substituting a range check.
8. Correct STATUS.md's "Complete" markers (M4); delete or fix COPPER_MELTING_POINT_C
(L1) done; document or remove done;
area_saturn (L4)re-frame the crosstalk note (L5) done.
9. Add — superseded: both run, but by hand; the CI
workflows were removed on 2026-10-09 (see the Current state table).
clippy + fmt --check to CIEither populate done.
clippy.toml or drop the inert disallowed_types lintAdd CLI integration tests done — 24 of them.
cargo build --workspace && cargo test --workspace --all-targetsEvery numeric claim above comes from driving target/debug/pcb-toolkit with --json at
the stated inputs, compared against an independent Python implementation of the published
formula. Key reproductions:
pcb-toolkit --json impedance microstrip -w 17 --height 10 -t 2.10 --er 4.6 -f 500MHz
pcb-toolkit --json ohms-law pi-pad --attenuation 20 --impedance 50
pcb-toolkit --json ohms-law t-pad --attenuation 20 --impedance 50
pcb-toolkit --json impedance stripline -w 100 --height 20 -t 1.4 --er 4.6
pcb-toolkit --json impedance coplanar -w 10 -g 200 --height 10 --er 4.6
pcb-toolkit --json impedance microstrip -w 10 --height 1 -t 500 --er 4.6