Files
go-sip/proto/ERRORS.md
T

4.6 KiB

W02 error, idempotency, and fencing contract

This document is part of the agent.v1 project-owned baseline. It does not change the SaaS/MQ contract.

Transport and domain errors

Handlers return normal gRPC status codes and, when a response message exists, put the stable FailureCode in Failure.code as well:

FailureCode gRPC status Retry rule
INVALID_ARGUMENT InvalidArgument Fix the request; never retry unchanged
UNAUTHENTICATED Unauthenticated Re-establish mTLS/session; do not replay business work
PERMISSION_DENIED PermissionDenied Stop; require a new authorization
FAILED_PRECONDITION FailedPrecondition Refresh state/barrier, then use the original operation ID only if allowed
ABORTED Aborted Re-read the CAS revision; do not assume the operation applied
RESOURCE_EXHAUSTED ResourceExhausted Wait for durable quota/resource release
UNAVAILABLE Unavailable Reconnect and reconcile the original operation before any retry
DEADLINE_EXCEEDED DeadlineExceeded Result is unknown unless a durable receipt exists
NOT_FOUND NotFound Do not create a substitute execution
ALREADY_EXISTS AlreadyExists Read the existing operation/result; do not create a second one

A transport success is not an application receipt. RESULT_CODE_ACCEPTED means that the receiving side durably recorded the request; APPLIED requires the specified state transition and barrier evidence.

Idempotency keys

RequestMeta.idempotency_key is required for mutating methods. The key is scoped by (agent_id, operation_id, idempotency_key) and the durable operation record also stores the request content digest. Reusing a key with different content returns ABORTED/RESULT_CODE_CONFLICT; it never overwrites the first request.

  • ActivateAgent: activation_operation_id is the idempotency key. A repeated identical request returns the same session generation and credential metadata.
  • SetAdmissionState: barrier_id plus the expected admission generation is persisted. A replay cannot move the generation twice.
  • Execute: the execution binding and permit ID are the deduplication identity. An unknown result is reconciled with QueryExecution; it is never retried as a new originate.
  • GetExecutionPermit: the reservation, binding, expected revision and idempotency key are persisted. A permit is not issued after the reservation is released or fenced.
  • ApplyTaskControl: (execution_id, expected_task_revision, action, idempotency_key) is CAS-checked. STOP is terminal; PAUSE may be resumed only by a new authorized request.
  • ReportExecutionEvent: (fact_id, content_sha256) is the durable fact key. An identical duplicate returns the original receipt; a digest mismatch is a conflict.
  • RequestUpload/CompleteUpload: upload_id and the asset checksum are retained. Completion is returned only after the OSS/SaaS verification state is known; a local PUT success is not recording.ready.

Read-only methods may be retried, but callers still preserve the original request and trace identity: GetAgentStatus, GetBootstrap, and QueryExecution.

Fencing and session rules

  1. The Dispatcher creates a new opaque dispatcher_epoch when its active instance changes. The Agent accepts mutations only for the active epoch.
  2. The Agent identity is the mTLS certificate plus the Dispatcher-approved (agent_id, cell_id, boot_id, session_generation) binding. Self-reported identity or endpoint values are not authorization.
  3. A newer boot or session generation fences older requests. The old request returns UNAUTHENTICATED or ABORTED and cannot release an unknown lease.
  4. A permit contains the dispatcher epoch, session generation, reservation and fencing_token. The Agent checks all of them immediately before originate.
  5. Admission close/drain is a prerequisite barrier. SetAdmissionState and ApplyTaskControl are applied only when their expected generation/revision matches durable state.
  6. When the result of a mutation is unknown, the caller first queries the original operation/execution and records UNKNOWN if evidence is absent. No new execution ID or new permit is invented for recovery.

Upload boundary

The Agent receives a restricted UploadGrant and uploads directly to the approved OSS target. The Dispatcher never receives audio bytes. The Agent reports only asset metadata/checksum through CompleteUpload; the Dispatcher coordinates the SaaS completion/verification and publishes the resulting OSS ID through the existing MQ event path.