smith-agents 0.12.6 → 0.12.7

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: 97813bcba79ce652b05eb860da067e3c566b8ba3450344d66940c9f65d23a1dc
4
- data.tar.gz: ea20e0a30b7517aab44a43b2668cb5e59fde6b98a829056e8e73ba585338f216
3
+ metadata.gz: 8158004e28c8bec8f58a83727cbfe9d91a7fff89dd24cc3435aefd06f87d826f
4
+ data.tar.gz: 6b7088fd850554492cbe98edb93c76b2d1958024206eec9a497fd423f7d2b794
5
5
  SHA512:
6
- metadata.gz: 37d47a1f6268dc96cd05ce69f4138998d1c5a9649bbb41921882b6ae93a8f5d030586c273f37231501c121dd43492e1a37034cefe88981a5f89138cbf1ccd128
7
- data.tar.gz: 40eb2c1a4ac979411860e4971b4814e0c2cdaebc39f1a827e956f7fcb2a5ca33c3f34d18aad339edfa1460a8fce07188f505aa174a2e59233d735c50bab258d3
6
+ metadata.gz: 442ebb9375a3e912f6d98c08da04e67d3aeec1afa8aa1b0f1a45f936e4e33ef9b9dd477d847b113510545a34327451566bd264b3ca2970a26762d61291c5d5f4
7
+ data.tar.gz: dc3fb7433a59f12a2e947e8eeec20670f4430e5c86b654ad5e1795c4f6e75da753450905de141b409e19162c2f034f070685bf40ef83aa3a93b370abd21fcab6
data/CHANGELOG.md CHANGED
@@ -4,6 +4,33 @@ All notable changes to Smith are documented in this file.
4
4
 
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Smith is pre-1.0 and under active development; expect occasional contract tightening between minor versions until 1.0.
6
6
 
7
+ ## [0.12.7] - 2026-10-13
8
+
9
+ ### Added
10
+
11
+ - A workflow can rename a state or a transition and keep its persisted runs:
12
+ `renamed_state :old, to: :new` and `renamed_transition :old, to: :new`.
13
+ On restore, a run persisted under an old name is mapped to the new one
14
+ before anything checks it: its state, the transition it takes next, the
15
+ transition its wait, pending retry or pending batch is in, and its last
16
+ failed step's names, each kept the type it was persisted as. A run waiting
17
+ in a renamed step resumes there under its wait's own token; one in a
18
+ renamed state carries on from the new one. A renamed transition keeps its
19
+ keys: its steps' idempotency keys and wait tokens are made under the first
20
+ name in its chain (`Workflow.transition_key_name`), so a step cut short, a
21
+ retry or an early delivery meets the keys its earlier attempt used. Renames
22
+ chain (a to b, then b to c); a name renamed twice or back to a name it had,
23
+ and two names renamed to one transition, are refused where declared. A name
24
+ the class still declares is never taken for an old one, a rename to a name
25
+ the class does not know is still refused on restore
26
+ (`Smith::UnknownStateOnRestore`, `UnknownTransitionOnRestore`), and
27
+ `validate_graph` reports both (`:rename_shadowed`,
28
+ `:renamed_to_unknown_state`, `:renamed_to_unknown_transition`). Subclasses
29
+ inherit their parent's renames, and `stuck_for?` follows them. Renames apply
30
+ after `migrate_from`; no `persistence_schema_version` is needed for one.
31
+ `Workflow.current_state_name` and `current_transition_name` give what a
32
+ persisted name stands for now, renames followed.
33
+
7
34
  ## [0.12.6] - 2026-10-13
8
35
 
9
36
  ### Fixed
data/README.md CHANGED
@@ -30,7 +30,7 @@ What you get:
30
30
 
31
31
  ```ruby
32
32
  # Gemfile
33
- gem "smith-agents", "0.12.6", require: "smith"
33
+ gem "smith-agents", "0.12.7", require: "smith"
34
34
  ```
35
35
 
36
36
  In a Rails app:
@@ -137,8 +137,11 @@ Your app delivers events (`resume!`), schedules the timeout
137
137
  (`expire_wait!` once `deadline_at` passes), and runs the next step from a
138
138
  job. Smith stores runs through an adapter (`:active_record`, `:redis`,
139
139
  `:rails_cache`, `:memory` or your own) and refuses a state past
