dav: tag a refusal with the card it names
The fingerprint still folds the id, so one issue holds the lot;
the card now rides along as a tag, to search which ones were caught.
Assisted-by: Claude Opus 5 via Claude Code
diff --git a/lib/pro_tacts/refusal_alerts.rb b/lib/pro_tacts/refusal_alerts.rb
index 33fb400..ff53ca7 100644
--- a/lib/pro_tacts/refusal_alerts.rb
+++ b/lib/pro_tacts/refusal_alerts.rb
@@ -34,16 +34,21 @@ module ProTacts
private
# Fingerprinted on the route with the card id replaced, so Sentry
- # groups a refusal that repeats across cards as one issue.
+ # groups a refusal that repeats across cards as one issue. The id
+ # rides as the `card` tag instead, so an issue's events can be
+ # searched by card.
#: (Rack::env env, Integer status) -> void
def alert(env, status)
method = env.fetch("REQUEST_METHOD")
- route = env["PATH_INFO"].to_s.sub(%r{/[^/]+\.vcf\z}, "/{id}.vcf")
+ path = env["PATH_INFO"].to_s
+ card = path[%r{/([^/]+)\.vcf\z}, 1]
+ route = path.sub(%r{/[^/]+\.vcf\z}, "/{id}.vcf")
Sentry.capture_message(
"#{method} #{route} answered #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}",
level: :warning,
fingerprint: [method, route, status.to_s],
+ tags: card ? { card: } : {},
)
end
end
diff --git a/sig/gems/sentry.rbs b/sig/gems/sentry.rbs
index f1b8de7..0618afc 100644
--- a/sig/gems/sentry.rbs
+++ b/sig/gems/sentry.rbs
@@ -4,7 +4,7 @@
# and the photo decode refusal contact.rb captures. ExchangeLog tags the
# request's scope and reads whether anything was reported under it.
module Sentry
- def self.capture_message: (String message, ?level: Symbol, ?fingerprint: Array[String]) -> untyped
+ def self.capture_message: (String message, ?level: Symbol, ?fingerprint: Array[String], ?tags: Hash[Symbol, String]) -> untyped
def self.capture_exception: (Exception exception, ?level: Symbol) -> untyped
diff --git a/test/pro_tacts/test_refusal_alerts.rb b/test/pro_tacts/test_refusal_alerts.rb
index 1667c59..be421a2 100644
--- a/test/pro_tacts/test_refusal_alerts.rb
+++ b/test/pro_tacts/test_refusal_alerts.rb
@@ -56,6 +56,15 @@ class RefusalAlertsTest < Minitest::Test
assert_equal "PUT /dav/addressbook/{id}.vcf answered 412 Precondition Failed", sentry_messages.first
end
+ def test_the_card_a_refusal_names_is_a_tag
+ @status = 412
+
+ dav "/dav/addressbook/aiden.vcf"
+ dav "/dav/addressbook/"
+
+ assert_equal ["aiden", nil], sentry_events.map { it.tags[:card] }
+ end
+
def test_the_method_and_status_split_groups
@status = 412
dav "/dav/addressbook/aiden.vcf", method: "PUT"