noresponse 9.4.2 → 9.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/no_response/accounts.rb +2 -2
  3. data/lib/no_response/assessments.rb +1 -1
  4. data/lib/no_response/models/operations/listreviews_request.rb +10 -0
  5. data/lib/no_response/models/operations/listreviews_request.rbi +6 -0
  6. data/lib/no_response/models/shared/accountdirectorypage.rb +1 -1
  7. data/lib/no_response/models/shared/accountdirectorypageitem.rb +20 -2
  8. data/lib/no_response/models/shared/accountdirectorypageitem.rbi +12 -0
  9. data/lib/no_response/models/shared/accountdirectorysearchrequest.rb +20 -2
  10. data/lib/no_response/models/shared/accountdirectorysearchrequest.rbi +12 -0
  11. data/lib/no_response/models/shared/assessmentsearchitem.rb +20 -2
  12. data/lib/no_response/models/shared/assessmentsearchitem.rbi +6 -0
  13. data/lib/no_response/models/shared/assessmentsearchrequest.rb +11 -1
  14. data/lib/no_response/models/shared/assessmentsearchrequest.rbi +6 -0
  15. data/lib/no_response/models/shared/filter.rb +18 -1
  16. data/lib/no_response/models/shared/filter.rbi +6 -0
  17. data/lib/no_response/models/shared/identifiermatch.rb +105 -0
  18. data/lib/no_response/models/shared/identifiermatch.rbi +44 -0
  19. data/lib/no_response/models/shared/identifiersearch.rb +80 -0
  20. data/lib/no_response/models/shared/identifiersearch.rbi +32 -0
  21. data/lib/no_response/models/shared/identifiersearchkind.rb +20 -0
  22. data/lib/no_response/models/shared/identifiersearchkind.rbi +9 -0
  23. data/lib/no_response/models/shared/match.rb +20 -0
  24. data/lib/no_response/models/shared/match.rbi +9 -0
  25. data/lib/no_response/models/shared/namespace.rb +18 -0
  26. data/lib/no_response/models/shared/namespace.rbi +9 -0
  27. data/lib/no_response/models/shared/provenance.rb +18 -0
  28. data/lib/no_response/models/shared/provenance.rbi +9 -0
  29. data/lib/no_response/models/shared/waiting_for.rb +19 -0
  30. data/lib/no_response/models/shared/waiting_for.rbi +9 -0
  31. data/lib/no_response/models/shared.rb +7 -0
  32. data/lib/no_response/reviews.rb +3 -2
  33. data/lib/no_response/sdkconfiguration.rb +2 -2
  34. metadata +15 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4841d5bf61440a9ed5297a66f4e7d7fb820bed09831a82e47f82e64667b392ed
4
- data.tar.gz: 5066f04bd959fbc943c8db239e9f514d961a66a62c2482df743c37b1b00b5024
3
+ metadata.gz: 52bf0e469211da6bcdaa3def8fae14b509718f9099b95e0caefbcb5dc3d4b790
4
+ data.tar.gz: b071853ab63121d223b6707fb2c55577d0c932ea1a08b422ed05873107faf719
5
5
  SHA512:
6
- metadata.gz: a8c8a8067ffce9661db26303506a401a66c4ac29aa3762e22fd1cb2b2c19b9668e584efc4213616369b211c19cc36a3c42a211a6e00c171115234db3c0692b82
7
- data.tar.gz: e18056623cc7625e67347c7fe43b15751fa16d4e978f5acfa9a3e2718672b045771b28fada6c5cbf16dcc66eee7446de480927f17f75a049ccf19f99b2acd52a
6
+ metadata.gz: 72fbb0a9f8444ac044317a62e72c19d21d95767f76caa6304e9dc4204e0647d7e67d0ecbe82858963e98a3dda7214321c370e8b1c6dbcda14ae94e1c8e5dc867
7
+ data.tar.gz: a0db4c974286509b49ef6c63ca94836a8547736ad3d00a2d50e6928e3f418203b0e5fba31547759710e6c51c1285dca3d5b234999022f86ce25c3694b72475e9
@@ -4277,8 +4277,8 @@ module NoResponse
4277
4277
  .returns(Models::Operations::SearchAccountsResponse)
4278
4278
  }
4279
4279
  def search(request:, retries: nil, timeout_ms: nil, http_headers: nil)
4280
- # search - Search distinct accounts by email or account ID
4281
- # Search distinct accounts observed in retained assessments in this environment. Match an exact account_id or canonical email; an email matches any retained assessment belonging to the account. The response contains one row per account with its newest retained assessment, current decision when available, per-account assessment count, and total distinct-account count. Send next_cursor with unchanged filters to continue. Totals are exact below 10000 and capped at 10000. Results are live across pages. Requires history access and identifier access for email. Read-only and safe to retry.
4280
+ # search - Search distinct accounts by submitted identifier or account ID
4281
+ # Search distinct accounts observed in retained assessments in this environment. identifier matches an exact, canonical or explicitly selected mailbox form of a submitted email, phone or customer-namespace username. It matches historical retained inputs and returns matched_identifier with the original value and matching assessment. Each row has its newest retained assessment, current account decision when available, retained assessment count, and total distinct-account count. identifier and legacy email are mutually exclusive; account_id and needs_action combine with either using AND. Set needs_action to select accounts with a retained open or in-progress review, or a current review/block account decision without an effective retained account outcome. This filter applies before counting and pagination and adds waiting_for reasons. Current decisions include account list overrides and shared-key scoring and preserve admission holds. Typed identifier search uses stable opaque account order; ordinary and legacy email searches retain newest-seen order. Results are live across pages; each page's items and total share a database snapshot, while current account risk is read separately. Cursors are expiring and bound to scope, operation and filters. Totals are exact below 10000 and capped at 10000. Requires history or investigate authority and identifier-read permission for identifier or email filtering. needs_action additionally requires management scope. Source-discovered associations are not searched and equality is not verified ownership.
4282
4282
  url, params = @sdk_configuration.get_server_details
