diff --git a/modules/mesh-delivery-watchman/internal/watch/finding.go b/modules/mesh-delivery-watchman/internal/watch/finding.go index b0707089..837e3db3 100644 --- a/modules/mesh-delivery-watchman/internal/watch/finding.go +++ b/modules/mesh-delivery-watchman/internal/watch/finding.go @@ -66,15 +66,29 @@ func (f Finding) Key() string { return FindingKey(f.Scope, f.ID, token) } +// KeyID is an id as the parts of a key: each dot-separated part made safe for a bus key, as the key of a condition is +// (mcc.Key), so the finding's key keeps the shape its condition had. +func KeyID(id string) string { + parts := strings.Split(id, ".") + for i, p := range parts { + p = unsafeKey.ReplaceAllString(strings.TrimSpace(p), "_") + if p == "" { + p = "_" + } + parts[i] = p + } + return strings.Join(parts, ".") +} + // Contract is f as the seat mesh-conditions' generated finding (design 47 G §686, §689): a ref, where the finding has a // token other than its kind, goes into the id as `.` (A-14), and is kept in `ref` so the finding reads back as // it was written. The resolved words are not a field of the seat (A-22), and its `at` is its `since`, so the same thing // observed again writes the same bytes. func (f Finding) Contract() condseat.Finding { - id, ref := f.ID, "" + id, ref := KeyID(f.ID), "" if f.Token != "" && f.Token != f.Kind { ref = f.Token - id = f.ID + "." + ref + id = id + "." + KeyID(ref) } v := condseat.Finding{Scope: f.Scope, ID: id, Kind: f.Kind, Ref: ref, Severity: f.Severity, Summary: f.Summary, Headline: f.Headline, Explanation: f.Explanation, Needs: f.Needs, Source: f.Source, Observer: Observer,