Category: spec-conformance Severity: blocker
Location: src/Arcp.Runtime/SessionState.Jobs.cs:28-45
Spec: ARCP v1.1 §6.4
What
The running job is launched with the session's _cts.Token (and Job.CancellationSource is linked to that same token via the parentCancellation argument). SessionState.CloseAsync (SessionState.cs:122) and the ReceiverLoop finally (SessionState.cs:90) call _cts.Cancel(); HeartbeatLoop calls CloseAsync on idle ≥ 2 intervals (SessionState.Outbound.cs:49). So a heartbeat timeout, a graceful close, or a transient transport drop cancels every running job. Spec §6.4 states the runtime MUST NOT terminate jobs on heartbeat loss, and §6.7 states in-flight jobs are not affected by close and remain resumable within the resume window.
Evidence
var submission = await _server.JobManager
.SubmitAsync(submit, SessionId, Principal?.Subject, emit, inboundTraceId, _cts.Token, cancellationToken)
.ConfigureAwait(false);
...
_ = Task.Run(() => _server.JobManager.RunAsync(job, resolved, emit, _cts.Token), _cts.Token);
Proposed fix
Decouple job lifetime from session lifetime: give each job (or the JobManager) its own CancellationTokenSource rooted at the server/runtime, not the submitting session's _cts. Session teardown should stop streaming to that transport but leave the job running and resumable.
Acceptance criteria
Category: spec-conformance Severity: blocker
Location:
src/Arcp.Runtime/SessionState.Jobs.cs:28-45Spec: ARCP v1.1 §6.4
What
The running job is launched with the session's _cts.Token (and Job.CancellationSource is linked to that same token via the parentCancellation argument). SessionState.CloseAsync (SessionState.cs:122) and the ReceiverLoop finally (SessionState.cs:90) call _cts.Cancel(); HeartbeatLoop calls CloseAsync on idle ≥ 2 intervals (SessionState.Outbound.cs:49). So a heartbeat timeout, a graceful close, or a transient transport drop cancels every running job. Spec §6.4 states the runtime MUST NOT terminate jobs on heartbeat loss, and §6.7 states in-flight jobs are not affected by close and remain resumable within the resume window.
Evidence
Proposed fix
Decouple job lifetime from session lifetime: give each job (or the JobManager) its own CancellationTokenSource rooted at the server/runtime, not the submitting session's _cts. Session teardown should stop streaming to that transport but leave the job running and resumable.
Acceptance criteria