4283
4283
  base_url = Utils.template_url(url, params)
4284
4284
  url = "#{base_url}/v1/accounts/search"
@@ -1841,7 +1841,7 @@ module NoResponse
1841
1841
  }
1842
1842
  def search(request:, retries: nil, timeout_ms: nil, http_headers: nil)
1843
1843
  # search - Search assessments across this environment
1844
- # Search retained assessments created in [from,to), over at most 366 days. Filters use each assessment decision, rather than the current account decision. Results can change between pages. Keep the assessment version to retrieve the exact decision later. Each item's detail.identifiers holds the identifiers its assessment was sent, exactly as received, and first_decision holds the decision of its first answer. email finds every assessment of the accounts that sent a mailbox, matched as lists match it. changed keeps the assessments a later revision changed. total counts every match, exactly up to 10000. This read does not require an idempotency key.
1844
+ # Search retained assessments created in [from,to), at most 366 days. identifier directly matches that assessment's submitted email, phone or customer-namespace username using exact, canonical or explicitly selected email mailbox matching. matched_identifier explains the original value and match basis. Legacy email keeps its account-wide mailbox semantics and cannot be combined with identifier. Other filters combine using AND and describe assessment decisions, separate from current account decisions. Each item carries the original submitted identifiers and its first_decision when available. Newest-created order has an assessment-ID tie break. Results are live across pages; each page's total and items use one database snapshot. Totals are exact below 10000 and capped at 10000. Requires history or investigate authority and identifier-read permission for identifier/email filters; detailed mode also requires detailed permission. No Idempotency-Key.
1845
1845
  url, params = @sdk_configuration.get_server_details
1846
1846
  base_url = Utils.template_url(url, params)
1847
1847
  url = "#{base_url}/v1/assessments/search"
@@ -57,6 +57,12 @@ module NoResponse
57
57
  Crystalline::Nilable.new(::String),
58
58
  {'query_param': {'field_name': "assignee_principal_id", 'style': "form", 'explode': true}}
59
59
  )
60
+ # Only reviews of this exact account in the authenticated workspace and environment. Applied before pagination and bound into the cursor.
61
+ field(
62
+ :account_id,
63
+ Crystalline::Nilable.new(::String),
64
+ {'query_param': {'field_name': "account_id", 'style': "form", 'explode': true}}
65
+ )
60
66
 
61
67
  field(
62
68
  :limit,
@@ -74,6 +80,7 @@ module NoResponse
74
80
  assignee: T.nilable(::String),
75
81
  unassigned: T.nilable(T::Boolean),
76
82
  assignee_principal_id: T.nilable(::String),
83
+ account_id: T.nilable(::String),
77
84
  limit: T.nilable(::Integer)
78
85
  )
79
86
  .void
@@ -87,6 +94,7 @@ module NoResponse
87
94
  assignee: nil,
88
95
  unassigned: nil,
89
96
  assignee_principal_id: nil,
97
+ account_id: nil,
90
98
  limit: 50
91
99
  )
92
100
  @workspace_id = workspace_id
@@ -97,6 +105,7 @@ module NoResponse
97
105
  @assignee = assignee
98
106
  @unassigned = unassigned
99
107
  @assignee_principal_id = assignee_principal_id
108
+ @account_id = account_id
100
109
  @limit = limit
101
110
  end
102
111
 
@@ -111,6 +120,7 @@ module NoResponse
111
120
  return false unless @assignee == other.assignee
112
121
  return false unless @unassigned == other.unassigned
113
122
  return false unless @assignee_principal_id == other.assignee_principal_id
123
+ return false unless @account_id == other.account_id
114
124
  return false unless @limit == other.limit
115
125
  true
116
126
  end
@@ -54,6 +54,12 @@ class NoResponse::Models::Operations::ListReviewsRequest
54
54
  def assignee_principal_id=(str_)
55
55
  end
56
56
 
57
+ def account_id
58
+ end
59
+
60
+ def account_id=(str_)
61
+ end
62
+
57
63
  def limit
58
64
  end
59
65
 
@@ -4,7 +4,7 @@
4
4
  module NoResponse
5
5
  module Models
6
6
  module Shared
7
- # Accounts observed in retained assessments, newest seen first, with each account once per page and across pages. Counts and keyset pagination are computed over distinct accounts in one database snapshot per page. Live data can change between pages.
7
+ # Distinct observed accounts with retained assessments. Typed identifier searches use stable opaque account order, independent of newly submitted assessments; ordinary and legacy email searches use newest-seen order. One repeatable-read database snapshot supplies each page's rows and totals. Pages do not share a snapshot: new matching accounts may appear on a later page or before the cursor and be missed until a fresh search; retention, erasure and changed membership can remove results. Current account decisions are read separately and may advance during a page. Cursors bind the workspace/environment, operation and filters, expire, and cannot cross scopes. Erasure and retention always take precedence over pagination.
8
8
  class AccountDirectoryPage
9
9
  extend T::Sig
10
10
  include Crystalline::MetadataFields
@@ -27,27 +27,43 @@ module NoResponse
27
27
  ::Integer,
28
28
  {'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessments"), required: true}}
29
29
  )
