Anvilate
Anvilate turns a described part into a scorecard: one typed result per check, each citing the clause it came from. It is a T1 analytical screening library — closed-form, unit-checked, and fast — and it is not a certified analysis.
This file is documentation. It grants nothing. Every rule below is enforced by the library whether or not you loaded this, and the same calls produce the same results either way.
The four things agents get wrong
- Recalling a standard dimension instead of retrieving it.
- Reporting success without reading the scorecard.
- Reading "not evaluated" as a pass.
- Presenting a screening result as a certified analysis, which it is not.
Each has a section below, and each section's claim is carried by a worked example that runs in CI.
1. Retrieve, do not recall
Standard dimensions live in the bundled databases with their citations attached. Look them up. A remembered width-across-flats is a number with no provenance, and Anvilate's whole product is provenance.
from anvilate.standards import default_hex_bolt_table
bolts = default_hex_bolt_table()
bolt = bolts.get("ISO4014-M12")
print(bolt.width_across_flats.quantity)
print(bolt.citations()["width_across_flats"].source)
18 mm
ISO 4014 / ISO 4017 hexagon-head bolt and screw head dimensions
An unknown designation is refused with the near misses named, rather than resolved to something plausible:
from anvilate.standards import default_hex_bolt_table
from anvilate.standards.hexbolts import UnknownHexBoltError
try:
default_hex_bolt_table().get("M12")
except UnknownHexBoltError as exc:
print("refused:", exc)
refused: "no record for hex bolt 'M12'"
Do not paper over that refusal by supplying the number yourself. Ask which record is meant, or say the database does not carry it.
2. Read the scorecard before you report
Every check returns a ScorecardEntry with a tri-state status. Roll them into a
Scorecard and report status, not your impression of how the calculation went.
from anvilate.analysis import bolt_shear_stress, strength_scorecard
from anvilate.scorecard import Scorecard, ScorecardEntry
from anvilate.units import Quantity
shear = bolt_shear_stress(force=Quantity.parse("8 kN"), diameter=Quantity.parse("8 mm"))
bolt = strength_scorecard(
"bolt shear", stress=shear, allowable=Quantity.parse("380 MPa"), required=1.5
)
tearout = ScorecardEntry.from_safety_factor("plate tear-out", computed=None, required=2.0)
card = Scorecard(entries=(bolt, tearout))
governing = card.governing()
print(card.status.value, "|", "None" if governing is None else governing.name)
print(bolt.detail)
not_evaluated | plate tear-out
safety factor 2.39 vs required minimum 1.50
card.governing() names the check to quote, and its ordering is status first, then
utilization. The four rungs are the card's own roll-up order — fail, then
not_evaluated, then over_margin, then pass — so a failing check outranks one that
could not run, which outranks an over-engineered one, which outranks an ordinary passing
check however close to its limit. So the tear-out check governs here at a utilization of
None, ahead of a bolt at 63% — pointing you at the thing that blocks rather than at the
tightest number.
Inside a rung it is the highest utilization, except on over_margin, where the limit being
passed is the top of a declared band and furthest past it is the lowest utilization —
the most over-engineered check governs, not the least.
It returns None when nothing blocks and no check carries a safety factor, which every
deflection-only card looks like. Write card.governing() into a variable and check it;
card.governing().name raises AttributeError on exactly those cards.
3. "Not evaluated" is not a pass
A check that could not run reports NOT_EVALUATED. It is not a pass, and it does not
become one by going unmentioned. A scorecard containing one is never passed.
from anvilate.scorecard import CheckStatus, Scorecard, ScorecardEntry
gap = ScorecardEntry.from_safety_factor("plate tear-out", computed=None, required=2.0)
good = ScorecardEntry.from_safety_factor("pin bearing", computed=2.7, required=2.0)
card = Scorecard(entries=(good, gap))
assert gap.status is CheckStatus.NOT_EVALUATED
assert gap.passed is False
assert card.status is CheckStatus.NOT_EVALUATED
assert card.passed is False
print(card.status.value, "|", len(card.not_evaluated()), "not evaluated")
not_evaluated | 1 not evaluated
When you report, name the unevaluated checks and say what is missing. "Two of three checks pass" is a true sentence that reads as a passing part; do not write it.
4. Repair with the inverse first
A failing check MAY carry a repair_hint naming the parameter and the direction, and
where a design inverse exists it solves for the value that lands at the required margin
— one call instead of a search. Reach for the inverse before you start guessing sizes.
Not every screen offers one: 30 of the library's 60 screens do, and
docs/api/repair-levers.txt records the decision for every one of them. When a check
carries no hint, read its own numbers and reach for the inverse yourself, as below —
do not read the silence as "nothing can be done".
from anvilate.analysis.fastener import bolt_diameter_for_shear, bolt_shear_stress
from anvilate.units import Quantity
load = Quantity.parse("8 kN")
allowable = Quantity.parse("380 MPa")
needed = bolt_diameter_for_shear(
shear_load=load, allowable_shear=allowable, required_safety_factor=2.0
)
achieved = (
allowable.to("MPa").magnitude
/ bolt_shear_stress(force=load, diameter=needed).to("MPa").magnitude
)
print(f"{needed.to('mm').magnitude:.3f} mm gives SF {achieved:.3f}")
7.322 mm gives SF 2.000
The inverse lands exactly at the required margin, never above it. Rounding up to a stock size is a decision for the engineer, and it is one you should state rather than make silently.
5. Confirm inputs; a draft is not an input
Values read out of a requirements document or a calibration certificate arrive as
drafts. release() refuses while any load-bearing value is unconfirmed, and it names
them. Do not work around that by reading the drafts directly.
from anvilate.ingest import extract_requirements
draft = extract_requirements("design load: 50 kN\nbore diameter: 25 mm", document="rfq.txt")
try:
draft.release()
except ValueError as exc:
print("blocked:", str(exc).split(".")[0])
released = (
draft.with_confirmation("design_load", by="R. Engineer")
.with_confirmation("bore_diameter", by="R. Engineer")
.release()
)
print(sorted(released), released["design_load"])
blocked: 2 load-bearing value(s) are still drafts and nobody has confirmed them: ['bore_diameter', 'design_load']
['bore_diameter', 'design_load'] 50 kN
Confirmation is per value and names a person. Do not name yourself; ask the user who is confirming, or report the values as unconfirmed.
6. Say what a screening result is
A green scorecard means the closed-form checks Anvilate ran were satisfied by the inputs it was given. It is not a certified analysis, not a substitute for a licensed engineer's review, and not evidence that the part was tested.
The evidence bundle enforces the distinction rather than leaving it to prose: a bundle
carrying a verification plan with nothing performed is NOT_EVALUATED even when every
check passed, and verified is true only when a plan exists and every item in it has a
recorded, passing outcome.
from anvilate.bundle import BundleSections
from anvilate.scorecard import Scorecard, ScorecardEntry
card = Scorecard(
entries=(ScorecardEntry.from_safety_factor("pin bearing", computed=2.7, required=2.0),)
)
bundle = BundleSections(scorecard=card)
assert bundle.verified is False
print(bundle.summary())
bundle PASS over 1 layer (checks); not covered: design basis, verification, review, exploration, callouts, load combinations, export, geometric tolerances; not test-verified
Report the bundle's own sentence, including what it does not cover. When you are asked whether the part is good, the honest answer names the layers nobody has run.
7. Screen the document, not a rebuilt element
When the part arrives as a Design Spec, screen the spec. screen_spec reads the element
the document declares — element_type names the element and element_params carries its
own fields — and dispatches it to the discipline pack that screens it. Rebuilding the pack
element by hand from the same document is how a transcription error enters a run nobody
can see it in.
from anvilate.screening import screen_spec
from anvilate.spec import (
AcceptanceCriteria,
Constraints,
DesignSpec,
Manufacturing,
ManufacturingProcess,
MaterialRef,
Provenanced,
ValidationTier,
)
from anvilate.units import Quantity, UnitSystem
spec = DesignSpec(
name="padeye",
description="A lifting padeye on a skid frame.",
units=Provenanced.stated(UnitSystem.SI),
material=MaterialRef(ref="ASTM-A36"),
manufacturing=Manufacturing(process=ManufacturingProcess.SHEET_METAL),
element_type="lifting_lug",
element_params={
"name": "padeye",
"material": "ASTM-A36",
"width": Quantity.parse("120 mm"),
"hole_diameter": Quantity.parse("40 mm"),
"thickness": Quantity.parse("20 mm"),
"load": Quantity.parse("60 kN"),
},
constraints=Constraints(min_safety_factor=Provenanced.stated(2.0)),
acceptance=AcceptanceCriteria(tiers=[ValidationTier.T1_ANALYTICAL]),
)
card = screen_spec(spec)
print(card.status.value, "|", len(card.entries), "checks")
bare = spec.model_copy(update={"constraints": Constraints()})
print(screen_spec(bare).entries[0].detail)
pass | 3 checks
the lifting_lug screen is judged against a required safety factor and the spec states none; declare constraints.min_safety_factor
Two things in the document are yours to ask about and never to choose:
- The element. A document that declares none is
NOT_EVALUATEDnaming that, and an unknown tag is refused with the near miss suggested.anvilate.screening.element_registrylists the tags;structureis the one that takes a list of members, for a part that is an assembly rather than a single element. - The required safety factor. It is read from
constraints.min_safety_factor. A spec that states none isNOT_EVALUATED, as above. Ask the user for the figure and where it comes from; a screen run against a number you supplied is a screen against your assumption.
At the shell the same path is anvilate check <document>, and its exit code carries the
verdict.
What you must not do
- Do not present a screening result as certified, stamped, or sealed analysis.
- Do not report a scorecard as passing while any check is
not_evaluated. - Do not substitute a recalled dimension for a database record that refused to resolve.
- Never make the confirmation decision for the user; ask who is confirming.
- Do not describe a check as citing a clause you did not read off the entry itself.
Where to look next
Read docs/ in the repository for the layer you are working in — docs/citations.md for
what a clause reference does and does not claim, docs/evidence-bundle.md for the
roll-up, docs/repair-feedback.md for the repair loop, and
docs/quality-interchange.md for handing results to quality software.