Skip to content

event_seq is incremented but never written to the wire; gap-free ordering guarantee unmet and counter is mis-scoped (§8.3) #93

@nficano

Description

@nficano

Category: spec-conformance Severity: major
Location: Sources/ARCP/Runtime/JobManager.swift:29-35, Sources/ARCP/Envelope/Envelope.swift:8-46
Spec: ARCP v1.1 §5, §8.1, §8.3, §6.6

What

JobManager.send increments a per-job lastEventSeq counter, but Envelope has no event_seq field at all, so the sequence number is never serialized. §5/§8.1 list event_seq as a required envelope field and §8.3 requires session-scoped, strictly-monotonic, gap-free sequence numbers a client can use to detect gaps and trigger resume. Without it on the wire, clients cannot implement §6.3 resume or §8.3 gap detection. Additionally lastEventSeq is job-scoped, but §8.3 mandates a session-scoped sequence — so even the value stored in JobListEntry.lastEventSeq does not match the spec's semantics. This is broader than the existing #74 (which notes envelopes carry no event_seq): the counter that does exist is also computed with the wrong scope and is only mutated inside send (so envelopes sent via rawSend/transport.send directly — handshake, pong, nack, subscribe.accepted — are never counted, guaranteeing gaps).

Evidence

private func send(_ envelope: Envelope) async throws {
    if let jid = envelope.jobId, var record = jobs[jid] {
        record.lastEventSeq &+= 1     // per-JOB, not per-session
        jobs[jid] = record
    }
    try await rawSend(envelope)        // envelope has no event_seq field
}

Envelope declares no eventSeq property and CodingKeys has no event_seq.

Proposed fix

  1. Add eventSeq: UInt64? to Envelope with wire key event_seq.
  2. Maintain a single session-scoped monotonic counter (in ARCPRuntime or a per-session actor), assign it to every job-event envelope as it is sent, and persist it.
  3. Use that counter as the source for JobListEntry.lastEventSeq.

Acceptance criteria

  • Job-event envelopes carry a session-scoped, gap-free event_seq on the wire.
  • Resume/backfill key off the wire event_seq.

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