30
+ # Present for needs_action searches. outcome means a current review/block decision lacks a retained effective outcome; review means a retained open or in-progress review. Both can apply.
31
+ field(
32
+ :waiting_for,
33
+ Crystalline::Nilable.new(Crystalline::Array.new(Models::Shared::WaitingFor)),
34
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("waiting_for")}}
35
+ )
30
36
  # Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling workspace's accounts. It is the risk of the account's latest assessment that has a decision (status complete or partial), by created_at and then assessment_id, scored exactly as GET /v1/assessments/{assessment_id} scores that assessment, plus the account's own reason shared_api_key when a key issued to the account was used from many IP addresses or countries (POST /v1/key_usage/batches). Its assessments are the account's history (GET /v1/accounts/{account_id}/assessments).
31
37
  field(
32
38
  :current,
33
39
  Crystalline::Nilable.new(Models::Shared::Account),
34
40
  {'format_json': {'letter_case': ::NoResponse::Utils.field_name("current")}}
35
41
  )
42
+ # Why this result matched a typed identifier search. value is the original value submitted in assessment_id. Provenance records a customer submission, not a source discovery or verified ownership. Equality is deterministic and has no inferred confidence score. An account result names its newest retained matching assessment, which can differ from latest.
43
+ field(
44
+ :matched_identifier,
45
+ Crystalline::Nilable.new(Models::Shared::IdentifierMatch),
46
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("matched_identifier")}}
47
+ )
36
48
 
37
49
  sig {
38
50
  params(
39
51
  account_id: ::String,
40
52
  latest: Models::Shared::AssessmentRevision,
41
53
  assessments: ::Integer,
42
- current: T.nilable(Models::Shared::Account)
54
+ waiting_for: T.nilable(T::Array[Models::Shared::WaitingFor]),
55
+ current: T.nilable(Models::Shared::Account),
56
+ matched_identifier: T.nilable(Models::Shared::IdentifierMatch)
43
57
  )
44
58
  .void
45
59
  }
46
- def initialize(account_id:, latest:, assessments:, current: nil)
60
+ def initialize(account_id:, latest:, assessments:, waiting_for: nil, current: nil, matched_identifier: nil)
47
61
  @account_id = account_id
48
62
  @latest = latest
49
63
  @assessments = assessments
64
+ @waiting_for = waiting_for
50
65
  @current = current
66
+ @matched_identifier = matched_identifier
51
67
  end
52
68
 
53
69
  sig { params(other: T.untyped).returns(T::Boolean) }
@@ -56,7 +72,9 @@ module NoResponse
56
72
  return false unless @account_id == other.account_id
57
73
  return false unless @latest == other.latest
58
74
  return false unless @assessments == other.assessments
75
+ return false unless @waiting_for == other.waiting_for
59
76
  return false unless @current == other.current
77
+ return false unless @matched_identifier == other.matched_identifier
60
78
  true
61
79
  end
62
80
  end
@@ -24,9 +24,21 @@ class NoResponse::Models::Shared::AccountDirectoryPageItem
24
24
  def assessments=(str_)
25
25
  end
26
26
 
27
+ def waiting_for
28
+ end
29
+
30
+ def waiting_for=(str_)
31
+ end
32
+
27
33
  def current
28
34
  end
29
35
 
30
36
  def current=(str_)
31
37
  end
38
+
39
+ def matched_identifier
40
+ end
41
+
42
+ def matched_identifier=(str_)
43
+ end
32
44
  end
@@ -4,7 +4,7 @@
4
4
  module NoResponse
5
5
  module Models
6
6
  module Shared
7
- # Bounded distinct-account search for a single authenticated workspace/environment. Email matches any retained admitted assessment of an account, using assessment search's canonical mailbox rules. No assessment history download is required.
7
+ # Bounded distinct-account search for one authenticated workspace/environment. identifier matches any retained admitted assessment of an account, including historical submitted values. email preserves the legacy canonical-mailbox filter. identifier and email cannot be combined. All other filters combine using AND. Typed identifier search uses stable opaque account order; ordinary and legacy email searches retain newest-seen ordering. Pages are live, not a cross-page snapshot. Requires history or investigate authority and identifier-read permission for identifier or email filtering.
8
8
  class AccountDirectorySearchRequest
9
9
  extend T::Sig
10
10
  include Crystalline::MetadataFields
@@ -27,6 +27,18 @@ module NoResponse
27
27
  Crystalline::Nilable.new(::String),
28
28
  {'format_json': {'letter_case': ::NoResponse::Utils.field_name("cursor")}}
29
29
  )
30
+ # One customer-submitted identifier. Defaults to exact comparison of the original submitted value. canonical uses the supported identifier normalisation without an ownership claim: email preserves local-part case, NFC-normalises it and lowercases the domain without removing dots or tags; phone uses international E.164 without extensions or an inferred region; username uses NFC and Unicode case folding within the customer namespace. mailbox is email-only and explicitly selects existing list rules: case-insensitive, remove +tag, and ignore local-part dots at gmail.com and googlemail.com; googlemail.com maps to gmail.com. Username requires namespace customer. Email and phone forbid namespace. Source-discovered identifiers and platform handles are not searched. Unsupported kinds, namespaces, modes and invalid values return 400. Search equality does not establish verified ownership or merge accounts.
31
+ field(
32
+ :identifier,
33
+ Crystalline::Nilable.new(Models::Shared::IdentifierSearch),
34
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("identifier")}}
35
+ )
36
+ # Select accounts with a retained open or in-progress review, or a current review/block account decision with no retained effective account outcome. The server applies this filter before counting and pagination. Requires reviews.read as well as history.read for console members; API keys additionally require management.
37
+ field(
38
+ :needs_action,
39
+ Crystalline::Nilable.new(Crystalline::Boolean.new),
40
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("needs_action")}}
41
+ )
30
42
 
