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
- Add
eventSeq: UInt64? to Envelope with wire key event_seq.
- 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.
- Use that counter as the source for
JobListEntry.lastEventSeq.
Acceptance criteria
Category: spec-conformance Severity: major
Location:
Sources/ARCP/Runtime/JobManager.swift:29-35,Sources/ARCP/Envelope/Envelope.swift:8-46Spec: ARCP v1.1 §5, §8.1, §8.3, §6.6
What
JobManager.sendincrements a per-joblastEventSeqcounter, butEnvelopehas noevent_seqfield at all, so the sequence number is never serialized. §5/§8.1 listevent_seqas 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. AdditionallylastEventSeqis job-scoped, but §8.3 mandates a session-scoped sequence — so even the value stored inJobListEntry.lastEventSeqdoes not match the spec's semantics. This is broader than the existing #74 (which notes envelopes carry noevent_seq): the counter that does exist is also computed with the wrong scope and is only mutated insidesend(so envelopes sent viarawSend/transport.senddirectly — handshake, pong, nack, subscribe.accepted — are never counted, guaranteeing gaps).Evidence
Envelopedeclares noeventSeqproperty andCodingKeyshas noevent_seq.Proposed fix
eventSeq: UInt64?toEnvelopewith wire keyevent_seq.ARCPRuntimeor a per-session actor), assign it to every job-event envelope as it is sent, and persist it.JobListEntry.lastEventSeq.Acceptance criteria
event_seqon the wire.event_seq.