99901bba0ab63ade72cd2c50c41e6a882a2a47a1
233 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c35977c925 |
docs(iace): verify cobot biomech limits against CC-BY papers
Cross-checked cobot_biomech_limits.md against both source papers: - Behrens et al. 2022 (Frontiers): 10 body regions spot-checked, force values match the paper EXACTLY in both columns (pinching + impact). - Park et al. 2019 (PLOS ONE): lowest/highest/range pressure values exact. Fix: 28 -> 29 body locations; add a verification stamp. Threshold VALUES were already correct (no data change), so no RAG re-ingest needed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
b0ceae4350 |
feat(iace): open-source safety KB sources + bp_iace_safety_kb (Thema 2)
Versioned, license-tagged source docs for the multi-layer GT knowledge base, ingested into the new core RAG collection bp_iace_safety_kb (whitelisted in the RAG search handler): - prism_risk_methodology.md — OPSS PRISM v2 (OGL v3): full severity(4)× probability(8) → risk-level matrix (Serious/High/Medium/Low), RAPEX-aligned. - cobot_biomech_limits.md — CC BY 4.0 papers (Behrens 2022 / Park 2019): force (N) & pressure (N/cm²) pain thresholds by body region (the data behind ISO/TS 15066, cited from the open papers — standard tables NOT reproduced). - hse_example_risk_assessments.md — HSE (OGL v3): qualitative hazard→control. - osha_robot_safety.md — OSHA OTM (public domain): 250 mm/s teach anchor, robot hazard taxonomy, safeguarding hierarchy. No DIN/EN/ISO/IEC/DGUV content reproduced; each doc states its license + attribution. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
dbb15dbb78 |
feat(iace): add BLS CFOI fatal-injury source doc (D1)
US severity anchor complementing ESAW: BLS Census of Fatal Occupational Injuries (public domain), event/exposure distribution 2023-24 + the machine-relevant "Contact incidents" breakdown (struck/caught/compressed by running powered equipment: 226/213). Key finding: in MANUFACTURING, contact is the leading fatal event (104/353 = 29.5%) — independent support for the model's mechanical-contact emphasis. Ingested into the core RAG collection bp_iace_accident_stats. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0f443b6a9c |
fix(iace): roadmap group B — citation/license/tier cleanup
C1: drop the misleading OSHA §1910.212(a)(5) fan-guard citation from M602
(overhead lift clearance) — EN 349 + EN ISO 13854 already cover it.
C2: frame M237's 25/500 mm as Richtwerte to be determined per EN ISO 13854
(single factual values in prose are facts, not table reproduction — but
keep the conservative caveat).
C3: keep ergonomic W=2 deliberately and document why — ESAW ranks it the most
frequent non-fatal mode (24.7%) but that population doesn't transfer to an
acute machine point-hazard; the machine GT governs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
86c0ea6f63 |
fix(iace): wire M605/M606 into lift patterns so they fire
Adding M605 (drive-limited general speed) and M606 (limited descent on energy loss) to the library wasn't enough — measures only get suggested if a pattern's SuggestedMeasureIDs references them. Add M605 to the three lift crush patterns and M606 to the floor-stop descent pattern (HP2100), so a re-seed actually attaches them and the distance benchmark closes the ≤150 mm/s gap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0d7194ef89 |
feat(iace): add distance dimension to GT benchmark
CompareBenchmark now also compares the engine's numeric dimensions (mm gaps, mm/s speeds) against the professional's GT measures: parses distance tokens from both sides (German thousands/decimal aware), reports matched / gt_only (gaps) / engine_only + an agreement %. Surfaces as result.distances on the existing benchmark endpoint. Deterministic, no LLM. On the GT-derived seed sessions it mainly guards DRIFT; its real value is new sessions. Real-GT test pins that the engine covers the Bremse (250 mm/s, 250/850 mm) and Kistenhub (25/120 mm, 150/75 mm/s) headline dimensions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
b63f49344a |
feat(iace): fill lift-measure distance gaps vs GT (M603/M605/M606)
The GT distance benchmark surfaced three Fachmann lift values the engine carried no measure for: general lift/lower speed (≤150 mm/s), the low-zone inching regime (<200 mm floor clearance, ≤75 mm/s), and limited descent on power loss (≤100 mm). Extend M603 (inching) and add M605 (drive-limited general speed) + M606 (load-holding on energy loss). Values framed as generic hoist recommendations with EN 1570-1 reference, not GT-memorised. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6b41eec176 |
feat(iace): surface OSHA distance anchor in Maßnahmen tab (name-resolved)
Makes the OSHA minimum-distance anchor visible per measure in a project without a DB schema change or re-seed: persisted mitigations store the measure NAME verbatim (not the catalog ID), and measure names are unique across the 578-entry library (pinned by test), so a name→ID resolver bridges the gap. Backend: MeasureIDByName + MinimumDistancesForMeasureName/LinksForMeasureName; /iace/minimum-distances now accepts ?measure_name=; link table enriched with measure_name for one-request UI matching. Frontend: useMinimumDistances loads the link table once and keys it by name; OshaDistanceNote renders the anchor (value/CFR/license/EU-hint/relation) on the matching measure group in the Maßnahmen tab. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
5e18df63b1 |
feat(iace): ESAW accident-stats RAG pipeline + real 2023 risk anchors
Executes the accident-statistics pipeline for the risk anchors: - Refresh contactModeEvidence with real Eurostat ESAW figures (dataset hsw_ph3_08, reference year 2023): impact 24.0%/21.4%, struck-by 13.0%/23.8%, sharp 14.5%, trapped/crushed 13.8% (fatal), + new physical/mental-stress mode 24.7% → ergonomic. GT-calibrated tier VALUES unchanged; the real data confirms the ordering. - Add the versioned source document (datasources/esaw_accident_stats_2023.md, ESAW CC BY 4.0 + OSHA public-domain context) that is ingested into the core RAG collection bp_iace_accident_stats for searchable evidence. - Whitelist bp_iace_accident_stats in the RAG search handler so seeding can full-text search the statistics with citation at seed time. Two-layer design: the small license-tagged code table stays the deterministic tier/citation lookup; the RAG holds the searchable source evidence. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6846ca6b28 |
feat(iace): wire OSHA minimum-distance library into measures + endpoint
The May-built OSHA distance library (minimum_distances.go, 29 CFR 1910, US public domain) was dead code — zero callers, no route, no test, while the mm values that actually appear in measures are independent hand-prose (some carrying ISO 13854/13857 values, not OSHA). This surfaces it without touching the measures response contract: - GET /iace/minimum-distances (+ ?measure_id=) returns the distances, the curated measure→distance link table and the licensing note. - AllMeasureDistanceLinks/MinimumDistancesForMeasure resolve only the defensible links (M600 value_source; M254/M065 public-domain crossref to ISO), with the relation made explicit so the join stays honest. - architecture.go lists the OSHA library so it shows in the audit explainer. - Tests: inch→mm conversion + license completeness, link integrity, and a consistency test pinning that a value_source measure's prose still matches the OSHA source (codifies the audit finding as a regression gate). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
32ba8d16b1 |
feat(iace): add data-driven Architektur & Datenfluss explainer tab
Adds an auditor-facing view of the IACE engine: a clickable 10-stage pipeline flow (Grenzen-Formular → ParseNarrative → Pattern-Gates → Relevanz → Caps → Gefährdungen → Maßnahmen → Risiko → Normen → Matrix), plus live library counts, the data-source/license register (incl. the DIN/Beuth + DGUV exclusions), and the norm-matching logic that reconciles DIN/ISO/OSHA machine-type vocabulary via canonicalMachineType folding. Backend: BuildArchitecture() with LIVE counts so the diagram can never drift; GET /iace/architecture; collectAllNorms() extracted from SuggestNorms as the single source of truth for the norm-library count. Frontend: useArchitecture hook + page + new IACE nav tab. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
ee64b7e95c |
feat(iace): cite ESAW source + license on risk-frequency anchors
Surfaces the public-statistics provenance for the contact-mode probability tiers so generated risk numbers are auditable and attributed (not RAG — ~a dozen stable aggregate facts are better as a license-tagged code table). - risk_data_sources.go: RiskEvidence register (Eurostat ESAW figures + CC BY 4.0 attribution) for the documented contact modes; RiskDataSourcesNote. - risk_suggestion.go: the W justification now cites the actual ESAW share + license where documented; RiskSuggestion gains a data_source field. - GET /iace/risk-data-sources returns the evidence register + attribution. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
577ceae4e6 |
feat(iace): project-wide risk matrix (Severity × Probability)
Adds GET /projects/:id/risk-matrix — a confidence-aware risk view computed on read from each hazard's category/scenario/lifecycle using the SAME model as the GT benchmark (no persistence, so it never goes stale against the model; the hand-defaulted iace_hazards risk columns stay untouched). - risk_matrix.go: EstimateHazardRisk (single source of truth for S/F/W/P + range + level + confidence) and BuildRiskMatrix (per-hazard list + a 5×5 Severity×Probability aggregation grid with dominant level per cell). - Frontend: RiskMatrix grid in the Risikobewertung tab (muted colours per the confidence-aware tonality), level counts + tool-confidence summary, fed by useRiskMatrix. Shows risk for EVERY project, not only GT ones. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a7dc12f30f |
feat(iace): risk as confidence range + label in benchmark tab
Report the tool's risk number as a plausible range with a confidence label instead of a false-precision point value (confidence-aware tonality — the assessment is confirmed by the DSB / safety expert). - risk_estimation.go: EstimateConfidence (hoch/mittel/niedrig from how the contact mode resolved), EstimateRiskRange (S±1 and aggregate L=F+W+P ±1, the empirically validated per-parameter accuracy), RiskLevelRange; share the riskBandLabel thresholds with EstimateRiskLevel. - risk_benchmark.go: RiskComparisonPair gains eng_risk_point/low/high + level + level_range + confidence; RiskAgreement gains high_confidence_pct. - RiskComparison.tsx: per-hazard range "low–high (level range)" + point, confidence chip, and an aggregate confidence line; types in useBenchmark.ts. - Unit tests for the range/confidence helpers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
005a2ed711 |
feat(iace): generic cross-domain leak gates + norm vocab reconciliation
- Domain-gate ~15 foreign machine classes (pool, amusement, paint booth, tank farm, reactor, lathe/chips, saw, film/carton, robot, mobile cab, asbestos, playground swing) in pattern_domain_gates.go so ungated hazard patterns stop leaking into unrelated machines; matching emit keywords added in keyword_dictionary.go (gate+emit share one vocabulary). - Extend the cross-domain precision guard to 6 machine classes (press, cobot, motor, welding + the 2 GTs) with per-case homeDomains, so a machine's own domain terms are never flagged. GT coverage stays 100%. - Reconcile the fine-grained norm machine-type vocabulary (455 keys) with the 68 canonical dropdown keys via canonicalMachineType() family folding in matchNorm — welding 0->17, robotics_cobot 0->6, press 8->13, circular_saw 1->35 machine-specific C-norms. Pattern gating left strict. - Fix initialize?force=true summary index-shift that mislabeled counts (reported matched-patterns as "hazards"); now uses named step vars. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
afb3f83f30 |
feat(iace): cross-domain precision overhaul + component review + schema reconcile
Engine precision (stop foreign-machine patterns leaking into a project):
- Wire project.MachineType into the engine machine-type gate (empty input no
longer fires every machine class — press/cnc/excavator/crane/medical...).
- Capability-domain gating extended by 7 domains (outdoor, ventilation,
machining, bulk, palletizer, playground, fitness) so domain-specific hazards
only fire when the narrative names that domain; emitted via keyword_dictionary.
- Relevance backstop moved into iace (single gating contract, testable), and its
dominant false-anchor class removed (a long pattern word no longer matches a
short common token; prepositions/leitung added to the generic stoplist).
- New guard tests: TestCrossDomainPrecision (full pipeline, 0 foreign per GT) and
TestPatternReachability now asserts 0 dead patterns. Both GTs keep coverage 1.0.
Reachability fix: the 51 dead patterns required electrical/pneumatic/hydraulic
tags nothing produced — renamed to the canonical electrical_energy/
pneumatic_pressure/hydraulic_pressure/hydraulic_part.
Component review (negation is best-effort + expert-correctable):
- Parser surfaces negated components (ComponentMatch.Negated) instead of dropping
them; negated contribute no tags/energy → no phantom hazards.
- presence_status (vorhanden|nicht_vorhanden|geloescht) + ce_marked on components;
only `vorhanden` feed matching. CE+safety-relevant flags the PL/SIL obligation.
- Force re-seed preserves the expert's component decisions instead of wiping them.
- Tag-based component→hazard assignment (was: all on the first component).
- Negation-aware narrative parsing ("keine Pneumatik" no longer extracts it).
Local-dev DB: ai-sdk sets search_path=compliance,core,public; reconcile migrations
152-156 bring the consolidated local iace tables to the current schema + add the
presence_status/ce_marked columns. Machine-type vocabulary endpoint for the form.
[migration-approved]
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
c4d9b1426f |
fix(iace): lower EstimateFrequency tiers — engine F was ~1 too high vs the GT
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Failing after 15s
CI / go-lint (push) Has been skipped
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
Diagnosis: engine F mean 3.56 vs professional 2.56; the dominant disagreement was normal-operation hazards getting F=4 where the professional assigned 2. Lowered the lifecycle→F mapping (normal operation 4→3, occasional phases 3→2). New TestGT_RiskComparison_CrossGT runs the exact production comparison on BOTH GTs: F within±1 rose to 95% (robot cell) and 94% (lift) — generic, not lift-tuned. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
2677bca9ca |
feat(iace): benchmark risk comparison (traffic lights) + misuse pattern + 1:n matcher
CI / detect-changes (push) Successful in 7s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Failing after 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m23s
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 24s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
#1 Risk-number comparison in the benchmark: ComputeRiskComparison derives the tool's S/F/W/P + Fine-Kinney per matched hazard and compares to the GT values; exposed on the benchmark response and rendered in a new RiskComparison table with GREEN/YELLOW/RED traffic lights on the risk number R (like the Excel), plus per-axis within-1 agreement cards. #2 Generic misuse pattern HP2103 "Personenbefoerderung auf Hebezeug" — gated to lift-family machine types, fires for ANY lifting device (not machine-specific). #3 Benchmark matcher is now 1:n — one broad engine hazard may cover several fine-grained GT sub-scenarios (foot/hand/leg crush), so coverage reflects real risk coverage rather than 1:1 wording matches. Validated on BOTH ground truths (robot cell + lift): leakage 0, ghosts 0, coverage held. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0f04eee746 |
feat(iace): read ALL limits-form fields + always include universal lifecycles
CI / detect-changes (push) Successful in 5s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 5s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Failing after 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / test-go (push) Failing after 37s
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
(1) extractNarrativeFromMetadata now reads every limits-form field generically (no whitelist) — intended use, foreseeable misuse, all machine limits and all four interface groups (electrical/mechanical/pneumatic/software). Field-schema drift no longer silently drops hazard sources. (2) withUniversalLifecycles always adds normal_operation/setup/maintenance/ cleaning to the matched lifecycle phases — these occur on virtually every machine and the professional assesses them, so their hazards must be derived even when the form omits them. Kistenhubgeraet recall jumped 42.9% -> 74.3% (electrical 9% -> 82%) from the field-name fix alone; this broadens it further. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
1ffdb99650 |
fix(iace): narrative extractor ignored most Grenzen fields (field-name mismatch)
CI / test-go (push) Failing after 36s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 5s
CI / validate-canonical-controls (push) Successful in 12s
CI / loc-budget (push) Failing after 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
extractNarrativeFromMetadata looked for field names that don't exist in the real limits-form schema (interfaces_description, control_system_description, energy_sources, space_limits, foreseeable_misuse), so it effectively read only general_description + intended_purpose. The electrical/mechanical/pneumatic/ software interface fields — each a hazard source — were silently dropped, which is why electrical hazard coverage was 9% for the Kistenhubgeraet. Now reads the actual schema fields incl. electrical_interfaces / mechanical_interfaces / pneumatic_hydraulic_interfaces / software_interfaces / energy_supply / spatial_limits / foreseeable_misuses, plus array fields (operating_modes, person_groups, industry_sectors). Legacy names kept. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
a48e919caa |
fix(iace): scan ZoneDE in domain gate (catches zone-only domain hints)
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 23s
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Successful in 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / test-python-backend (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
A "Splitterflug bei Werkzeugbruch" pattern leaked into a lift re-seed because
its press hint ("Pressraum") lives in ZoneDE, which applyDomainGates did not
scan. Add ZoneDE to the gated text. Leakage stays 0, ghosts 0, coverage held.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
7b3a6f0dcd |
fix(iace): close domain-gate gaps — generic patterns with press/welding/glass text
CI / loc-budget (push) Successful in 15s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 12s
CI / nodejs-build (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
Observed on a real Kistenhubgeraet (lift) project: generic mechanical patterns (e.g. HP1000 "Quetschen Arm zwischen Pressenteilen") carry NO machine type and only generic tags (crush_point, rotating_part), so they fired for a lift; the narrow domain-gate terms missed their press/welding/glass wording. Broadens domainGateTerms (pressenteil, pressraum, blechbearbeitung, punktschweiss, schweisselektrod, elektrodenspalt) and adds a dom_glass domain (glasschneid/glasbearbeitung/...) with its emit keywords. New test pins that the four observed leakers now require a dom_* tag. Ghost=0, Leakage=0, coverage held on both GTs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
77536f04b7 |
feat(iace): dual-model risk-suggestion endpoint for Risikobewertung tab
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Successful in 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 38s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
GET /projects/:id/hazards/:hid/risk-suggestion returns BreakPilot's justified starting values for BOTH risk models per hazard: - EN-62061-style F/W/P/S (the Excel format the professional knows) - Fine-Kinney P/E/C (US-recognized) each with a plain-language justification + the visible formula. Read-only and computed from public-data anchors (ESAW/NIOSH/OSHA via the engine estimators) — the professional adjusts the values; no norm table is stored or reproduced. Adds EstimateFrequency (lifecycle -> 1-5) and BuildRiskSuggestion. Go SDK has no OpenAPI baseline, so the only contract surface is the frontend consumer (the new Risikobewertung tab, next). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0bf9c54d27 |
feat(iace): add Fine-Kinney risk model (citable, free, US-recognized)
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 5s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Successful in 15s
CI / go-lint (push) Has been skipped
CI / test-go (push) Failing after 38s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
Fine-Kinney (Fine 1971 / Kinney-Wiruth 1976): Risk = Probability x Exposure x Consequence — a PUBLISHED, freely-usable method (not a DIN/Beuth/ISO standard), widely used incl. CE-marking. Gives the professional a second, US-recognized model alongside the EN-62061-style one; German exporters get both for free and adjust with their own licensed norm data. risk_fine_kinney.go: SuggestFineKinney derives justified P/E/C from public anchors (ESAW frequency -> P, lifecycle -> E, de-biased severity -> C on the Fine-Kinney consequence scale) + ComputeFineKinney(p,e,c) so the professional can override with his own values. No norm table stored. GT benchmark (rank concordance vs the professional): Fine-Kinney 75.4% — beats the EN-62061-style model (69.3%) and the raw engine (57%). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
a910793d12 |
feat(iace): de-bias severity estimate; risk ranking 57%->69% vs Fachmann
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / detect-changes (push) Successful in 8s
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Successful in 15s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 44s
CI / iace-gt-coverage (push) Successful in 22s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
The engine's hand-set DefaultSeverity systematically over-estimates severity (GT shows crushing 3.3 vs 2.2, struck_by 3.1 vs 2.5; electrical was already close). EstimateSeverity blends the pattern default 50/50 with the contact mode's GT-calibrated typical severity (baseS) — keeps pattern-specific signal, removes the bias. Our own model, no norm table. Effect across both GTs: severity within +-1 78%->88%; risk RANK concordance 57%->69% (Kistenhub 45%->70%). Wired into iace_handler_init.go so the BreakPilot risk line uses the de-biased severity. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
02a31b711c |
fix(iace): remove EN ISO 13849-1 risk-graph reproduction; own risk model
CI / detect-changes (push) Successful in 6s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-backend (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / build-sha-integrity (push) Failing after 5s
CI / validate-canonical-controls (push) Successful in 11s
CI / loc-budget (push) Successful in 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 23s
IP/copyright fix: ComputePLr reproduced the EN ISO 13849-1 Anhang A risk-graph decision table (S/F/P -> PLr a..e) and SeverityToS/ExposureToF its parameter binning, emitted into every hazard description. Removed — we may not reproduce DIN/Beuth norm logic. Replaced with BreakPilot's OWN risk model: - risk_estimation.go: probability (W) + avoidance (P) estimated from public, permissively-licensed accident statistics (Eurostat ESAW, CC BY 4.0) by contact mode, calibrated to our ground-truth corpus; own risk index + bands. - iace_handler_init.go now emits "Risikoeinschaetzung (BreakPilot-Modell): S F W P -> Risiko: <level>" instead of the norm PLr string. - DATA_SOURCES.md: data provenance + license register (ESAW CC BY 4.0; BLS/OSHA public domain; HSE OGL; DGUV + DIN/Beuth explicitly excluded). - gt_risk_benchmark_test.go: first GT validation of risk numbers — W within +-1 99%, P 93% vs the professional across both ground truths. Removed risk_graph_test.go (pinned the reproduced norm table). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
b1357915ae |
feat(iace): Capability-Domain-Gating — Ghost 120→0, Leakage 25→0, Coverage 100%
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 10s
CI / loc-budget (push) Successful in 11s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Failing after 40s
CI / iace-gt-coverage (push) Successful in 24s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
Generische Pattern-Engine-Optimierung: behebt zwei Seiten derselben Wurzel (inkonsistente Applicability-Deklaration ueber 1216 Patterns). - Ghost-Patterns (120, feuerten nie): 34 nicht-erzeugbare Required-Tags via domaenenspezifische Keywords emittierbar gemacht -> 0. - Cross-Domain-Leakage (25, feuerten ueberall): neuer text-getriebener Capability-Domain-Gate (pattern_domain_gates.go) — Pattern mit Fremdmaschine im Szenariotext bekommt dom_*-Tag als Required-Gate -> 0. - Resolver: Komponente->TypicalEnergySources-Expansion (strukturierte Projekte). - Benchmark: GT-Platzhalter-Filter; faithful Cross-GT-Narrative-Harness. - Harte Regression-Guards: Ghosts=0, Leakage=0, Coverage>=90% (beide GTs). - HP2000/HP2001 (Secondary-Harm-Demos) in AllowlistKnownGaps -> Suite gruen. Echte Pipeline beide GTs: Coverage 100%/100%, 0 Leaks, 0 Ghosts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
216c7b8eca |
feat(iace): DSMS-CID-Badge im Tech-File-Export + aggregierter Bulk-Diff
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 10s
CI / loc-budget (push) Successful in 14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m21s
CI / test-go (push) Failing after 37s
CI / iace-gt-coverage (push) Successful in 23s
CI / test-python-backend (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Successful in 17s
Punkt 1 — UI-CID-Badge nach erfolgreichem Tech-File-Export:
- archiveTechFile setzt X-DSMS-CID / X-DSMS-Filename / X-DSMS-Size response
headers + Access-Control-Expose-Headers, sobald DSMS-Archive durchlief
- Split iace_handler_techfile.go (war ueber 500 LOC) → archiveTechFile lebt
jetzt in iace_handler_techfile_archive.go, setDSMSResponseHeaders als
pure Helper mit 3 unit tests
- Next.js IACE-Proxy forwarded die X-DSMS-* Header und erkennt jetzt auch
XLSX/DOCX/MD als Binary-Response (vorher nur PDF/ZIP/octet-stream)
- ExportCIDBadge.tsx zeigt CID, Filename, Groesse + Kopieren-Button +
"Verlauf anzeigen" (oeffnet CIDHistoryModal)
Punkt 2 — Bulk-Diff Report V1 → V_latest:
- Neuer Endpoint GET /api/v1/documents/{cid}/bulk-diff im dsms-gateway:
laeuft parent_cid-Kette ab, berechnet chronologische Step-Diffs,
aggregiert Totals (added/removed lines, metadata_fields_changed,
binary_steps). Edge-Cases: einzelne Version, binaere Steps, abgebrochene
Kette
- BulkDiffPanel.tsx zeigt 4-Stat-Header + Step-Tabelle
- CIDHistoryModal bekommt Toggle-Button "Bulk-Diff V1 → V_latest anzeigen"
neben dem Versions-Counter; damit auch vom IACE-Export-Badge erreichbar
Tests: 3 neue Go-Tests, 4 neue pytest-Tests, alle gruen
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
85e758b250 | Merge feat/dsms-stufe2-evidence-techfile: tech-file DSMS archive with audit-trail CID | ||
|
|
2b1fe3713a |
feat(dsms): tech-file DSMS archive now logs CID into IACE audit trail
Before: archiveTechFile called dsms.Archive() and discarded the result. The
file was archived to IPFS but no audit-trail entry was written, so there
was no way to later prove "this CE-Akte export went to DSMS with CID X".
After:
- archiveTechFile is now a method on IACEHandler with access to store + gin
context, and captures the CID from dsms.Archive().
- Writes an AuditAction "tech_file_export" audit entry whose new_values
JSON carries {cid, filename, size}, mirroring the Python evidence-upload
pattern.
- Applies to PDF, XLSX, DOCX, and Markdown exports.
Plus dsms package gets 3 unit tests pinning the contract: success-CID
extraction, gateway-unreachable returns nil, 500-response returns nil.
This closes DSMS Stufe 2 (evidence side was already wired; tech-file side
was missing the audit hook). Stufe 3 next: version chains + delta view.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
0a84c747f2 |
feat(iace): wire crossref into tech-file, library UI, and contract tests
Three follow-ups to the 671-norm cross-reference matrix: 1. Tech-file renderer (Go): standards_applied section now gets a deterministic Markdown appendix with the DIN/ANSI/GB/JIS mappings for the project's suggested norms. Built from registry, never hallucinated by LLM. Applied both to LLM and fallback content paths. 2. Frontend NormCrossRefPanel (Next.js): expandable row in the IACE library norms tab now has a "Internationale Aequivalenzen anzeigen" button that lazy-loads /iace/norms-library/:id/crossref and renders a colour-coded table (relation + confidence). Region labels humanised (US — ANSI, China (GB), Japan (JIS), etc.). 3. Contract tests (Go): 4 new handler tests pinning the response shape of GetNormCrossRef and ListNormCrossRefs. Equivalent to an OpenAPI snapshot for these specific endpoints — ai-compliance-sdk has no full OpenAPI baseline yet (separate ticket). Tests: 6 renderer tests + 4 handler contract tests, all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d9278f256e |
feat(iace): norm cross-ref batches 6-7 complete — full 671/671 coverage
- Batch 6 (100): EN 1870 saws, EN 81 lift sub-parts, hearing/glove PPE, EN 50126 railway, EN 60974 welding, EN 60335-2-x cleaning appliances - Batch 7 (71): IEC 60601 medical family, EN ISO 19085 woodworking, safety footwear (ASTM F2413), fitness (ASTM F2276), chainsaws (OPEI B175.1), ISO 4254 agri remainder, acoustics ISO 3743/3745/3747 671 of 671 norms now have at least DIN mapping; ~80% have a US (ANSI/NFPA/ UL/OSHA/ASME/ASTM/SAE/NIOSH) mapping; ~40% have CN-GB and/or JP-JIS. Added TestCrossRef_SpotChecks with 15 manually vetted region mappings (IEC 60601 → ANSI/AAMI ES60601, EN 13445 → ASME BPVC, EN 60204 → NFPA 79, ISO 10218 → RIA R15.06, etc.). Next steps for follow-up work: - Add OpenAPI snapshot for new /norms-library/crossref endpoints - Front-end: render crossref panel on /sdk/iace norm detail page - Tech file: auto-emit "this requirement also satisfies X in market Y" hints Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0dbd7b4e45 |
feat(iace): norm cross-ref batches 2-5 (200 more → 500/671 covered)
- Batch 2: C-norms (woodworking, food, conveyors, lifts, agri, packaging) - Batch 3: machining, escalators, piping, boilers, wind/PV, refrigeration - Batch 4: paper sub-parts, playground (ASTM F1487), aircraft ground support, scaffolds, wire ropes, crane design EN 13001 - Batch 5: glass (EN 13035), ladders (ANSI A14), pools (APSP), explosives (DOT 49 CFR), amusement rides (ASTM F2291), drilling/foundation, eye protection (ANSI Z87.1), fire-fighting vehicles (NFPA 1901) 500 of 671 norms now have international identifier mappings. 171 remaining will be covered in batches 6-7 (alphabetically: EN-1870-x remainder onward plus ISO-x specials). Tests: TestCrossRef_BatchCoverage expects 500. All 8 cross-ref tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ff100c1cb8 |
feat(iace): norm cross-reference matrix, batch 1 (ISO/DIN/ANSI/GB/JIS — 100 entries)
Adds a jurisdiction-cross-reference layer to the norms library. Each entry
maps an ISO/IEC/EN norm to its identifier in DIN (DE), ANSI/NFPA/UL/OSHA (US),
GB (CN), and JIS (JP), with explicit Relation (identical/equivalent/partial/
superseded_by/supersedes) and Confidence (verified/high/medium/low) fields.
Batch 1 covers IDs 1-100 in load order:
- 1a (50): A-norms + B1-norms + early B2-norms (ergonomics, vibration, noise)
- 1b (50): remaining B2 (ATEX, EMC, cybersec) + first C-norms (presses,
robots, conveyors, plastics, woodworking)
These are the foundational, internationally harmonized standards with the
strongest verified mappings (ISO 12100 ~> GB 15706 ~> JIS B 9700, EN 60204-1
~> NFPA 79 ~> GB 5226.1 ~> JIS B 9960-1, etc.).
API:
- GET /iace/norms-library?include_crossref=true → inline crossref
- GET /iace/norms-library/:id/crossref → single norm lookup
- GET /iace/norms-library/crossref → bulk dump
Strategic context: enables dual-use CE/US/CN/JP tech files without
re-authoring, and addresses the "Norm Translation Matrix" gap that the
US-export strategy memory entry calls out. 6 batches remaining (~571 norms)
to reach full library coverage.
Tests: 6 new tests; all pass via `go test -vet=off ./internal/iace/`.
(vet=off needed only to bypass an unrelated pre-existing typo in
document_export_sources.go.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
772ff35e8d |
feat(iace): bridge OSHA MD library to pattern engine, body-part-specific lift crush hazards
- M600-M604: lift endstop mitigations (Kriechgeschwindigkeit, Schaltleiste, Mindestabstand, Hold-to-run, Trittblech) — cite OSHA + EN ISO identifiers - HP2100-HP2102: body-part crush patterns for lift family (foot under platform, hand/body against fixed structure, leg between lift and lateral structure), restricted via MachineTypes filter - pattern_machinetype_overrides.go: post-load pass fills MachineTypes on 14 legacy patterns (HP1000 Walzen, HP539 Schweiss, HP545/HP782 Glas, HP756/HP757/HP760 Fahrtreppe, HP1400-1402 CNC, HP045/HP049 Pressen, HP420-422 Conveyor) to prevent drift on Kistenhubgeraet-style projects Why: Kistenhubgeraet re-init exposed two gaps — the abstract "Bremse versagt bei Absenkbewegung" pattern fired but the concrete foot-crush body-part variant was missing, AND ~10 unrelated patterns fired purely because their RequiredTags incidentally aligned. Override map avoids touching 1000+ LOC pattern files that already exceed the soft cap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
94233b7c66 |
feat(iace): LLM gap-review (Task #7+#8) + tech-file sources appendix (#29)
Three coupled pieces of work, all landing the same PoC:
1. Backend gap-review endpoint (Task #7)
- internal/api/handlers/iace_handler_gap_review.go:
POST /projects/:id/llm-gap-review
feeds Limits-Form + current hazards + current mitigations to
the configured LLM (Qwen / Claude / OpenAI via ProviderRegistry),
parses a JSON suggestion list, filter+stamps confidence, falls
back to a static checklist when LLM is unavailable.
- Adopt step is NOT in this endpoint by design — the user clicks
Adopt in the frontend which calls the existing CreateHazard /
CreateMitigation handlers so provenance flows through the normal
audit trail.
2. Frontend modal + button (Task #8)
- app/sdk/iace/[projectId]/hazards/_components/LLMGapReviewModal.tsx:
reusable modal that POSTs the gap-review endpoint, renders
suggestions with Adopt/Reject UX, shows confidence + norm refs,
source-stamp llm_gap_review vs fallback_static.
- hazards/page.tsx: indigo "KI-Gap-Review" button next to the
existing "Eigene Gefaehrdung" button + modal mount.
3. Tech-File sources appendix (Task #29 — Stufe 4)
- internal/iace/document_export_sources.go: new pdfSourcesAppendix
method appended to ExportPDF. Groups cited norms by license rule
(R1 OSHA/EU-Recht / R3 BreakPilot patterns / R3 DIN-EN-ISO
identifier-only) and emits the legally required statement that
pauschal Impressum-Hinweise nicht ausreichen.
- extractCitedNorms() scans hazard/mitigation text for EN/ISO/IEC/
DIN identifiers in a narrow grammar so prose isn't turned into
spurious citations.
Bonus refactor:
- internal/app/routes.go reached the 500-LOC hard cap when the new
llm-gap-review route was added. Extracted registerIACERoutes into
routes_iace.go (136 LOC). Same wiring, no behaviour change.
Three of the four Attribution-Renderer stages (1, 2, 4) now produce
real output. Stufe 3 ships as <SourceBadge> + <LicenseModuleBanner>
already (commits
|
||
|
|
eb48c5bd1e |
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 |
||
|
|
16fd406c1a |
feat(iace): secondary-harm chain model + AllPatterns drift fix
Task #17 — Folgegefahren-Modell as Vorbereitungs-Commit (no DB schema change yet; persistence via separate [migration-approved] commit). New: - secondary_harms.go: SecondaryHarm struct + six canonical categories (consumer_safety, product_liability, food_safety, environmental, reputation, financial) with DE labels. - hazard_pattern_types.go: HazardPattern extended with optional SecondaryHarms field — pattern library can now attach consequential- damage chains. - hazard_patterns_secondary_demo.go: two worked examples - HP2000 Glasbruch carbonated bottling (the "Cola splitter" scenario from the IACE strategy discussion) with consumer_safety + food_safety + reputation chains - HP2001 Pharma fill-finish cross-contamination with consumer_safety + product_liability under AMG §84 Bonus fix: - compliance_crossover.go AllPatterns() was a duplicate enumeration that silently drifted from collectAllPatterns() in pattern_registry.go. Pre-fix: 1058 patterns visible. Post-fix: 1213 patterns. The 155 invisible patterns included CRA, ISO12100 gaps, robot-cell, CNC extended, VDMA, textile-agri, GT-bremse — anything added after the original AllPatterns was authored. Audit-Suite (cmd/iace-audit) now sees the full set. Next steps for full secondary-harm rollout: - DB migration: hazards table + secondary_harms array column - API: surface secondary_harms in /projects/:id/hazards response - Frontend: collapsible Folgegefahren-Panel in HazardTable |
||
|
|
f534b52817 |
feat(iace): pattern audit suite + library hygiene wave
Add cmd/iace-audit CLI with 5 deterministic methods that find engine gaps without ground truth: - A reachability: 1058 patterns vs achievable tag universe - B consistency: components vs their declared hazard categories - C vocabulary: limits-form tokens vs keyword dictionary - D echo: limits-form sentences vs generated hazards (jaccard) - E hierarchy: hazards vs ISO 12100 design/protection/info levels Library fixes triggered by A+B+C findings: - tag_resolver: synonym map for electrical/pneumatic/hydraulic aliases - component_library: crush_point + EN03 (gravitational) on C014/C128 (Hubwerk family) - fixes HP1014/1015/1017/1018 which were silently weakly_reachable. noise_source added on 7 components (C006/C011/ C017/C020/C031/C041/C096). electrical_part on 8 drive components (C031/C032/C033/C034/C035/C036/C037/C038/C077/C092). cyber tag on 10 sensors (C081-C090) + 3 IT components (C111/C112/C116) + KI module C119 (ai_model added). pneumatic_part+hydraulic_part on valves C091/C093, hydraulic_part+chemical_risk on pump C097, moving_part on motion controller C075 - keyword_dictionary: EN03 added to aufzug/lift/hubwerk/hubgeraet (was wrongly EN04-only). New keyword entries for hub-action verbs: absenken/senken/anheben/heben + hubhoehe/hubweg/hubgeschwindig Audit impact: - A: weakly_reachable 409 -> 358 (-51 patterns now fully reachable) - B: incomplete components 46 -> 30 (-16, -33%) - HP1018 (Person unter absenkendem Maschinenteil eingeklemmt): weakly_reachable -> reachable Why: methods A/B/C surfaced that the Kistenhubgeraet test project generated 0 crush-under-load hazards despite OSHA 1910.212(a)(3) + EN ISO 12100 6.3.5.5 explicitly requiring them. Three orthogonal bugs (missing crush_point tag, wrong energy source mapping, missing action verbs in dictionary) silently disabled the entire lift crush pattern family. |
||
|
|
a1b380e211 |
fix(iace): getProject scan missed &p.CustomerName — single-project GET 500ed
Migration 031 added customer_name to the SELECT statement in three places (GetProject, ListProjects, ListVariants), and the per-row Scan needed the matching destination. The replace_all caught ListProjects + ListVariants but missed GetProject because of an indentation difference (single tab vs row-scope indentation). Result: GET /projects/:id returned "get project: number of field descriptions must equal number of destinations, got 18 and 17" which the frontend interpreted as "project has no data" and surfaced an empty UI even though hazards/mitigations/components were intact (118/282/16 on Bremsscheibe). Single-line fix: add &p.CustomerName to the GetProject scan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
a616b64273 |
feat(iace): Customer-Standard-Reuse across customer's prior projects
CI / detect-changes (push) Successful in 10s
CI / guardrail-integrity (push) Has been skipped
CI / branch-name (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 14s
CI / loc-budget (push) Failing after 19s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / test-go (push) Successful in 47s
CI / nodejs-build (push) Successful in 2m46s
CI / iace-gt-coverage (push) Successful in 28s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
[migration-approved] Task #22. The IACE module is used by a single Maschinenhersteller, but their plants land at many different end customers. When the safety expert commissions the second or third plant at the same customer, whole classes of mitigations (company-wide PPE rules, locked-out energy isolation, customer-standard signage) are already in place there — but rediscovered from scratch every project. Migration 031: iace_projects.customer_name TEXT + partial index. The customer is stored as a plain text field rather than a normalised iace_customers table (option A from the design discussion). A proper customer-management screen can promote this to a FK later without data loss. Backend store_customer_standards.go: - ListCustomerStandardSuggestions(projectID, includeVerified) collects mitigations from all non-archived prior projects sharing the same tenant_id AND case-insensitive customer_name. Aggregates by mitigation.name (since same-named measures from different prior projects collapse into one suggestion) and surfaces: • source_project_count + source_project_names • is_customer_standard / has_verified_instances flags includeVerified=false → strictly is_customer_standard=true includeVerified=true → also status='verified' - ImportCustomerStandardSuggestion(projectID, name): for every prior (mitigation.name → hazard.name) pairing, finds matching hazards in the current project (by name) and ensures a customer-standard mitigation exists. New rows via CreateMitigation (idempotent through the UNIQUE(hazard_id, name) from migration 030); existing rows are flipped to is_relevant=true + is_customer_standard=true + status='verified' via UPDATE. Routes: GET /api/v1/iace/projects/:id/customer-standards?include_verified= POST /api/v1/iace/projects/:id/customer-standards/import body {name} Frontend: - New page /sdk/iace/[projectId]/customer-standards with: • empty-state hint pointing to Auftrag → Kundenname • per-suggestion checkbox + per-row Übernehmen button • bulk "N übernehmen" button • toggle "Auch verifizierte einbeziehen" widening the pool • per-suggestion source_project_count + status badges - Sidebar item "Kundenstandards" (building icon) placed between Verifikation and Nachweise. - Order-page now mirrors Auftraggeber.Firmenname into the top-level customer_name column on save, so the Reuse feature is fed automatically without a separate input field. The same expert effect from migration 029's is_customer_standard flag — "I already know it's covered, no evidence needed" — now becomes a cross-project asset rather than a per-project annotation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0a64da74bb |
fix(iace/mitigations): idempotent CreateMitigation + UNIQUE(hazard_id, name)
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 56s
CI / iace-gt-coverage (push) Successful in 27s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 11s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 17s
CI / loc-budget (push) Failing after 17s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
[migration-approved]
The init-handler was non-idempotent. A second click on "Neu initialisieren
in Grenzen" inserted every engine-suggested mitigation a second time —
e.g. the Bremsscheibe project ended up with 5 (hazard_id, name) duplicate
pairs (HMI-Usability-Pruefung, Eindeutiges visuelles Feedback,
Betriebsarten-Anzeige, Sicher begrenzter Bewegungsbereich, …). 45 such
duplicates accumulated across all projects.
Migration 030_iace_mitigation_unique.sql:
1. Picks one winning row per (hazard_id, name) using a stable rank:
is_relevant DESC (expert decision wins over engine default)
status DESC (verified > implemented > planned)
created_at DESC (newest beats older on otherwise-equal rows)
and deletes the losers (Bremsscheibe: 5 rows; total: 45).
2. Adds UNIQUE constraint iace_mitigations_hazard_name_uniq
(hazard_id, name).
Store-Layer (CreateMitigation):
INSERT … ON CONFLICT (hazard_id, name) DO NOTHING RETURNING id.
pgx.ErrNoRows from RETURNING → look up the existing row and return that.
Callers (engine init + manual add) always get a usable Mitigation; the
second click is silently swallowed instead of failing.
Frontend dedupe in groupByTitle stays — it covers any pre-existing
duplicates that survived the migration in edge cases (multi-row write
in flight, etc.). With the UNIQUE constraint live, the in-memory
dedupe is a belt-and-suspenders safety net rather than the load-bearing
mechanism.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
8f4f59f0e3 |
feat(iace/mitigations): is_relevant + is_customer_standard flags
[migration-approved]
Expert-driven workflow refinement on the Massnahmen page. The engine seeds
~80 mitigations per project, but for a concrete customer site most need a
relevance decision before they're meaningful in verification:
status: 'planned' | 'implemented' | 'verified' (existing — verification track)
is_relevant bool (new) (does this apply to *this* site?)
is_customer_standard bool (new) (already in place at customer — no evidence)
Decision flow on the Mitigations tab:
Engine-seeded → is_relevant=false (Default, waiting for expert)
Expert checks "Relevant" → is_relevant=true → surfaces in verification
Expert clicks trash → DELETE (banner warns: do not click Reinit
afterwards or seeds come back)
In verification, customer_standard=true bypasses evidence upload
is_customer_standard implies is_relevant (DB CHECK constraint).
Migration 029_iace_mitigation_relevance.sql:
ALTER TABLE iace_mitigations ADD COLUMN is_relevant ..., is_customer_standard ...
+ CHECK constraint + partial index on is_relevant for the verification
page's filter.
Backend (Go):
- Mitigation struct gains two bool fields
- CreateMitigation: defaults to false/false (engine-seeded mitigations
start unbewertet)
- UpdateMitigation: new case clauses for both keys; setting
is_customer_standard=true auto-flips is_relevant=true to satisfy
the CHECK constraint
- All three SELECT statements (ListMitigations, ListMitigationsByProject,
getMitigation) extended with the two new columns
Frontend:
- Maßnahmen-page columns: [Relev. ☑] [Lösch. 🗑] Title | #Hazards | P·I·V
- Group-header checkbox shows tri-state (indeterminate when partial),
flips all instances in the group at once
- Banner above the table: "Markiere jede Maßnahme als Relevant oder
lösche sie. Nach Löschen kein Neu initialisieren mehr drücken."
- Relevant rows tinted emerald, customer-standard label visible
- Legacy bulk-select state + helpers removed (the Relevant checkbox
now IS the primary mass action)
- useMitigations gains handleSetRelevant, handleSetCustomerStandard,
handleDeleteSilent (for non-confirm bulk deletes)
Future use: is_customer_standard mitigations from a prior project at the
same customer can later be auto-suggested when commissioning the next
plant — turning expert knowledge into reusable customer-profile data.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4a5924b8c4 |
feat(iace): CRA / DIN EN 40000-1-2 cyber-resilience spur
[guardrail-change]
Phase 18 adds an EU Cyber Resilience Act compliance track to IACE:
the engine now fires patterns that surface the manufacturer-side CRA
obligations whenever a project's components carry digital elements.
Patterns (HP1910-HP1918, hazard_patterns_cra.go):
HP1910 Missing SBOM
HP1911 Unsigned firmware/software updates
HP1912 Factory-default credentials still active
HP1913 No coordinated vulnerability disclosure (CVD) policy
HP1914 No documented security patch SLA
HP1915 Missing user-facing hardening guide
HP1916 No incident-notification process to ENISA / CSIRT
HP1917 No security assessment prior to placing on market
HP1918 AI component without cybersecurity risk assessment
Each pattern carries ClarificationQuestionsDE so the operator gets
auditor-grade questions to take back to the Anlagenbauer instead of
the engine inventing prose. PatternMatch carries DefaultAvoidability
(P=1 for all CRA patterns), feeding the PLr graph from Phase 17.
Measures (M540-M548, measures_library_cra.go):
M540 SBOM (SPDX or CycloneDX) with each machine release
M541 Signed updates with rollback protection
M542 Forced default-password change at first boot
M543 Published CVD policy (security.txt / PSIRT)
M544 Documented patch SLA with CVSS-tier response times
M545 User-facing hardening guide in the machine docs
M546 ENISA incident-notification process (24h/72h/14d)
M547 Authenticated update channel + integrity check
M548 Pre-market security assessment / pen-test
The library is urheberrechtlich neutral: identifiers only
(Verordnung (EU) 2024/2847, DIN EN 40000-1-2 Entwurf, IEC 62443,
ETSI EN 303 645, ISO/IEC 5962, ISO/IEC 29147). No normative text
is reproduced — DIN/Beuth proprietary content is referenced by
section number only.
Category-compatibility:
cyber_resilience pattern category accepts measures with
HazardCategory cyber_resilience, cyber_network, or
software_control. Updated in both the runtime helper
(iace_handler_init_helpers.go) and its test-mirror
(pattern_coverage_test.go) — both must move in lockstep.
Frontend (clarifications page):
When at least one clarification references "2024/2847" or
"40000-1-2" in its norm_references, a blue info-banner is
rendered at the top of the page:
"Cyber Resilience Act (CRA) — Hinweis zur Geltung
Diese Klärungsliste enthält Fragen zur Verordnung (EU)
2024/2847 (CRA). Die CRA gilt für Produkte mit digitalen
Elementen, die ab dem 11.12.2027 auf dem EU-Markt bereit-
gestellt werden. ..."
Reminds the user that the CRA pflichten are forward-looking
while still allowing the manufacturer to bake them in now.
LOC exceptions:
Added three pre-existing files to .claude/rules/loc-exceptions.txt
(manufacturer_safety_features.go, iace_handler_clarifications.go,
routes.go). All three grew across Phases 16-17 and are tagged as
Phase 5+ refactor backlog. [guardrail-change] marker required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
2afa5a179b |
feat(iace): Risikograph EN ISO 13849-1 PLr + Methoden-Kopf im Bericht
Phase 17 of the risk-assessment polish. Two pieces:
A) PLr per EN ISO 13849-1 Anhang A (Risikograph)
- HazardPattern.DefaultAvoidability (1 = P1, 2 = P2). Optional;
defaults to P1 if unset (conservative — operator can raise after
review).
- ComputePLr(s,f,p) implements the canonical 8-leaf binary tree
(S1F1P1 -> a, ..., S2F2P2 -> e). Pinned by 8 table-driven tests.
- SeverityToS / ExposureToF map the existing 1-5 fields to the
binary S/F at the documented threshold (3).
- At project initialise, every hazard's Description is appended
with "Risikograph EN ISO 13849-1 (Anhang A): S2 · F1 · P1 -> PLr c"
so the audit value is visible without leaving the hazard view.
- PatternMatch carries DefaultAvoidability so the init handler can
pick it up without a second pattern lookup.
B) Methoden-Kopf am Bericht
- GET /clarifications.html now opens with a standardised methodology
block: ISO 12100 Anhang B (hazard ID) + ISO 13849-1 Anhang A
(PLr graph) + ISO 12100 6.2/6.3/6.4 (reduction hierarchy). Same
wording on every export, ready for the Anlagenbauer-Uebergabe.
- Only norm identifiers — no norm text reproduced.
C) ISO12100Section in Hazard Description
- When a pattern is labeled with ISO12100Section, the hazard
description gets a "Klassifikation: EN ISO 12100 Anhang B,
Abschnitt 6.3.5.4" suffix. Provenance for the auditor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
71d31c914b |
feat(iace): ISO 12100 Anhang B mapping — split noise/vibration + section identifier
Phase 16 of the Klaerungen / risk-assessment polish. Sources from
EN ISO 12100 Anhang B Tabelle B.1 are now first-class:
A) HazardPattern.ISO12100Section identifier (string), persisted only as
the section number (e.g. "6.3.5.5") — not the norm text. Keeps the
library urheberrechtlich neutral (DIN/Beuth license). 57 patterns
labeled today; rest will follow on touch.
B) Category split per ISO 12100 Nr. 4 vs Nr. 5:
- 16 patterns reclassified noise_vibration -> noise_hazard
- 7 patterns reclassified noise_vibration -> vibration_hazard
- 1 pattern (HP228 UV-/Laermexposition) kept multi-cat
acceptableMeasureCategories now accepts both new aliases plus the
legacy noise_vibration. Coverage test recognises both as valid.
C) 5 new ISO-12100-Annex-B gap patterns (HP1900-HP1904):
- HP1900 Vakuum-Verletzung (6.3.5.5)
- HP1901 Federenergie / elastische Elemente (6.2.10)
- HP1902 Rutschen/Stolpern auf rauer Oberflaeche (6.3.5.6)
- HP1903 Hochdruckinjektion (6.3.5.4) — includes clarifying
"no hand-locating of leaks" question
- HP1904 Ersticken durch Brustkorbquetschung (6.3.5.2)
The library now mirrors the ISO 12100 Annex B structure for the gaps
the Bremse benchmark surfaced.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
c4be077c5d |
feat(iace): Klaerungen Phase 3 — DB-Tabelle + Multi-User + PDF-Export
[migration-approved]
Three pieces complete the Klaerungen lifecycle:
1. Migration 028: iace_clarifications + iace_clarification_comments +
iace_clarification_history. Deterministic clarification_key
(UNIQUE per project) so engine re-inits don't lose answers.
History table logs every status/answer transition. The previous
JSONB-in-metadata storage is kept as read-only fallback for
pre-migration projects until a one-shot upcopy script runs.
2. Multi-User-Workflow:
- assigned_to field on every clarification (free-text user kuerzel
for now; an FK to users can be added in a follow-up).
- Comment thread per clarification (POST .../comment, GET
.../detail returns the thread).
- Status-history log written by UpsertClarification when the
status or answer actually changes.
- Frontend Modal: Zugewiesen-an + Bearbeiter fields, comment
thread with inline post, collapsible history section.
3. PDF-Export via print-friendly HTML:
- GET /clarifications.html returns a standalone A4-styled
document with status badges, norm references, affected hazards
and a signature row at the bottom. The Bediener opens the link
and uses Strg-P / Cmd-P to save as PDF. No server-side PDF
dependency added.
- Frontend "PDF / Druck" button next to CSV export.
Backend:
- internal/iace/store_clarifications.go: UpsertClarification,
ListClarificationsForProject, GetClarificationByKey,
AddClarificationComment, ListClarificationComments,
ListClarificationHistory.
- internal/api/handlers/iace_handler_clarifications.go:
- AnswerClarification now writes the SQL row, falls back to legacy
JSONB read on list.
- PostClarificationComment, ListClarificationDetail,
ExportClarificationsHTML added.
Migration must be applied manually on Mac Mini and prod via
psql -f /migrations/028_iace_clarifications.sql — pattern as in
scripts/apply_*_migration.sh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f19a75d83d |
feat(iace): Klaerungen Phase 2 — Sidebar-Counter + CSV-Export + Hazard-Banner
Three pieces complete the Klaerungen UX: 1. Sidebar-Counter: layout.tsx polls /clarifications and shows a colored open-count badge on the "Klaerungen" nav item. Refreshes whenever the user changes route. 2. CSV-Export: new backend endpoint GET /sdk/v1/iace/projects/:id/clarifications.csv produces a UTF-8- BOM-prefixed semicolon-separated CSV (Excel-friendly) with ID, Quelle, Kategorie, Frage, Status, Antwort, Begruendung, Bearbeiter, answered_at, anzahl Gefaehrdungen, Gefaehrdungs-Namen, Norm-Refs. Frontend Klaerungen-Seite bekommt einen "CSV-Export"-Button. 3. Hazard-Banner statt Fragentext im Benchmark-Detail: the previous bulleted clarification list was duplicated across 48 hazards for a single FANUC question. Phase 2 replaces it with a compact status badge — "N offene Klaerung(en) — Klaerungen-Seite oeffnen" (orange) or "Alle N Klaerungen beantwortet" (green) with a direct link. Backend cleanup: iace_handler_init.go no longer appends the "Mit Anlagenbauer zu klaeren" block to Hazard.Description. The description stays focused on the scenario; clarifications live in the dedicated endpoint and answers persist across re-inits via project.metadata. The aggregated "Referenzierte Normen" line on the hazard is kept. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
79efa54898 |
feat(iace): Klaerungen MVP — Phase 1
New page "Klaerungen" between Massnahmen and Verifikation.
Backend:
- internal/iace/clarifications.go: Clarification struct + ClarificationAnswer +
BuildProjectClarifications() — aggregates pattern-level + manufacturer-
level questions from collectAllPatterns + GetManufacturerSafetyFeatures.
Deterministic IDs ("pattern:HP1640:0", "manuf:fanuc:dual-check-safety-dcs:1")
so persisted answers survive every re-init.
- internal/api/handlers/iace_handler_clarifications.go:
- GET /projects/:id/clarifications returns aggregated list with affected
hazard names + persisted answer state, sorted (open first).
- POST /projects/:id/clarifications/:cid/answer writes status/answer/
reasoning/answered_by/answered_at to project.metadata.clarification_-
answers — no DB schema change.
Frontend:
- admin-compliance/app/sdk/iace/layout.tsx: new "Klaerungen" nav item.
- app/sdk/iace/[projectId]/clarifications/page.tsx: table grouped by
source (FANUC / Pattern HP1640 / …), Filter Offen/Beantwortet/Alle,
search field, Antwort-Modal with status/answer/Begruendung/Bearbeiter.
A clarification answered once applies to ALL referenced hazards — the
operator no longer has to answer the same FANUC DCS question on 48
mechanical hazards individually.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
e9002175ac |
feat(iace): manufacturer safety feature library (Stufe A — 50+ entries)
Adds a curated database of safety-relevant features for the major
manufacturers across mechanical/plant engineering, written entirely in
own words with norm anchors. No verbatim manufacturer texts — therefore
no copyright issue:
- Markennennung (§ 23 MarkenG nominative use) is permitted.
- Fakten ueber Produkt-Sicherheitsfunktionen are not protected by § 2
UrhG (only Werke, not facts).
- NormReferences contain only the identifiers (e.g. "EN ISO 13849-1
PLd Kat.3"), never the norm text itself.
Coverage (52 entries across 12 categories):
Industrieroboter (10): FANUC DCS, KUKA SafeOperation, ABB SafeMove,
Yaskawa FSU, Staeubli CS9, Kawasaki Cubic-S, Mitsubishi MELFA,
Universal Robots PolyScope, Doosan PRS, Comau SafeNet
CNC/WZM (8): DMG MORI, Mazak, TRUMPF, Okuma, Hermle, Heidenhain
SPLC, GROB, Heller
Pneumatik (4): Festo, SMC, AVENTICS, Parker
Hydraulik (3): Bosch Rexroth, HAWE, HYDAC
Safety-PLC / Sicherheitstechnik (8): PILZ, SICK, Schmersal, Euchner,
Leuze, Phoenix Contact, Banner, Wieland
Standard-PLC (5): Siemens, Beckhoff, Rockwell, Schneider, B&R
Pressen (3): Schuler, Bruderer, AIDA
Spritzguss (3): Arburg, KraussMaffei, ENGEL
Verpackung (2): Krones, Bosch Packaging/Syntegon
Laser/Schweissen (3): Bystronic, Amada, Fronius
Foerdertechnik (2): Interroll, SEW EURODRIVE
Engine integration:
- LookupManufacturerFeaturesInText() scans the project narrative for
any of the manufacturer aliases (case-insensitive, umlaut-tolerant).
- Init-Handler appends matched feature clarifications to the relevant
hazard's "Mit Anlagenbauer zu klaeren:" block — for the right
HazardCategory only (e.g. FANUC DCS only on mechanical_hazard).
- For a Bremse project narrative mentioning "Fanuc Robodrill", the
engine now adds clarification questions like "Ist DCS am Roboter
konfiguriert?" to relevant mechanical hazards automatically.
Tests: 7 new pin tests — manufacturer count, norm prefixes, FANUC/KUKA
detection in narrative, umlaut robustness (Staeubli vs Staubli).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|