140
- `persistence_max_bytes`. Waits, child runs, durable retries, replay safety
141
- and storage: [`docs/PERSISTENCE.md`](docs/PERSISTENCE.md).
140
+ `persistence_max_bytes`. A later version can rename a state or a step
141
+ (`renamed_state :drafted, to: :written`, `renamed_transition :approve, to:
142
+ :review`), and runs persisted under the old names carry on under the new ones,
143
+ waits included, under the keys they had. Waits, child runs, durable retries, replay safety, renames and
144
+ storage: [`docs/PERSISTENCE.md`](docs/PERSISTENCE.md).
142
145
 
143
146
  ## Agent outputs
144
147
 
data/docs/PERSISTENCE.md CHANGED
@@ -72,12 +72,40 @@ What Smith does for you:
72
72
  `migrate_from` and after the `definition_digest` check, so a digest
73
73
  mismatch is reported as one and a migration can map an old name: bump
74
74
  `persistence_schema_version` and declare `migrate_from(<previous version>)`,
75
- since migrations run only when the stored version is behind. Finished runs
76
- are refused too, by `restore`, `restore_or_initialize`,
77
- `restorable_billing_state?` and the class-level `run_persisted!`: to read the
78
- outcome of a finished run whose terminal state was renamed, migrate it or
79
- read the stored JSON directly. `stuck_for?` reports a stored run in an
80
- unknown state as stuck, since it can neither advance nor restore
75
+ since migrations run only when the stored version is behind. A rename needs
76
+ neither: `renamed_state :old, to: :new` and `renamed_transition :old, to:
77
+ :new` map a run persisted under the old name to the new one after
78
+ `migrate_from` (a migration sees the names as they were persisted) and
79
+ before anything checks it (its state, the transition it takes next, the
80
+ transition its wait, pending retry or pending batch is in, and its last
81
+ failed step's names, each kept the type it was persisted as), so a run
82
+ waiting in a renamed step resumes there under its wait's own token. A
83
+ renamed transition keeps its keys: its steps' idempotency keys and wait
84
+ tokens are made under the first name in its chain
85
+ (`Workflow.transition_key_name`), so a step a deploy cut short runs again, a
86
+ retry makes its next attempt, and a delivery that came before its wait was
87
+ stored meets the block's token, all under the keys they had before the
88
+ rename. Renames chain (a to b, then b to c); a name is renamed at most once,
89
+ never back to a name it had, and at most one name is renamed to a given
90
+ transition, each refused with `ArgumentError` where it is declared. A name
91
+ the class still declares is never taken for an old one, and a rename to a
92
+ name the class does not know is refused as above when a run restores
93
+ through it; `validate_graph` reports both before then (`:rename_shadowed`,
94
+ a warning; `:renamed_to_unknown_state` and `:renamed_to_unknown_transition`,
95
+ errors). A subclass inherits its parent's renames. A state's rename stays
96
+ declared while runs persisted under its old name may remain; a
97
+ transition's, for good, since dropping it moves the transition's keys to
98
+ its new name.
99
+ `Workflow.current_state_name` and `current_transition_name` give what a
100
+ persisted name stands for now, renames followed. In strict mode a payload
101
+ caught mid-step is refused before renames apply, so
102
+ `Smith::StepInProgressOnRestore` names its transition as persisted. Finished
103
+ runs are refused too, by `restore`, `restore_or_initialize`,
104
+ `restorable_billing_state?` and the class-level `run_persisted!`: a finished
105
+ run whose terminal state was renamed restores while the rename is declared;
106
+ to read one whose terminal state was removed, migrate it or read the stored
107
+ JSON directly. `stuck_for?` reports a stored run in an unknown state
108
+ (renames followed) as stuck, since it can neither advance nor restore
81
109
 
82
110
  `preserve_seed: true` is intended for workflows whose seed is durable external
83
111
  conversation and whose later accepted outputs are internal stage handoffs. Smith
@@ -860,8 +888,9 @@ end
860
888
  transition raises `Smith::SerializationError`; one whose transition the
861
889
  class no longer declares exactly (kind, event, `into:`) or that does not
862
890
  start from the run's state raises `Smith::UnknownTransitionOnRestore`. A
863
- `migrate_from` that renames such things must rewrite `awaiting` too, and
864
- `pending_retry` for a retry wait.
891
+ rename declared with `renamed_transition` (or `renamed_state`) maps the
892
+ wait's transition first; a `migrate_from` that renames such things itself
893
+ must rewrite `awaiting` too, and `pending_retry` for a retry wait.
865
894
  - A wait that does not end within the store's persistence TTL is refused when
866
895
  it is entered, before the block runs. `stuck_for?` reports a waiting run as stuck
867
896
  only once its deadline has passed by the threshold.
data/lib/smith/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Smith
4
- VERSION = "0.12.6"
4
+ VERSION = "0.12.7"
5
5
  EXECUTION_SEMANTICS_VERSION = "7"
6
6
  end
@@ -141,7 +141,8 @@ module Smith
141
141
  check_deadline!
142
142
  namespace = ArtifactIntegration.instance_method(:execution_namespace).bind_call(self)
143
143
  token = IdempotencyKey.__send__(:root_scope, namespace)
144
- .within(:step, @step_count + 1, transition.name.to_s).within(:spawn).key
144
+ .within(:step, @step_count + 1, self.class.transition_key_name(transition.name))
145
+ .within(:spawn).key
145
146
  launch_child_runs(transition, token)
146
147
  nil
147
148
  end
@@ -33,6 +33,8 @@ module Smith
33
33
  subclass.instance_variable_set(:@persistence_key_builder, @persistence_key_builder)
34
34
  subclass.instance_variable_set(:@persistence_schema_version, @persistence_schema_version)
35
35
  subclass.instance_variable_set(:@migrations, (@migrations || {}).dup)
36
+ subclass.instance_variable_set(:@renamed_states, @renamed_states)
37
+ subclass.instance_variable_set(:@renamed_transitions, @renamed_transitions)
36
38
  subclass.instance_variable_set(:@seed_validation_mode, @seed_validation_mode)
37
39
  subclass.instance_variable_set(:@idempotency_mode, @idempotency_mode)
38
40
  subclass.instance_variable_set(:@session_mode, @session_mode)
@@ -165,6 +167,77 @@ module Smith
165
167
  @migrations || {}
166
168
  end
167
169
 
170
+ # A state a later version renamed: a run persisted in `old`
171
+ # restores in `to` and carries on from there. Renames chain (a to
172
+ # b, then b to c); a name is renamed at most once and never back
173
+ # to a name it had. A name the class still declares is never taken
174
+ # for an old one (validate_graph warns of such a rename). The
175
+ # persisted run is mapped after migrate_from, before anything
176
+ # checks its names, so a rename needs no persistence_schema_version.
177
+ # A rename stays declared while runs persisted under its old name
178
+ # may remain.
179
+ def renamed_state(old, to:)
180
+ @renamed_states = renamed_name_map(renamed_states, old, to, kind: "state")
181
+ end
182
+
183
+ # A transition a later version renamed: a run persisted about to
184
+ # take `old`, or waiting in it (its wait, pending retry or batch),
185
+ # restores at `to`, as renamed_state. A renamed transition keeps
186
+ # its keys: its steps' idempotency keys and wait tokens are made
187
+ # under the first name in its chain (transition_key_name), so a
188
+ # step a deploy cut short, a retry or an early delivery meets the
189
+ # keys its earlier attempt used. Hence at most one name is renamed
190
+ # to a transition, and the rename stays declared for good: dropping
191
+ # it moves the transition's keys to its new name.
192
+ def renamed_transition(old, to:)
193
+ renames = renamed_name_map(renamed_transitions, old, to, kind: "transition")
194
+ earlier = renamed_transitions.key(renames.fetch(old.to_s))
195
+ if earlier
196
+ raise ArgumentError, "transition #{to.inspect} is already the new name of #{earlier.inspect}; a " \
197
+ "transition keeps the keys of one first name, so only one name is renamed to it"
198
+ end
199
+
200
+ @renamed_transitions = renames
201
+ end
202
+
203
+ def renamed_states
204
+ @renamed_states || {}.freeze
205
+ end
206
+
207
+ def renamed_transitions
208
+ @renamed_transitions || {}.freeze
209
+ end
210
+
211
+ # The state a persisted state name stands for now, renames
212
+ # followed, or nil when the class knows none. `O(R·(S + T))` for
213
+ # `R` renamed states.
214
+ def current_state_name(name)
215
+ return if name.nil?
216
+
217
+ resolve_state_name(follow_renames(name, renamed_states) { |candidate| resolve_state_name(candidate) })
218
+ end
219
+
220
+ # The transition a persisted transition name stands for now,
221
+ # renames followed, or nil when the class knows none. `O(R·T)` for
222
+ # `R` renamed transitions.
223
+ def current_transition_name(name)
224
+ return if name.nil?
225
+
226
+ transition_named(follow_renames(name, renamed_transitions) { |candidate| transition_named(candidate) })&.name
227
+ end
228
+
229
+ # The name a transition's steps are keyed under (their idempotency
230
+ # keys and wait tokens): the first name in its rename chain, so a
231
+ # renamed transition keeps its keys. Renames have no cycles and at
232
+ # most one name renamed to each, so the chain back is a line.
233
+ # `O(R)` for `R` renamed transitions.
234
+ def transition_key_name(name)
235
+ earlier = renamed_transitions.invert
236
+ current = name.to_s
237
+ current = earlier[current] while earlier.key?(current)
238
+ current
239
+ end
240
+
168
241
  # Controls whether restore validates that the seed_messages
169
242
  # builder still produces the same digest as when this workflow
170
243
  # was originally persisted.
@@ -313,6 +386,56 @@ module Smith
313
386
  Identifier.normalize(identifier, label: "workflow identifier")
314
387
  end
315
388
 
389
+ # The renames with `old` renamed to `to`: refused when `old` is
390
+ # already renamed, or when the chain from `to` leads back to `old`
391
+ # (a rename back), so every chain is a line. `O(R)`.
392
+ def renamed_name_map(renames, old, to, kind:)
393
+ old_name = renamed_identifier(old, kind:)
394
+ new_name = renamed_identifier(to, kind:)
395
+ check_rename!(renames, old_name, new_name, kind:)
396
+ renames.merge(old_name => new_name).freeze
397
+ end
398
+
399
+ def check_rename!(renames, old_name, new_name, kind:)
400
+ if old_name == new_name
401
+ raise ArgumentError, "a renamed #{kind} must differ from its new name, got #{old_name.inspect}"
402
+ end
403
+
404
+ if renames.key?(old_name)
405
+ raise ArgumentError, "#{kind} #{old_name.inspect} is already renamed to #{renames[old_name].inspect}; " \
406
+ "rename #{renames[old_name].inspect} instead"
407
+ end
408
+
409
+ return unless renamed_back?(renames, old_name, new_name)
410
+
411
+ raise ArgumentError, "#{kind} #{new_name.inspect} was renamed from #{old_name.inspect}; a #{kind} is " \
412
+ "never renamed back to a name it had"
413
+ end
414
+
415
+ def renamed_back?(renames, old_name, new_name)
416
+ current = new_name
417
+ current = renames[current] while renames.key?(current) && current != old_name
418
+ current == old_name
419
+ end
420
+
421
+ def renamed_identifier(name, kind:)
422
+ unless (name.is_a?(Symbol) || name.is_a?(String)) && !name.to_s.strip.empty?
423
+ raise ArgumentError, "a renamed #{kind} must be a non-blank Symbol or String, got #{name.inspect}"
424
+ end
425
+
426
+ name.to_s
427
+ end
428
+
429
+ # The name `name` stands for now: itself while the class declares
430
+ # it (`declared` says so), else where its renames lead. Chains are
431
+ # lines (renamed_name_map), so the walk ends. `O(R)` calls of
432
+ # `declared`.
433
+ def follow_renames(name, renames, &declared)
434
+ current = name.to_s
435
+ current = renames[current] until declared.call(current) || !renames.key?(current)
436
+ current
437
+ end
438
+
316
439
  def transitions_by_state
317
440
  @transitions_by_state ||= Hash.new { |index, state| index[state] = [] }
318
441
  end
@@ -244,10 +244,11 @@ module Smith
244
244
  false
245
245
  end
246
246
 
247
- # A state the class no longer knows can never advance or restore, so
248
- # it is not terminal: an old one reports as stuck.
247
+ # A state the class no longer knows, renames followed, can never
248
+ # advance or restore, so it is not terminal: an old one reports as
249
+ # stuck.
249
250
  def terminal_payload_state?(klass, state_name, next_transition)
250
- state = klass.resolve_state_name(state_name)
251
+ state = klass.current_state_name(state_name)
251
252
  !state.nil? && !klass.transition_from?(state) && next_transition.nil?
252
253
  end
253
254
 
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smith
4
+ class Workflow
5
+ class Graph
6
+ # Renames (renamed_state, renamed_transition) found wanting before a
7
+ # run restores through one: a rename leading to no name the workflow
8
+ # declares is an error, as a run persisted under its old name cannot
9
+ # restore; one whose old name the workflow still declares is a
10
+ # warning, as a run persisted under that name stays there.
11
+ # `O(R·(S + T))` for `R` renames.
12
+ class RenameDiagnostics
13
+ attr_reader :graph
14
+
15
+ def initialize(graph)
16
+ @graph = graph
17
+ end
18
+
19
+ def to_a
20
+ workflow = graph.workflow_class
21
+
22
+ [
23
+ *diagnostics_for(:state, workflow.renamed_states) do |name|
24
+ [workflow.resolve_state_name(name), workflow.current_state_name(name)]
25
+ end,
26
+ *diagnostics_for(:transition, workflow.renamed_transitions) do |name|
27
+ [workflow.transition_named(name), workflow.current_transition_name(name)]
28
+ end
29
+ ]
30
+ end
31
+
32
+ private
33
+
34
+ def diagnostics_for(kind, renames)
35
+ renames.filter_map do |old, new|
36
+ declared, current = yield(old)
37
+ if declared
38
+ shadowed(kind, old, new)
39
+ elsif current.nil?
40
+ leads_nowhere(kind, old, new)
41
+ end
42
+ end
43
+ end
44
+
45
+ def shadowed(kind, old, new)
46
+ Diagnostic.new(
47
+ severity: :warning,
48
+ code: :rename_shadowed,
49
+ kind => old,
50
+ message: "Renamed #{kind} #{old.inspect} is still declared, so a run persisted in it stays there " \
51
+ "rather than moving to #{new.inspect}.",
52
+ suggestion: "Drop the rename, or move such runs with persistence_schema_version and migrate_from."
53
+ )
54
+ end
55
+
56
+ def leads_nowhere(kind, old, new)
57
+ Diagnostic.new(
58
+ severity: :error,
59
+ code: :"renamed_to_unknown_#{kind}",
60
+ kind => old,
61
+ message: "Renamed #{kind} #{old.inspect} leads through #{new.inspect} to no #{kind} this workflow " \
62
+ "declares, so a run persisted in it cannot restore.",
63
+ suggestion: "Declare #{kind} #{new.inspect} or rename #{old.inspect} to a declared #{kind}."
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -29,6 +29,7 @@ module Smith
29
29
  def all_diagnostics
30
30
  [
31
31
  *StateDiagnostics.new(graph).to_a,
32
+ *RenameDiagnostics.new(graph).to_a,
32
33
  *TransitionDiagnostics.new(graph).to_a,
33
34
  *ReachabilityDiagnostics.new(graph, reachable_transition_names).to_a
34
35
  ]
@@ -88,6 +88,7 @@ require_relative "graph/identifier_projection"
88
88
  require_relative "graph/transition_contract"
89
89
  require_relative "graph/diagnostic"
90
90
  require_relative "graph/state_diagnostics"
91
+ require_relative "graph/rename_diagnostics"
91
92
  require_relative "graph/targets"
92
93
  require_relative "graph/execution_successors"
93
94
  require_relative "graph/reachability"
@@ -87,7 +87,7 @@ module Smith
87
87
  def restore_state(hash, allow_step_in_progress: false)
88
88
  validate_raw_step_in_progress!(hash) if
89
89
  self.class.idempotency_mode == :strict && !allow_step_in_progress
90
- migrated = migrate_if_needed(hash)
90
+ migrated = apply_renames(migrate_if_needed(hash))
91
91
  normalized = normalize_persisted_state(migrated)
92
92
  persistence_version = validated_persistence_version(normalized)
93
93
  restore_persisted_keys(normalized)
@@ -447,6 +447,74 @@ module Smith
447
447
  payload
448
448
  end
449
449
 
450
+ # A run persisted under names a later version renamed
451
+ # (renamed_state, renamed_transition) carries on under the new
452
+ # ones: its state, the transition it takes next, the transition its
453
+ # wait, pending retry and pending batch are in, and its last failed
454
+ # step's names, each kept the type it was persisted as. A name the
455
+ # class still declares stays as it is.
456
+ RENAMED_RECORDS = {
457
+ awaiting: { transition: %w[transition] },
458
+ pending_retry: { transition: %w[transition] },
459
+ pending_batch: { transition: %w[transition] },
460
+ last_failed_step: { transition: %w[transition], state: %w[from to] }
461
+ }.freeze
462
+ private_constant :RENAMED_RECORDS
463
+
464
+ def apply_renames(payload)
465
+ return payload unless renames?
466
+
467
+ renamed = payload.dup
468
+ renamed[:state] = renamed_state_name(payload[:state])
469
+ renamed[:next_transition_name] = renamed_transition_name(payload[:next_transition_name]) if
470
+ payload.key?(:next_transition_name)
471
+ RENAMED_RECORDS.each_key { |key| renamed[key] = renamed_record(payload[key], RENAMED_RECORDS[key]) }
472
+ renamed
473
+ end
474
+
475
+ def renames? = !(self.class.renamed_states.empty? && self.class.renamed_transitions.empty?)
476
+
477
+ def renamed_state_name(name)
478
+ renamed_value(name) do |text|
479
+ self.class.send(:follow_renames, text, self.class.renamed_states) do |candidate|
480
+ self.class.resolve_state_name(candidate)
481
+ end
482
+ end
483
+ end
484
+
485
+ def renamed_transition_name(name)
486
+ renamed_value(name) do |text|
487
+ self.class.send(:follow_renames, text, self.class.renamed_transitions) do |candidate|
488
+ self.class.transition_named(candidate)
489
+ end
490
+ end
491
+ end
492
+
493
+ # A persisted name renamed, kept the type it was persisted as.
494
+ def renamed_value(name)
495
+ return name unless name.is_a?(String) || name.is_a?(Symbol)
496
+
497
+ renamed = yield(name.to_s)
498
+ name.is_a?(Symbol) ? renamed.to_sym : renamed
499
+ end
500
+
501
+ # A persisted record's name fields renamed, each by its kind
502
+ # (:state or :transition), under String or Symbol keys alike.
503
+ def renamed_record(record, fields_by_kind)
504
+ return record unless record.is_a?(Hash)
505
+
506
+ renamed = record.dup
507
+ fields_by_kind.each do |kind, fields|
508
+ fields.each do |field|
509
+ key = [field, field.to_sym].find { |candidate| renamed.key?(candidate) }
510
+ next if key.nil?
511
+
512
+ renamed[key] = kind == :state ? renamed_state_name(renamed[key]) : renamed_transition_name(renamed[key])
513
+ end
514
+ end
515
+ renamed
516
+ end
517
+
450
518
  def normalize_persisted_state(hash)
451
519
  normalized = snapshot_value(hash).transform_keys { |k| k.is_a?(String) ? k.to_sym : k }
452
520
  normalized[:outcome] = symbolize_value(normalized[:outcome]) if normalized[:outcome].is_a?(Hash)
@@ -99,7 +99,8 @@ module Smith
99
99
  namespace = ArtifactIntegration.instance_method(:execution_namespace).bind_call(self)
100
100
  outer = IdempotencyKey.__send__(:current_scope)
101
101
  base = outer && outer.run == namespace ? outer : IdempotencyKey.__send__(:root_scope, namespace)
102
- IdempotencyKey.__send__(:install, base.within(:step, @step_count + 1, transition.name.to_s))
102
+ position = base.within(:step, @step_count + 1, self.class.transition_key_name(transition.name))
103
+ IdempotencyKey.__send__(:install, position)
103
104
  end
104
105
 
105
106
  def teardown_step_context
@@ -140,7 +140,8 @@ module Smith
140
140
 
141
141
  def wait_token_for(transition, scope)
142
142
  IdempotencyKey.__send__(:root_scope, ArtifactIntegration.instance_method(:execution_namespace).bind_call(self))
143
- .within(:step, @step_count + 1, transition.name.to_s).within(:wait).key(scope)
143
+ .within(:step, @step_count + 1, self.class.transition_key_name(transition.name))
144
+ .within(:wait).key(scope)
144
145
  end
145
146
 
146
147
  def check_wait_admissible!(transition, seconds)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smith-agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.6
4
+ version: 0.12.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Ralak
@@ -485,6 +485,7 @@ files:
485
485
  - lib/smith/workflow/graph/reachability.rb
486
486
  - lib/smith/workflow/graph/reachability_diagnostics.rb
487
487
  - lib/smith/workflow/graph/reference.rb
488
+ - lib/smith/workflow/graph/rename_diagnostics.rb
488
489
  - lib/smith/workflow/graph/report.rb
489
490
  - lib/smith/workflow/graph/retry_policy_diagnostic.rb
490
491
  - lib/smith/workflow/graph/run_launcher_diagnostic.rb