31
43
  field(
32
44
  :limit,
@@ -39,14 +51,18 @@ module NoResponse
39
51
  account_id: T.nilable(::String),
40
52
  email: T.nilable(::String),
41
53
  cursor: T.nilable(::String),
54
+ identifier: T.nilable(Models::Shared::IdentifierSearch),
55
+ needs_action: T.nilable(T::Boolean),
42
56
  limit: T.nilable(::Integer)
43
57
  )
44
58
  .void
45
59
  }
46
- def initialize(account_id: nil, email: nil, cursor: nil, limit: 25)
60
+ def initialize(account_id: nil, email: nil, cursor: nil, identifier: nil, needs_action: false, limit: 25)
47
61
  @account_id = account_id
48
62
  @email = email
49
63
  @cursor = cursor
64
+ @identifier = identifier
65
+ @needs_action = needs_action
50
66
  @limit = limit
51
67
  end
52
68
 
@@ -56,6 +72,8 @@ module NoResponse
56
72
  return false unless @account_id == other.account_id
57
73
  return false unless @email == other.email
58
74
  return false unless @cursor == other.cursor
75
+ return false unless @identifier == other.identifier
76
+ return false unless @needs_action == other.needs_action
59
77
  return false unless @limit == other.limit
60
78
  true
61
79
  end
@@ -24,6 +24,18 @@ class NoResponse::Models::Shared::AccountDirectorySearchRequest
24
24
  def cursor=(str_)
25
25
  end
26
26
 
27
+ def identifier
28
+ end
29
+
30
+ def identifier=(str_)
31
+ end
32
+
33
+ def needs_action
34
+ end
35
+
36
+ def needs_action=(str_)
37
+ end
38
+
27
39
  def limit
28
40
  end
29
41
 
@@ -70,6 +70,12 @@ module NoResponse
70
70
  }
71
71
  }
72
72
  )
73
+ # Why this result matched a typed identifier search. value is the original value submitted in assessment_id. Provenance records a customer submission, not a source discovery or verified ownership. Equality is deterministic and has no inferred confidence score. An account result names its newest retained matching assessment, which can differ from latest.
74
+ field(
75
+ :matched_identifier,
76
+ Crystalline::Nilable.new(Models::Shared::IdentifierMatch),
77
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("matched_identifier")}}
78
+ )
73
79
 
74
80
  sig {
75
81
  params(
@@ -79,11 +85,21 @@ module NoResponse
79
85
  depth: Models::Shared::Depth,
80
86
  detail: Models::Shared::AssessmentDetail,
81
87
  schema_version: ::String,
82
- first_decision: T.nilable(Models::Shared::Decision)
88
+ first_decision: T.nilable(Models::Shared::Decision),
89
+ matched_identifier: T.nilable(Models::Shared::IdentifierMatch)
83
90
  )
84
91
  .void
85
92
  }
86
- def initialize(id:, status:, flow:, depth:, detail:, schema_version: "1", first_decision: nil)
93
+ def initialize(
94
+ id:,
95
+ status:,
96
+ flow:,
97
+ depth:,
98
+ detail:,
99
+ schema_version: "1",
100
+ first_decision: nil,
101
+ matched_identifier: nil
102
+ )
87
103
  @id = id
88
104
  @status = status
89
105
  @flow = flow
@@ -95,6 +111,7 @@ module NoResponse
95
111
 
96
112
  @schema_version = "1"
97
113
  @first_decision = first_decision
114
+ @matched_identifier = matched_identifier
98
115
  end
99
116
 
100
117
  sig { params(other: T.untyped).returns(T::Boolean) }
@@ -107,6 +124,7 @@ module NoResponse
107
124
  return false unless @detail == other.detail
108
125
  return false unless @schema_version == other.schema_version
109
126
  return false unless @first_decision == other.first_decision
127
+ return false unless @matched_identifier == other.matched_identifier
110
128
  true
111
129
  end
112
130
  end
@@ -47,4 +47,10 @@ class NoResponse::Models::Shared::AssessmentSearchItem
47
47
 
48
48
  def first_decision=(str_)
49
49
  end
50
+
51
+ def matched_identifier
52
+ end
53
+
54
+ def matched_identifier=(str_)
55
+ end
50
56
  end
@@ -4,7 +4,7 @@
4
4
  module NoResponse
5
5
  module Models
6
6
  module Shared
7
- # Search retained assessments created in [from,to), over at most 366 days. Filters use each assessment decision, rather than the current account decision. Results can change between pages. Keep the assessment version to retrieve the exact decision later. This read does not require an idempotency key.
7
+ # Search retained assessments created in [from,to), at most 366 days. identifier matches the submitted value of each returned assessment directly. The legacy email filter keeps its account-wide mailbox semantics and cannot be combined with identifier. Other filters combine using AND and describe assessment decisions, separate from current account decisions. Results use newest-created order with an assessment-ID tie break and are live, not a snapshot across pages. Requires history or investigate authority; identifier/email filtering also requires identifier-read permission. Detailed response mode additionally requires detailed permission. No Idempotency-Key.
8
8
  class AssessmentSearchRequest
9
9
  extend T::Sig
10
10
  include Crystalline::MetadataFields
@@ -181,6 +181,12 @@ module NoResponse
181
181
  Crystalline::Nilable.new(Crystalline::Boolean.new),
182
182
  {'format_json': {'letter_case': ::NoResponse::Utils.field_name("changed")}}
183
183
  )
