bitfab 0.43.0 → 0.51.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32715330094ba79b22d0d629581b3d3ffb22dbfffc3ac6024545b7f841b6d7a5
4
- data.tar.gz: 76a4c5cb83b5850596d2d54227402fc86320854d5d1925dd1861588ac0cd4f04
3
+ metadata.gz: 5ece2db3c44be909ec097e539479143d0c4138663809c26a05a968076e681066
4
+ data.tar.gz: 6d68e352c7e484586147d1700998de7936fe904c5d04cabfe07df80e302104b1
5
5
  SHA512:
6
- metadata.gz: f2a5f30d4298a65e358cd2bd313c2ebbe443740f757f0f60e07f3fa4aa272e7f9e90b6d3a0b2d9184039bfaba563df1441e1692a7cbdb0dea0ad24aaf42c5aa3
7
- data.tar.gz: 143e9f6be9ba689edfd12ffd4cc30efda985cafa7198e56ff68ea6369ff6615b849e508ee4624ac719489d64288b212974c70055df25b22f157c3d563fdc149c
6
+ metadata.gz: bbb4750e80b63864d612592e1bebaac664463059e2d139fe7d556f68ce73b46868001daa54391d1a4562767a2e7e16355fdb8eefc89c64ace8f864dffffce86b
7
+ data.tar.gz: 02d731c682b787b8233a1c9a43135fc8b6d17d5959806ff65bec3be9979dbda95d1bfb6d01373b427405a5fb9fccd976c87706d8d488ea7733fe70ab0f8fa15b
data/lib/bitfab/client.rb CHANGED
@@ -93,11 +93,11 @@ module Bitfab
93
93
  # @param method_name [Symbol] the method to replay
94
94
  # @param trace_function_key [String] the trace function key for this method
95
95
  # @param limit [Integer, nil] maximum number of traces to replay (default: 5;
96
- # maximum: 5,000). Ignored when trace_ids or dataset_id is passed because
96
+ # maximum: 5,000). Ignored when trace_ids or a dataset is passed because
97
97
  # either source already determines how many traces replay. Supplying
98
98
  # trace_ids also emits a warning.
99
99
  # @param trace_ids [Array<String>, nil] optional list of trace IDs to replay (max 100),
100
- # mutually exclusive with dataset_id
100
+ # mutually exclusive with dataset_id and dataset_ids
101
101
  # @param max_concurrency [Integer, nil] max threads for parallel replay (default: 10)
102
102
  # @param code_change_description [String, nil] optional rationale for the
103
103
  # code change being tested in this replay (stored on the experiment).
@@ -110,6 +110,9 @@ module Bitfab
110
110
  # Omit to capture automatically, or pass nil to suppress file capture.
111
111
  # @param experiment_group_id [String, nil] optional UUID grouping multiple
112
112
  # replay runs into a single experiment batch
113
+ # @param dataset_ids [Array<String>, nil] optional UUIDs of the datasets this
114
+ # replay runs against, for benchmarking one method against several corpora
115
+ # in a single run; mutually exclusive with dataset_id
113
116
  # @param dataset_id [String, nil] optional UUID of the dataset this replay
114
117
  # runs against, mutually exclusive with trace_ids and stored on the
115
118
  # resulting experiment for durable attribution
@@ -158,7 +161,7 @@ module Bitfab
158
161
  # queued work from in-flight work. A raising callback never crashes the run.
159
162
  # @return [Hash] with :items, :test_run_id, :test_run_url
160
163
  def replay(receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, max_concurrency: 10,
161
- name: nil, code_change_description: Replay::CODE_CHANGE_UNSET, code_change_files: Replay::CODE_CHANGE_UNSET, experiment_group_id: nil, dataset_id: nil, grader_ids: nil, mock: "marked",
164
+ name: nil, code_change_description: Replay::CODE_CHANGE_UNSET, code_change_files: Replay::CODE_CHANGE_UNSET, experiment_group_id: nil, dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked",
162
165
  adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil)
163
166
  Replay.run(
164
167
  self,
@@ -173,6 +176,7 @@ module Bitfab
173
176
  code_change_files:,
174
177
  experiment_group_id:,
175
178
  dataset_id:,
179
+ dataset_ids:,
176
180
  grader_ids:,
177
181
  mock:,
178
182
  adapt_inputs:,
@@ -173,14 +173,17 @@ module Bitfab
173
173
  # replay runs into a single experiment batch
174
174
  # @param name [String, nil] optional display name for the resulting
175
175
  # experiment/test run
176
- # @param dataset_id [String, nil] optional UUID of the dataset this replay
177
- # runs against, stored on the resulting experiment for durable attribution
176
+ # @param dataset_ids [Array<String>, nil] optional UUIDs of the datasets this
177
+ # replay runs against. The run replays the union of their traces, graded by
178
+ # the union of their graders, and is attributed to every one of them. A
179
+ # single id travels as datasetId so a new SDK keeps working against a
180
+ # server that predates datasetIds.
178
181
  # @param grader_ids [Array<String>, nil] optional UUIDs of graders attached
179
182
  # directly to this experiment, graded as the union with the dataset's
180
183
  # runnable graders at completion; each must be an active/live grader in the
181
184
  # same org and trace function or the server rejects the replay
182
185
  def start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil,
183
- code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil,
186
+ code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_ids: nil,
184
187
  grader_ids: nil, db_branch_settings: nil)
