Skip to content

Idempotency replay omits the credentials array on the cached job.accepted, breaking the §7.2 identical-payload guarantee #94

@nficano

Description

@nficano

Category: spec-conformance Severity: major
Location: Sources/ARCP/Runtime/JobManager.swift:577-611
Spec: ARCP v1.1 §7.2, §9.8.2

What

§7.2: "the runtime MUST return the same job.accepted payload for any subsequent submission with the same key and identical parameters." The replay path synthesizes a fresh job.accepted with credentials: nil and re-emits the cached terminal envelope. Two problems: (1) the replayed job.accepted differs from the original (which carried credentials), violating "same payload"; and (2) more seriously, the replay never provisions credentials, so a client that legitimately retries an interrupted submit (the whole point of idempotency) gets a terminal result it cannot act on if the job's output depended on credential-mediated upstreams. Worse, the original credentials were already revoked at job termination (§9.8.2), so they cannot be re-emitted either — the cache is fundamentally unable to honor a credential-bearing idempotent replay. The correct behavior is to cache and replay the original job.accepted payload exactly, or to document that credential-bearing jobs are not idempotency-cacheable.

Evidence

try? await send(
    Envelope(
        sessionId: sessionId,
        jobId: jobId,
        correlationId: invokeId,
        payload: .jobAccepted(JobAcceptedPayload(jobId: jobId, credentials: nil))  // original had credentials
    )
)

Only the terminal envelope is cached (persistIdempotencyIfNeeded), never the original job.accepted payload, so the replayed accept is necessarily a fabricated one.

Proposed fix

  1. Cache the full original job.accepted payload alongside the terminal envelope (keyed by idempotency key), and replay it verbatim — but redacting credentials.value per §9.8.2 since the original credentials are revoked.
  2. Alternatively, for jobs that provisioned credentials, return DUPLICATE_KEY or re-provision fresh credentials on replay; document the chosen semantics.

Acceptance criteria

  • A replayed job.accepted matches the original payload's non-secret fields.
  • Credential-bearing idempotent replays have defined, tested behavior.

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