feat(iace): OSHA minimum-distance library — Task #18

Verbatim OSHA 29 CFR 1910 Subpart O values anchored as the rechtssicher
zitierbare Werte-Basis for the IACE engine. Per strategy discussion
(2026-05-20) US Federal Code is the only public-domain corpus we can
reproduce wholesale; DIN/EN values stay identifier-only.

Coverage in this initial batch:
- MD_OSHA_O10_R1, MD_OSHA_O10_R4 (Table O-10 rows 1 + 4 — point of
  operation guard distance vs max opening width)
- MD_OSHA_212_FAN (§1910.212(a)(5) fan-blade guards: 1/2 in)
- MD_OSHA_217_PSDI (§1910.217 hand-speed constant 63 in/s for
  presence-sensing-device-initiation and two-hand-trip distances)

Each entry carries four parallel value sets:
- OriginalValue/Min/Max in source unit (verbatim, R1)
- ExactMM via deterministic conversion (mathematics, no copyright)
- RecommendedMM with safe-side rounding documented in RoundingNote
- EUNormHints — identifier-only references to EN ISO 13857, EN 13855,
  EN 349 with a human-curated DINComparisonNote (qualitative judgement,
  not a copy)

Open follow-ups (separate iterations):
- Full Table O-10 (rows 2-10) — same shape
- §1910.219 mechanical power-transmission distances
- Cross-reference IACE patterns to MD_OSHA_* identifiers so the Suppression
  Engine surfaces concrete metric values in mitigation suggestions