185
188
  payload = {
186
189
  "traceFunctionKey" => trace_function_key
@@ -195,7 +198,13 @@ module Bitfab
195
198
  payload["experimentGroupId"] = experiment_group_id unless experiment_group_id.nil?
196
199
  payload["includeDbBranchLease"] = true if include_db_branch_lease
197
200
  payload["lazyDbBranchLease"] = true if include_db_branch_lease
198
- payload["datasetId"] = dataset_id unless dataset_id.nil?
201
+ unless dataset_ids.nil?
202
+ if dataset_ids.length == 1
203
+ payload["datasetId"] = dataset_ids.first
204
+ else
205
+ payload["datasetIds"] = dataset_ids
206
+ end
207
+ end
199
208
  payload["graderIds"] = grader_ids unless grader_ids.nil?
200
209
  payload["dbBranchSettings"] = db_branch_settings unless db_branch_settings.nil?
201
210
 
data/lib/bitfab/replay.rb CHANGED
@@ -187,7 +187,7 @@ module Bitfab
187
187
  # @param method_name [Symbol] the method to replay
188
188
  # @param trace_function_key [String] the trace function key for this method
189
189
  # @param limit [Integer, nil] maximum number of traces to replay (default: 5).
190
- # Ignored when trace_ids or dataset_id is passed because either source
190
+ # Ignored when trace_ids or a dataset is passed because either source
191
191
  # already determines how many traces replay. Supplying trace_ids also
192
192
  # emits a warning.
193
193
  # @param trace_ids [Array<String>, nil] optional list of trace IDs to replay (max 100)
@@ -205,7 +205,13 @@ module Bitfab
205
205
  # @param experiment_group_id [String, nil] optional UUID grouping multiple
206
206
  # replay runs into a single experiment batch
207
207
  # @param dataset_id [String, nil] optional UUID of the dataset this replay
208
- # runs against, stored on the resulting experiment for durable attribution
208
+ # runs against, stored on the resulting experiment for durable attribution;
209
+ # mutually exclusive with dataset_ids
210
+ # @param dataset_ids [Array<String>, nil] optional UUIDs of the datasets this
211
+ # replay runs against, for benchmarking one method against several corpora
212
+ # in a single run; mutually exclusive with dataset_id. The run replays the
213
+ # union of their traces, graded by the union of their graders, and is
214
+ # attributed to every one of them
209
215
  # @param grader_ids [Array<String>, nil] optional UUIDs of graders attached
210
216
  # directly to this experiment, graded as the union with the dataset's
211
217
  # runnable graders at completion; each must be an active/live grader in the
@@ -248,7 +254,7 @@ module Bitfab
248
254
  # @return [Hash] with :items, :test_run_id, :test_run_url
249
255
  def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil,
250
256
  max_concurrency: 10, code_change_description: CODE_CHANGE_UNSET, code_change_files: CODE_CHANGE_UNSET, experiment_group_id: nil,
251
- dataset_id: nil, grader_ids: nil, mock: "marked",
257
+ dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked",
252
258
  adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil)
253
259
  unless MOCK_STRATEGIES.include?(mock.to_s)
254
260
  raise ArgumentError, "Invalid mock strategy '#{mock}'. Must be one of: #{MOCK_STRATEGIES.join(", ")}"
@@ -260,9 +266,10 @@ module Bitfab
260
266
  raise ArgumentError, "trace_ids supports at most 100 trace IDs per replay (got #{trace_ids.length})."
261
267
  end
262
268
  end
263
- if trace_ids && dataset_id
269
+ resolved_dataset_ids = resolve_dataset_ids(dataset_id, dataset_ids)
270
+ if trace_ids && resolved_dataset_ids
264
271
  raise ArgumentError,
265
- "trace_ids and dataset_id select different replay sources and cannot be used together."
272
+ "trace_ids and dataset_ids select different replay sources and cannot be used together."
266
273
  end
267
274
  if limit && trace_ids
268
275
  warn "Bitfab: limit is ignored when trace_ids is passed: the explicit trace ID list already " \
@@ -321,7 +328,7 @@ module Bitfab
321
328
  code_change_files:,
322
329
  experiment_group_id:,
323
330
  include_db_branch_lease:,
