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>
This commit is contained in:
@@ -113,6 +113,38 @@ func TestMeasureDistanceLinks_ValueSourceProseConsistency(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The name→ID resolver underpins surfacing OSHA anchors on persisted
|
||||
// mitigations (which store the name, not the catalog ID). It is only safe if
|
||||
// measure names are unique — pin that, and that the resolver round-trips for
|
||||
// every linked measure.
|
||||
func TestMeasureNames_UniqueAndResolvable(t *testing.T) {
|
||||
idByName := map[string]string{}
|
||||
nameByID := map[string]string{}
|
||||
for _, m := range GetProtectiveMeasureLibrary() {
|
||||
if prev, dup := idByName[m.Name]; dup {
|
||||
t.Errorf("duplicate measure name %q (IDs %s, %s) — name→ID resolver unsafe",
|
||||
m.Name, prev, m.ID)
|
||||
}
|
||||
idByName[m.Name] = m.ID
|
||||
nameByID[m.ID] = m.Name
|
||||
}
|
||||
|
||||
for _, l := range AllMeasureDistanceLinks() {
|
||||
name := nameByID[l.MeasureID]
|
||||
if name == "" {
|
||||
t.Errorf("linked measure %q not found in library", l.MeasureID)
|
||||
continue
|
||||
}
|
||||
gotID, ok := MeasureIDByName(name)
|
||||
if !ok || gotID != l.MeasureID {
|
||||
t.Errorf("MeasureIDByName(%q) = %q,%v; want %q", name, gotID, ok, l.MeasureID)
|
||||
}
|
||||
if len(MinimumDistancesForMeasureName(name)) != len(MinimumDistancesForMeasure(l.MeasureID)) {
|
||||
t.Errorf("name vs id resolution mismatch for %q", l.MeasureID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proseMentionsDistance reports whether the (dot-stripped, lowercased) measure
|
||||
// text contains a numeric form of the distance's value, formula or recommended mm.
|
||||
func proseMentionsDistance(text string, md MinimumDistance) bool {
|
||||
|
||||
Reference in New Issue
Block a user