Class: Insika::Commands::RecordShadowReply

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/commands/record_shadow_reply.rb

Overview

C4 — the incumbent's half of a shadow pair, recorded on the mirror's word. One command, two doors: Shape 1 (the reply rides the mirror call itself) and Shape 2 (the follow-up route, for a consumer that mirrors before answering) both dispatch HERE, so there is one behaviour and one store method behind both.

Idempotency is first-write-wins: the customer received ONE reply, and letting a retry overwrite it would silently rewrite evidence. The guarantee lives in ShadowPairStore#record_incumbent (inside its transaction); the find below is only the cheap fast path for the common retry. A reply for a pair that does not exist yet creates it :open — the mirror may legitimately arrive before our turn finishes.

Instance Method Summary collapse

Constructor Details

#initialize(shadow_pairs:, event_stream: nil) ⇒ RecordShadowReply

Returns a new instance of RecordShadowReply.



20
21
22
23
# File 'lib/insika/commands/record_shadow_reply.rb', line 20

def initialize(shadow_pairs:, event_stream: nil)
  @shadow_pairs = shadow_pairs
  @event_stream = event_stream
end

Instance Method Details

#call(command) ⇒ Object

payload: { channel:, external_id:, event_id:, reply:, at: } -> { pair_id:, status: }

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/insika/commands/record_shadow_reply.rb', line 27

def call(command)
  payload = command.payload
  channel = Coercion.presence(payload[:channel] || payload["channel"])
  external_id = Coercion.presence(payload[:external_id] || payload["external_id"])
  event_id = Coercion.presence(payload[:event_id] || payload["event_id"])
  reply = payload[:reply] || payload["reply"]

  raise ValidationError, "channel is required" if channel.nil?
  raise ValidationError, "external_id is required" if external_id.nil?
  raise ValidationError, "event_id is required" if event_id.nil?
  raise ValidationError, "reply is required" if reply.to_s.strip.empty?

  id = ShadowPairStore.key_for(channel: channel, external_id: external_id,
                               event_id: event_id)
  existing = @shadow_pairs.find(id)
  if existing && !existing.incumbent_reply.nil?
    emit(id, "already_recorded")
    return { pair_id: id, status: "already_recorded" }
  end

  pair = @shadow_pairs.record_incumbent(id: id, channel: channel, event_id: event_id,
                                        external_id: external_id, reply: reply.to_s,
                                        at: payload[:at] || payload["at"])
  emit(id, pair.status.to_s)
  { pair_id: id, status: pair.status.to_s }
end