184
+ # One customer-submitted identifier. Defaults to exact comparison of the original submitted value. canonical uses the supported identifier normalisation without an ownership claim: email preserves local-part case, NFC-normalises it and lowercases the domain without removing dots or tags; phone uses international E.164 without extensions or an inferred region; username uses NFC and Unicode case folding within the customer namespace. mailbox is email-only and explicitly selects existing list rules: case-insensitive, remove +tag, and ignore local-part dots at gmail.com and googlemail.com; googlemail.com maps to gmail.com. Username requires namespace customer. Email and phone forbid namespace. Source-discovered identifiers and platform handles are not searched. Unsupported kinds, namespaces, modes and invalid values return 400. Search equality does not establish verified ownership or merge accounts.
185
+ field(
186
+ :identifier,
187
+ Crystalline::Nilable.new(Models::Shared::IdentifierSearch),
188
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("identifier")}}
189
+ )
184
190
 
185
191
  field(
186
192
  :limit,
@@ -211,6 +217,7 @@ module NoResponse
211
217
  score_max: T.nilable(::Integer),
212
218
  list_match: T.nilable(Models::Shared::ListMatch),
213
219
  changed: T.nilable(T::Boolean),
220
+ identifier: T.nilable(Models::Shared::IdentifierSearch),
214
221
  limit: T.nilable(::Integer)
215
222
  )
216
223
  .void
@@ -237,6 +244,7 @@ module NoResponse
237
244
  score_max: nil,
238
245
  list_match: nil,
239
246
  changed: nil,
247
+ identifier: nil,
240
248
  limit: 20
241
249
  )
242
250
  @from = from
@@ -260,6 +268,7 @@ module NoResponse
260
268
  @score_max = score_max
261
269
  @list_match = list_match
262
270
  @changed = changed
271
+ @identifier = identifier
263
272
  @limit = limit
264
273
  end
265
274
 
@@ -287,6 +296,7 @@ module NoResponse
287
296
  return false unless @score_max == other.score_max
288
297
  return false unless @list_match == other.list_match
289
298
  return false unless @changed == other.changed
299
+ return false unless @identifier == other.identifier
290
300
  return false unless @limit == other.limit
291
301
  true
292
302
  end
@@ -132,6 +132,12 @@ class NoResponse::Models::Shared::AssessmentSearchRequest
132
132
  def changed=(str_)
133
133
  end
134
134
 
135
+ def identifier
136
+ end
137
+
138
+ def identifier=(str_)
139
+ end
140
+
135
141
  def limit
136
142
  end
137
143
 
@@ -9,6 +9,13 @@ module NoResponse
9
9
  extend T::Sig
10
10
  include Crystalline::MetadataFields
11
11
 
