Skip to content

Replay only events strictly greater than from_event_seq on job.subscribe (§7.6) #75

@nficano

Description

@nficano

Category: spec-conformance Severity: minor
Location: lib/arcp/runtime/session_actor.rb:297-300 (secondary: lib/arcp/runtime/event_log.rb:61-69)
Spec: ARCP v1.1 §7.6

What

Spec §7.6: with history: true, "the runtime replays buffered events with seq > from_event_seq." handle_subscribe calls replay_job(sub.job_id, from_event_seq: sub.from_event_seq) with no +1, and EventLog#replay_job skips only env.event_seq < from_event_seq, thereby including the event whose seq == from_event_seq. The subscriber receives one event it already has. Contrast the resume path (session_actor.rb:143), which correctly compensates with from_event_seq: last_processed_seq + 1. The off-by-one is benign only because callers like the stream_resume recipe dedup by chunk_seq.

Evidence

# lib/arcp/runtime/session_actor.rb:297-300
if sub.history
  replay = @runtime.event_log.replay_job(sub.job_id, from_event_seq: sub.from_event_seq)  # no +1
  replay.each { |e| send_envelope(e) }
end

# lib/arcp/runtime/event_log.rb:63-65 — keeps seq == from_event_seq
@jobs[job_id].each_with_object([]) do |(env, _t), out|
  next if env.event_seq && from_event_seq && env.event_seq < from_event_seq
  out << env
end

Proposed fix

Replay strictly greater than from_event_seq: either pass from_event_seq: sub.from_event_seq + 1 (guarding nil) in handle_subscribe, or change the replay_job predicate to env.event_seq <= from_event_seq. Keep the resume path consistent. Add a test subscribing with from_event_seq: N, history: true and asserting the first replayed event has event_seq > N.

Acceptance criteria

  • job.subscribe history replay excludes event_seq == from_event_seq.
  • Resume replay behavior is unchanged.
  • Test asserts the strict-greater boundary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions