Feature design: governed REST bulk delivery V1¶
- Status: RESEARCHED
- Owner: dpone maintainers and Data Platform Architecture
- Target release: 0.75.0 or later Last verified: 2026-08-30
This revision incorporates four external architecture reviews received on 2026-08-30. It replaces the earlier broad “universal REST sink” claim with a bounded, certifiable V1 and makes the identity, generation, remote-effect, immutable-plan, zero-RPO journal, source-sealing, recovery, and Airflow contracts normative. Runtime implementation remains NO-GO until maintainers approve this specification, the companion proposed ADRs, the machine-readable design contract, strict Draft 2020-12 schema, and the threat model.
Executive summary¶
dpone can read REST APIs but cannot publish governed datasets to HTTP destinations. Teams therefore implement authentication, serialization, batching, rate limits, asynchronous polling, retry, and recovery in individual DAGs. That duplicates high-risk behavior and makes a remote mutation's outcome depend on process-local state.
V1 adds a governed REST bulk-delivery sink for two protocol families:
- one-request synchronous batch delivery;
- one-submit asynchronous bulk jobs with read-only receipt polling.
V1 is not a general CRUD, reverse-ETL, resumable-upload, callback, or arbitrary OpenAPI workflow engine. Those families have separate contracts and roadmap gates.
A delivery is a durable state machine. dpone freezes a source boundary, seals
an immutable payload, reserves a logical delivery_key, binds an immutable
mutation intent, submits at most when the remote effect is known absent or a
certified fence makes repetition safe, records a receipt, observes any remote
job, verifies the effect, and only then promotes the source checkpoint. A
transport error never proves that the receiver did not mutate.
Acceptance requires fault-injection evidence for zero silent loss, zero false success, and zero automatic unproved resend across every process-cut boundary. A 30-minute asynchronous job must consume no more than five seconds of Airflow worker time after submission.
Architecture-review closure¶
The following items are approval gates, not optional follow-ups.
| Review item | Normative resolution |
|---|---|
| Mutation identity | Separate delivery_key, mutation_intent_digest, execution_policy_digest, and explicit generation. |
| Changed payload for the same logical scope | Fail before HTTP with REST_DELIVERY_INTENT_CONFLICT; replacement requires a new explicit generation. |
| Terminal-state overload | Model execution, remote effect, acknowledgement, verification, and checkpoint as independent axes. |
| Continuation | Return DeliveryCompleted, DeliveryPending, or DeliveryBlocked; persist all authority before returning pending. |
Existing ETLProcessor |
Preserve relational behavior; introduce ResumableDeliveryProcessor for non-relational continuation. |
| Airflow trigger safety | Trigger is read-only, duplicate-safe, bounded, and carries only an operation id and non-secret journal locator. |
| Self-service boundary | Workloads select a versioned platform-owned operation_profile_ref; protocol semantics are not authored per route. |
| Journal authority | PostgreSQL 15+ is the only V1 production operation journal; SQLite is local development only. |
| Takeover after submit starts | Lease expiry never authorizes another mutation; takeover becomes observation/reconciliation only. |
| Fence retention | Compact effect authority survives the maximum replay horizon; successful append and replacement watermarks are not deleted on receiver TTL. |
| Adaptive planning | One source boundary is materialized; all children are planned, sealed, and admitted as immutable topology before submit. |
| Parallel checkpoint | Only the highest contiguous completed frontier can be promoted. |
| Recovery | Recovery uses the immutable journal plan and operation id, never a current authoring manifest. |
| Protocol scope | V1 is synchronous batch plus one-submit async bulk job; CRUD and multi-step protocols are excluded. |
| Airflow matrix | Airflow 3.2.x is primary; the latest supported patch of every declared >=2.10,<3.4 minor is a compatibility target. |
| Per-record partial results | V1 fails the delivery and retains bounded result evidence; automatic per-record quarantine is V1.1. |
Open approval blockers after second architecture review¶
The second review exposed distributed-correctness invariants that were not fully specified by the first closure. Their normative contracts are now written, but they remain approval blockers until owners accept the ADRs, machine-readable contract, threat model, and required evidence. “Specified” is not presented as implemented or certified.
| Review item | Normative resolution in this revision | Remaining approval/evidence |
|---|---|---|
| P0.17 overlapping replacement generations | Overlap-aware effect conflict domain, ordered (scheduled_interval_end_utc, explicit_correction_revision), stale watermark, and pre-submit fence with stable errors. |
Architecture approval plus concurrency/property evidence. |
| P0.18 durable child topology | parent_plan_digest binds frozen parent, compiled plan, planner version, ordered children, payload refs, and coverage; one transaction admits every child before mutation. |
PostgreSQL transaction/fault evidence. |
| P0.19 source survival | Production V1 materializes and verifies one immutable parent artifact, closes the source snapshot immediately, then plans/seals every child before the first mutation. | Source/artifact hard-kill evidence. |
| P0.20 zero-loss journal | Critical transitions require synchronous remote-apply quorum, immutable MAY_ATTEMPT, journal epoch, and a post-restore environment mutation gate. |
Control-plane and security approval plus failover/PITR campaign. |
| P0.21 identity algebra | Split operation semantics, execution policy, and full profile contract; bind operation namespace, stable remote principal, and complete rendered-request envelope. | Canonicalization/property evidence and certified connection handshake. |
| P0.22 replay horizon | Compact success authority survives the maximum replay horizon; replacement keeps a permanent highest-generation watermark. | Retention/decommission/reset operating approval. |
| P0.23 legal state cross-product | UNDETERMINED separates normal running work from lost proof; legal tuples, transitions, terminality, monotonic fields, operator-only paths, and CAS predicates are frozen in YAML. |
State-machine model/property evidence. |
Implementation is not authorized while any row above lacks its named approval.
The exact executable design authority is
dpone.rest-bulk-delivery-design.v1,
not prose substring tests.
Formal closure after third architecture review¶
The third review accepted the design for merge as RESEARCHED and identified
the final formalization required before ADR approval. This revision makes those
choices normative; implementation remains blocked until owners approve them
and the named certification evidence exists.
| Approval blocker | Frozen V1 decision |
|---|---|
| Safe retry versus terminal state | Add RETRY_WAIT; REQUEST_NOT_STARTED with remaining budget transitions SUBMITTING -> RETRY_WAIT -> SUBMITTING under explicit guards and a new attempt ordinal. final_not_started is used only when automatic retry is unavailable or intentionally abandoned. |
| Success acknowledgement with contradictory effect | Preserve acknowledgement independently: SUCCEEDED can finalize as FULLY_APPLIED, PARTIALLY_APPLIED, or UNKNOWN; failed, cancelled, expired, accepted, and not-accepted acknowledgement variants are also retained. |
| Cancellation continuation | poll_receipt is the only automatic V1 continuation and reports externally observed CANCELLED; there is no observe_external_cancel continuation or active cancel mutation. |
| Overlap linearization | PostgreSQL domain-lock row acquired with SELECT FOR UPDATE, half-open range scopes, GiST && lookup, and one admission transaction. Permanent watermarks are a normalized non-overlapping interval map, not one scalar for the resource. |
| Append correction | incremental_append rejects correction generations and an already-applied exact scope by default with REST_DELIVERY_APPEND_SCOPE_ALREADY_APPLIED; only a separately certified dedup/upsert/replacement/compensation profile may opt in. |
| Parent-level async execution | Narrow V1 allows exactly one in-flight child for async_bulk_job; bounded-parallel async supervision is V1.1. Synchronous batch may retain profile-bounded parallelism. |
| Attempt and capacity authority | MAY_ATTEMPT is keyed by operation namespace, operation id, and attempt ordinal. Capacity reservation, attempt row/marker binding, and CAS to SUBMITTING share one PostgreSQL critical transaction. |
| Executable contract | Draft 2020-12 JSON Schema, duplicate-key-rejecting bounded YAML load, semantic validator CLI, transition/failure reachability, terminal closure, acknowledgement preservation, and model-wide generation guards are mandatory CI. |
The machine contract and validator freeze these decisions. Their existence is design evidence, not runtime or environment certification.
Final closure after fourth architecture review¶
The fourth review classified the direction as GO and merge as conditional on
three packaging/validator fixes. It also identified five approval-level gaps.
This revision closes all eight in the normative contract while preserving the
separate organizational approval and runtime evidence gates.
| Review finding | Normative resolution |
|---|---|
Base-wheel jsonschema availability |
jsonschema is a base dependency because the validator is public base CLI. Primary CI installs the built wheel into a clean venv and runs the contract command. |
| Malformed UTF-8 bypass | The application service reads contract bytes through the filesystem port. Bounded YAML owns UTF-8 validation and CLI returns exit 2 plus yaml.invalid_utf8 without a traceback. |
| Incomplete error catalog | stable_error_codes and error_catalog are exact-set checked; every normative REST_DELIVERY_* reference must resolve to complete metadata. |
| Cross-namespace receiver key collision | receiver_mutation_key = H(operation_namespace, delivery_key) is the remote fence; payload digest is excluded. |
| Undefined receiver binding digest | The executable contract binds authority, principal, account, resource namespace, authentication semantics, TLS policy identity, and network policy identity. Secret rotation is excluded when semantics remain unchanged. |
| Locally split physical conflict domains | Effect conflicts are keyed by physical receiver identity, resource, and profile-owned effect_conflict_group; operation namespace and mutation kind cannot split one physical effect. |
| Reconciliation cannot prove effect independently | Every unknown acknowledgement variant can resolve to no effect, full effect, partial effect, or remain unknown while preserving acknowledgement. Full+verified results become checkpoint eligible regardless of acknowledgement. |
Mutable promotion of RESEARCHED |
The design artifact remains immutable. A separate dpone.rest-bulk-delivery-approval.v1 receipt binds the design digest, ADR digests, owner decisions, and evidence requirements. Production certification remains a third artifact. |
The validator provides deterministic mutation, negative, graph-reachability, terminal-closure, and model-wide invariant tests. Stateful/generative model checking remains required implementation evidence; this document does not mislabel the current suite as Hypothesis-style property-based testing.
Personas and self-service journey¶
| Persona | Responsibility | Success signal |
|---|---|---|
| Data product author | Select a certified profile, map a dataset, and choose a mutation scope. | YAML and SQL only; no endpoint-specific Python or protocol fields. |
| Platform owner | Own connection bindings, operation profiles, policy bounds, and certification. | Workloads cannot alter authority, credentials, acknowledgement, or retry safety. |
| Operator | Inspect and recover durable operations. | One operation id explains effect certainty and permits only proven-safe actions. |
| Security engineer | Constrain egress, credentials, evidence, and retention. | No secret or unbounded body reaches manifests, XCom, trigger kwargs, logs, or metrics. |
| Connector maintainer | Implement and certify protocol capabilities. | Ports and profiles remain independent of Airflow and customer DAGs. |
The authoring journey is:
- discover a certified
operation_profile_refand its supported mutations; - reference a governed connection and mapping;
- run offline
dpone checkanddpone plan; - inspect the compiled source boundary, delivery keys, generations, limits, and profile digest;
- deploy an immutable release;
- let the runtime freeze, seal, submit, observe, verify, and checkpoint;
- recover by operation id from durable state if execution is interrupted.
Scope and protocol families¶
V1 in scope¶
sink.type: restfor governed bulk delivery indpone.batch.v1.- Platform-owned, versioned operation profiles selected by reference.
- Immutable connection-binding snapshots with fixed authority and secret refs.
POSTand naturally idempotent or conditionally fencedPUTfor certified profiles.PATCHis allowed only when a profile proves its exact retry fence.- Deterministic CSV/gzip, JSON array, NDJSON, and raw sealed-file payloads.
- Multipart file upload and single-body requests.
- One-request synchronous acknowledgement.
- One-submit asynchronous job acknowledgement with read-only status polling.
- Body- and header-derived receipts through bounded typed extractors.
- Deterministic batching by rows, decoded bytes, wire bytes, and date windows.
- Frozen source boundaries, immutable payload artifacts, lineage, and coverage proofs for every split.
- Serial async child delivery in V1 and profile-bounded synchronous delivery, both with ordered contiguous checkpoint promotion.
- Distributed submit/poll rate limits, request concurrency, and remote-job concurrency.
- Durable identity, CAS transitions, leases, effect tombstones, attempts, receipts, observations, verification, and checkpoint evidence.
- Airflow deferral through the full provider package.
- CLI inspection, reconciliation, safe resume, observation of externally cancelled jobs, and connector certification.
Explicitly excluded from V1¶
- Per-record add/change/remove reverse-ETL semantics.
- Automatic item retry, rejection splitting, item quarantine, or dead-letter routing after a partial result.
- Generic CRUD resource discovery and
DELETE. - Multi-request create/upload/finalize workflows.
- Resumable range upload, presigned-URL upload, and callback/webhook completion.
- Response-driven arbitrary next URLs or general protocol graphs.
- Arbitrary OpenAPI operation execution. OpenAPI may later bootstrap a draft platform profile, but never becomes runtime authority by itself.
- Arbitrary Jinja, Python, JavaScript, shell, or expression evaluation.
- SOAP/WSDL, GraphQL subscriptions, gRPC, WebSockets, and unbounded streaming.
- Distributed transactions with the receiver.
- Active receiver cancellation. A cancel endpoint is another mutation and is deferred to V1.2; V1 observes externally cancelled work only.
Versioned protocol-family roadmap¶
| Family | V1 | V1.1 | V1.2 |
|---|---|---|---|
| Synchronous batch | Yes | Yes | Yes |
| One-submit async bulk job | Yes | Yes | Yes |
| Object mutation: add/change/remove | No | Yes | Yes |
| Per-record result routing/quarantine | Evidence only | Yes | Yes |
Generic DELETE |
No | Profile-specific | Yes |
| Create/upload/finalize | No | No | Yes |
| Resumable byte ranges | No | No | Yes |
| Presigned upload | No | No | Yes |
| Callback completion | No | No | Yes |
The state and evidence models reserve compatible continuation and item-result types, but unsupported families fail compilation in V1.
Current dpone baseline¶
The implementation survey, refreshed on dpone 0.74.32, found:
- REST is registered as an API source, not a sink;
ConnectionType, sink factories, and runtime endpoint factories have no REST target branch;ETLProcessorandAbstractSink.load()have a synchronous relational lifecycle;- immutable artifact publication is reusable, but current route execution stores are local JSON/SQLite rather than a production mutation journal;
- the repository already has platform-owned profile and connection-projection patterns that can be extended without inventing workload-local protocol authority;
dpone-airflow-packis intentionally PyYAML-only, whileapache-airflow-providers-dponedeclares Airflow>=2.10,<3.4.
The design therefore adds a typed non-relational path. It does not scatter
sink_type == "rest" branches through the relational processor.
Authority model and public authoring contract¶
Three authorities¶
REST delivery has three non-overlapping sources of authority:
- Connection binding: platform registry owns base authority, credential reference, TLS, proxy, egress, and network policy.
- Operation profile: platform registry owns method, semantic path/query/ headers, codecs, acknowledgement, duplicate handling, retry fences, polling, limits, result extraction, timeout bounds, and profile version.
- Workload intent: author owns dataset mapping, logical resource, mutation kind and source scope, plus bounded planning preferences allowed by the profile.
The compiler resolves all three into an immutable deployment plan. The runtime does not read authoring YAML, a mutable registry, or the network to reinterpret an active operation.
Workload manifest¶
The following linked examples describe a synthetic local mock, not a deployed service or a certified vendor profile. Limits and receipt vocabulary are illustrative; production profiles require independent certification.
sink:
type: rest
connection_ref: mock_measurements
operation_profile_ref: mock.dataset-jobs@1
resource: measurements
mutation:
kind: partition_replace
generation_from: scheduled_interval
scope:
type: inclusive_date_window
source_field: business_date
payload:
mapping_ref: mock.measurements.v1
delivery_overrides:
preferred_window_days: 3
No request path, bearer header, task-state vocabulary, duplicate status, retry
classification, or low-level timeout can be authored in this workload.
delivery_overrides is closed and range-checked against the selected profile.
Platform operation profile¶
id: mock.dataset-jobs
version: 1
protocol_family: async_bulk_job
request:
method: POST
path: /mock/v1/dataset-jobs
media_type: multipart/form-data
body:
type: multipart_file
payload_part:
name: file
format: csv
compression: gzip
content_type: application/gzip
scalar_parts:
range_start: {value_from: scope.from, format: date}
range_end: {value_from: scope.to, format: date}
acknowledgement:
accepted_statuses: [202]
receipt:
id: {body_json_pointer: /job_id, required: true}
duplicate:
statuses: [409]
requires_receipt_for_same_delivery_key: true
poll:
method: GET
path: /mock/v1/dataset-jobs/{receipt.id}
state: {body_json_pointer: /phase}
running: [pending, running]
succeeded: [complete]
partial: [incomplete]
failed: [error]
mutation_fence:
type: receiver_duplicate_key
location: payload_filename
value_from: receiver_mutation_key
key_payload_binding: required
certification_ref: required_before_production
effect_conflict_group: mock.measurements
limits:
max_rows: 100000
max_decoded_bytes: 64000000
planning_decoded_bytes: 56000000
max_wire_bytes: 16000000
planning_wire_bytes: 14000000
preferred_window_days: {default: 3, min: 1, max: 4}
result_policy:
all_rows_accounted: true
partial_result: fail_and_retain
The registry publishes immutable operation_semantics_digest,
execution_policy_digest, and profile_contract_digest plus lifecycle
metadata. Changing protocol semantics creates a new version. Profiles can be
deprecated but cannot be mutated in place while referenced by a release. A
separate mutable deny-only revocation authority can prevent every new submit
using a compromised profile or binding; it cannot enable a behavior, reinterpret
a pinned plan, or prevent read-only observation and reconciliation.
V1 path segments, query parameters, semantic headers, multipart scalar parts,
and receipt fields are typed profile fields with RFC-compliant encoding. They
use a finite symbol set (resource, delivery_key, scope.*, receipt.*) and
never accept absolute URLs, traversal, control characters, header names from
data, or executable templates. Null, omitted, and empty values are distinct and
profile-owned. Conditional headers and header-derived receipts are supported
only as typed certified fields. An absolute Location or Operation-Location
is accepted only when a typed profile canonicalizes it to the same HTTPS origin
and an allowlisted relative receipt path. Scheme, authority, port, userinfo,
fragment, path escape, and DNS-policy changes fail closed.
V1 multipart contains exactly one sealed payload part plus bounded scalar
parts. Multiple file parts, nested multipart, application/x-www-form-urlencoded,
XML bodies, and arbitrary response-derived request parameters are unsupported
and fail profile compilation. Reserved media types, HTTP 207, and vendor error
envelopes require an explicit profile extractor and certification.
Connection-binding snapshot¶
connection_type: rest
authority: https://receiver.example.test
auth_provider: bearer
credential_ref: vault://path/to/token
remote_principal_id: reference-account-example-company
remote_account_id: reference-b2b
remote_resource_namespace: ingest
remote_identity:
mode: receiver_attested
evidence_ref: evidence://reference/whoami/sha256:...
verified_at: 2026-08-30T08:00:00Z
valid_until: 2026-11-28T08:00:00Z
tls_policy_ref: corporate-public-tls@1
network_policy_ref: reference-egress@1
binding_digest: sha256:...
The snapshot contains secret references, never secret values. A certified
connection handshake records stable non-secret remote_principal_id,
remote_account_id, and remote_resource_namespace; authority URL alone is
not receiver identity. Every process resolves a fresh short-lived credential
from the same immutable binding. OAuth refresh, token rotation, and certificate
rotation do not change mutation identity when the certified remote principal,
authority, and authentication semantics are unchanged. A principal/account
swap changes binding identity and cannot resume an existing mutation.
remote_identity.mode is either receiver_attested, backed by a certified
receiver identity endpoint/claim, or platform_attested when no trustworthy
whoami capability exists. Platform attestation requires two-person approval,
immutable evidence, an expiry, and periodic recertification; an expired
attestation blocks new submissions but not observation/reconciliation. Secret
objects are non-serializable and never enter a plan, journal, trigger event,
XCom, metric, span, or exception.
Compiled contract, compatibility, and migration¶
The compiler emits dpone.rest_delivery_plan.v1 with the exact workload
intent, operation semantics/policy/profile-contract digests, binding semantics
digest, source-boundary contract,
allowed policy values, and required adapter capabilities. It is immutable in a
release and closed to unknown fields.
- Existing source and sink manifests retain their meaning.
apiremains a source spelling; the new sink spelling isrest.- Relational
LoadConfig,LoadResult,AbstractSink, andETLProcessorimports and behavior remain unchanged. - A REST sink does not synthesize database, schema, table, DDL, staging, or schema-evolution fields.
- V1 artifact schemas permit additive optional fields only. Breaking semantic changes require V2, dual-read migration, and an accepted ADR.
- Migration must import verified checkpoint and receipt state explicitly; it must never infer successful delivery from the current schedule.
- Runtime downgrade refuses operations whose plan/profile schema it cannot read. It does not reinterpret them with an older profile.
Artifacts and evidence¶
| Schema | Durable purpose | Retention authority |
|---|---|---|
dpone.rest_delivery_plan.v1 |
Immutable compiled semantics and capability requirements. | Release plus operation tombstone. |
dpone.rest_source_parent.v1 |
Frozen source boundary, ordering, digest, row count, and completeness. | Parent operation policy. |
dpone.rest_payload.v1 |
Child scope, lineage, content address, codec settings, counts, and sizes. | Remote-effect-aware payload policy. |
dpone.rest_delivery_operation.v1 |
Identities, state axes, CAS revision, leases, attempts, and pinned refs. | PostgreSQL journal. |
dpone.rest_delivery_receipt.v1 |
Accepted receipt and bounded observations. | Certified receipt/task TTL plus margin. |
dpone.rest_delivery_result.v1 |
Accepted, rejected, unprocessed, remote ids, counters, and verification. | Data classification and result policy. |
dpone.rest_delivery_reconciliation.v1 |
Read proof, operator decision, expected digests, and safe action. | Audit policy. |
dpone.rest_delivery_effect_tombstone.v1 |
Compact mutation/effect authority after large artifact GC. | Maximum replay horizon; successful append route lifetime, permanent replacement watermark, unknown/partial until reconciliation. |
dpone.rest_sink_certification.v1 |
Static, local-live, vendor-live, fault, TTL, and security evidence. | Certification policy. |
dpone.rest-bulk-delivery-design.v1 |
Machine-readable identities, invariants, legal state tuples/transitions, and gates. | Versioned design authority retained with implementation lineage. |
Canonical JSON evidence uses sorted keys, UTF-8, schema id, producer version, environment, creation time, content digest, and operation/delivery identity. Only allowlisted bounded response scalars are embedded. Large item results are content-addressed spill artifacts. Publication is create-if-absent and digest verified; overwriting evidence is forbidden.
Canonical identity and conflict policy¶
The earlier design incorrectly made payload content part of a single operation identifier. That allowed a changed source read after an ambiguous submit to look like a new operation. V1 separates namespace, mutation semantics, rendered intent, execution policy, and the complete pinned profile contract.
operation_namespace = H(
platform_instance_id,
tenant_id,
environment_id,
namespace_revision
)
delivery_key = H(
logical_route_id,
target_effect_scope,
source_boundary,
mutation_kind,
explicit_generation
)
receiver_mutation_key = H(
operation_namespace,
delivery_key
)
receiver_binding_semantics_digest = H(
authority_origin,
remote_principal_id,
remote_account_id,
remote_resource_namespace,
authentication_semantics,
tls_policy_identity,
network_policy_identity
)
operation_semantics_digest = H(
method_semantics,
path_query_header_semantics,
canonical_body_envelope_semantics,
acknowledgement_contract,
mutation_fence_contract,
verification_contract
)
rendered_request_semantics_digest = H(
method,
normalized_rendered_path_and_query,
all_non_secret_semantic_headers,
ordered_scalar_multipart_parts,
payload_part_name,
deterministic_filename,
content_disposition_and_type,
deterministic_multipart_boundary,
sealed_payload_digest
)
mutation_intent_digest = H(
receiver_binding_semantics_digest,
operation_semantics_digest,
rendered_request_semantics_digest
)
execution_policy_digest = H(
timeout_policy,
retry_policy,
distributed_rate_policy,
retention_policy,
observability_policy
)
profile_contract_digest = H(
operation_semantics_digest,
execution_policy_digest,
profile_schema_id,
profile_version
)
H is canonical SHA-256 over a versioned, typed, length-delimited encoding;
display strings are not hash inputs. Semantic headers exclude ephemeral
authorization, tracing, date, and transport-generated fields. The concrete
multipart boundary is deterministic, collision-checked against every part, and
bound to the rendered envelope. Hard max_wire_bytes is measured over the
complete emitted request body, including boundaries, scalar parts, part
headers, CRLF framing, filename, and file bytes; payload size alone is never
used as wire size.
source_boundary in delivery_key is the logical extraction occurrence and
interval/checkpoint span, not a content hash or mutable snapshot token. The
frozen source version and parent/payload digests belong to the mutation intent.
Consequently, rereading the same logical boundary with corrected bytes after an
ambiguous submit produces the same delivery key and a different intent, so it
is blocked. target_effect_scope is the receiver-visible partition/resource
scope after canonical time-zone and inclusivity rules.
Rules:
- Unique admission is keyed by
(operation_namespace, delivery_key). Same key and samemutation_intent_digestresumes the existing operation. It never creates a second mutation intent. - Same
delivery_keyand differentmutation_intent_digestfails before HTTP withREST_DELIVERY_INTENT_CONFLICT. - A deliberate replacement uses a new, explicit monotonic generation. Runtime retries and Airflow try numbers never create generations.
- Policy-only changes update
execution_policy_digestwithin certified bounds and do not changeoperation_semantics_digestor mutation identity. The fullprofile_contract_digestis nevertheless pinned in the immutable parent plan so recovery uses the exact certified policy rather than the current registry. - The receiver idempotency key, when used, is derived from
delivery_key, not payload digest or Airflow task identity. The concrete remote fence isreceiver_mutation_key = H(operation_namespace, delivery_key), preventing collisions between platform instances, tenants, environments, and namespace revisions that share one receiver account. - A duplicate receipt is accepted only when it proves the same delivery key and
intent. A bare
409is not proof.
Replacement generation and overlap fence¶
explicit_generation is an ordered tuple, not an opaque label:
generation = (
scheduled_interval_end_utc,
explicit_correction_revision
)
effect_conflict_domain = H(
remote_principal_id,
remote_account_id,
remote_resource_namespace,
receiver_resource_id,
effect_conflict_group
)
explicit_correction_revision is a governed non-negative integer for
partition_replace and permits a legitimate correction for the same scheduled
interval without reusing an old intent. Ordinary incremental_append does not
permit a correction revision: a second append for an already fully applied
exact scope fails before HTTP with
REST_DELIVERY_APPEND_SCOPE_ALREADY_APPLIED. A profile may opt in only when
certification proves receiver deduplication/upsert, a natural idempotent key,
replacement semantics, or an explicit compensating-correction contract.
effect_conflict_group is immutable platform-owned profile authority. It joins
all operation kinds and local namespaces that can mutate the same physical
receiver effect; the synthetic mock profile uses mock.measurements. partition_replace
uses canonical interval overlap, because adaptive child
boundaries may change between independent generations.
Normative rules, enforced atomically with revision CAS before SUBMITTING:
- once generation
Nis admitted for an effect scope, every lower overlapping generation is permanently forbidden from enteringSUBMITTINGand returnsREST_DELIVERY_STALE_GENERATION; - generation
Ncannot submit while any lower overlapping generation isSUBMITTING, accepted/running withUNDETERMINEDeffect,UNKNOWN, orPARTIALLY_APPLIED; it returnsREST_DELIVERY_OVERLAPPING_EFFECT_IN_FLIGHTand waits for reconciliation; - once generation
NisFULLY_APPLIED, the compact effect index permanently marks every lower overlapping generation stale; - admission and the effect index are scoped by stable physical receiver
identity, resource, and
effect_conflict_group. Local operation namespaces remain admission/tenancy authority but cannot hide two mutations that reach the same physical receiver effect.
The PostgreSQL adapter linearizes admission, rather than merely checking then inserting:
- canonicalize each effect scope as a half-open
daterangeortstzrange; - create the
rest_delivery_effect_domain_lockrow idempotently and lock it withSELECT FOR UPDATE, keyed by the complete physical effect-conflict domain; - query overlapping operations and watermarks with the range
&&operator through a GiST index; - reject stale/unresolved overlaps or insert the admission while the same row lock is held;
- commit before any child may enter
SUBMITTING.
All code paths acquire domain locks in canonical conflict-domain order. A fully
applied replacement updates, under the same domain lock and effect transaction,
a normalized non-overlapping interval map
(effect_conflict_domain, conflict_scope_range,
highest_applied_generation). Therefore a January generation never stales a
lower, non-overlapping February generation. PostgreSQL row locks and range/GiST
semantics are used as documented by PostgreSQL 15
(explicit locking,
range types).
Frozen source boundary and adaptive planning¶
One parent source boundary is frozen before payload planning. Production V1 then enforces a seal-all-before-submit barrier:
- open a consistent source read using an immutable version or snapshot;
- materialize the parent boundary as immutable authority;
- verify parent completeness, row count, ordering, and content digest;
- close the source snapshot immediately after materialization is durable;
- plan every child from the immutable parent and prove complete gap-free coverage;
- seal and publish every child payload from that parent artifact;
- durably admit the complete parent/child topology;
- only then permit the first remote mutation.
A database snapshot token provides consistency only while materializing the
immutable parent and is closed before potentially long CSV/gzip planning and
sealing. The durable parent artifact, not the source snapshot, is the sole
input to planning and sealing and the recovery authority after materialization.
An exception requires a separately certified durable_reopenable_snapshot
capability proving survival after process loss, cross-worker reopen, and a
lifetime beyond the maximum sealing horizon. A mutable query rerun is never a
source boundary. Adaptive shrinking cannot re-read a newer source version.
The parent records deterministic sort and split keys, row count, logical scope, source version, and content digest. Each child records parent id, ordinal, scope, row interval, digest, decoded bytes, wire bytes, and coverage proof. Children are split deterministically until every limit is met. A receiver-atomic scope that exceeds one-request limits fails; it is never silently divided.
Before the first child can enter SUBMITTING, PostgreSQL admits in one
transaction the parent operation, immutable plan, every child ordinal/scope,
delivery key, payload ref/digest, generation, frontier order, and coverage
proof. The authoritative topology is bound by:
parent_plan_digest = H(
frozen_parent_digest,
compiled_plan_digest,
profile_contract_digest,
planner_algorithm_version,
ordered_child_descriptors,
complete_coverage_proof
)
Artifacts are published create-if-absent before the transaction and digest
verified during admission; unreferenced artifacts are safe GC orphans. An
existing parent operation always resumes its pinned child topology and must
not invoke the planner again, even after a code or planner-version upgrade.
The invariant is first child SUBMITTING => complete parent plan durably
ADMITTED and source snapshot closed.
For bounded parallel execution, successful later children do not advance the
checkpoint past a gap. If 01-07 succeeds, 08-14 fails, and 15-21
succeeds, the promotable frontier remains 07. An empty boundary advances only
when the frozen read proves complete and the profile's empty-input policy
allows promotion.
Deterministic CSV parameters are profile-owned: UTF-8 encoding, BOM policy,
delimiter, quote and escape characters, line terminator, header order, null and
empty-string encoding, decimal format, timestamp precision/time zone, filename,
gzip level, and gzip mtime. JSON profiles own stable field ordering, numeric
and timestamp encoding, null behavior, Unicode policy, and framing. Content-Digest
or Repr-Digest may be added only according to RFC 9530
and a certified receiver profile.
Outcome model¶
One terminal enum cannot distinguish a failed request from a partially applied or unknown remote effect. Each operation stores independent axes.
execution_state:
PLANNED | SEALED | SUBMITTING | RETRY_WAIT | ACCEPTED | WAITING | VERIFYING |
FINALIZED
remote_effect:
NONE_PROVEN | UNDETERMINED | FULLY_APPLIED | PARTIALLY_APPLIED | UNKNOWN
acknowledgement_state:
NOT_ACCEPTED | ACCEPTED | RUNNING | SUCCEEDED | FAILED | CANCELLED |
EXPIRED | PROTOCOL_UNKNOWN
verification_state:
NOT_RUN | PASSED | FAILED | NOT_PROVABLE
checkpoint_state:
BLOCKED | ELIGIBLE | PROMOTED
Invariants:
checkpoint_state=ELIGIBLErequiresremote_effect=FULLY_APPLIEDandverification_state=PASSED.- V1 does not promote a checkpoint for
PARTIALLY_APPLIED, even when rejected items are durably recorded. A future explicit quarantine policy may allow that in V1.1. NONE_PROVENis valid before transport or after positive proof that no request/effect occurred.UNDETERMINEDis the normal effect state after submit while a receipt is accepted/running.UNKNOWNmeans proof was lost, expired, contradictory, or unavailable; it is not a synonym for normal asynchronous waiting.UNKNOWNnever becomesNONE_PROVENbecause a local lease expired or a worker restarted. It can be refined only by an operator reconciliation with new immutable evidence and CAS.- Acknowledgement
FAILED,CANCELLED, orEXPIREDdoes not implyNONE_PROVEN; the profile's verification contract determines remote effect. FINALIZEDmeans no automatic transition remains, not necessarily success.FINALIZED + RUNNINGandUNKNOWN + RUNNINGare illegal. An operator-only reconciliation may CAS a finalized unknown/partial tuple back toVERIFYINGwith a new reconciliation id; prior evidence is append-only, never rewritten.verification_state=FAILEDorNOT_PROVABLEcan becomePASSEDonly through that operator-only reconciliation path with a new evidence digest.- Source checkpoint promotion is a separately leased and CAS-guarded action.
SUBMITTING -> RETRY_WAITis legal only with durableREQUEST_NOT_STARTEDproof and remaining retry budget. The due transitionRETRY_WAIT -> SUBMITTINGpreserves the delivery key, incrementsattempt_ordinal, and atomically creates a new attempt-scoped marker and capacity reservation.final_not_startedis terminal only when automatic retry is exhausted, permanently blocked, or intentionally abandoned.- Acknowledgement is never collapsed into effect:
SUCCEEDEDcan finalize asFULLY_APPLIED,PARTIALLY_APPLIED, orUNKNOWN;FAILED,CANCELLED,EXPIRED,PROTOCOL_UNKNOWN,ACCEPTED, andNOT_ACCEPTEDhave independent no-effect, full, partial, and unknown resolution tuples. Operator reconciliation preserves the observed acknowledgement while read-only receiver evidence refines effect. AnyFULLY_APPLIED + PASSEDresult is checkpoint eligible regardless of the acknowledgement axis.
The exhaustive initial tuple, legal tuple names, automatic and operator-only transitions, terminal tuples, monotonic fields, forbidden combinations, and CAS preconditions are frozen in the machine-readable state contract. Runtime accepts only a listed tuple and transition; the prose failure table is explanatory and cannot introduce another enum value. Mandatory monotonic fields include journal revision/epoch, attempt and observation ordinals, correction revision, highest applied generation, and contiguous checkpoint frontier.
Safe retry and remote fencing¶
RFC 9110
defines method semantics but does not make arbitrary POST or PATCH mutation
safe to repeat. The proposed Idempotency-Key field remains an
expired Internet-Draft,
not a ratified RFC. Therefore a header name alone is not a safety proof.
A mutation may be retried automatically only when one of these is true:
- the transport proves
REQUEST_NOT_STARTEDand no request byte could have reached the peer; - the operation profile certifies receiver idempotency for the delivery key, payload binding, concurrency, and retention window;
- the request uses a deterministic resource identity with naturally idempotent PUT semantics and verified representation rules;
- a conditional request provides a certified remote precondition;
- a read-only query proves exact absence for the delivery key under certified consistency;
- a receiver-owned fence proves the previous attempt cannot still apply.
DNS, connect, TLS, write, read, idle, and total-request timeouts have distinct
classification. Once a request may have reached the receiver, POST/PATCH moves
to remote_effect=UNKNOWN unless a certified fence permits same-key replay.
An Airflow task retry never changes this rule and is not an HTTP retry policy.
For an already permitted retry, delay is full jitter in
[0, min(max_delay, initial_delay * 2**attempt)]. A valid Retry-After sets a
lower bound on the next attempt. If that full server delay exceeds the remaining
request/operation budget, the operation becomes blocked/expired with
REST_DELIVERY_RETRY_AFTER_EXCEEDS_BUDGET; dpone never truncates the delay and
retries earlier than the server allowed. 429, 408, and 5xx are not
independently retry-safe for a mutation; both status classification and the
remote-fence predicate must pass.
Read-only receipt polling has a separate retry budget and can repeat under its
observation lease. Circuit-breaker state and distributed token buckets are
shared by certified endpoint/principal scope, not process-local.
Certification records:
- idempotency-key retention TTL and pruning behavior;
- whether the key is bound to payload or semantic intent;
- concurrent duplicate behavior;
- receipt/task/result retention TTLs and expiry response;
- query consistency and read-after-write behavior;
- maximum operation duration and clock-skew allowance.
Stripe's documented behavior illustrates why this is endpoint-specific: keys may be pruned after a retention interval and parameter mismatches are rejected. dpone imports no vendor behavior without a profile-specific certification.
Durable continuation contract¶
Runtime result¶
The connector-neutral supervisor returns one of these immutable results:
RouteExecutionResult = (
DeliveryCompleted
| DeliveryPending
| DeliveryBlocked
)
DeliveryPending(
operation_id="op_v1_...",
continuation_kind="poll_receipt",
next_check_after="2026-08-30T08:00:10Z",
)
DeliveryCompleted includes durable receipt and checkpoint eligibility.
DeliveryBlocked includes effect certainty, stable error code, retained
evidence, and allowed operator actions. DeliveryPending is returned only
after operation identity, payload ref, submit attempt, accepted receipt, and
next-check bound are durable.
The only automatic V1 continuation is poll_receipt. It reports terminal
SUCCEEDED, FAILED, CANCELLED, EXPIRED, or PROTOCOL_UNKNOWN
observations; external cancellation is not a second continuation kind. For
async_bulk_job, V1 fixes max_in_flight_children: 1: the parent supervisor
submits one child, returns pending while that child is active, and resumes the
next admitted child only after the prior child is terminal. Bounded-parallel
async parent supervision is V1.1. Synchronous batch profiles may still use a
certified bounded child concurrency.
RETRY_WAIT is an internal durable mutation-supervisor state, not a public
continuation kind. A live worker waits only within the bounded submit retry
budget; after worker loss, ordinary orchestration retry rereads the same journal
state and may perform the guarded due transition. The orchestration retry is
therefore a wake-up mechanism, never authority to resend.
reconcile_delivery_key remains a blocked/operator workflow when no accepted
receipt exists; it is never generic automatic polling of a mutation. Active
remote cancellation is outside V1 because invoking a cancel endpoint is itself
a mutation.
Integration with the current ETL lifecycle¶
The existing ETLProcessor.run() owns a payload, calls synchronous
AbstractSink.load(), finalizes the owned payload, and then persists source
state. Changing that behavior in place would put relational sinks at risk.
V1 therefore introduces ResumableDeliveryProcessor and a typed
DeliverySink protocol. The compiler and composition root choose it for REST
delivery. Existing ETLProcessor, AbstractSink.load(), LoadResult, and
relational route behavior remain unchanged. Shared extraction, quality,
artifact, logging, and source-state services are injected into both processors;
policy is not copied. A later convergence requires an independent compatibility
ADR and tests.
The resumable processor owns the payload until FINALIZED and retention
eligibility. A pending return does not call payload success or promote source
state. A completed return promotes only the contiguous eligible frontier.
Airflow adapter¶
The Airflow implementation lives in apache-airflow-providers-dpone, whose
declared compatibility already spans Airflow >=2.10,<3.4. It does not enter
the PyYAML-only dpone-airflow-pack scheduler package.
execute
-> submit_or_resume(operation_id)
-> DeliveryPending
-> defer(trigger=DeliveryReceiptTrigger(operation_id, journal_locator))
trigger
-> read journal
-> acquire observation lease
-> GET certified receipt URL
-> CAS bounded observation
-> emit bounded TriggerEvent(operation_id, observed_revision)
execute_complete
-> reread journal as authority
-> verify terminal result
-> publish receipt/result evidence
-> promote checkpoint if eligible
Trigger requirements follow Airflow's documented deferrable model:
- trigger kwargs are JSON-serializable and contain no token, certificate, payload, authored manifest, or response body;
- trigger code is read-only toward the business receiver: GET/HEAD only;
- duplicate trigger instances and repeated events are safe;
- trigger events are hints, never state authority;
- polling and journal writes are bounded and CAS-protected;
- trigger packaging contains a minimal async journal/observation client with
lazy imports; blocking
requests, synchronous PostgreSQL calls, and the full dpone runtime are forbidden in the shared asyncio triggerer process; execute_completerereads the journal and distrusts event payload state;- deferral frees worker and usually pool capacity, so a separate distributed remote-job semaphore remains held while the receiver job is active.
The primary acceptance image is Airflow 3.2.x. Because the provider declares
apache-airflow>=2.10,<3.4, compatibility evidence covers the latest supported
patch of 2.10, 2.11, 3.0, 3.1, 3.2, and 3.3. A release may instead narrow the
feature's declared range before implementation, but cannot claim untested
minors. Triggerer restart, duplicate trigger execution, worker loss, and
scheduler replay are mandatory tests.
Production journal and leases¶
Selected authority¶
PostgreSQL 15+ in a dedicated control-plane database/schema is the only V1 production journal. SQLite is a local-development reference adapter only. Object storage remains authority for immutable parent/payload/result artifacts; the PostgreSQL journal stores pinned artifact identities and effect tombstones.
The production adapter requires:
- unique
delivery_keyand immutablemutation_intent_digestadmission; - integer
revisionCAS on every transition; - database-clock lease decisions, never worker clocks;
- transactionally appended attempts and observations;
- row-level tenancy and environment scoping;
- schema migrations with expand/migrate/contract compatibility;
mutation_admission_rpo: zeroandsubmit_attempt_rpo: zerousing a certified synchronous replication quorum andsynchronous_commit = remote_applyfor critical transitions;- refusal to submit when the synchronous quorum or its proof is unavailable;
- HA topology, backups, point-in-time recovery, journal epochs, restore exercises, monitoring, and capacity policy supplied by the environment profile;
- no submission when journal or artifact authority is unavailable.
Zero-RPO mutation admission and disaster recovery¶
Technology choice alone does not protect a receiver from journal rewind. Every
parent-plan admission, generation fence, pre-attempt correlation,
SUBMITTING, accepted receipt, effect decision, and checkpoint transition is a
critical transaction that must be acknowledged by the certified synchronous
remote-apply quorum before a dependent external action occurs.
The pre-submit sequence is normative:
- assign the next monotonic
attempt_ordinaland deterministicattempt_id; - create an immutable, independently retained
MAY_ATTEMPTmarker with create-if-absent key(operation_namespace, operation_id, attempt_ordinal), binding operation and parent/child identity, generation, expected journal revision, journal epoch, mutation-intent digest, and creation time; - in one PostgreSQL critical transaction reserve remote-job capacity, append
the attempt row and marker digest, and CAS the operation to
SUBMITTING; - commit that transaction with the required synchronous quorum;
- only after confirmed commit, execute HTTP.
A marker without its exact matching journal attempt_id, ordinal, expected
revision, and epoch is treated as possible remote effect, never as permission
to resend. The marker authority uses a failure domain and credentials
independent from PostgreSQL restore. Orphan markers created before a failed
journal transaction are conservative reconciliation work keyed by attempt id,
not mutation authority.
Every failover/restore carries a journal_epoch. If zero-RPO continuity cannot
be proven, the environment-wide mutation gate becomes BLOCKED; read-only
inspection, receipt observation, and reconciliation remain available. A
reconciliation campaign compares journal rows, immutable markers, receipts,
effect authority, and receiver proof. New mutations resume only after a new
epoch attestation and explicit platform/security approval. PITR never implies
that an external receiver rolled back.
Lease separation¶
Three independent leases exist:
mutation_lease: may initiate a mutation only beforeSUBMITTINGand under the safe-retry rules;observation_lease: may perform duplicate-safe read-only polling;checkpoint_lease: may promote an already eligible contiguous frontier.
The V1 remote-job semaphore is not Redis, etcd, or process memory: its slots and
reservations live in the same PostgreSQL control plane as the operation
journal. Capacity reservation, attempt-scoped marker binding, attempt append,
and CAS to SUBMITTING are committed atomically. It survives Airflow deferral,
worker/triggerer loss, and journal lease turnover. Accepted/running and
UNKNOWN operations retain capacity until certified expiry plus reconciliation
or an audited operator transfer to incident-reserved capacity; ordinary TTL GC
cannot silently free it and exceed receiver concurrency. A proven
REQUEST_NOT_STARTED attempt transfers/releases capacity only in the durable
RETRY_WAIT or terminal transaction; reconciliation repairs orphan
reservations by attempt_id.
Lease expiry after SUBMITTING does not authorize a replacement POST.
Another worker can observe or reconcile only. It may submit again only after
exact absence is proven or a certified remote fence authorizes same-key replay.
The local fence prevents concurrent dpone decisions; it cannot stop an HTTP
request already executing at the receiver.
Retention and compact effect authority¶
Large payloads and verbose observations may expire only after policy permits. A compact operation tombstone/effect index retains, at minimum, operation namespace, delivery key, intent digest, generation, effect conflict domain, target scope, payload/profile/binding digests, remote effect, receipt identity, terminal verification, checkpoint decision, and retention horizon. Its authority is based on the maximum permitted replay horizon, not only receiver TTL:
- successful append keys live until route decommission or an audited namespace reset;
- replacement keeps a permanent
highest_applied_generationover canonical conflict-scope coverage; UNKNOWNandPARTIALLY_APPLIEDlive until explicit reconciliation and then their governed post-reconciliation horizon;- payloads and verbose observations may be collected much earlier because they are not the replay fence;
- reset is a separate audited administrative operation unavailable to workload authors and ordinary runtime GC.
Artifact policy includes encryption at rest, KMS key reference, tenant prefix, ACL, classification, residency, access audit, quota, secure deletion, legal hold, and retention alerts. Payload data never enters PostgreSQL rows.
Execution algorithm¶
- Resolve and freeze the deployment's connection snapshot, operation profile, workload intent, semantic/policy/profile digests, and journal epoch.
- For a new parent, freeze and materialize one source boundary, verify its completeness/digest, and close the source snapshot.
- Plan deterministic children from the immutable parent artifact and prove complete, non-overlapping coverage.
- Seal all child payloads from that artifact and validate complete row/decoded/wire limits.
- Compute every child identity and
parent_plan_digest. - In one PostgreSQL transaction admit the parent and complete immutable child topology. Reject intent, namespace, principal, generation, or coverage conflict before any HTTP or secret resolution.
- For an existing parent operation, load the admitted topology and artifacts directly; never run source freeze, planner, or sealer again.
- Before each new submit, assign an attempt ordinal/id and publish its
create-if-absent
MAY_ATTEMPT; then, under the PostgreSQL domain lock, one critical transaction rechecks overlap/append policy, reserves remote-job capacity, appends the attempt/marker binding, and CAS-commitsSUBMITTINGunder the journal epoch. Resolve a fresh credential but never persist it. - Classify transport evidence. Persist receipt and
ACCEPTED, or persist the exact remote-effect certainty before releasing the lease. - Return
DeliveryPendingfor async work. Airflow defers using operation id only. V1 never submits a second async child while one child is pending. - Poll with an observation lease and independent rate limits until bounded terminal, expired, cancelled, or protocol-unknown state.
- Verify counters, digests, scope, and profile-specific invariants. Publish bounded terminal and optional item-result artifacts.
- Mark remote effect, verification, and checkpoint eligibility independently.
- Under a checkpoint lease, promote only the highest contiguous eligible source frontier.
- Finalize evidence and apply retention without deleting replay/generation authority.
Generic pseudocode¶
def execute_delivery(compiled_plan, source_boundary, parent_operation_id=None):
if parent_operation_id is not None:
parent = journal.load_admitted_parent(parent_operation_id)
# Recovery authority is pinned topology; planner/sealer are not called.
else:
frozen_parent = source_snapshot.freeze_and_materialize(source_boundary)
frozen_parent.verify_complete_digest()
source_snapshot.close(frozen_parent)
descriptors = planner.plan_and_prove(
frozen_parent,
compiled_plan.limits,
algorithm_version=compiled_plan.planner_algorithm_version,
)
sealed_children = payload_sealer.seal_all(frozen_parent, descriptors)
parent_plan = plan_factory.build_complete(
frozen_parent,
compiled_plan,
sealed_children,
)
parent = journal.admit_complete_parent_plan(parent_plan)
for operation in parent.ordered_children:
if operation.intent_conflict:
return DeliveryBlocked(code="REST_DELIVERY_INTENT_CONFLICT")
if operation.needs_submission:
retry_guard.assert_mutation_permitted(operation)
attempt = attempt_factory.next_for(operation)
marker = pre_attempt_store.create_if_absent(operation, attempt)
operation = journal.reserve_and_cas_submitting_with_zero_rpo(
operation,
attempt,
marker.digest,
lock_effect_domain=True,
)
submit_result = submitter.submit_after_durable_fence(operation)
operation = journal.record_submit_result(submit_result)
if operation.needs_observation:
return DeliveryPending(
operation_id=operation.id,
continuation_kind="poll_receipt",
next_check_after=operation.next_check_after,
)
terminal = verifier.verify(operation)
journal.record_terminal_axes(terminal)
checkpoint.promote_contiguous_frontier_if_eligible(parent.id)
return DeliveryCompleted(parent_id=parent.id)
Failure and partial-result policy¶
| Evidence | Remote effect | Automatic action | Checkpoint |
|---|---|---|---|
| Validation or admission failed before transport | NONE_PROVEN |
Fix and retry same generation/intent as applicable. | Blocked. |
| Transport proves request not started | NONE_PROVEN |
Retry within policy. | Blocked. |
| Request may have reached receiver, no certified fence | UNKNOWN |
Observe/reconcile; never automatic POST. | Blocked. |
| Accepted receipt persisted | UNDETERMINED |
Return pending and poll. | Blocked. |
| Duplicate with receipt proving same key and intent | Profile-derived | Resume observation. | Blocked until verified. |
| Bare duplicate/conflict response | UNKNOWN |
Reconcile; no resend. | Blocked. |
| Receiver says failed/cancelled/expired | Profile-derived, possibly PARTIALLY_APPLIED or UNKNOWN |
Verify and retain evidence. | Blocked. |
| Partial or per-record rejection | PARTIALLY_APPLIED unless receiver proves atomic rollback |
Publish bounded accepted/rejected/unprocessed evidence; no item replay in V1. | Blocked. |
| All rows accounted and verification passes | FULLY_APPLIED |
Finalize. | Eligible, then promoted under lease. |
| Verification counters missing or contradictory | UNKNOWN or PARTIALLY_APPLIED |
Reconcile. | Blocked. |
V1 result artifacts reserve accepted, rejected, unprocessed, and remote-id collections with bounded counts and content-addressed spill files. They support diagnosis but do not authorize per-record retry. Automatic quarantine and rejection bisection are explicitly V1.1 because they are unsafe for atomic partition replacement and require item-level mutation identities.
Receiver errors use bounded typed mappings. Profiles may recognize
application/problem+json according to RFC 9457,
HTTP 207, or vendor envelopes only when their semantics are certified.
Edge cases¶
- Empty input: promote only from a complete frozen read and an explicit profile policy; otherwise skip without checkpoint or fail.
- Null versus empty: codecs preserve profile-owned distinct encodings; ambiguous mappings fail before sealing.
- Unicode: input is normalized only as declared; invalid source bytes fail with field evidence before mutation. UTF-8 round-trip goldens include Cyrillic.
- Duplicate rows: dpone does not invent row deduplication. Mapping/profile contracts define whether duplicates are valid and verification accounts for them.
- Schema drift: closed mapping compilation fails; an active sealed payload is never rebuilt under a newer mapping.
- Oversized atomic scope: fail with
REST_DELIVERY_SCOPE_EXCEEDS_LIMIT; do not split a receiver-atomic replacement. - Timeout or connection reset: use transport-phase evidence and the safe retry rules; timeout alone never proves absence.
- Process crash: resume from the admitted parent topology and pinned artifacts. No process-local variable is recovery authority; recovery never replans or reseals.
- Receipt expiry: retain effect as unknown unless another certified proof establishes it; do not resubmit merely because GET returns 404/410.
- Partial/207 result: publish bounded result evidence, mark partial or unknown according to profile, and block checkpoint.
- Redirect/DNS change: fail authority validation and never forward auth to a new authority.
- Cancellation: V1 only observes an externally cancelled job. It never calls a cancel endpoint. A cancellation acknowledgement does not prove rollback; verification still derives remote effect.
- Journal restore/failover: without an attested zero-RPO epoch, block the
environment mutation gate and reconcile immutable
MAY_ATTEMPTmarkers; never infer that PITR rolled back receiver state. - Stale generation: a lower overlapping replacement cannot submit after a higher admission and remains permanently stale after higher full application.
- Clock skew: journal leases use PostgreSQL time; receiver TTL certification includes skew margin.
- Unsupported family/capability: fail compile or preflight before source extraction and secret resolution.
- Deep/nested response: reject beyond profile byte, depth, field, and string bounds; arbitrary body content is not evidence.
CLI and recovery¶
Recovery never accepts an authoring manifest. The immutable plan referenced by the journal is runtime authority.
dpone delivery inspect \
--environment dev \
--operation-id op_v1_... \
--format json
dpone delivery reconcile \
--environment dev \
--operation-id op_v1_... \
--expected-release-digest sha256:... \
--expected-profile-contract-digest sha256:... \
--apply
dpone delivery resume \
--environment dev \
--operation-id op_v1_... \
--apply
--environment resolves only the journal/artifact control-plane profile. It
does not resolve a current workload manifest. Optional expected digests are
operator guards. inspect is read-only. reconcile --apply and resume
require audited authority and appropriate leases. resume refuses any mutation
not permitted by the durable operation's certified fence. No V1 CLI command
calls a receiver cancel endpoint.
Commands are non-interactive unless --apply is present; automation SHOULD add
--yes where the CLI requires confirmation. --format json writes one stable,
redacted schema to stdout and human diagnostics to stderr. Evidence publication
is atomic create-if-absent; a conflicting existing digest fails. Exit codes are:
| Code | Meaning |
|---|---|
| 0 | Command completed, including successful inspection of a failed operation. |
| 2 | Invalid arguments, unsupported schema/profile, or intent conflict. |
| 3 | Journal, artifact authority, credential provider, or receiver unavailable. |
| 4 | Remote effect unknown/partial or manual authority required. |
| 5 | Proven terminal receiver failure with no safe automatic action. |
inspect exposes each outcome axis, child/frontier position, artifact ids,
receipt age, certified TTL horizon, and a machine-readable list of allowed next
actions. It never prints arbitrary headers, query secrets, payload rows, or raw
response bodies.
Stable errors include:
REST_DELIVERY_INTENT_CONFLICT;REST_DELIVERY_REMOTE_EFFECT_UNKNOWN;REST_DELIVERY_PARTIALLY_APPLIED;REST_DELIVERY_UNSAFE_RETRY;REST_DELIVERY_SCOPE_EXCEEDS_LIMIT;REST_DELIVERY_COUNT_MISMATCH;REST_DELIVERY_RECEIPT_EXPIRED;REST_DELIVERY_PROTOCOL_UNKNOWN;REST_DELIVERY_STALE_GENERATION;REST_DELIVERY_OVERLAPPING_EFFECT_IN_FLIGHT;REST_DELIVERY_RETRY_AFTER_EXCEEDS_BUDGET;REST_DELIVERY_APPEND_SCOPE_ALREADY_APPLIED;REST_DELIVERY_JOURNAL_EPOCH_BLOCKED.
The machine contract is the stable error metadata authority. In particular:
| Code | Exit class | Retryability | Required operator action | Severity/evidence |
|---|---|---|---|---|
REST_DELIVERY_INTENT_CONFLICT |
2 | Never | Correct intent or create an explicit governed generation. | Warning; operation evidence. |
REST_DELIVERY_REMOTE_EFFECT_UNKNOWN |
4 | Reconciliation only | Inspect immutable evidence and reconcile. | Critical; reconciliation evidence. |
REST_DELIVERY_PARTIALLY_APPLIED |
4 | Compensation/reconciliation only | Reconcile or run the certified compensation contract. | Critical; reconciliation evidence. |
REST_DELIVERY_UNSAFE_RETRY |
4 | Never | Reconcile the delivery key before any resend. | Critical; reconciliation evidence. |
REST_DELIVERY_SCOPE_EXCEEDS_LIMIT |
2 | Never | Shrink the scope or change the certified receiver atomicity contract. | Warning; operation evidence. |
REST_DELIVERY_COUNT_MISMATCH |
4 | Reconciliation only | Inspect receiver counts and reconcile effect. | Critical; reconciliation evidence. |
REST_DELIVERY_RECEIPT_EXPIRED |
4 | Reconciliation only | Query by delivery key when certified or reconcile manually. | Warning; reconciliation evidence. |
REST_DELIVERY_PROTOCOL_UNKNOWN |
4 | Reconciliation only | Inspect protocol evidence and reconcile. | Critical; reconciliation evidence. |
REST_DELIVERY_STALE_GENERATION |
2 | Never | Inspect the newer overlapping generation. | Warning; operation evidence. |
REST_DELIVERY_OVERLAPPING_EFFECT_IN_FLIGHT |
4 | Observation/reconciliation only | Resolve or observe the older overlap. | Warning; reconciliation evidence. |
REST_DELIVERY_RETRY_AFTER_EXCEEDS_BUDGET |
4 | Blocked | Extend the governed budget or wait for the server window. | Warning; operation evidence. |
REST_DELIVERY_APPEND_SCOPE_ALREADY_APPLIED |
2 | Never | Use an explicitly certified correction contract. | Warning; effect tombstone. |
REST_DELIVERY_JOURNAL_EPOCH_BLOCKED |
4 | Reconciliation only | Complete restore reconciliation and approve the new epoch. | Critical; reconciliation evidence. |
Public Python contracts and ports¶
Immutable public models live under dpone.contracts.rest_delivery. Runtime
services depend on capability ports, not concrete HTTP, PostgreSQL, object
storage, clocks, Airflow, or secret SDKs.
from dpone.contracts.rest_delivery import (
AcknowledgementState,
CheckpointState,
DeliveryBlocked,
DeliveryCompleted,
DeliveryPending,
DeliveryOperation,
ExecutionState,
RemoteEffect,
RestSinkSpec,
VerificationState,
)
from dpone.runtime.delivery import ResumableDeliveryProcessor
Required ports include:
DeliveryJournalPortwith CAS admission/transitions and typed leases;ImmutableArtifactPortfor parent, payload, result, and evidence objects;SourceSnapshotPort;PayloadCodecPort;RestTransportPortwith phase evidence;CredentialResolverPort;DistributedRateLimiterPort;RemoteJobSemaphorePort;DeliveryVerifierPort;CheckpointFrontierPort;ClockPortand deterministic jitter source.
The composition root selects adapters. Domain services never instantiate their dependencies. HTTP request classes containing credentials remain private.
Architecture components¶
| Component | Existing/new | Responsibility | Dependencies |
|---|---|---|---|
| Manifest compiler | Extend | Resolve references offline and emit immutable typed delivery plan. | Pure contracts and registries. |
| Operation profile registry | Extend trusted-profile pattern | Own versioned protocol semantics, overrides, certification, and digest. | Registry/artifact ports. |
| Connection projection | Extend | Resolve immutable authority/security snapshot without secret values. | Existing binding resolver. |
| Source freezer | New | Produce immutable parent artifact or certified source snapshot. | Source and artifact ports. |
| Adaptive planner | New | Split one frozen parent deterministically and prove coverage. | Pure contracts only. |
| Payload sealer | New | Produce canonical streamable payload and measurements. | Codec and artifact ports. |
| Identity service | New | Derive delivery, intent, and policy identities and detect conflicts. | Pure canonical encoder. |
| Delivery supervisor | New | Enforce state transitions, retry gates, continuation, and verification. | Capability ports only. |
| PostgreSQL journal adapter | New | Provide zero-RPO admission, epoch/restore gate, CAS, leases, attempts, effect index, and GC metadata. | DeliveryJournalPort, PostgreSQL driver. |
| Object-storage adapter | Reuse/extend | Store encrypted immutable parent/payload/result/evidence artifacts. | Existing immutable artifact port. |
| REST transport | New | Apply auth/TLS/proxy, stream bytes, and report transport-phase evidence. | Transport and credential ports. |
| Airflow provider | Extend | Convert pending results to deferral and terminal journal state to task outcome. | Public runtime continuation API. |
| CLI | Extend | Inspect, reconcile, resume, and certify by operation id. | Application services, no adapter policy. |
Dependency direction is contracts ← ports ← domain/runtime services ← adapters/composition roots. Airflow, HTTP libraries, PostgreSQL, object storage, and secret SDKs remain outside pure contracts and policy. Concrete construction occurs only in CLI/runtime/provider composition roots.
flowchart LR
W[Workload intent] --> C[Offline compiler]
P[Operation profile] --> C
B[Connection projection] --> C
C --> I[Immutable deployment plan]
S[Source] --> F[Freeze parent]
I --> F
F --> A[Adaptive plan and seal]
A --> J[(PostgreSQL journal)]
A --> O[(Object artifacts)]
J --> D[Delivery supervisor]
D --> H[REST receiver]
H --> D
D -->|pending| AF[Airflow deferral]
AF --> D
D --> V[Verify and contiguous checkpoint]
V --> J
The companion decisions are:
- ADR 0053: identity, outcome axes, journal, leases, source freeze, and checkpoint frontier;
- ADR 0054: continuation, processor compatibility, and Airflow boundary;
- ADR 0055: connection, operation-profile, workload, and protocol-family authority.
Alternatives and tradeoffs¶
| Alternative | Advantage | Rejected because |
|---|---|---|
| Keep native DAG code | Fastest reference-only change. | Repeats unsafe protocol policy and provides no platform recovery contract. |
| Put all HTTP fields in workload YAML | Maximum apparent flexibility. | Moves security, idempotency claims, and protocol drift to data authors. |
Extend ETLProcessor with REST branches |
Reuses one entry point. | Couples synchronous relational cleanup to pending remote jobs and risks compatibility. |
| Use Airflow retries/Variables as journal | No new control-plane database. | Task state cannot prove remote effect; Variables lack the required admission/CAS/lease model. |
| Use only object storage as journal | Reuses an existing authority. | Cross-object CAS, ordered attempts, leases, and queryable recovery are operationally weaker for V1. |
| Generic protocol graph in V1 | Covers more APIs immediately. | Multiplies state, secret, and retry semantics before the two core families are certified. |
| PostgreSQL journal plus object artifacts | Strong transactional control state with scalable immutable payloads. | Selected; adds an operated database and migrations. |
Quality-budget impact¶
Implementation MUST stay within docs/benchmarks/quality_budgets.yml, including
the current 400-SLOC module cap and import-graph non-regression. Planned cohesive
modules are contracts/state, compiler/profile resolution, identity, frozen
source/planning, sealing/codecs, supervisor, verifier/frontier, journal port,
PostgreSQL adapter, transport adapter, CLI applications, and Airflow adapter.
No module owns more than one state transition policy and one adapter concern. The supervisor coordinates injected services rather than becoming a god module. HTTP response parsing is profile-driven but implemented by typed bounded extractors, not a generic expression engine. New import edges point inward to contracts/ports; provider and adapter dependencies do not reach base imports. The change-aware check plan, module-size check, layer metrics, import rules, ruff, mypy, and non-live suite are merge gates for implementation PRs.
Market comparison¶
The comparison is based on rolling official documentation verified on 2026-08-30, not marketing rank. A version is named only where the source names one; otherwise “current docs” means the page observed on that date. The second column records an observed pattern and what dpone adopts. The third column is an explicit design inference or rejected/deferred pattern. Products solve different scopes, so “best” means stronger evidence and recovery within V1's declared bulk-delivery boundary, not more connector breadth.
| System/context | Capability and observed design | Strength and adopted pattern | Limitation and rejected/deferred pattern | Official source/date |
|---|---|---|---|---|
| dlt, current docs | Python custom destinations use load packages/jobs, configurable batch size, retry, failed-job evidence, and pending package recovery. | Adopt immutable load artifacts, explicit job outcomes, and checkpoint blocking while a package is incomplete. | Its docs warn a half-committed custom API batch can duplicate and atomicity is implementer-owned; reject blind batch replay. | Reverse ETL/custom destination, checked 2026-08-30. |
| Duckle, current repository/docs | Local-first DuckDB engine with snk.rest POST/PUT/PATCH batched JSON, webhook, GraphQL, Salesforce, and Salesforce Bulk sinks plus a broad visual catalog. |
Adopt compact declarative REST authoring, batching ergonomics, searchable catalog, preview, and consistent UX vocabulary. | The reviewed public contract does not document a PostgreSQL-backed durable mutation journal, async receipt lifecycle, cross-process effect reconciliation, or checkpoint fence; do not infer those guarantees from connector breadth. | Official repository, checked 2026-08-30. |
Redpanda Connect http_client, current docs |
HTTP output exposes count/byte/time batching, max_in_flight, retry/backoff/status policy, rate limiting, TLS/mTLS, OAuth/JWT/Basic, multipart, and backpressure. |
Adopt systematic transport controls and explicit performance knobs behind governed profiles. | Transport retry and backpressure do not prove a receiver mutation's durable effect; dpone keeps effect journal, generation fence, and async recovery as separate correctness authority. | HTTP client output, checked 2026-08-30. |
| Apache NiFi InvokeHTTP 2.11.0 | Configurable HTTP methods/body/TLS route FlowFiles through explicit Original, Retry, No Retry, Failure, and optional response relationships while projecting status, duration, URL, transaction id, and bounded response attributes. |
Adopt explicit response/retry/no-retry result channels and redacted HTTP evidence projection. | Status-family routing alone is unsafe for ambiguous non-idempotent remote effects; dpone additionally requires certified fences and durable effect/reconciliation state. | InvokeHTTP, checked 2026-08-30. |
| Informatica REST V2, current Cloud docs | OpenAPI/Swagger-backed source, target, and midstream operations with multiple auth and TLS modes. | Adopt profile bootstrap, typed operations, enterprise connection ownership, and mapping UX. | Generated breadth does not prove endpoint-specific idempotency/effect recovery; reject automatic certification from OpenAPI. | REST V2 Connector, checked 2026-08-30. |
| Microsoft SSIS, SQL Server 2022/current docs | Separate HTTP Connection Manager and Web Service Task configure URL, credentials, timeout, WSDL operation, and outputs. | Adopt separation of reusable connection authority from operation execution. | Built-in task is WSDL/SOAP-oriented with limited auth; REST and async recovery are component/script-specific. | Web Service Task, checked 2026-08-30. |
| Airbyte, repository master | Destination protocol has record/batch delivery, destination state/checkpoint concepts, and connector release/certification stages. | Adopt explicit state acknowledgement, generation-aware identity, and maturity evidence. | A generic receiver's mutation fence remains connector-specific; do not equate destination acknowledgement with exact remote effect. | Destination implementation reference, checked 2026-08-30. |
| Fivetran Activations, current docs | Per-record results and recursive splitting isolate rejected records during retry. | Defer item-result routing and rejection bisection to a V1.1 contract with item identities. | Splitting is unsafe for receiver-atomic partition replacement; reject as a universal retry strategy. | Retry handling, checked 2026-08-30. |
| Sling, current docs | Compact YAML/JSON replication defines source, target, streams, modes, defaults, keys, transforms, and target options. | Adopt concise defaults plus bounded per-stream overrides. | Targets center on stores/files rather than async REST mutation recovery; reject protocol semantics in free-form hooks. | Replication structure, checked 2026-08-30. |
| Hightouch HTTP Request, current hosted docs | Added/changed/removed triggers drive configurable methods, paths, payloads, rate, concurrency, and error handling. | Adopt strong request preview/inspector and explicit future mutation modes. | Complex chained operations are limited and per-sync controls are not the V1 durable journal; defer reverse ETL to V1.1. | HTTP Request destination, checked 2026-08-30. |
| Confluent Cloud HTTP Sink V2 | OpenAPI paths, upsert, path parameters, tombstone delete, and success/error topics. | Adopt typed path/query parameters, profile templates, and explicit result channels. | Kafka offset and stream semantics differ from frozen bulk scopes; reject leaking sensitive receiver content into generic result topics. | HTTP Sink V2, checked 2026-08-30. |
| Pentaho Data Integration 11.0 | REST Client exposes method, body, parameters, headers, auth, TLS, status, and response fields in visual transformations. | Adopt redacted request preview and field-level mapping UX. | Data-driven URL/method are too permissive for production authority; reject ungoverned dynamic authority. | REST Client step, checked 2026-08-30. |
| Apache Beam, current docs | Runner-portable processing, state, timers, and checkpoint/retry primitives. | Adopt deterministic partitioning and injected runner-independent domain policy. | N/A as a direct REST sink comparator: it does not supply a certified generic receiver mutation protocol. | Programming guide, checked 2026-08-30. |
| gusty, repository main | Declarative Airflow DAG authoring from YAML/front matter. | Adopt concise authoring as a UX reference. | N/A to receiver correctness: no REST intent, receipt, remote-effect, or journal contract. | Official repository, checked 2026-08-30. |
| Astronomer Cosmos, current docs | Separates dbt parsing/rendering, execution modes, and connection/profile mapping into Airflow. | Adopt thin provider integration and runtime-mode separation. | N/A as a REST sink: it orchestrates dbt and delegates destination commit semantics. | How Cosmos works, checked 2026-08-30. |
| Salesforce Data Cloud ingestion | Explicit create-job, upload, and close lifecycle with job ids. | Reserve a bounded multi-step continuation graph. | More than one mutation step; defer to V1.2 rather than weakening V1 recovery. | Create ingestion job, checked 2026-08-30. |
| Microsoft Graph upload session | Session creation and byte-range PUT continuation with upload-specific authorization rules. | Reserve range checkpoints and credential-free upload URL handling. | Requires resumable-range state and new security rules; defer to V1.2. | Upload session, checked 2026-08-30. |
| Google long-running operations | Standard operation name plus done/error/response observation shape. | Candidate platform async profile template. | Field, authority, cancellation, and retention still need endpoint certification; do not certify by shape alone. | Long-running operations, checked 2026-08-30. |
| Stripe, current API docs | Reusing a key returns the stored result, parameters are compared, and keys can be pruned after a finite interval. | Adopt key-to-intent binding and explicit TTL certification. | Vendor behavior is not a universal Idempotency-Key standard; reject header-presence as proof. |
Idempotent requests, checked 2026-08-30. |
Industrial differentiation targets¶
The “industrial standard” goal is evaluated on reproducible axes, not feature count.
axis: mutation safety after ambiguous transport failure
scenario: receiver commits a POST, then connection is cut before any response byte
baseline: synthetic naive Airflow HTTP task retry fixture
metric: duplicate mutations, false successes, unproved automatic resends
target: 0, 0, 0 across every injected process/transport cut
procedure: deterministic fault proxy plus worker restart on a second host
artifact: test_artifacts/connectors/rest/remote_effect_fault_matrix.json
limitations: applies only to certified endpoint fences and tested transport phases
axis: immutable-intent conflict protection
scenario: same route, target scope, source boundary, and generation are resealed with changed bytes
baseline: payload-derived operation identity that creates a new operation
metric: HTTP mutations before conflict and stable error classification
target: 0 HTTP mutations; 100% REST_DELIVERY_INTENT_CONFLICT
procedure: property tests over payload, profile, binding, and policy mutations
artifact: test_artifacts/connectors/rest/identity_conflict_matrix.json
limitations: canonical encoder correctness remains part of the trusted base
axis: asynchronous orchestrator efficiency and correctness
scenario: 30-minute remote job with worker and triggerer restart plus duplicate trigger event
baseline: worker-resident polling sensor/operator
metric: post-submit worker time, duplicate mutations, lost terminal observations
target: <=5 seconds, 0, 0; remote-job semaphore never exceeded
procedure: Airflow 3.2 primary acceptance with controlled receiver and journal
artifact: test_artifacts/connectors/rest/airflow_async_acceptance.json
limitations: excludes receiver processing latency and scheduler-wide capacity
axis: adaptive frozen-window utilization and checkpoint correctness
scenario: synthetic variable-volume source bounded by the selected mock profile
baseline: fixed-width files and mutable-query replanning
metric: requests, limit violations, source gaps/overlaps, invalid checkpoint jumps
target: fewer requests than fixed-width baseline; 0 violations/gaps/overlaps/jumps
procedure: freeze one synthetic parent, split/restart under all child completion orders
artifact: test_artifacts/connectors/rest/adaptive_frontier_benchmark.json
limitations: request count is distribution-specific; correctness targets are universal
axis: operator recovery UX
scenario: one unknown-effect operation with a queryable certified receipt
baseline: inspect DAG logs, Variables, files, and receiver manually
metric: commands, median elapsed time, unsafe resend choices, evidence completeness
target: <=3 commands; <=10 minutes; 0 unsafe choices; 100% required evidence
procedure: 10 fresh operators follow only CLI output and the generated runbook
artifact: test_artifacts/connectors/rest/recovery_ux.json
limitations: small internal usability study, not a general human-factors claim
Security, timeout, and operations policy¶
Production profiles require HTTPS, verified TLS, authority allowlisting, redirect policy, DNS-rebinding defense, proxy governance, bounded response parsing, header allowlists, and connection isolation. Data cannot choose scheme, host, port, credential, proxy, TLS policy, poll authority, or response-derived next URL.
The normative REST bulk-delivery threat model covers journal rewind, generation rollback, remote-principal swap, cross-tenant collision/leakage, object-store compromise, namespace reset, profile revocation, SSRF/redirects, triggerer exhaustion, semaphore loss, and evidence leakage. Security-owner approval is a Phase 0 and production gate, not a future documentation task.
V1 authentication capabilities are bearer token, API key in an allowlisted header, HTTP Basic, OAuth 2.0 client credentials, and mTLS. API key in query is forbidden by production default because URLs leak through proxy/WAF/access logs, tracing, exceptions, and receiver telemetry. A profile-specific exception requires security approval and verified URL redaction across every one of those layers. HMAC, AWS SigV4, delegated-user/browser OAuth, arbitrary token exchange, and response-derived credentials require a later profile capability and threat-model approval. A mutable deny-only revocation can block new submissions for a profile/binding while preserving read-only observation and reconciliation.
Timeouts are a vector, not one integer:
- DNS, connect, TLS, write, read, idle, and request-total bounds;
- operation-total, poll interval, poll retry, and receiver-expiry bounds;
- submit retry budget and observation retry budget;
- explicit behavior for
Retry-Afterdate and delta values.
Distributed controls are separately keyed for submit requests, polls, result downloads, active requests, and active remote jobs. Scope can include endpoint, credential principal, tenant, and environment. Deferral does not release the remote-job semaphore.
Metrics use bounded labels; operation ids belong in logs and spans. Required metrics cover operations by every state axis, source and checkpoint lag, rows/bytes, rate-limit wait, active remote jobs, receipt age, unknown-effect age, artifact retention, CAS conflict, and recovery action. Audit records include actor, operation id, expected digests, decision, and artifact ids.
Test and certification plan¶
| Layer | Mandatory scenarios | Evidence |
|---|---|---|
| Design authority | Draft 2020-12 schema with additionalProperties: false, bounded duplicate-key-rejecting YAML load, reachable transitions, terminal closure, failure mapping, acknowledgement preservation, and monotonic generation checks through dpone docs check-rest-delivery-design-contract. |
CLI JSON report plus negative fixtures. |
| Schema/compiler | Closed workload/profile schemas, bounded overrides, unsupported family rejection, absolute URL/secret rejection. | Negative fixture matrix. |
| Identity/property | Namespace isolation, same key/intent resume, intent conflict, semantic/policy split, principal swap, rendered envelope, concurrent overlap winner, range-scoped watermark, append correction rejection. | Property/model-test artifact. |
| Source/planner | Seal-all barrier, immutable complete parent topology, planner-upgrade recovery without replanning, codecs, limits, coverage, empty proof, contiguous frontier. | Golden digests, transaction cuts, and coverage proofs. |
| Journal | PostgreSQL unique admission, CAS, three leases, DB clock, synchronous quorum, attempt-scoped MAY_ATTEMPT, domain-lock/range linearization, atomic capacity reservation, epoch, lossy restore gate, permanent interval effect index. |
Failover/PITR/restore, concurrent admission, and retention matrix. |
| Transport | Phase-specific timeout evidence, redirects, 409/413/429/5xx, Retry-After, idempotent/non-idempotent cases. |
HTTP classification matrix. |
| Sync integration | JSON, NDJSON, multipart, counters, duplicate proof, contradictory results, partial application. | Connector certification artifact. |
| Async integration | Serial child supervision, 202/receipt, expired receipt, duplicate trigger, restart, external-cancel observation through poll_receipt, no active cancel, no-receipt blocked taxonomy. |
Continuation matrix. |
| Process cuts | Kill before/after every journal write and request boundary; restart elsewhere. | Zero-unproved-resend fault matrix. |
| Airflow primary | 3.2.x submit/defer/resume, triggerer restart, worker loss, duplicate event, pre-submit remote-job semaphore, minimal async/lazy trigger client. | Airflow acceptance JSON. |
| Airflow compatibility | Same suite on latest supported patch of every declared minor: 2.10, 2.11, 3.0, 3.1, 3.2, and 3.3. | Compatibility evidence. |
| Security | Dedicated threat model: journal rewind, principal swap, cross-tenant isolation, object compromise, SSRF, revocation, trigger exhaustion, secret/evidence limits. | Security-owner approval and zero-leak matrix. |
| Performance | Profile-bounded rows and bytes, bounded RSS, stream upload, adaptive planning. | Throughput/RSS benchmark. |
| Vendor live | Certified environment-specific profile, receipt TTL, duplicate behavior, counters, Unicode, restart and recovery. | Signed environment-bound receipt. |
Maturity is experimental after static tests, beta after PostgreSQL,
object-storage, local-live, and Airflow 3.2 gates, and production only after
vendor-live fault recovery, restore, security, operator-runbook, and retention
certification. Skipped live evidence is UNVERIFIED, never PASS.
Implementation roadmap and estimate¶
Implementation begins only after this specification and ADRs 0053–0055 are approved. Each phase must ship its own negative tests and evidence; no phase may claim a later guarantee.
| Phase | Deliverable | Acceptance gate | Estimate |
|---|---|---|---|
| 0 | Approve scope, threat model, identities, state axes, PostgreSQL journal, TTL policy, ADRs. | No unresolved P0 contract. | 1–2 weeks |
| 1 | Operation-profile registry, workload schema, compiler, immutable deployment plan. | Offline closed-schema and compatibility suite. | 2 weeks |
| 2 | Reference state model, identity algebra, strict design schema/validator, property/state-machine tests. | Exhaustive legal-transition, failure-mapping, duplicate-key, acknowledgement, and conflict tests. | 2 weeks |
| 3 | PostgreSQL journal, domain-lock/range linearization, atomic remote capacity, zero-RPO quorum, epoch/restore gate, attempt-scoped markers/artifacts, leases, interval effect index. | Hard-kill, concurrent admission, failover/PITR, capacity, and retention gates. | 3–4 weeks |
| 4 | First synchronous JSON vertical slice and secure transport. | End-to-end sync delivery without Airflow. | 2 weeks |
| 5 | Deterministic file codecs/envelope, frozen source, seal-all barrier, immutable adaptive plan, multipart. | Golden payload, process-cut, no-replan, and coverage/limit gates. | 2–3 weeks |
| 6 | Serial-child async receipt/poll continuation and reconciliation. | Process-cut, one-in-flight-child, cancellation-observation, and expiry matrix. | 2–3 weeks |
| 7 | Airflow provider integration for 3.2 primary and every declared compatibility minor. | Worker/triggerer restart, async-client, and semaphore gates. | 2 weeks |
| 8 | V1 production hardening, threat-model controls, certification UX, inspectors, runbooks. | Multi-worker/load/security/DR exercises and owner approvals. | 2–4 weeks |
| 9 | Production observation and closeout. | SLO window with no unsafe resend, false success, generation rollback, or unresolved DR gap. | Calendar observation window |
Effort and calendar commitments must be estimated for the selected certified profiles and environments. The phase ordering above is a dependency plan, not a customer deployment commitment.
V1.1/V1.2 are a separate 24–36+ engineer-week broad program after the V1 production gate and observation decision. Per-record result routing, object mutation/quarantine, OpenAPI bootstrap beyond profile drafting, and multi-step protocols must not start between V1 core and its hardening/migration gates.
Documentation deliverables¶
- self-service tutorial using a certified local mock profile;
- operation-profile authoring and certification guide for platform owners;
- reference for workload schema, profile schema, state axes, identities, continuation, errors, CLI, artifacts, metrics, and maturity;
- runbooks for intent conflict, unknown effect, partial application, expired receipt, overlapping generation, checkpoint gap, zero-RPO failover/restore gate, namespace reset, and effect-authority retention;
- machine-readable design/state contract and generated legal-transition reference;
- dedicated security threat model and approval record;
- Airflow 3.2 primary plus 2.10/2.11/3.0/3.1/3.3 compatibility deployment and triggerer capacity guide;
- generated profile catalog, source/sink matrix, and certification evidence;
- request preview/inspector that renders redacted semantic request metadata and sealed payload measurements without credentials or network I/O.
Rollout and rollback¶
The connector ships behind runtime.features.rest_bulk_delivery_v1: false and
maturity experimental. Rollout stages are compile-only, frozen seal-only
shadow, controlled local-live, environment-specific canary, scheduled DEV, and production
candidate. Static tests alone never raise maturity.
New submissions require the flag. Disabling it stops new mutation admission but does not abandon accepted or unknown work: observation, reconciliation, checkpoint completion, evidence retention, and operator CLI remain available.
Rollback triggers include any duplicate mutation, false success, checkpoint promotion without verified full effect, source coverage gap/overlap, secret sentinel leak, unbounded response, journal/artifact inconsistency, TTL violation, or rate/semaphore breach. Rollback preserves journal, artifacts, tombstones, and receipts. It does not delete or compensate receiver data automatically.
Post-release verification repeats the exact vendor-live profile after every profile, transport, journal, Airflow-provider, or receiver-contract change. Certification is bound to commit, environment, binding/profile digest, and test artifact; stale evidence does not authorize production.
Agent execution plan¶
One integrator owns public schemas, shared indexes, mkdocs.yml, and final
reconciliation. Parallel writers may start only after the approved contracts
land, in separate worktrees with disjoint task contracts.
| Role | Owned paths | Read-only paths | Forbidden paths | Dependency |
|---|---|---|---|---|
| Contract integrator | src/dpone/contracts/rest_delivery/**, manifest/profile schemas, public exports, mkdocs.yml |
Entire repository | Unrelated feature code | Approved spec and ADRs |
| Identity/state implementer | Pure identity, state machine, property tests | Approved contracts | Adapters, provider, shared schemas | Contract PR merged |
| Journal implementer | Journal port, PostgreSQL/SQLite adapters, migrations, fault/restore tests | Contracts and ADR 0053 | HTTP/provider/compiler | State contract merged |
| Source/payload implementer | Freeze, planner, codecs, sealing, object artifacts, golden tests | Contracts/artifact ports | Journal/HTTP/provider | Contract PR merged |
| HTTP/security implementer | REST transport, auth projection adapter, bounds, classifiers, adversarial tests | Profile/ports | Runtime state and provider | Ports merged |
| Runtime integrator | ResumableDeliveryProcessor, supervisor, verifier, frontier |
All prior public APIs | Adapter internals and shared schemas | Journal/payload/transport merged |
| Airflow integrator | Full provider operator/trigger and 3.2 primary plus every declared compatibility minor | Runtime continuation API | dpone-airflow-pack runtime expansion |
Runtime API merged |
| UX/certification owner | CLI applications, profile inspector, docs, runbooks, evidence producers | Implemented public API | Core policy | Behavior stable |
The dpone maintainer assigned to the implementation series is the named integrator and shared-file owner. Every implementation PR runs focused red-green tests, then the change-aware selector and full required gate. No role may edit a shared semantic file without integrator handoff.
Approval checklist¶
- First, second, third, and fourth external-review P0 items are addressed normatively in prose, ADRs, and the machine-readable contract.
- V1 protocol-family scope and exclusions are explicit.
- Namespace, principal, operation semantics, rendered intent, generation, execution policy, and full profile contract are separate.
- Remote effect and checkpoint eligibility are not overloaded into one enum.
- Continuation and current
ETLProcessorcompatibility are explicit. - PostgreSQL is selected with zero-RPO critical commits, immutable pre-attempt markers, journal epoch, and post-restore mutation gate.
- Seal-all source barrier, immutable complete parent topology, adaptive split lineage, no-replan recovery, and contiguous frontier are explicit.
- Recovery is independent of the current manifest.
- Airflow 3.2 primary and every declared
>=2.10,<3.4minor are explicit. - V1 partial-result behavior is explicit and fail-closed.
- Market comparison and estimates are scoped honestly.
- Dedicated threat model covers journal rewind, principal/tenant isolation, object authority, revocation, SSRF, and triggerer exhaustion.
- Safe retry has a reachable
RETRY_WAITpath and terminal no-retry path. - Success/failure/cancel/expiry acknowledgements survive partial/unknown effect classification and operator reconciliation.
- PostgreSQL domain-lock/range linearization and range-scoped watermark are selected; append correction is forbidden by default.
- V1 async bulk execution is serial across child operations.
-
MAY_ATTEMPTis attempt-scoped and remote capacity shares the PostgreSQL submit transaction. - Strict schema, byte-preserving duplicate-key/UTF-8 loader, semantic validator, clean-wheel smoke, and model-wide state guardrails make the design contract executable in CI.
- Receiver mutation identity is namespace-bound; receiver binding semantics and physical effect conflict grouping are explicit.
- The stable error catalog is complete and exact-set checked.
- The immutable
RESEARCHEDcontract promotes only through a separate digest-bound approval receipt; production certification remains separate. - Architecture owner approves P0.17–P0.23 and the design contract.
- PostgreSQL owner approves synchronous quorum, journal epoch, restore gate, and marker authority.
- Maintainer approves this specification.
- Maintainer approves ADRs 0053–0055.
- Security owner approves the threat model and artifact-retention profile.