12
+ # Only reviews of this exact account in the authenticated workspace and environment. Applied before pagination.
13
+ field(
14
+ :account_id,
15
+ Crystalline::Nilable.new(::String),
16
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("account_id")}}
17
+ )
18
+
12
19
  field(
13
20
  :status,
14
21
  Crystalline::Nilable.new(Models::Shared::ReviewStatus),
@@ -51,6 +58,7 @@ module NoResponse
51
58
 
52
59
  sig {
53
60
  params(
61
+ account_id: T.nilable(::String),
54
62
  status: T.nilable(Models::Shared::ReviewStatus),
55
63
  priority: T.nilable(Models::Shared::Priority),
56
64
  assignee: T.nilable(::String),
@@ -59,7 +67,15 @@ module NoResponse
59
67
  )
60
68
  .void
61
69
  }
62
- def initialize(status: nil, priority: nil, assignee: nil, unassigned: nil, assignee_principal_id: nil)
70
+ def initialize(
71
+ account_id: nil,
72
+ status: nil,
73
+ priority: nil,
74
+ assignee: nil,
75
+ unassigned: nil,
76
+ assignee_principal_id: nil
77
+ )
78
+ @account_id = account_id
63
79
  @status = status
64
80
  @priority = priority
65
81
  @assignee = assignee
@@ -70,6 +86,7 @@ module NoResponse
70
86
  sig { params(other: T.untyped).returns(T::Boolean) }
71
87
  def ==(other)
72
88
  return false unless other.is_a?(self.class)
89
+ return false unless @account_id == other.account_id
73
90
  return false unless @status == other.status
74
91
  return false unless @priority == other.priority
75
92
  return false unless @assignee == other.assignee
@@ -6,6 +6,12 @@ class NoResponse::Models::Shared::Filter
6
6
  end
7
7
 
8
8
  class NoResponse::Models::Shared::Filter
9
+ def account_id
10
+ end
11
+
12
+ def account_id=(str_)
13
+ end
14
+
9
15
  def status
10
16
  end
11
17
 
@@ -0,0 +1,105 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+ # Why this result matched a typed identifier search. value is the original value submitted in assessment_id. Provenance records a customer submission, not a source discovery or verified ownership. Equality is deterministic and has no inferred confidence score. An account result names its newest retained matching assessment, which can differ from latest.
8
+ class IdentifierMatch
9
+ extend T::Sig
10
+ include Crystalline::MetadataFields
11
+
12
+ field(
13
+ :kind,
14
+ Models::Shared::IdentifierSearchKind,
15
+ {
16
+ 'format_json': {
17
+ 'letter_case': ::NoResponse::Utils.field_name("kind"),
18
+ required: true,
19
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::IdentifierSearchKind, false)
20
+ }
21
+ }
22
+ )
23
+
24
+ field(
25
+ :value,
26
+ ::String,
27
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("value"), required: true}}
28
+ )
29
+ # exact compares the original submitted value; canonical uses identifier-specific normalisation; mailbox explicitly selects the email alias rules used by lists.
30
+ field(
31
+ :match_basis,
32
+ Models::Shared::Match,
33
+ {
34
+ 'format_json': {
35
+ 'letter_case': ::NoResponse::Utils.field_name("match_basis"),
36
+ required: true,
37
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::Match, false)
38
+ }
39
+ }
40
+ )
41
+ # Customer-submitted input. It does not mean the customer or NoResponse verified ownership.
42
+ field(
43
+ :provenance,
44
+ Models::Shared::Provenance,
45
+ {
46
+ 'format_json': {
47
+ 'letter_case': ::NoResponse::Utils.field_name("provenance"),
48
+ required: true,
49
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::Provenance, false)
50
+ }
51
+ }
52
+ )
53
+ # Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the workspace; another workspace's assessment id answers 404.
54
+ field(
55
+ :assessment_id,
56
+ ::String,
57
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_id"), required: true}}
58
+ )
59
+ # Required for username: the username submitted by this customer in this workspace/environment. It does not name or join a source platform. Omit for email and phone.
60
+ field(
61
+ :namespace,
62
+ Crystalline::Nilable.new(Models::Shared::Namespace),
63
+ {
64
+ 'format_json': {
65
+ 'letter_case': ::NoResponse::Utils.field_name("namespace"),
66
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::Namespace, true)
67
+ }
68
+ }
69
+ )
70
+
71
+ sig {
72
+ params(
73
+ kind: Models::Shared::IdentifierSearchKind,
74
+ value: ::String,
75
+ match_basis: Models::Shared::Match,
76
+ provenance: Models::Shared::Provenance,
77
+ assessment_id: ::String,
78
+ namespace: T.nilable(Models::Shared::Namespace)
79
+ )
80
+ .void
81
+ }
82
+ def initialize(kind:, value:, match_basis:, provenance:, assessment_id:, namespace: nil)
83
+ @kind = kind
84
+ @value = value
85
+ @match_basis = match_basis
86
+ @provenance = provenance
87
+ @assessment_id = assessment_id
88
+ @namespace = namespace
89
+ end
90
+
91
+ sig { params(other: T.untyped).returns(T::Boolean) }
92
+ def ==(other)
93
+ return false unless other.is_a?(self.class)
94
+ return false unless @kind == other.kind
95
+ return false unless @value == other.value
96
+ return false unless @match_basis == other.match_basis
97
+ return false unless @provenance == other.provenance
98
+ return false unless @assessment_id == other.assessment_id
99
+ return false unless @namespace == other.namespace
100
+ true
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,44 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::IdentifierMatch
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::IdentifierMatch
9
+ def kind
10
+ end
11
+
12
+ def kind=(str_)
13
+ end
14
+
15
+ def value
16
+ end
17
+
18
+ def value=(str_)
19
+ end
20
+
21
+ def match_basis
22
+ end
23
+
24
+ def match_basis=(str_)
25
+ end
26
+
27
+ def provenance
28
+ end
29
+
30
+ def provenance=(str_)
31
+ end
32
+
33
+ def assessment_id
34
+ end
35
+
36
+ def assessment_id=(str_)
37
+ end
38
+
39
+ def namespace
40
+ end
41
+
42
+ def namespace=(str_)
43
+ end
44
+ end
@@ -0,0 +1,80 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+ # One customer-submitted identifier. Defaults to exact comparison of the original submitted value. canonical uses the supported identifier normalisation without an ownership claim: email preserves local-part case, NFC-normalises it and lowercases the domain without removing dots or tags; phone uses international E.164 without extensions or an inferred region; username uses NFC and Unicode case folding within the customer namespace. mailbox is email-only and explicitly selects existing list rules: case-insensitive, remove +tag, and ignore local-part dots at gmail.com and googlemail.com; googlemail.com maps to gmail.com. Username requires namespace customer. Email and phone forbid namespace. Source-discovered identifiers and platform handles are not searched. Unsupported kinds, namespaces, modes and invalid values return 400. Search equality does not establish verified ownership or merge accounts.
8
+ class IdentifierSearch
9
+ extend T::Sig
10
+ include Crystalline::MetadataFields
11
+
12
+ field(
13
+ :kind,
14
+ Models::Shared::IdentifierSearchKind,
15
+ {
16
+ 'format_json': {
17
+ 'letter_case': ::NoResponse::Utils.field_name("kind"),
18
+ required: true,
19
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::IdentifierSearchKind, false)
20
+ }
21
+ }
22
+ )
23
+ # The comparison value. Stored original identifiers remain unchanged. An invalid identifier is refused instead of returning an empty result.
24
+ field(
25
+ :value,
26
+ ::String,
27
+ {'format_json': {'letter_case': ::NoResponse::Utils.field_name("value"), required: true}}
28
+ )
29
+ # exact compares the original submitted value; canonical uses identifier-specific normalisation; mailbox explicitly selects the email alias rules used by lists.
30
+ field(
31
+ :match,
32
+ Crystalline::Nilable.new(Models::Shared::Match),
33
+ {
34
+ 'format_json': {
35
+ 'letter_case': ::NoResponse::Utils.field_name("match"),
36
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::Match, true)
37
+ }
38
+ }
39
+ )
40
+ # Required for username: the username submitted by this customer in this workspace/environment. It does not name or join a source platform. Omit for email and phone.
41
+ field(
42
+ :namespace,
43
+ Crystalline::Nilable.new(Models::Shared::Namespace),
44
+ {
45
+ 'format_json': {
46
+ 'letter_case': ::NoResponse::Utils.field_name("namespace"),
47
+ 'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::Namespace, true)
48
+ }
49
+ }
50
+ )
51
+
52
+ sig {
53
+ params(
54
+ kind: Models::Shared::IdentifierSearchKind,
55
+ value: ::String,
56
+ match: T.nilable(Models::Shared::Match),
57
+ namespace: T.nilable(Models::Shared::Namespace)
58
+ )
59
+ .void
60
+ }
61
+ def initialize(kind:, value:, match: nil, namespace: nil)
62
+ @kind = kind
63
+ @value = value
64
+ @match = match
65
+ @namespace = namespace
66
+ end
67
+
68
+ sig { params(other: T.untyped).returns(T::Boolean) }
69
+ def ==(other)
70
+ return false unless other.is_a?(self.class)
71
+ return false unless @kind == other.kind
72
+ return false unless @value == other.value
73
+ return false unless @match == other.match
74
+ return false unless @namespace == other.namespace
75
+ true
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,32 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::IdentifierSearch
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::IdentifierSearch
9
+ def kind
10
+ end
11
+
12
+ def kind=(str_)
13
+ end
14
+
15
+ def value
16
+ end
17
+
18
+ def value=(str_)
19
+ end
20
+
21
+ def match
22
+ end
23
+
24
+ def match=(str_)
25
+ end
26
+
27
+ def namespace
28
+ end
29
+
30
+ def namespace=(str_)
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+
8
+ class IdentifierSearchKind
9
+ include ::Crystalline::Enum
10
+ enums do
11
+ EMAIL = new("email")
12
+ PHONE = new("phone")
13
+ USERNAME = new("username")
14
+ end
15
+
16
+ open!
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::IdentifierSearchKind
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::IdentifierSearchKind
9
+ end
@@ -0,0 +1,20 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+ # Match - exact compares the original submitted value; canonical uses identifier-specific normalisation; mailbox explicitly selects the email alias rules used by lists.
8
+ class Match
9
+ include ::Crystalline::Enum
10
+ enums do
11
+ EXACT = new("exact")
12
+ CANONICAL = new("canonical")
13
+ MAILBOX = new("mailbox")
14
+ end
15
+
16
+ open!
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::Match
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::Match
9
+ end
@@ -0,0 +1,18 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+ # Namespace - Required for username: the username submitted by this customer in this workspace/environment. It does not name or join a source platform. Omit for email and phone.
8
+ class Namespace
9
+ include ::Crystalline::Enum
10
+ enums do
11
+ CUSTOMER = new("customer")
12
+ end
13
+
14
+ open!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::Namespace
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::Namespace
9
+ end
@@ -0,0 +1,18 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+ # Provenance - Customer-submitted input. It does not mean the customer or NoResponse verified ownership.
8
+ class Provenance
9
+ include ::Crystalline::Enum
10
+ enums do
11
+ SUBMITTED = new("submitted")
12
+ end
13
+
14
+ open!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::Provenance
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::Provenance
9
+ end
@@ -0,0 +1,19 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module NoResponse
5
+ module Models
6
+ module Shared
7
+
8
+ class WaitingFor
9
+ include ::Crystalline::Enum
10
+ enums do
11
+ OUTCOME = new("outcome")
12
+ REVIEW = new("review")
13
+ end
14
+
15
+ open!
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class NoResponse::Models::Shared::WaitingFor
5
+ extend ::Crystalline::MetadataFields::ClassMethods
6
+ end
7
+
8
+ class NoResponse::Models::Shared::WaitingFor
9
+ end
@@ -153,6 +153,9 @@ module NoResponse
153
153
  autoload :HookPoint, "no_response/models/shared/hookpoint.rb"
