Tighten failure and manifest contracts

This commit is contained in:
ms2k 2026-07-13 17:23:32 +09:00
commit a44b687897
3 changed files with 47 additions and 8 deletions

View file

@ -22,8 +22,9 @@ deletion and cancellation semantics still use this request identity.
Internal claim uses job ID plus `operation_id` because no attempt exists yet. Internal claim uses job ID plus `operation_id` because no attempt exists yet.
Renew, progress, and outcome use attempt ID, fencing token, worker incarnation, Renew, progress, and outcome use attempt ID, fencing token, worker incarnation,
and `operation_id`. A replay has the original effect; a different, stale, or and `operation_id`. Each operation identity retains a request fingerprint. An
non-authoritative tuple returns `precondition_failed` without mutation. exact replay has the original effect; a changed worker, fence, payload, stale,
or non-authoritative tuple returns `precondition_failed` without mutation.
## Authorization and errors ## Authorization and errors
@ -55,6 +56,11 @@ unauthorized, absent, and never-committed results are not exposed. The hard
delete endpoint returns the durable deletion resource established by the delete endpoint returns the durable deletion resource established by the
architecture. architecture.
Worker failure outcomes accept only attempt-reportable runtime classes and do
not accept a caller-supplied retryable flag. The service derives the durable
disposition from the class mapping in the architecture. Validation,
cancellation, and lost-attempt projection use their dedicated boundaries.
## WebSocket replay ## WebSocket replay
An HTTP job or list snapshot carries `event_cursor` at its consistency An HTTP job or list snapshot carries `event_cursor` at its consistency

View file

@ -515,15 +515,47 @@ components:
type: integer type: integer
minimum: 0 minimum: 0
JobFailure: JobFailure:
oneOf:
- type: object
additionalProperties: false
required: [class, retryable, message]
properties:
class:
type: string
enum: [validation, authorization, source_not_found, source_changed, cancelled]
retryable:
const: false
message:
type: string
maxLength: 500
safe_details:
type: object
additionalProperties:
type: [string, integer, boolean, 'null']
- type: object
additionalProperties: false
required: [class, retryable, message]
properties:
class:
type: string
enum: [transient_source, transient_target, integrity, capacity, internal, lost_attempt]
retryable:
const: true
message:
type: string
maxLength: 500
safe_details:
type: object
additionalProperties:
type: [string, integer, boolean, 'null']
AttemptRuntimeFailure:
type: object type: object
additionalProperties: false additionalProperties: false
required: [class, retryable, message] required: [class, message]
properties: properties:
class: class:
type: string type: string
enum: [validation, authorization, source_not_found, source_changed, transient_source, transient_target, integrity, capacity, internal, cancelled, lost_attempt] enum: [authorization, source_not_found, source_changed, transient_source, transient_target, integrity, capacity, internal]
retryable:
type: boolean
message: message:
type: string type: string
maxLength: 500 maxLength: 500
@ -722,4 +754,4 @@ components:
kind: kind:
const: failure const: failure
failure: failure:
$ref: '#/components/schemas/JobFailure' $ref: '#/components/schemas/AttemptRuntimeFailure'

View file

@ -100,6 +100,7 @@ flowchart TD
- Every successful job is represented by one immutable `ResultManifest`. A single-object transfer uses a one-member manifest. - Every successful job is represented by one immutable `ResultManifest`. A single-object transfer uses a one-member manifest.
- A manifest is the exact inventory of immutable member identities and carries sufficient integrity metadata to validate the aggregate. - A manifest is the exact inventory of immutable member identities and carries sufficient integrity metadata to validate the aggregate.
- Manifest member paths are NFC-normalized relative POSIX segment sequences. Empty segments, dot segments, traversal, leading or trailing separators, and backslashes are invalid rather than normalized into aliases.
- Manifest construction uses memory bounded independently of member count and total result size. - Manifest construction uses memory bounded independently of member count and total result size.
- Remora resolves a result only from its `CommittedResult`; it never derives one by listing a target bucket or prefix. - Remora resolves a result only from its `CommittedResult`; it never derives one by listing a target bucket or prefix.
- An authorized reader may access committed members directly in `TargetStore` using exact manifest identities or time-limited URLs. - An authorized reader may access committed members directly in `TargetStore` using exact manifest identities or time-limited URLs.
@ -127,7 +128,7 @@ flowchart TD
- Attempt-reported runtime failures carry a durable permanent or retryable disposition into `JobProtocol`. The model is the sole definition of how that disposition affects execution phase and attempt budget. - Attempt-reported runtime failures carry a durable permanent or retryable disposition into `JobProtocol`. The model is the sole definition of how that disposition affects execution phase and attempt budget.
- Authorization, source-not-found, and source-changed runtime failures are permanent. Transient-source, transient-target, integrity, capacity, and internal failures are retryable. Unrecognized runtime errors map to a redacted internal failure. - Authorization, source-not-found, and source-changed runtime failures are permanent. Transient-source, transient-target, integrity, capacity, and internal failures are retryable. Unrecognized runtime errors map to a redacted internal failure.
- Validation normally rejects submission before a job exists. Cancellation and lost attempts follow their dedicated `JobProtocol` behavior rather than a worker-selected failure disposition. - Validation normally rejects submission before a job exists. Cancellation and lost attempts follow their dedicated `JobProtocol` behavior rather than a worker-selected failure disposition.
- All retryable work uses the model-wide attempt bound. Source adapters may vary connect, response-start, no-progress, bounded full-jitter, and bounded server-hint timing without changing that bound. - All retryable work uses the model-wide attempt bound. Source adapters may vary connect, response-start, no-progress, bounded full-jitter, and bounded server-hint timing without changing that bound. Invalid or excessive server hints are ignored or capped; they never change a retryable disposition into a permanent failure.
- Remora has no elapsed wall-clock job deadline. Per-operation timeouts produce a structured runtime failure and remain subject to `JobProtocol`. - Remora has no elapsed wall-clock job deadline. Per-operation timeouts produce a structured runtime failure and remain subject to `JobProtocol`.
- Public failure details are constructed from per-class allowlists. Credentials, upstream bodies, raw URLs, and internal exception text are excluded. - Public failure details are constructed from per-class allowlists. Credentials, upstream bodies, raw URLs, and internal exception text are excluded.