Module: Plutonium::Wizard::InstanceKey

Defined in:
lib/plutonium/wizard/instance_key.rb

Overview

Computes the deterministic identity digest a wizard session row is keyed by (§4). There are two builders, mirroring the two identity axes:

  • InstanceKey.concurrency — a wizard with a concurrency_key. The digest is over the wizard name and the serialized key value(s) (which already include the folded tenant, §4.4). The keyed row IS the lock — two launches with the same key collapse to one digest, so the second resumes the first.
  • InstanceKey.tokened — a wizard without a concurrency_key. The digest is over the wizard name and the per-launch wizard_token, so every launch is a fresh, independent (repeatable) run.

The two recipes MUST stay byte-identical between the place that creates rows (runner/driving) and the place that recomputes the key (the gate), or one-time gating silently breaks.

Class Method Summary collapse

Class Method Details

.concurrency(wizard_name, key_values) ⇒ String

Keyed (concurrency_key) identity.

Parameters:

  • wizard_name (String)

    the wizard class name

  • key_values (Object, Array)

    the concurrency_key value(s); arrays are serialized element-wise then joined. The tenant is expected to already be folded in by the caller (§4.4).

Returns:

  • (String)

    a hex SHA256 digest



30
31
32
# File 'lib/plutonium/wizard/instance_key.rb', line 30

def self.concurrency(wizard_name, key_values)
  digest("concurrency", wizard_name, serialize(key_values))
end

.serialize(value) ⇒ Object

Serialize a key value into a STRUCTURED, unambiguous form for the digest:

- Array → each element serialized, kept as a nested array
- AR record / GlobalID-able → its GlobalID string
- nil → nil (a nil tenant folds to a stable, distinct blank)
- scalar → to_s

Structure (not a flat join) is the point: the digest hashes the JSON of the nested form, so ["a", "b"] and the scalar "a|b" serialize to distinct JSON (["a","b"] vs "a|b") and can never collide. A separator-joined form would make a key element containing the separator indistinguishable from a structural boundary (two distinct runs collapsing to one row — cross-run data exposure / one-time gating satisfied by the wrong run).

Parameters:

  • value (Object)

Returns:

  • (Object)

    a JSON-serializable structure (String / nested Array / nil)



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/plutonium/wizard/instance_key.rb', line 58

def self.serialize(value)
  case value
  when Array
    value.map { |v| serialize(v) }
  when nil
    nil
  when String, Symbol, Numeric, true, false
    value.to_s
  else
    if value.respond_to?(:to_global_id)
      value.to_global_id.to_s
    else
      value.to_s
    end
  end
end

.tokened(wizard_name, token) ⇒ String

Tokened (no concurrency_key) identity.

Parameters:

  • wizard_name (String)

    the wizard class name

  • token (String)

    the per-launch wizard token

Returns:

  • (String)

    a hex SHA256 digest



39
40
41
# File 'lib/plutonium/wizard/instance_key.rb', line 39

def self.tokened(wizard_name, token)
  digest("tokened", wizard_name, token.to_s)
end