154
154
  autoload :Identifier, "no_response/models/shared/identifier.rb"
155
155
  autoload :IdentifierKind, "no_response/models/shared/identifierkind.rb"
156
+ autoload :IdentifierMatch, "no_response/models/shared/identifiermatch.rb"
157
+ autoload :IdentifierSearch, "no_response/models/shared/identifiersearch.rb"
158
+ autoload :IdentifierSearchKind, "no_response/models/shared/identifiersearchkind.rb"
156
159
  autoload :Impact, "no_response/models/shared/impact.rb"
157
160
  autoload :IncompleteReason, "no_response/models/shared/incompletereason.rb"
158
161
  autoload :IncompleteSource, "no_response/models/shared/incompletesource.rb"
@@ -203,6 +206,7 @@ module NoResponse
203
206
  autoload :ListImpactTransitionFrom, "no_response/models/shared/listimpacttransitionfrom.rb"
204
207
  autoload :ListMatch, "no_response/models/shared/listmatch.rb"
205
208
  autoload :ListPreviewRequest, "no_response/models/shared/listpreviewrequest.rb"
209
+ autoload :Match, "no_response/models/shared/match.rb"
206
210
  autoload :Member, "no_response/models/shared/member.rb"
207
211
  autoload :MemberList, "no_response/models/shared/memberlist.rb"
208
212
  autoload :MemberStatus, "no_response/models/shared/memberstatus.rb"
@@ -212,6 +216,7 @@ module NoResponse
212
216
  autoload :MemberDeniedAction, "no_response/models/shared/member_denied_action.rb"
213
217
  autoload :MemberEnvironment, "no_response/models/shared/member_environment.rb"
214
218
  autoload :Metric, "no_response/models/shared/metric.rb"
219
+ autoload :Namespace, "no_response/models/shared/namespace.rb"
215
220
  autoload :NotFoundErrorCode, "no_response/models/shared/notfounderrorcode.rb"
216
221
  autoload :OnExpiry, "no_response/models/shared/onexpiry.rb"
217
222
  autoload :OperationalAggregate, "no_response/models/shared/operationalaggregate.rb"
@@ -252,6 +257,7 @@ module NoResponse
252
257
  autoload :Population, "no_response/models/shared/population.rb"
253
258
  autoload :Priority, "no_response/models/shared/priority.rb"
254
259
  autoload :ProblemInvalidParam, "no_response/models/shared/probleminvalidparam.rb"
260
+ autoload :Provenance, "no_response/models/shared/provenance.rb"
255
261
  autoload :Publication, "no_response/models/shared/publication.rb"
256
262
  autoload :RateLimitErrorCode, "no_response/models/shared/ratelimiterrorcode.rb"