324
- dataset_id:,
331
+ dataset_ids: resolved_dataset_ids,
325
332
  grader_ids:,
326
333
  db_branch_settings: resolved_db_branch_settings
327
334
  )
@@ -369,6 +376,8 @@ module Bitfab
369
376
  # run's tokens (span-aggregated server-side), used below to fill each
370
377
  # item's :tokens.
371
378
  replay_tokens = complete_response&.dig("tokens") || {}
379
+ replay_outlines = complete_response&.dig("traceOutlines") || {}
380
+ original_outlines = complete_response&.dig("originalTraceOutlines") || {}
372
381
 
373
382
  # trace_id_map maps each item's client-side correlation id (:_sdk_trace_id,
374
383
  # which tagged that item's spans during the run) to the server's trace row
@@ -392,7 +401,11 @@ module Bitfab
392
401
  completed_count += 1
393
402
  missing << local_id if mapped.nil?
394
403
  end
395
- item[:tokens] = normalize_tokens(replay_tokens[mapped]) if mapped
404
+ if mapped
405
+ item[:tokens] = normalize_tokens(replay_tokens[mapped])
406
+ item[:trace_outline] = replay_outlines[mapped]
407
+ end
408
+ item[:original_trace_outline] = original_outlines[item[:original_trace_id]] if item[:original_trace_id]
396
409
  end
397
410
  # ALL completed items missing: systemic (the replayed method is not
398
411
  # traced, or uploads are wholesale broken). Raise; the run's traces
@@ -466,6 +479,19 @@ module Bitfab
466
479
  CC_MAX_FILE_BYTES = 500_000
467
480
  CC_MAX_TOTAL_BYTES = 2_000_000
468
481
 
482
+ def resolve_dataset_ids(dataset_id, dataset_ids)
483
+ if dataset_id && dataset_ids
484
+ raise ArgumentError,
485
+ "dataset_id and dataset_ids are the same selector: pass one dataset through dataset_id, " \
486
+ "or several through dataset_ids."
487
+ end
488
+ return [dataset_id] if dataset_id
489
+ return nil if dataset_ids.nil?
490
+ raise ArgumentError, "dataset_ids must contain at least one dataset ID." if dataset_ids.empty?
491
+
492
+ dataset_ids.uniq
493
+ end
494
+
469
495
  # Whether the caller asked for database branching. +true+ and a Hash both
470
496
  # turn it on; +false+ and +nil+ leave it off. Kept separate from
471
497
  # +db_branch_settings+ because +db_branch: true+ enables branching while
@@ -778,7 +804,9 @@ module Bitfab
778
804
  tokens: result[:tokens],
779
805
  model: result[:model],
780
806
  db_snapshot_ref: result[:db_snapshot_ref],
781
- db_branch_timings: result[:db_branch_timings]
807
+ db_branch_timings: result[:db_branch_timings],
808
+ trace_outline: result[:trace_outline],
809
+ original_trace_outline: result[:original_trace_outline]
782
810
  }
783
811
  })
784
812
  rescue => e
@@ -965,7 +993,9 @@ module Bitfab
965
993
  source_trace_id: original_trace_id,
966
994
  source_span_id: original_span_id,
967
995
  db_snapshot_ref:,
968
- db_branch_timings:
996
+ db_branch_timings:,
997
+ trace_outline: nil,
998
+ original_trace_outline: nil
969
999
  }
970
1000
  ensure
971
1001
  release_db_branch_lease(http_client, lease) if lease
@@ -1265,7 +1295,9 @@ module Bitfab
1265
1295
  source_trace_id: source_bitfab_trace_id,
1266
1296
  source_span_id: input_source_span_id,
1267
1297
  db_snapshot_ref:,
1268
- db_branch_timings:
1298
+ db_branch_timings:,
1299
+ trace_outline: nil,
1300
+ original_trace_outline: nil
1269
1301
  }
1270
1302
  end
1271
1303
  end
@@ -20,7 +20,7 @@ module Bitfab
20
20
  class ReplayRegistry
21
21
  OPTION_NAMES = %i[
22
22
  limit trace_ids name max_concurrency code_change_description
23
- code_change_files experiment_group_id dataset_id grader_ids mock
23
+ code_change_files experiment_group_id dataset_id dataset_ids grader_ids mock
24
24
  mock_override adapt_inputs db_branch
25
25
  ].freeze
26
26
 
@@ -97,29 +97,34 @@ module Bitfab
97
97
  options.merge!(dynamic_options)
98
98
  end
99
99
 
100
- if options[:trace_ids] && options[:dataset_id]
100
+ selected_dataset_ids = registry_dataset_ids(options)
101
+ options.delete(:dataset_id)
102
+ options.delete(:dataset_ids)
103
+ options[:dataset_ids] = selected_dataset_ids if selected_dataset_ids
104
+
105
+ if options[:trace_ids] && selected_dataset_ids
101
106
  raise ArgumentError,
