fix(iace): pattern-specific measures take priority over category fallback
Each hazard now gets measures from its SOURCE PATTERN first (SuggestedMeasureIDs), then category fallback for remaining slots. Previously all mechanical hazards got the same generic top-5 measures (Gefahrstelle eliminieren, Sicherheitsabstaende, Scharfe Kanten...). Now a KSS-Schlauch hazard gets M420 (Druckfeste Auslegung) first. SuggestedMeasureIDs added to PatternMatch struct and passed through from pattern definition to hazard creation to measure assignment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -140,6 +140,7 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
|
||||
existingHazards, _ := h.store.ListHazards(ctx, projectID)
|
||||
hazardStep := InitStep{Name: "Gefaehrdungen erstellt", Status: "skipped"}
|
||||
hazardIDsByCategory := make(map[string][]uuid.UUID)
|
||||
hazardPatternMeasures := make(map[uuid.UUID][]string)
|
||||
|
||||
if len(existingHazards) == 0 && len(matchOutput.MatchedPatterns) > 0 {
|
||||
comps, _ := h.store.ListComponents(ctx, projectID)
|
||||
@@ -226,6 +227,10 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
|
||||
created++
|
||||
catCount[cat]++
|
||||
hazardIDsByCategory[cat] = append(hazardIDsByCategory[cat], hz.ID)
|
||||
// Remember this pattern's suggested measures for this hazard
|
||||
if len(mp.SuggestedMeasureIDs) > 0 {
|
||||
hazardPatternMeasures[hz.ID] = mp.SuggestedMeasureIDs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,42 +271,44 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
|
||||
}
|
||||
|
||||
// For each hazard: assign up to maxMitigationsPerHazard measures
|
||||
// Priority: pattern-suggested first, then category fallback
|
||||
suggestedByMeasCat := make(map[string][]iace.ProtectiveMeasureEntry)
|
||||
for _, sm := range matchOutput.SuggestedMeasures {
|
||||
if entry, ok := measureByID[sm.MeasureID]; ok {
|
||||
suggestedByMeasCat[entry.HazardCategory] = append(suggestedByMeasCat[entry.HazardCategory], entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 1: Pattern-specific SuggestedMeasureIDs (from the pattern that created this hazard)
|
||||
// Priority 2: Category fallback (generic measures for the hazard category)
|
||||
for _, hazID := range allHazardIDs {
|
||||
hazCat := hazardCatByID[hazID]
|
||||
measCat := patternCatToMeasureCat(hazCat)
|
||||
added := 0
|
||||
usedIDs := make(map[string]bool)
|
||||
|
||||
// First: pattern-suggested measures for this category
|
||||
for _, entry := range suggestedByMeasCat[measCat] {
|
||||
if added >= maxMitigationsPerHazard {
|
||||
break
|
||||
}
|
||||
rt := iace.ReductionType(entry.ReductionType)
|
||||
if rt == "" {
|
||||
rt = iace.ReductionTypeInformation
|
||||
}
|
||||
_, cerr := h.store.CreateMitigation(ctx, iace.CreateMitigationRequest{
|
||||
HazardID: hazID, ReductionType: rt,
|
||||
Name: entry.Name, Description: entry.Description,
|
||||
})
|
||||
if cerr == nil {
|
||||
created++
|
||||
added++
|
||||
// Priority 1: Pattern-specific measures
|
||||
if patternMIDs, ok := hazardPatternMeasures[hazID]; ok {
|
||||
for _, mid := range patternMIDs {
|
||||
if added >= maxMitigationsPerHazard {
|
||||
break
|
||||
}
|
||||
entry, ok := measureByID[mid]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
rt := iace.ReductionType(entry.ReductionType)
|
||||
if rt == "" {
|
||||
rt = iace.ReductionTypeInformation
|
||||
}
|
||||
_, cerr := h.store.CreateMitigation(ctx, iace.CreateMitigationRequest{
|
||||
HazardID: hazID, ReductionType: rt,
|
||||
Name: entry.Name, Description: entry.Description,
|
||||
})
|
||||
if cerr == nil {
|
||||
created++
|
||||
added++
|
||||
usedIDs[mid] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then: category fallback if still under limit
|
||||
// Priority 2: Category fallback (skip already-used IDs)
|
||||
for _, m := range measuresByCat[measCat] {
|
||||
if added >= maxMitigationsPerHazard {
|
||||
break
|
||||
if added >= maxMitigationsPerHazard || usedIDs[m.ID] {
|
||||
continue
|
||||
}
|
||||
rt := iace.ReductionType(m.ReductionType)
|
||||
if rt == "" {
|
||||
|
||||
Reference in New Issue
Block a user