257
263
  autoload :ReasonCode, "no_response/models/shared/reasoncode.rb"
@@ -360,6 +366,7 @@ module NoResponse
360
366
  autoload :SocialProfileUnion, "no_response/models/shared/social_profile_union.rb"
361
367
  autoload :Timezone, "no_response/models/shared/timezone.rb"
362
368
  autoload :TimezoneUnion, "no_response/models/shared/timezone_union.rb"
369
+ autoload :WaitingFor, "no_response/models/shared/waiting_for.rb"
363
370
  autoload :Website, "no_response/models/shared/website.rb"
364
371
  autoload :WebsiteUnion, "no_response/models/shared/website_union.rb"
365
372
  end
@@ -49,7 +49,7 @@ module NoResponse
49
49
  }
50
50
  def list(request:, retries: nil, timeout_ms: nil, http_headers: nil)
51
51
  # list - List retained account reviews.
52
- # List retained investigation reviews using filters and an authenticated cursor.
52
+ # List retained investigation reviews using filters and an authenticated cursor. Optional account_id selects one exact account in this environment before pagination. All filters are bound into the cursor.
53
53
  url, params = @sdk_configuration.get_server_details
54
54
  base_url = Utils.template_url(url, params)
55
55
  url = Utils.generate_url(
@@ -179,7 +179,8 @@ module NoResponse
179
179
  priority: request.priority,
180
180
  assignee: request.assignee,
181
181
  unassigned: request.unassigned,
182
- assignee_principal_id: request.assignee_principal_id
182
+ assignee_principal_id: request.assignee_principal_id,
183
+ account_id: request.account_id
183
184
  ),
184
185
  http_headers: http_headers
185
186
  )
@@ -95,9 +95,9 @@ module NoResponse
95
95
 
96
96
  @language = "ruby"
97
97
  @openapi_doc_version = "1"
98
- @sdk_version = "9.4.2"
98
+ @sdk_version = "9.4.4"
99
99
  @gen_version = "internal"
100
- @user_agent = "noresponse-sdk/ruby 9.4.2 internal 1 noresponse"
100
+ @user_agent = "noresponse-sdk/ruby 9.4.4 internal 1 noresponse"
101
101
  end
102
102
 
103
103
  sig { returns([String, T::Hash[Symbol, String]]) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noresponse
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.4.2
4
+ version: 9.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - NoResponse
@@ -971,6 +971,12 @@ files:
971
971
  - lib/no_response/models/shared/identifier.rbi
972
972
  - lib/no_response/models/shared/identifierkind.rb
973
973
  - lib/no_response/models/shared/identifierkind.rbi
974
+ - lib/no_response/models/shared/identifiermatch.rb
975
+ - lib/no_response/models/shared/identifiermatch.rbi
976
+ - lib/no_response/models/shared/identifiersearch.rb
977
+ - lib/no_response/models/shared/identifiersearch.rbi
978
+ - lib/no_response/models/shared/identifiersearchkind.rb
979
+ - lib/no_response/models/shared/identifiersearchkind.rbi
974
980
  - lib/no_response/models/shared/impact.rb
975
981
  - lib/no_response/models/shared/impact.rbi
976
982
  - lib/no_response/models/shared/incompletereason.rb
@@ -1075,6 +1081,8 @@ files:
1075
1081
  - lib/no_response/models/shared/location.rbi
1076
1082
  - lib/no_response/models/shared/location_union.rb
1077
1083
  - lib/no_response/models/shared/location_union.rbi
1084
+ - lib/no_response/models/shared/match.rb
1085
+ - lib/no_response/models/shared/match.rbi
1078
1086
  - lib/no_response/models/shared/member.rb
1079
1087
  - lib/no_response/models/shared/member.rbi
1080
1088
  - lib/no_response/models/shared/member_denied_action.rb
@@ -1097,6 +1105,8 @@ files:
1097
1105
  - lib/no_response/models/shared/name_candidate.rbi
1098
1106
  - lib/no_response/models/shared/name_candidate_union.rb
1099
1107
  - lib/no_response/models/shared/name_candidate_union.rbi
1108
+ - lib/no_response/models/shared/namespace.rb
1109
+ - lib/no_response/models/shared/namespace.rbi
1100
1110
  - lib/no_response/models/shared/notfounderrorcode.rb
1101
1111
  - lib/no_response/models/shared/notfounderrorcode.rbi
1102
1112
  - lib/no_response/models/shared/onexpiry.rb
@@ -1171,6 +1181,8 @@ files:
1171
1181
  - lib/no_response/models/shared/priority.rbi
1172
1182
  - lib/no_response/models/shared/probleminvalidparam.rb
1173
1183
  - lib/no_response/models/shared/probleminvalidparam.rbi
1184
+ - lib/no_response/models/shared/provenance.rb
1185
+ - lib/no_response/models/shared/provenance.rbi
1174
1186
  - lib/no_response/models/shared/publication.rb
1175
1187
  - lib/no_response/models/shared/publication.rbi
1176
1188
  - lib/no_response/models/shared/ratelimiterrorcode.rb
@@ -1319,6 +1331,8 @@ files:
1319
1331
  - lib/no_response/models/shared/usagecountflow.rbi
1320
1332
  - lib/no_response/models/shared/useractor.rb
1321
1333
  - lib/no_response/models/shared/useractor.rbi
1334
+ - lib/no_response/models/shared/waiting_for.rb
1335
+ - lib/no_response/models/shared/waiting_for.rbi
1322
1336
  - lib/no_response/models/shared/webhookaggregaterequest.rb
1323
1337
  - lib/no_response/models/shared/webhookaggregaterequest.rbi
1324
1338
  - lib/no_response/models/shared/webhookdeliveryattempt.rb