102
- "Replay registry options trace_ids and dataset_id select different sources and cannot be used together."
107
+ "Replay registry options trace_ids and dataset_ids select different sources and cannot be used together."
103
108
  end
104
109
 
105
110
  if args[:trace_ids]
106
111
  options.delete(:limit)
107
- options.delete(:dataset_id)
112
+ options.delete(:dataset_ids)
108
113
  options[:trace_ids] = args[:trace_ids]
109
- elsif args[:dataset_id]
114
+ elsif args[:dataset_ids]
110
115
  options.delete(:trace_ids)
111
116
  options.delete(:limit)
112
117
  elsif args[:limit]
113
118
  options.delete(:trace_ids)
114
- options.delete(:dataset_id)
119
+ options.delete(:dataset_ids)
115
120
  options[:limit] = args[:limit]
116
- elsif options[:trace_ids] || options[:dataset_id]
121
+ elsif options[:trace_ids] || selected_dataset_ids
117
122
  options.delete(:limit)
118
123
  else
119
124
  options[:limit] = options.fetch(:limit, 10)
120
125
  end
121
126
 
122
- %i[name max_concurrency experiment_group_id dataset_id grader_ids mock].each do |key|
127
+ %i[name max_concurrency experiment_group_id dataset_ids grader_ids mock].each do |key|
123
128
  options[key] = args[key] unless args[key].nil?
124
129
  end
125
130
 
@@ -145,8 +150,7 @@ module Bitfab
145
150
  options[:on_item_start] = reporter
146
151
  options[:on_item_finish] = reporter
147
152
 
148
- count = options[:trace_ids]&.length || options[:limit] || "dataset"
149
- stderr.puts "[replay] Replaying #{count} traces from \"#{registration.trace_function_key}\"..."
153
+ stderr.puts "[replay] Replaying #{describe_selection(options)} from \"#{registration.trace_function_key}\"..."
150
154
 
151
155
  result = begin
152
156
  registration.client.replay(
@@ -186,7 +190,7 @@ module Bitfab
186
190
  end
187
191
  options.on("--code-change PATH") { |value| args[:code_change] = value }
188
192
  options.on("--experiment-group-id UUID") { |value| args[:experiment_group_id] = value }
189
- options.on("--dataset-id UUID") { |value| args[:dataset_id] = value }
193
+ options.on("--dataset-ids IDS", "--dataset-id IDS") { |value| args[:dataset_ids] = comma_separated("--dataset-ids", value) }
190
194
  options.on("--grader-ids IDS") { |value| args[:grader_ids] = comma_separated("--grader-ids", value) }
191
195
  options.on("--mock STRATEGY", %w[none all marked]) { |value| args[:mock] = value }
192
196
  options.on("--db-branch") { args[:db_branch] = true }
@@ -196,9 +200,9 @@ module Bitfab
196
200
  options.on("--param NAME=VALUE") { |value| (args[:param] ||= []) << value }
197
201
  end
198
202
  parser.parse!(argv)
199
- if args[:trace_ids] && args[:dataset_id]
203
+ if args[:trace_ids] && args[:dataset_ids]
200
204
  raise OptionParser::InvalidArgument,
201
- "--trace-ids and --dataset-id select different replay sources and cannot be used together"
205
+ "--trace-ids and --dataset-ids select different replay sources and cannot be used together"
202
206
  end
203
207
  if args[:code_change] && args[:no_code_change]
204
208
  raise OptionParser::InvalidArgument, "--code-change and --no-code-change cannot be used together"
@@ -210,6 +214,26 @@ module Bitfab
210
214
  args.merge(pipeline:)
211
215
  end
212
216
 
217
+ def registry_dataset_ids(options)
218
+ dataset_id = options[:dataset_id]
219
+ dataset_ids = options[:dataset_ids]
220
+ if dataset_id && dataset_ids
221
+ raise ArgumentError,
222
+ "Replay registry options dataset_id and dataset_ids are the same selector: set one of them."
223
+ end
224
+ return [dataset_id] if dataset_id
225
+
226
+ dataset_ids
227
+ end
228
+
229
+ def describe_selection(options)
230
+ return "#{options[:trace_ids].length} traces" if options[:trace_ids]
231
+ return "#{options[:limit]} traces" if options[:limit]
232
+
233
+ dataset_count = options[:dataset_ids]&.length || 1
234
+ (dataset_count > 1) ? "#{dataset_count} datasets' traces" : "dataset traces"
235
+ end
236
+
213
237
  def positive_integer(flag, value)
214
238
  raise OptionParser::InvalidArgument, "#{flag} must be a positive integer" if value < 1
215
239
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.43.0"
4
+ VERSION = "0.51.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitfab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.0
4
+ version: 0.51.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team