bitfab 0.73.2 → 0.74.1
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.
- checksums.yaml +4 -4
- data/lib/bitfab/assertions.rb +28 -2
- data/lib/bitfab/client.rb +8 -1
- data/lib/bitfab/http_client.rb +8 -1
- data/lib/bitfab/replay.rb +20 -1
- data/lib/bitfab/replay_registry.rb +32 -11
- data/lib/bitfab/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1def1a5df451e3c7b1afa22248c2c54b2b135f5712eb19a989b41209a8c5622
|
|
4
|
+
data.tar.gz: 16a9741bbda86c16c78aafec91688d962c9ae58e9b032681a07d7b633497c258
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2be36b8b49c5b7c6d6525364c6f10a24d696eb40d8dae2343bdf1b1017e2f2fd47e6c52d8cdf200b4f1cf22a75fdd0ea41bf217e533090a9a42fa725ee7018a8
|
|
7
|
+
data.tar.gz: 5a4fe53c914d211714bbd2a31d44af37743edf1007f4599f52c6dfcce9e3bf970d90778588b1ee17267394017ed554752882f63d45a06fa7ce693786b97dc152
|
data/lib/bitfab/assertions.rb
CHANGED
|
@@ -4,9 +4,11 @@ require "uri"
|
|
|
4
4
|
|
|
5
5
|
module Bitfab
|
|
6
6
|
class Traces
|
|
7
|
+
CODE_DRAFT_SAVE_TIMEOUT_SECONDS = 300
|
|
8
|
+
CODED_KINDS = ["code", "hybrid", :code, :hybrid].freeze
|
|
7
9
|
CATEGORY_ID_KEYS = ["category_id", :category_id].freeze
|
|
8
10
|
DEPRECATED_CATEGORY_ID_KEYS = ["category_assertion_id", :category_assertion_id].freeze
|
|
9
|
-
private_constant :CATEGORY_ID_KEYS, :DEPRECATED_CATEGORY_ID_KEYS
|
|
11
|
+
private_constant :CODE_DRAFT_SAVE_TIMEOUT_SECONDS, :CODED_KINDS, :CATEGORY_ID_KEYS, :DEPRECATED_CATEGORY_ID_KEYS
|
|
10
12
|
|
|
11
13
|
def initialize(http_client)
|
|
12
14
|
@http_client = http_client
|
|
@@ -44,6 +46,17 @@ module Bitfab
|
|
|
44
46
|
# pass "kind" => "judge" to remove the code. Returned assertions carry
|
|
45
47
|
# "kind", "code", and "codeBrokenReason".
|
|
46
48
|
#
|
|
49
|
+
# Send "kind" => "code" or "hybrid" without "code", on an assertion that
|
|
50
|
+
# has no code yet, to have Bitfab write the code: the text is checked by
|
|
51
|
+
# the guided rewrite (unless skipped), code of that kind is written and run
|
|
52
|
+
# on the trace, and the save waits for both, so that entry's "rewrite" is
|
|
53
|
+
# already final. Its returned "codeDraft" hash says what happened:
|
|
54
|
+
# "requestedKind", "status" ("written", or "not_written" when no working
|
|
55
|
+
# code could be written and the assertion was saved as "judge" without
|
|
56
|
+
# code), and "reason" (why not, or nil). Every other entry's "codeDraft"
|
|
57
|
+
# is nil. At most 10 assertions per save may ask for code this way, and a
|
|
58
|
+
# save that asks for any waits up to five minutes.
|
|
59
|
+
#
|
|
47
60
|
# By default, after the save, Bitfab checks each assertion's text against its
|
|
48
61
|
# trace. When the text bundles two claims, adds a condition, points at a
|
|
49
62
|
# value instead of stating it, names an id from the recorded run, or cannot
|
|
@@ -77,7 +90,8 @@ module Bitfab
|
|
|
77
90
|
"updates" => updates.map { |update| with_new_category_key(update) },
|
|
78
91
|
"source" => source,
|
|
79
92
|
"guidedRewrite" => !skip_guided_rewrite
|
|
80
|
-
}
|
|
93
|
+
},
|
|
94
|
+
timeout: save_timeout(updates)
|
|
81
95
|
)["assertions"]
|
|
82
96
|
saved.is_a?(Array) ? saved.map { |assertion| with_both_category_keys(assertion) } : saved
|
|
83
97
|
end
|
|
@@ -88,6 +102,18 @@ module Bitfab
|
|
|
88
102
|
|
|
89
103
|
private
|
|
90
104
|
|
|
105
|
+
def save_timeout(updates)
|
|
106
|
+
asks = updates.any? do |update|
|
|
107
|
+
(update["assertions"] || update[:assertions] || []).any? { |assertion| asks_bitfab_to_write_code?(assertion) }
|
|
108
|
+
end
|
|
109
|
+
asks ? CODE_DRAFT_SAVE_TIMEOUT_SECONDS : nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def asks_bitfab_to_write_code?(assertion)
|
|
113
|
+
kind = assertion["kind"] || assertion[:kind]
|
|
114
|
+
CODED_KINDS.include?(kind) && !assertion.key?("code") && !assertion.key?(:code)
|
|
115
|
+
end
|
|
116
|
+
|
|
91
117
|
def assertions_path(trace_id, suffix = "")
|
|
92
118
|
"/api/sdk/traces/#{URI.encode_www_form_component(trace_id).gsub("+", "%20")}/assertions#{suffix}"
|
|
93
119
|
end
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -182,6 +182,12 @@ module Bitfab
|
|
|
182
182
|
# directly to this experiment, graded as the union with the dataset's
|
|
183
183
|
# runnable graders at completion; each must be an active/live grader in the
|
|
184
184
|
# same org and trace function or the server rejects the replay
|
|
185
|
+
# @param category_ids [Array<String>, nil] optional category UUIDs. With
|
|
186
|
+
# trace_ids, dataset_id or dataset_ids, only the selected traces carrying
|
|
187
|
+
# an approved assertion in one of these categories replay. It changes
|
|
188
|
+
# which traces replay, not which assertions are judged. Raises
|
|
189
|
+
# ArgumentError when empty or passed without a trace ID or dataset
|
|
190
|
+
# selection.
|
|
185
191
|
# @param mock [String] mock strategy for child spans: "marked" (default),
|
|
186
192
|
# "none", or "all". "marked" only mocks spans declared with
|
|
187
193
|
# mock_on_replay: true; "all" mocks every matched recorded child span. A selected
|
|
@@ -228,7 +234,7 @@ module Bitfab
|
|
|
228
234
|
# @return [Hash] with :items, :experiment_id, :experiment_url, and the
|
|
229
235
|
# deprecated aliases :test_run_id and :test_run_url carrying the same values
|
|
230
236
|
def replay(receiver, method_name = nil, trace_function_key:, limit: nil, trace_ids: nil, concurrency: nil, max_concurrency: ReplayConcurrency::UNSET,
|
|
231
|
-
name: nil, notes: nil, metadata: nil, code_change: nil, code_change_description: nil, code_change_files: nil, code_change_base: nil, experiment_group_id: nil, experiment_group_name: nil, dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
237
|
+
name: nil, notes: nil, metadata: nil, code_change: nil, code_change_description: nil, code_change_files: nil, code_change_base: nil, experiment_group_id: nil, experiment_group_name: nil, dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, category_ids: nil, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
232
238
|
adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil,
|
|
233
239
|
on_experiment_start: nil, experimental_selective_replay: nil)
|
|
234
240
|
Replay.run(
|
|
@@ -245,6 +251,7 @@ module Bitfab
|
|
|
245
251
|
max_concurrency:,
|
|
246
252
|
attempts:,
|
|
247
253
|
only_with_assertions:,
|
|
254
|
+
category_ids:,
|
|
248
255
|
skip_assertion_judging:,
|
|
249
256
|
judge_assertions:,
|
|
250
257
|
dry_run:,
|
data/lib/bitfab/http_client.rb
CHANGED
|
@@ -276,9 +276,15 @@ module Bitfab
|
|
|
276
276
|
# directly to this experiment, graded as the union with the dataset's
|
|
277
277
|
# runnable graders at completion; each must be an active/live grader in the
|
|
278
278
|
# same org and trace function or the server rejects the replay
|
|
279
|
+
# @param category_ids [Array<String>, nil] optional category UUIDs. With
|
|
280
|
+
# trace_ids, dataset_id or dataset_ids, only the selected traces carrying
|
|
281
|
+
# an approved assertion in one of these categories replay. It changes
|
|
282
|
+
# which traces replay, not which assertions are judged. Raises
|
|
283
|
+
# ArgumentError when empty or passed without a trace ID or dataset
|
|
284
|
+
# selection.
|
|
279
285
|
def start_replay(trace_function_key, limit, trace_ids: nil, code_change_type: nil, code_change_description: nil,
|
|
280
286
|
code_change_files: nil, experiment_group_id: nil, experiment_group_name: nil, name: nil, notes: nil, metadata: nil, include_db_branch_lease: false, dataset_ids: nil,
|
|
281
|
-
grader_ids: nil, db_branch_settings: nil, attempts: 1, only_with_assertions: false, skip_assertion_judging: false, include_original_metadata: false, experimental_selective_replay: nil, dry_run: false, invocation: nil)
|
|
287
|
+
grader_ids: nil, db_branch_settings: nil, attempts: 1, only_with_assertions: false, category_ids: nil, skip_assertion_judging: false, include_original_metadata: false, experimental_selective_replay: nil, dry_run: false, invocation: nil)
|
|
282
288
|
payload = {
|
|
283
289
|
"traceFunctionKey" => trace_function_key
|
|
284
290
|
}
|
|
@@ -306,6 +312,7 @@ module Bitfab
|
|
|
306
312
|
payload["graderIds"] = grader_ids unless grader_ids.nil?
|
|
307
313
|
payload["attempts"] = attempts if attempts > 1
|
|
308
314
|
payload["onlyWithAssertions"] = true if only_with_assertions
|
|
315
|
+
payload["categoryIds"] = category_ids unless category_ids.nil?
|
|
309
316
|
payload["judgeAssertions"] = true unless skip_assertion_judging
|
|
310
317
|
payload["dryRun"] = true if dry_run
|
|
311
318
|
payload["includeOriginalMetadata"] = true if include_original_metadata
|
data/lib/bitfab/replay.rb
CHANGED
|
@@ -274,6 +274,12 @@ module Bitfab
|
|
|
274
274
|
# directly to this experiment, graded as the union with the dataset's
|
|
275
275
|
# runnable graders at completion; each must be an active/live grader in the
|
|
276
276
|
# same org and trace function or the server rejects the replay
|
|
277
|
+
# @param category_ids [Array<String>, nil] optional category UUIDs. With
|
|
278
|
+
# trace_ids, dataset_id or dataset_ids, only the selected traces carrying
|
|
279
|
+
# an approved assertion in one of these categories replay. It changes
|
|
280
|
+
# which traces replay, not which assertions are judged. Raises
|
|
281
|
+
# ArgumentError when empty or passed without a trace ID or dataset
|
|
282
|
+
# selection.
|
|
277
283
|
# @param mock [String] mock strategy for child spans: "marked" (default),
|
|
278
284
|
# "none", or "all". "marked" only mocks spans declared with
|
|
279
285
|
# mock_on_replay: true; "all" mocks every matched recorded child span.
|
|
@@ -320,7 +326,7 @@ module Bitfab
|
|
|
320
326
|
# and progress events then carry a nil :experiment_id too.
|
|
321
327
|
def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil, notes: nil, metadata: nil,
|
|
322
328
|
concurrency: nil, max_concurrency: ReplayConcurrency::UNSET, code_change: nil, code_change_description: nil, code_change_files: nil, code_change_base: nil, experiment_group_id: nil, experiment_group_name: nil,
|
|
323
|
-
dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
329
|
+
dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, category_ids: nil, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
324
330
|
adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil,
|
|
325
331
|
on_experiment_start: nil, experimental_selective_replay: nil)
|
|
326
332
|
validate_code_change(code_change, code_change_description, code_change_files, code_change_base)
|
|
@@ -355,6 +361,7 @@ module Bitfab
|
|
|
355
361
|
end
|
|
356
362
|
end
|
|
357
363
|
resolved_dataset_ids = resolve_dataset_ids(dataset_id, dataset_ids)
|
|
364
|
+
validate_category_ids(category_ids, trace_ids, resolved_dataset_ids)
|
|
358
365
|
if limit && trace_ids
|
|
359
366
|
warn "Bitfab: limit is ignored when trace_ids is passed: the explicit trace ID list already " \
|
|
360
367
|
"determines how many traces replay."
|
|
@@ -422,6 +429,7 @@ module Bitfab
|
|
|
422
429
|
grader_ids:,
|
|
423
430
|
attempts:,
|
|
424
431
|
only_with_assertions:,
|
|
432
|
+
category_ids:,
|
|
425
433
|
skip_assertion_judging:,
|
|
426
434
|
include_original_metadata: !adapt_inputs.nil?,
|
|
427
435
|
db_branch_settings: resolved_db_branch_settings,
|
|
@@ -613,6 +621,17 @@ module Bitfab
|
|
|
613
621
|
skip_assertion_judging || judge_assertions == false
|
|
614
622
|
end
|
|
615
623
|
|
|
624
|
+
def validate_category_ids(category_ids, trace_ids, dataset_ids)
|
|
625
|
+
return if category_ids.nil?
|
|
626
|
+
if category_ids.empty?
|
|
627
|
+
raise ArgumentError, "category_ids must contain at least one category ID."
|
|
628
|
+
end
|
|
629
|
+
return if trace_ids || dataset_ids
|
|
630
|
+
|
|
631
|
+
raise ArgumentError,
|
|
632
|
+
"category_ids narrows a trace ID or dataset selection. Pass it with trace_ids, dataset_id or dataset_ids."
|
|
633
|
+
end
|
|
634
|
+
|
|
616
635
|
def resolve_dataset_ids(dataset_id, dataset_ids)
|
|
617
636
|
if dataset_id && dataset_ids
|
|
618
637
|
raise ArgumentError,
|
|
@@ -20,7 +20,7 @@ module Bitfab
|
|
|
20
20
|
class ReplayRegistry
|
|
21
21
|
OPTION_NAMES = %i[
|
|
22
22
|
limit trace_ids name notes metadata concurrency max_concurrency experiment_group_id experiment_group_name dataset_id dataset_ids grader_ids mock
|
|
23
|
-
mock_override adapt_inputs db_branch attempts only_with_assertions skip_assertion_judging judge_assertions dry_run on_item_finish
|
|
23
|
+
mock_override adapt_inputs db_branch attempts only_with_assertions category_ids skip_assertion_judging judge_assertions dry_run on_item_finish
|
|
24
24
|
].freeze
|
|
25
25
|
|
|
26
26
|
def initialize
|
|
@@ -97,31 +97,39 @@ module Bitfab
|
|
|
97
97
|
# approved assertion is checked on a replay, so narrowing on anything else
|
|
98
98
|
# would pick traces the run cannot be judged against. The server applies the
|
|
99
99
|
# same rule when it revalidates the selection.
|
|
100
|
-
def approved_assertion?(assertions)
|
|
101
|
-
assertions.any?
|
|
100
|
+
def approved_assertion?(assertions, category_ids = nil)
|
|
101
|
+
assertions.any? do |assertion|
|
|
102
|
+
assertion["approvalState"] == "approved" &&
|
|
103
|
+
(category_ids.nil? || category_ids.include?(assertion["category_id"]))
|
|
104
|
+
end
|
|
102
105
|
end
|
|
103
106
|
|
|
104
|
-
def bound_trace_ids(client, trace_ids, limit, only_with_assertions)
|
|
107
|
+
def bound_trace_ids(client, trace_ids, limit, only_with_assertions, category_ids = nil)
|
|
105
108
|
unless limit.is_a?(Integer) && limit.positive?
|
|
106
109
|
raise ArgumentError, "Replay limit must be a positive integer."
|
|
107
110
|
end
|
|
108
|
-
|
|
111
|
+
narrows = only_with_assertions || !category_ids.nil?
|
|
112
|
+
return trace_ids.first(limit) if !narrows || limit >= trace_ids.length
|
|
109
113
|
|
|
110
114
|
selected = []
|
|
111
115
|
trace_ids.each do |trace_id|
|
|
112
116
|
result = client.traces.get_assertions(trace_id)
|
|
113
|
-
if result.fetch("inheritedFrom").nil? && approved_assertion?(result.fetch("assertions"))
|
|
117
|
+
if result.fetch("inheritedFrom").nil? && approved_assertion?(result.fetch("assertions"), category_ids)
|
|
114
118
|
selected << trace_id
|
|
115
119
|
break if selected.length == limit
|
|
116
120
|
end
|
|
117
121
|
end
|
|
118
122
|
if selected.empty?
|
|
123
|
+
if category_ids
|
|
124
|
+
raise ArgumentError,
|
|
125
|
+
"No traces with an approved assertion in the given categories matched this replay selection."
|
|
126
|
+
end
|
|
119
127
|
raise ArgumentError, "No traces with approved assertions matched this replay selection."
|
|
120
128
|
end
|
|
121
129
|
selected
|
|
122
130
|
end
|
|
123
131
|
|
|
124
|
-
def pinned_dataset_members(client, dataset_ids, limit, only_with_assertions = false)
|
|
132
|
+
def pinned_dataset_members(client, dataset_ids, limit, only_with_assertions = false, category_ids = nil)
|
|
125
133
|
members = dataset_ids.flat_map { |dataset_id|
|
|
126
134
|
client.datasets.list_traces(dataset_id).fetch("traceIds")
|
|
127
135
|
}.uniq.sort
|
|
@@ -134,7 +142,7 @@ module Bitfab
|
|
|
134
142
|
"every selected dataset in full."
|
|
135
143
|
end
|
|
136
144
|
|
|
137
|
-
bound_trace_ids(client, members, limit, only_with_assertions)
|
|
145
|
+
bound_trace_ids(client, members, limit, only_with_assertions, category_ids)
|
|
138
146
|
end
|
|
139
147
|
|
|
140
148
|
def run(registry, argv: ARGV, stdout: $stdout, stderr: $stderr)
|
|
@@ -173,24 +181,32 @@ module Bitfab
|
|
|
173
181
|
end
|
|
174
182
|
|
|
175
183
|
only_with_assertions = args[:only_with_assertions] || options[:only_with_assertions]
|
|
184
|
+
category_ids = args[:category_ids] || options[:category_ids]
|
|
176
185
|
bound = args[:limit] || options[:limit]
|
|
177
186
|
options.delete(:limit)
|
|
178
187
|
bounded_dataset_ids = args[:dataset_ids] || options[:dataset_ids]
|
|
179
188
|
|
|
189
|
+
if category_ids && options[:trace_ids].nil? && bounded_dataset_ids.nil?
|
|
190
|
+
raise ArgumentError,
|
|
191
|
+
"--category-ids narrows a trace ID or dataset selection. Pass it with --trace-ids or --dataset-ids."
|
|
192
|
+
end
|
|
193
|
+
|
|
180
194
|
if options[:trace_ids]
|
|
181
195
|
if bound
|
|
182
|
-
options[:trace_ids] = bound_trace_ids(registration.client, options[:trace_ids], bound, only_with_assertions
|
|
196
|
+
options[:trace_ids] = bound_trace_ids(registration.client, options[:trace_ids], bound, only_with_assertions,
|
|
197
|
+
category_ids)
|
|
183
198
|
end
|
|
184
199
|
elsif bounded_dataset_ids
|
|
185
200
|
if bound
|
|
186
|
-
pinned = pinned_dataset_members(registration.client, bounded_dataset_ids, bound, only_with_assertions
|
|
201
|
+
pinned = pinned_dataset_members(registration.client, bounded_dataset_ids, bound, only_with_assertions,
|
|
202
|
+
category_ids)
|
|
187
203
|
options[:trace_ids] = pinned if pinned
|
|
188
204
|
end
|
|
189
205
|
else
|
|
190
206
|
options[:limit] = bound || 10
|
|
191
207
|
end
|
|
192
208
|
|
|
193
|
-
%i[name notes metadata max_concurrency experiment_group_id experiment_group_name dataset_ids grader_ids mock attempts only_with_assertions skip_assertion_judging dry_run].each do |key|
|
|
209
|
+
%i[name notes metadata max_concurrency experiment_group_id experiment_group_name dataset_ids grader_ids mock attempts only_with_assertions category_ids skip_assertion_judging dry_run].each do |key|
|
|
194
210
|
options[key] = args[key] unless args[key].nil?
|
|
195
211
|
end
|
|
196
212
|
|
|
@@ -363,6 +379,11 @@ module Bitfab
|
|
|
363
379
|
options.on("--grader-ids IDS") { |value| args[:grader_ids] = comma_separated("--grader-ids", value) }
|
|
364
380
|
options.on("--attempts N", Integer) { |value| args[:attempts] = positive_integer("--attempts", value) }
|
|
365
381
|
options.on("--only-with-assertions") { args[:only_with_assertions] = true }
|
|
382
|
+
options.on("--category-ids id1,id2",
|
|
383
|
+
"With --trace-ids or --dataset-ids: replay only the traces carrying an approved assertion in one of " \
|
|
384
|
+
"these categories; which assertions are judged stays the same") do |value|
|
|
385
|
+
args[:category_ids] = comma_separated("--category-ids", value)
|
|
386
|
+
end
|
|
366
387
|
options.on("--skip-assertion-judging",
|
|
367
388
|
"Don't judge approved assertions on each replay; judging is on by default and costs model calls") { args[:skip_assertion_judging] = true }
|
|
368
389
|
options.on("--judge-assertions", "Deprecated: judging is on by default") { args[:judge_assertions] = true }
|
data/lib/bitfab/version.rb
CHANGED