diff --git a/ai-compliance-sdk/internal/iace/minimum_distances.go b/ai-compliance-sdk/internal/iace/minimum_distances.go new file mode 100644 index 00000000..fc604833 --- /dev/null +++ b/ai-compliance-sdk/internal/iace/minimum_distances.go @@ -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."}, + }, + }, + } +}