diff --git a/internal/domain/observation.go b/internal/domain/observation.go index 853e1b4..4630ea5 100644 --- a/internal/domain/observation.go +++ b/internal/domain/observation.go @@ -90,7 +90,11 @@ func (i ObservationIncident) Key() string { } var ( - observationID = regexp.MustCompile(`\b[0-9A-HJKMNP-TV-Z]{26}\b`) + // Case-insensitive: a task id appears upper-case in a message and + // lower-case inside a pane name, and the live ledger's first run showed + // pane names keeping their task, which would give the same failure a + // different signature on every task. + observationID = regexp.MustCompile(`(?i)\b[0-9A-HJKMNP-TV-Z]{26}\b`) observationSHA = regexp.MustCompile(`\b[0-9a-f]{7,64}\b`) observationDuration = regexp.MustCompile(`\b\d+(\.\d+)?(ns|us|µs|ms|s|m|h)(\d+(\.\d+)?(ns|us|µs|ms|s|m|h))*\b`) observationNumber = regexp.MustCompile(`\b\d+\b`) diff --git a/internal/operations/observations_test.go b/internal/operations/observations_test.go index a140fab..fc5874e 100644 --- a/internal/operations/observations_test.go +++ b/internal/operations/observations_test.go @@ -207,3 +207,14 @@ func TestSignatureCollapsesIdsAndCounts(t *testing.T) { t.Fatal("two different failures collapsed to one signature") } } + +// The first live run of the ledger caught this: a pane name carries the task +// id in lower case, so the same failure signed differently on every task and +// could never accumulate recurrence. +func TestSignatureCollapsesAPaneName(t *testing.T) { + a := domain.ObservationSignature(`phase rotation 06G4XAFH1MBPC35VSJN7V3NS14: pane orchestra-06g4xafh1mbpc35vsjn7v3ns14-be13b045:1.0 still holds input`) + b := domain.ObservationSignature(`phase rotation 06G4WW6TND26M16CZA6WE5T458: pane orchestra-06g4ww6tnd26m16cza6we5t458-4d839c05:1.0 still holds input`) + if a != b { + t.Fatalf("one failure has two signatures:\n%s\n%s", a, b) + } +}