Files
TheRON 70787ea17d stock: records delegates to the descriptor, and the descriptor stops gating
geom.records no longer computes the section, cavity or laminae. It calls mechcomp.stock, so the shape of a piece of stock is defined once. All 123 oracle cases unmoved: 482 passed. stock.py also becomes a leaf module, ending an import cycle with geom that resolved only by accident of ordering.

Three defects in f5651d3 corrected. Provenance raised on an empty source, which made an unattributed dimension unrepresentable and blocked the ordinary use of the tool: type what the caliper reads, print, measure the print, adjust. Provenance now records and travels with the output. Fit refused negative clearance on the argument that interference is not assemblable, which is a design judgement and not the compilers to make. Interference is now computed and reported. CATALOGUE read as a whitelist and is documented as starting points, with a test asserting an entry built from nothing is as valid as one pulled from the dict.

emt_template takes the diameter, fit, designation and note from the caller. There is no standards table and no lookup. A parametric compiler cannot require its subject to be catalogued before it will run.

STOCK.md section 5 amended, since the refusals were implementing it. An entry without provenance no longer fails to ship, it ships labelled unattributed. The principle that a number must not appear from nowhere looking authoritative survives; the door does not.

Tests compare records and stock against a hand transcription of the reference rather than against each other, which would be tautological after delegation. Mutation testing found four gaps before landing: a dropped lamina stacking offset, emt_template silently ignoring its fit argument, describe discarding the note exactly when provenance was unverified, and a guard on float arithmetic that asserted a tautology.
2026-08-23 10:24:39 -05:00

7.4 KiB

STOCK.md

What the compiler is for, and what every catalogue entry has to declare.

Written 2026-08-22, from CIVICVS's statement of the project's subject.


1. The subject of this library

This is not a 3D-printing geometry library. BOSL2 is that, and it is vendored in legacy/ because the reference was built on it.

This library describes commercial off-the-shelf hardware, and then generates the printed part that encloses it, interfaces with it, or augments it.

The pallet strap is not the subject. It is the first stock entry, and it was described so thoroughly that the whole of rev 8.0.0 looks like a strap library. Electrical conduit is the second. Stock can be anything you can buy or make on site: pipe, sheet, net, poured, drilled, bent. Each gets described, one at a time, and added to the catalogue.

The printed part is the adapter. The stock is what it adapts to.

Why this framing changes the code

Three things in the current codebase are the same object seen three times, and none of them knows about the others:

Where What it is How it is expressed today
Geo.cavity_w / cavity_t a strap's occupied void strap width and thickness, plus fit_clearance_mm, times bundle_count
three_fin_bore_side_mm a polygonal void through the centre a bare side length in millimetres
bore_from_members() the void left over between members derived, not declared

The first two are stock occupying space. The third is not stock at all — it is a residual cavity, and the name collision between it and a declared bore is already a source of confusion. A declared stock void and a derived residual void are different things and should stop sharing a word.

2. What a stock entry declares

Every entry in the catalogue answers the same questions. An entry that cannot answer one of them is not described well enough to generate a part.

Designation. What you ask for at the counter. EMT 1/2", PET strap 15.875 x 0.508, #3 rebar. This is a label, never a dimension — see §5.

Section. The cross-section the stock presents where the printed part meets it, as a closed path in millimetres: a rectangle for strap, a circle for conduit, a hexagon for a bolt head, a deformed circle for rebar. Prismatic stock has one section along its whole length; non-prismatic stock declares the section at the interface and nothing else, because that is all this compiler can hold (see PRECISION.md).

Nominal versus actual. These differ, and the difference is where parts fail. Trade size is not outside diameter. Nominal lumber is not actual lumber. The catalogue stores actual, measured, with its source. The designation is looked up to reach it, never computed from it.

Fit. How much room the printed part must leave, and why. A strap that slides through a channel, a conduit that is meant to be a press fit, and a bolt that must clear a hole are three different numbers even at the same diameter. Fit is a property of the joint, not of the stock, so an entry declares its default and every placement may override it.

Tolerance of the stock itself. Extruded and rolled stock varies. A part designed to the nominal section jams on the fat end of the run. Where a manufacturing tolerance is known it is recorded; where it is not, that is recorded too, and it is not silently assumed to be zero.

Provenance. Where the numbers came from — a standard, a spec sheet, or a caliper. A measured value with a date beats a remembered one, and a remembered one does not go in.

3. The three roles a printed part plays

Naming these keeps profiles honest about what they are doing.

Enclose. The part surrounds the stock and holds it. The strap channels are this. Failure mode: the stock does not go in, or rattles once it is in.

Interface. The part mates two pieces of stock that were not made to meet, or mates stock to a fastener. The Y's conduit core is this — the conduit carries load or routes cable, and the printed body is what lets three straps meet it. Failure mode: the mating surface is thinner than the load through it.

Augment. The part adds a feature the stock does not have: a mounting boss, a cable exit, a label surface, a keyed orientation. Failure mode: the addition compromises the enclosure or interface it is attached to.

A profile may do all three. Most useful ones do.

4. Adding an entry

The order matters, and it is the same order that produced the strap:

  1. Describe the stock, per §2, with provenance. No geometry yet.
  2. State the fit, and what happens at both ends of its tolerance.
  3. Generate the section, and check it against a real sample if one exists.
  4. Only then write the profile that uses it.

Steps 1 and 2 are where the errors are, and they cost nothing to correct. Step 4 is where they become expensive.

Every entry lands additively. The 123-case oracle is frozen at rev 8.0.0 and is the only evidence the geometry is right. A new stock entry, a new parameter, or a new profile must leave all 123 cases building byte-identically, which means new parameters default to absent. If adding a capability perturbs one recorded value, the implementation is wrong — not the oracle. See ACCEPTANCE.md.

5. What stays out

No standards tables in the geometry layer. The map from EMT 1/2" to an outside diameter is data about the world. It gets revised, it varies by region and by decade, and a wrong entry in it is a wrong part. It belongs where it can be corrected and cited without touching geometry, and where a person can see which number was used. Geometry takes millimetres.

No structural claims. PRECISION.md §7 governs and is scope-locked. That a part encloses a conduit says nothing about what the assembly carries. Measure and attest; never adjudicate.

No inferred stock — but never a blocked build. A dimension nobody has attributed is recorded as unattributed and used. What must not happen is a number appearing from nowhere and looking authoritative.

This was originally written as a refusal — an entry without provenance does not ship — and implemented as a constructor that raised. That was wrong, and wrong against §1: a compiler whose subject is arbitrary COTS hardware cannot require the hardware to be catalogued before it will run. Every dimension is an input at every run. Type what your caliper reads, print, measure the print, adjust, print again. That loop is the tool.

Provenance therefore travels with the output instead of guarding the entrance, and a later measurement supersedes an earlier guess.

No design decisions taken on the operator's behalf. An interference fit is a legitimate choice — a conduit core that must not rattle wants one, and PLA deflects. The compiler computes the interference and reports it. Whether it is acceptable is not the compiler's call. Measure and attest; never adjudicate.

6. Consequence for what exists

Geo currently derives its cavity from strap_width_mm, strap_thickness_mm, bundle_count and fit_clearance_mm — a rectangular stock entry, inlined. Expressing it through the stock descriptor rather than beside it is the first migration, and it is the one that proves the abstraction: if all 123 cases stay byte-identical with the strap expressed as a catalogue entry, the descriptor is faithful. If they do not, it is not, and the second entry would have inherited the flaw.

That migration comes before the conduit core, not after it.