ADR-013 — Pure-stdlib Python, reaffirmed on corrected evidence

  • Status: Accepted

  • Date: 2026-08-29

  • Supersedes: ADR-001

  • Deciders: stakeholder, implementer

Context

ADR-001 chose pure-stdlib Python but justified it with two claims that were never measured. Challenged on the point — hand-rolling a standard file format is a custom API and a novel bug surface for a solved problem — the claims were tested directly against the live Fusion 2704.1.53 install. Both were wrong.

What was measured

Vendoring numpy works. numpy 2.5.2 ships cp314 wheels for every target platform. Unpacked onto sys.path inside Fusion, it imports and computes correctly, at speed indistinguishable from stock CPython (400×400 linalg.solve: 1.6 ms inside Fusion, 1.2 ms on system Python). ADR-001’s “not available and will not be vendored” was false on feasibility.

“Pure Python” libraries are not dependency-free. Measured full install trees:

Library

Installed size

Transitive dependencies

numpy

56 MB unpacked, per platform

— (compiled, ABI-pinned to cp314)

ezdxf

70 MB

numpy, fontTools, pyparsing, typing_extensions

fpdf2

37 MB (22 MB without Pillow)

fontTools, Pillow (compiled), defusedxml

reportlab

26 MB

Pillow (compiled), charset_normalizer

pypdf

4 MB

none

svgwrite

1 MB

none

Both PDF libraries drag in Pillow, which is compiled — reinstating the per-platform wheel matrix. ezdxf drags in numpy, so “use a DXF library” is the numpy question.

Fusion’s interpreter is ~5x slower than stock CPython on identical pure-Python code (PRD §11.12). numpy sidesteps this penalty because it executes native code. Measured inside Fusion on the Tier E relaxation, numpy gives ~11x, moving the 2 s ceiling from ~15 000 to ~180 000 triangles.

The hand-written replacements are small and verifiable. Prototyped and validated:

Module

Code lines

Validated against

core/linalg.py

123

numpy, thousands of random cases, worst error 2.8e-12

core/export/pdf.py

66

pypdf; rendered by macOS CoreGraphics; 1:1 verified

core/export/dxf.py

31

ezdxf auditor — 0 errors, 0 fixes

Deducting the vector primitives (written regardless, since the core exchanges plain tuples across the adapter boundary per G6) and the relaxation algorithm itself (written either way), the surface numpy would actually replace is about 90 lines.

Decision

Pure Python standard library, unchanged. The decision stands; the reasoning does not.

Per format:

  • numpy — do not vendor. Not because it is infeasible, but because 56 MB × 3 platforms pinned to the cp314 ABI buys headroom above a ceiling the workload does not approach. A realistic template patch is ~3 000 triangles → 0.394 s against a 2 s budget.

  • DXF — hand-write. 31 lines against 70 MB that reintroduces numpy.

  • PDF — hand-write, with mandated guards. 66 lines, but with required test coverage for the failure classes a library would have handled: non-ASCII text encoding (Ø, German component names), xref byte offsets, and multi-page tiling.

  • SVG — genuinely marginal. svgwrite is 1 MB with zero dependencies; hand-writing is ~40 lines. Either is defensible; hand-write for consistency.

Third-party libraries are used as dev-only test oracles. This captures the correctness assurance a library provides while shipping zero bytes, and is mandatory for every hand-written implementation (PRD §14.3).

Consequences

  • The oracle requirement is load-bearing, not decorative. It has already paid: the numpy cross-check caught a silent overflow in the symmetric-eigen Jacobi rotation (theta * theta overflowing for a near-circular section — exactly the Ø 12.50 mm end of the reference chainstay, PRD §11.10), which would have produced garbage principal axes with no error raised.

  • Because the oracle is what makes hand-rolling defensible, a hand-written component without an independent oracle is not acceptable. If a future format cannot be validated against an independent implementation, prefer the library and accept the vendoring cost.

  • The 300 ms preview budget (FR-9.6) no longer has comfortable margin: 3 000 triangles takes 394 ms in Fusion. The coarse preview grid is promoted from recommendation to requirement.

  • Revisit if a requirement genuinely exceeds the PRD §6.6.1 envelope. The escape hatch remains vendoring numpy, now known to work; the cost is the per-platform ABI-pinned bundle, not feasibility.