- Frontend integration: <MinimumDistanceCard> for each measure
This commit is contained in:
Benjamin Admin
2026-05-21 23:43:51 +02:00
parent 081e4f057a
commit eb48c5bd1e
@@ -0,0 +1,172 @@
package iace
// Minimum-distance library — Task #18.
//
// Anchor source: OSHA 29 CFR 1910 Subpart O (US Federal Public Domain,
// 17 U.S.C. §105). The values below are reproduced verbatim from the
// Federal Code; conversions to metric are mathematical and carry no
// copyright. Engineering rounding to safe-side mm values is BreakPilot's
// recommendation and labelled as such.
//
// EU norm equivalents (EN ISO 13857, EN 349, EN 13855, EN 1010) are
// referenced by identifier only — no values are reproduced, because
// DIN/Beuth retain copyright on the wording. The DINComparisonNote
// field carries a human-curated judgement on whether the EU norm is
// stricter / looser / equivalent — this is a qualitative observation
// about a publicly available document, not a copy of its text.
//
// See LICENSE_RULES.md and project_attribution_strategy.md for the
// licensing logic. The OSHA values are R1 (verbatim public domain);
// the recommended metric values are BreakPilot engineering output (R3
// own-work). DIN references are R3 identifier-only.
// MinimumDistanceUnit denotes the original unit system of the source.
type MinimumDistanceUnit string
const (
UnitInch MinimumDistanceUnit = "inch"
UnitFoot MinimumDistanceUnit = "foot"
UnitMeter MinimumDistanceUnit = "meter"
UnitMM MinimumDistanceUnit = "mm"
)
// MinimumDistance is the data contract for a single safety-distance rule.
// It can be (a) a fixed gap value, (b) a distance range, or (c) a formula
// like OSHA's Ds = 63 in/s × Ts (hand-speed constant).
type MinimumDistance struct {
ID string `json:"id"` // MD_OSHA_001
// Source identifier — full CFR citation or norm reference.
SourceCFR string `json:"source_cfr,omitempty"` // "29 CFR §1910.217(c)(1)(i)"
SourceTable string `json:"source_table,omitempty"` // "Table O-10"
License string `json:"license"` // "US Federal Public Domain"
LicenseRule int `json:"license_rule"` // 1 / 2 / 3 (see LICENSE_RULES.md)
// Original verbatim value in the source's own unit.
OriginalUnit MinimumDistanceUnit `json:"original_unit"`
OriginalValue float64 `json:"original_value,omitempty"`
OriginalMin float64 `json:"original_min,omitempty"`
OriginalMax float64 `json:"original_max,omitempty"`
// Exact conversion to mm — no engineering rounding.
ExactMM float64 `json:"exact_mm,omitempty"`
ExactMinMM float64 `json:"exact_min_mm,omitempty"`
ExactMaxMM float64 `json:"exact_max_mm,omitempty"`
// Engineering-recommended metric value with safe-side rounding.
// For minimum distances: rounded up. For maximum opening widths:
// rounded down.
RecommendedMM int `json:"recommended_mm,omitempty"`
RecommendedMinMM int `json:"recommended_min_mm,omitempty"`
RecommendedMaxMM int `json:"recommended_max_mm,omitempty"`
RoundingNote string `json:"rounding_note,omitempty"`
// Optional formula constant (e.g. OSHA hand-speed 63 in/s).
FormulaInchPerSecond float64 `json:"formula_inch_per_second,omitempty"`
FormulaMMPerSecond float64 `json:"formula_mm_per_second,omitempty"`
FormulaDescription string `json:"formula_description,omitempty"`
Context string `json:"context"` // "Point of Operation Guarding mechanical presses"
BodyPart string `json:"body_part,omitempty"` // "finger" / "hand" / "head" / "foot" / "body"
HazardTags []string `json:"hazard_tags,omitempty"` // [crush_point, cutting_part, ...]
// EU norm cross-reference — IDENTIFIER ONLY, no values reproduced.
EUNormHints []EUNormHint `json:"eu_norm_hints,omitempty"`
}
// EUNormHint references an EU standard by identifier without reproducing
// any value or text from it. The DINComparisonNote is a human-curated
// qualitative judgement (stricter / equivalent / looser) — not a copy.
type EUNormHint struct {
Norm string `json:"norm"` // "EN ISO 13857"
Section string `json:"section,omitempty"` // "Tab. 4, Schutz gegen Hineingreifen"
DINComparisonNote string `json:"din_comparison_note,omitempty"`
}
// GetOSHAMinimumDistances returns the verbatim OSHA values for
// machine-guarding distances. All values are US Federal Public Domain
// (17 U.S.C. §105). Engineering rounding is BreakPilot's safe-side
// recommendation; OSHA values themselves are unchanged.
func GetOSHAMinimumDistances() []MinimumDistance {
return []MinimumDistance{
// OSHA Table O-10 row 1 — verbatim values, mathematical conversion,
// safe-side rounded engineering recommendation.
{
ID: "MD_OSHA_O10_R1",
SourceCFR: "29 CFR §1910.217(c)(1)(i)",
SourceTable: "Table O-10 row 1",
License: "US Federal Public Domain (17 U.S.C. §105)",
LicenseRule: 1,
OriginalUnit: UnitInch,
OriginalMin: 0.5, OriginalMax: 1.5, OriginalValue: 0.25,
ExactMinMM: 12.7, ExactMaxMM: 38.1, ExactMM: 6.35,
RecommendedMinMM: 15, RecommendedMaxMM: 40, RecommendedMM: 6,
RoundingNote: "Distance auf 5-mm-Raster aufgerundet, opening auf 1-mm-Raster abgerundet (konservativ in beide Richtungen).",
Context: "Point-of-Operation Guarding bei mechanischen Pressen",
BodyPart: "finger",
HazardTags: []string{"crush_point", "cutting_part"},
EUNormHints: []EUNormHint{
{Norm: "EN ISO 13857", Section: "Tab. 4 (Hineingreifen)",
DINComparisonNote: "Andere Methodik (Reichweitenmodell). Unabhaengig pruefen — Werte koennen abweichen."},
},
},
// OSHA Table O-10 row 4 — used as a worked example in the strategy
// discussion. Distance 3.5-5.5 in, opening max 5/8 in.
{
ID: "MD_OSHA_O10_R4",
SourceCFR: "29 CFR §1910.217(c)(1)(i)",
SourceTable: "Table O-10 row 4",
License: "US Federal Public Domain (17 U.S.C. §105)",
LicenseRule: 1,
OriginalUnit: UnitInch,
OriginalMin: 3.5, OriginalMax: 5.5, OriginalValue: 0.625,
ExactMinMM: 88.9, ExactMaxMM: 139.7, ExactMM: 15.875,
RecommendedMinMM: 90, RecommendedMaxMM: 140, RecommendedMM: 15,
RoundingNote: "Distance 88.9→90 (+1.1 mm), 139.7→140 (+0.3 mm) aufgerundet; Opening 15.875→15 (-0.875 mm) abgerundet.",
Context: "Point-of-Operation Guarding bei mechanischen Pressen",
BodyPart: "finger",
HazardTags: []string{"crush_point", "cutting_part"},
EUNormHints: []EUNormHint{
{Norm: "EN ISO 13857", Section: "Tab. 4 (Hineingreifen)",
DINComparisonNote: "Andere Methodik (Reichweitenmodell). Compliance-Annotation pflegen."},
},
},
// OSHA §1910.212(a)(5) — fan blade guards. Verbatim 1/2 inch.
{
ID: "MD_OSHA_212_FAN",
SourceCFR: "29 CFR §1910.212(a)(5)",
License: "US Federal Public Domain (17 U.S.C. §105)",
LicenseRule: 1,
OriginalUnit: UnitInch,
OriginalValue: 0.5,
ExactMM: 12.7,
RecommendedMM: 12,
RoundingNote: "Luefterblatt-Schutzgitter: max. Spaltoeffnung 1/2 in = 12.7 mm. Konservativ auf 12 mm abgerundet.",
Context: "Lüfterblätter unter 7 ft (2.13 m) Höhe",
BodyPart: "finger",
HazardTags: []string{"rotating_part", "cutting_part"},
EUNormHints: []EUNormHint{
{Norm: "EN ISO 13857", Section: "Tab. 4",
DINComparisonNote: "DIN-Wert pruefen."},
},
},
// OSHA §1910.217 Hand-Speed Constant — formula Ds = 63 in/s × Ts
{
ID: "MD_OSHA_217_PSDI",
SourceCFR: "29 CFR §1910.217 (Ds = 63 in/s × Ts)",
License: "US Federal Public Domain (17 U.S.C. §105)",
LicenseRule: 1,
OriginalUnit: UnitInch,
FormulaInchPerSecond: 63.0,
FormulaMMPerSecond: 1600.2,
FormulaDescription: "Hand-Speed-Konstante 63 in/s ≈ 1600 mm/s. " +
"Ds (Mindestabstand) = 63 × Ts (Stoppzeit Presse in Sekunden).",
Context: "PSDI Presence-Sensing Device Initiation und Two-Hand-Trip",
BodyPart: "hand",
HazardTags: []string{"crush_point", "high_speed"},
EUNormHints: []EUNormHint{
{Norm: "EN 13855", Section: "Sicherheitsabstaende",
DINComparisonNote: "EN 13855 nutzt andere Konstante (1600 mm/s ≈ identisch); EU-Norm unabhaengig pruefen."},
},
},
}
}