| Internet-Draft | 2PHP-DTT | July 2026 |
| Venkateswaran & Jamwal | Expires 22 January 2027 | [Page] |
This document specifies the 2-Phase HTTP Protocol for Distributed Transaction Tracking (2PHP-DTT), a backward-compatible, opt-in extension to HTTP mutation semantics that introduces a two-phase handshake at service request boundaries. 2PHP ensures that a mutation request is durably registered on both the client and the server before any processing commences, addressing a structural gap in existing HTTP REST semantics where no standard mechanism exists to confirm bilateral intent registration prior to execution.¶
The acronym DTT expands to Distributed Transaction Tracking. 2PHP is not Two-Phase Commit (2PC). Microservices architectures deliberately avoid the cross-service locking and blocking that 2PC requires. 2PHP standardizes the intent-tracking pattern that implementations currently build ad hoc, providing a common wire contract and a queryable ledger of registered intent without introducing a distributed transaction coordinator.¶
A primary motivator for this work is the growing use of agent-driven HTTP invocations, including Model Context Protocol (MCP) tool calls and agent-to-agent (A2A) integrations. When an agent does not receive a response, its default behavior is to retry. Absent a queryable record of prior intent, retries pile onto services that may already be overwhelmed, causing deadlocks, resource exhaustion, and full outages. 2PHP's Phase 1 ledger record enables the client to inspect whether the prior intent was registered before issuing a retry, breaking the retry-storm feedback loop at the protocol layer.¶
2PHP operates at the HTTP protocol layer, requires no new transport mechanisms, and is composable across independently operating service boundaries. This document further defines a standardized Intent Ledger model for durable, queryable, cross-service correlation of request intent, distinct from execution telemetry provided by distributed tracing systems.¶
This document does not claim novelty over existing intent-tracking, idempotency, or distributed-tracing patterns. Its goal is to define a common HTTP-layer wire contract and a common ledger schema so that a single reference implementation--packaged as a library or framework module--can serve multiple deployments, replacing the per-team ad hoc implementations that currently reinvent this pattern.¶
This document defines the protocol headers, phase state machine, idempotency and replay behavior, the three-tier Intent Ledger architecture, cross-service correlation model, and IANA registration of the associated HTTP header fields. 2PHP-DTT targets the synchronous request-response boundary, where no standard acknowledgement primitive exists to confirm bilateral intent registration before processing. Asynchronous HTTP patterns -- 202 Accepted with Location-based polling in HTTP Semantics, Prefer: respond-async negotiation, webhooks, and message-broker delivery -- already provide durable acknowledgement of intent by construction, and are therefore out of scope for this specification.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 22 January 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
Microservices architectures built on HTTP REST APIs are widely deployed for distributed systems communication. Mutation requests--those using HTTP methods POST, PUT, PATCH, and DELETE--are treated as single atomic operations from the client's perspective. In practice, however, no standard protocol mechanism exists to confirm that both the client and server have durably registered the intent of a request before processing begins.¶
Existing approaches--including the Saga pattern [SAGA], Transactional Outbox [OUTBOX], and application-layer idempotency keys--address failure recovery after the fact or are implemented ad hoc without a standard contract. Distributed tracing systems such as OpenTelemetry [OTEL] provide execution telemetry but cannot answer whether both parties registered intent before processing commenced.¶
This document specifies the 2-Phase HTTP Protocol for Distributed Transaction Tracking (2PHP-DTT), an opt-in, backward-compatible extension to HTTP that introduces a lightweight two-phase handshake at each service boundary. 2PHP ensures bilateral durable registration of request intent before any business logic is executed. It further defines a standardized Intent Ledger model that enables cross-service correlation of request intent across distributed call trees.¶
The acronym DTT expands to Distributed Transaction Tracking. 2PHP is not Two-Phase Commit (2PC). 2PC requires cross-service locking and blocking coordination that microservices architectures deliberately avoid. 2PHP introduces no distributed transaction coordinator, no cross-service locks, and no thread-blocking. Each service boundary owns its own handshake independently; the Intent Ledger is a passive, queryable record of that handshake, not a coordinator. What is standardized here is the tracking pattern that implementations currently build ad hoc: a common wire contract and a common ledger contract, rather than a per-team reinvention.¶
A primary motivator for this work is the growing use of agent-driven HTTP invocations, including Model Context Protocol (MCP) tool calls and agent-to-agent (A2A) integrations. Agents default to retrying when a response is not received within an expected window. Without a queryable record of prior intent, successive retries--often from multiple relays or peer agents--pile onto services that may already be overwhelmed. The result is server-side deadlocks, resource exhaustion, and cascading outages. 2PHP's Phase1 ledger record enables the client, upstream service, or orchestrating agent to inspect whether the prior intent was durably registered before issuing a retry, breaking the retry-storm feedback loop at the protocol layer. This inspection step is the first line of defense in agent-driven integration topologies where retry pressure is otherwise unbounded.¶
This gap is specific to synchronous HTTP invocations.
Asynchronous integration patterns--202 Accepted
responses with Location-based status polling
([RFC9110]), Prefer: respond-async
negotiation ([RFC7240]), webhooks, and
message-broker delivery--already provide a durable
acknowledgement of intent as part of their wire contract: the
client receives a handle or ack the moment the server accepts
the request, and inspecting prior state before retrying is
built in. 2PHP-DTT does not attempt to duplicate those
mechanisms. It addresses the boundary they leave open:
synchronous request-response calls, which remain the dominant
integration style for microservices and agent-driven tool
invocations.¶
The value proposition of this specification is standardization, not novel mechanism. Intent tracking, idempotent retries, and correlation-based inspection are all patterns implemented today across microservices deployments, typically ad hoc and per-team. This document does not claim to be the only solution to any of these problems, nor does it claim novelty over existing patterns. Its aim is a consistent, standardized wire contract for intent registration and Distributed Transaction Tracking: client-supplied correlation identifiers, an explicit phase state contract carried in HTTP header fields, and a queryable Intent Ledger schema, specified together so that a common implementation--packaged as a library in Spring Boot, Express.js, an API gateway policy, or an agent framework middleware--can serve heterogeneous deployments without per-vendor reinvention. Where deployments already use client-supplied identifiers for retry safety, the correlation identifier defined here MAY carry the same value; nothing in this document precludes composing 2PHP-DTT with existing idempotency, retry, or tracing conventions.¶
2PHP is designed to be:¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
Current HTTP REST semantics treat a mutation request as a single atomic operation from the client's perspective. In reality, a server may:¶
No standard HTTP mechanism exists to confirm that both the client and the server have registered the intent of a request before processing commences.¶
Modern distributed tracing systems provide visibility into what executed across services, how long operations took, and where failures occurred. However, they cannot answer:¶
| Pattern | Scope | Client Involved? | Protocol Level? | Intent Ledger? |
|---|---|---|---|---|
| Two-Phase Commit (2PC) | Database | No | No | No |
| Saga Pattern | Application | No | No | No |
| Transactional Outbox | Server-side | No | No | No |
| Idempotency Keys | Application | Partial | No | No |
| HTTP 100 Continue | Protocol | Yes | Yes | No |
| 2PHP (this document) | Protocol | Yes | Yes | Yes |
2PHP extends HTTP mutation semantics with an opt-in two-phase handshake. Each service boundary owns its own independent handshake. Cross-service traceability is the responsibility of the centralized Intent Ledger, not the protocol itself.¶
Client Server | | |-- Phase 1: POST + payload --------> | | | Persist payload + | | ledger record atomically | <-- 200 OK + Server-Corr-ID ------- | | | | (Client writes local ledger entry) | | | |-- Phase 2: POST confirm ----------> | | | PONR crossed; | | business logic executes | <-- 200 OK + Resource-ID ---------- | | |
The server MUST atomically persist the intent payload and the initial ledger record before returning the Phase1 response. The resource is created only after Phase2 confirmation is received and business logic has successfully executed.¶
Clients signal 2PHP intent by including the following header on any mutation request:¶
Servers that do not recognize this header MUST ignore it and process the request normally, preserving backward compatibility.¶
The client MUST include
DTT-2PHP-Client-Correlation-ID with a unique
identifier for this request. This identifier
MUST be used in all subsequent protocol
exchanges and ledger entries for this interaction. The
server MUST NOT substitute a
server-generated proxy for this identifier: without a
client-supplied identifier the client cannot
deterministically query the ledger for prior intent,
which is the retry-inspection guarantee that motivates
this specification.¶
If a request carries DTT-2PHP-Enabled: true but
omits DTT-2PHP-Client-Correlation-ID, the server
MUST reject the request with
400 Bad Request and populate
DTT-2PHP-Message to identify the missing header.
The server MUST NOT synthesize a
correlation identifier on the client's behalf. This
requirement applies to both Standard 2PHP
(Section 5.3) and Auto-Confirm mode
(Section 5.5).¶
The client MAY include
DTT-2PHP-Requested-TTL (in milliseconds) to
request that the server override its default TTL setting.¶
The server MUST atomically persist the
intent payload and an initial ledger record with phase
state WAITING_CONFIRM before returning the
response.¶
Response header semantics:¶
DTT-2PHP-Requested-TTL, the server
MAY accommodate by increasing the TTL.¶
WAITING_CONFIRM on Phase1 response.¶
No DTT-2PHP-Resource-ID is returned in
Phase1. The resource does not yet exist; it is
created only after Phase2 confirmation is received
and business logic has successfully executed.¶
After receiving the Phase1 response, the client
MUST write a ledger entry to its local
ledger. The client writes after the Phase1 response
so that both client_correlation_id and
server_correlation_id are available at write
time. The client's parent_reference_id
MUST be set to its own
client_correlation_id as the root anchor.¶
The client confirms receipt of the Phase1 acknowledgement:¶
The client MUST send Phase2 before
the DTT-2PHP-PONR-Deadline timestamp received
in the Phase1 response.¶
A 2PHP-capable client
MUST NOT send a Phase2 confirmation if
the Phase1 response omitted the
DTT-2PHP-Server-Correlation-ID header. The absence
of that header indicates the server did not process the
request under 2PHP semantics--typically because the
server does not implement this specification. In that case
the response MUST be treated as a conventional
terminal HTTP response and the client
MUST NOT issue a Phase2 request against
any derived path. This preserves backward compatibility with
servers that ignore the DTT-2PHP-Enabled opt-in
header (see Section 11).¶
This revision specifies synchronous operation only. On receipt of a valid Phase2 confirmation, the server crosses the PONR, executes business logic inline, and responds once processing is complete:¶
The server MUST return 200 OK
only after business logic has completed and the resource
is fully created. The DTT-2PHP-Resource-ID is
authoritative--the resource exists at the point
this response is returned.¶
If business logic fails after PONR is crossed, the
server MUST return
500 Internal Server Error. If the request is
invalid, the server MUST return the
appropriate 4xx response. In both cases the
client receives a definitive outcome in the Phase2
response--no polling is required.¶
Asynchronous operation is out of scope for this
specification by design, not deferred. Asynchronous HTTP
already provides a durable acknowledgement primitive:
202 Accepted with a Location handle for
status polling as defined in [RFC9110],
optionally negotiated with Prefer: respond-async
as defined in [RFC7240]. Webhook and
message-broker delivery models similarly bake
acknowledgement into their wire contract. In all of these,
the client learns whether the server registered its intent
the moment the request is accepted, which is precisely the
gap 2PHP-DTT addresses for synchronous calls. Servers
requiring asynchronous execution semantics
SHOULD use those established mechanisms
rather than extending 2PHP-DTT.¶
Any Phase2 confirmation received after TTL expiry MUST be rejected with:¶
The server MAY apply an internal grace window (delta) after TTL expiry to handle race conditions at the PONR boundary. This grace window is server-internal and MUST NOT be exposed in protocol headers or communicated to the client.¶
Auto-Confirm mode is an opt-in server-side mode that
eliminates the explicit Phase2 client confirmation
round trip. When Auto-Confirm is enabled, the server
writes the ledger record and crosses the PONR immediately
after Phase1, then executes business logic inline
on the original request channel. The final result
(200 OK + DTT-2PHP-Resource-ID) is
returned synchronously on that same channel--
behaviorally identical to a standard HTTP request from the
client's perspective.¶
Auto-Confirm mode does not include an out-of-band callback. Earlier revisions of this specification described an asynchronous server-to-client callback to deliver the intent acknowledgement independently of the original response channel. That mechanism has been removed because it introduced failure modes (callback delivery loss, client callback endpoint availability, and server-side SSRF exposure via a client-supplied URL) that outweighed its observability benefit. Clients that require an out-of-band record of registered intent SHOULD use Standard 2PHP (Section 5.3), which records client-side intent by construction.¶
The client MUST include
DTT-2PHP-Client-Correlation-ID on the Phase1
request in Auto-Confirm mode, as in Standard 2PHP
(Section 5.2.1). The server
MUST NOT substitute a server-generated
proxy for this identifier: without a client-supplied
correlation identifier the client cannot deterministically
query the ledger for prior intent, which defeats the
retry-inspection guarantee that motivates this
specification. Requests missing this header
MUST be rejected with
400 Bad Request and
DTT-2PHP-Message indicating the missing header.
The server MUST return
DTT-2PHP-Server-Correlation-ID in the response so
the client can correlate the ledger record with its own
request.¶
Auto-Confirm mode is valuable for:¶
DTT-2PHP-Client-Correlation-ID to determine
whether the intent was registered and, if so, its
terminal outcome, before issuing any retry.¶
true, the server does not wait for a
Phase2 confirmation before crossing the PONR
and executing business logic. The final outcome is
returned synchronously on the original request channel.¶
Client Server | | |-- POST /orders ------------------> | | DTT-2PHP-Enabled: true | | DTT-2PHP-Auto-Confirm: true | | DTT-2PHP-Client-Corr-ID: C1 | | | | Ledger write | | (WAITING_CONFIRM -> | | PROCESSING, atomic) | | PONR crossed | | | | Server processes inline | | | | <-- 200 OK + Resource-ID -------- | | DTT-2PHP-Phase-State: | | COMMITTED | | DTT-2PHP-Server-Corr-ID: S1 | | |
Client POST (Phase 1, DTT-2PHP-Auto-Confirm: true)
|
v
( WAITING_CONFIRM ) <-- ledger write (transient, atomic)
|
v (immediate -- PONR crossed, no client confirmation)
( PROCESSING )
|
+-- Success --> ( COMMITTED ) <-- 200 OK + Resource-ID
| on original channel
|
+-- Failure --> ( FAILED ) <-- 500 / 4xx
on original channel
In Auto-Confirm mode, WAITING_CONFIRM is a
transient internal state written and immediately
superseded by PROCESSING within the same
atomic ledger operation. It is never visible to the
client on the original channel.¶
| Mode | Phase 2 Required | Latency | Client 2PHP Support | Ledger Participation |
|---|---|---|---|---|
| Standard 2PHP | Yes | 2 round trips | Full (correlation ID + Phase2) | Both sides |
| Auto-Confirm | No | 1 round trip | Correlation ID only | Both sides |
Client POST (Phase 1)
|
v
( WAITING_CONFIRM ) <-- persisted in durable storage
|
+-- Client confirms within TTL
| |
| v
| ( PROCESSING ) <-- PONR crossed; business logic
| | executing
| |
| +-- Success --> ( COMMITTED ) <- 200 OK +
| | Resource-ID
| +-- Failure --> ( FAILED ) <- 500 / 4xx
|
+-- TTL expires without confirmation
|
v
( TTL_EXPIRED ) -- after PONR + delta grace -->
( ABANDONED )
| State | Description |
|---|---|
WAITING_CONFIRM
|
Phase1 received and persisted. Awaiting client Phase2 confirmation. |
PROCESSING
|
Phase2 confirmed. PONR crossed. Business logic executing (synchronous mode). |
COMMITTED
|
Processing complete. Resource created. Terminal success state. |
FAILED
|
Processing failed after PONR. Server returned 500 or 4xx. Terminal failure state. |
TTL_EXPIRED
|
Client did not confirm within TTL. Pending cleanup. |
ABANDONED
|
Cleaned up after TTL + delta grace window. Terminal state. |
If a client replays Phase2 before TTL expiry, the
server MUST return the same response
associated with the original
DTT-2PHP-Server-Correlation-ID. No duplicate
processing occurs.¶
Any Phase2 confirmation received after TTL expiry
MUST be rejected with
408 Request Timeout and
DTT-2PHP-Phase-State: TTL_EXPIRED, consistent with
Section 5.4. The client
MUST re-submit as a new Phase1 request
with a new DTT-2PHP-Client-Correlation-ID. A late
Phase2 confirmation carrying the same correlation IDs
MUST NOT be reused to trigger execution of
the persisted intent.¶
This revision defines a single replay behavior. Earlier
revisions described a per-endpoint REUSE policy
that allowed acceptance of a late Phase2 within the
server-internal delta grace window. That policy has been
removed because it created an ambiguous boundary with
Section 5.4 and expanded the replay-attack
surface without a durable operational benefit.¶
The Intent Ledger is a durable, queryable log of all 2PHP transactions. It is distinct from execution telemetry--it is an intent registry, not a trace of execution. Its purpose is to provide provable bilateral registration of every mutation intent across all participating services.¶
The Intent Ledger is complementary to distributed tracing systems such as OpenTelemetry [OTEL], not a replacement. Distributed tracing records what executed: spans, timings, causal links, and error paths, typically aggregated in a downstream store with some ingestion lag. It is the appropriate tool for post-hoc analysis of execution behavior.¶
The Intent Ledger records what was registered as
intent before execution began, and makes that record
queryable in real time at the point of registration. This
serves a different question than tracing: not "what
happened?" but "did the server acknowledge my intent, and
should I retry?" A client that does not receive the
expected response can query the ledger by
DTT-2PHP-Client-Correlation-ID to determine
whether the prior intent was durably registered before
issuing a retry. This inspection step is only useful if
the answer is available synchronously and locally to the
participating service, which is why the ledger is
normatively local-first
(Section 12.5) rather than a
downstream aggregation.¶
Deployments SHOULD run both. Tracing answers questions about execution across services; the Intent Ledger answers questions about registered intent at each service boundary. Neither subsumes the other.¶
At each service boundary, the Intent Ledger
MUST record a durable entry for every
Phase1 receipt and every subsequent phase transition,
and that entry MUST be queryable by
DTT-2PHP-Client-Correlation-ID and by
DTT-2PHP-Server-Correlation-ID before Phase2
is processed. The ledger write and the intent-payload
persistence MUST be committed as a single
unit of work (see Section 5.2.2).¶
2PHP-DTT is not a Distributed Transaction Coordinator: no cross-service locking, thread blocking, or two-phase commit is defined or required. Each service boundary owns its own handshake and its own ledger authoritative record. How the ledger is stored, tiered, replicated, or exposed for aggregate query is an implementation matter and is discussed in Section 12.5.¶
Each ledger entry MUST include the following fields:¶
| Field | Description |
|---|---|
client_correlation_id
|
Client-assigned request identifier. |
server_correlation_id
|
Server-assigned intent identifier. |
service_ledger_id
|
GUID issued to the service at ledger registration. |
service_endpoint
|
Target service and resource path. |
actor
|
Role of the entry writer: client or
server.
|
source
|
Identity of the participant writing this entry
(e.g., client, serviceA,
serviceB1).
|
target
|
The downstream service being called. Populated
only when actor = client.
MUST be null for
actor = server entries.
|
parent_reference_id
|
The correlation ID that the immediate upstream caller provided when calling this service. Used to reconstruct the full distributed call tree. |
phase
|
Current or terminal phase state. |
phase_1_timestamp
|
When Phase1 was received (ISO8601). |
phase_2_timestamp
|
When Phase2 confirmation was received, if applicable (ISO8601). |
ttl_ms
|
Configured TTL for this request, in milliseconds. |
outcome
|
Terminal outcome: COMMITTED,
ABANDONED, or TTL_EXPIRED.
|
payload_ref
|
Reference to the persisted payload. Not the payload itself. |
sync_timestamp
|
When this entry was synced to the Central Ledger (ISO8601). |
transaction_reference
|
Reference to transaction ID (optional). |
When a service fans out to multiple downstream services,
the Intent Ledger captures every participant's view
of every call--both the caller
(actor = client) and the callee
(actor = server). This produces a unified,
traversable ledger that can reconstruct the full
distributed call tree without any distributed coordination
at the protocol level.¶
client_correlation_id and
server_correlation_id are available at write
time.¶
parent_reference_id MUST always
record what the immediate upstream caller provided as
its correlation ID when calling this service--
enabling upward tree traversal.¶
actor = client and
one actor = server, linked by the same
client_correlation_id +
server_correlation_id pair. This confirms
dual-side registration--the core guarantee of 2PHP.¶
target MUST be populated only
on actor = client rows. It
MUST be null on
actor = server rows.¶
Client --> Service A --> Service B1 --> Service C1
--> Service B2 --> Service D1
--> Service B3 --> Service E1
The complete ledger for this call chain contains 14
entries--two rows (one actor = client, one
actor = server) for each of the seven
service-boundary interactions. The root client entry uses
client-corr-id1 as both its
client_correlation_id and its
parent_reference_id, establishing the tree
anchor. Each subsequent tier sets
parent_reference_id to the correlation ID
received from its immediate upstream caller.¶
parent_reference_id = client-corr-id1
recursively--walks the entire fan-out tree.¶
source = serviceA AND
actor = client.¶
client_correlation_id +
server_correlation_id--one
actor = client, one actor = server.¶
phase = WAITING_CONFIRM or
phase = TTL_EXPIRED across any
source.¶
2PHP is designed to be fully backward compatible:¶
DTT-2PHP-Enabled: true
MUST experience no change in behavior.¶
DTT-2PHP-Server-Correlation-ID in the response to
the initial mutation request (see
Section 5.3.1). The absence of that
header identifies the response as originating from a
non-2PHP server; the response
MUST be treated as a conventional terminal
HTTP response. This prevents a 2PHP client from issuing a
spurious Phase2 request to a legacy server that has
already committed the mutation.¶
Implementations SHOULD use one of the following for durable storage of intent payload and ledger records:¶
The following are recommended starting values. Implementations MAY adjust these per endpoint.¶
| Scenario | TTL | delta (server-internal) |
|---|---|---|
| Low-latency APIs | 5,000 ms | 1,000 ms |
| Standard APIs | 30,000 ms | 5,000 ms |
| Long-running operations | 120,000 ms | 10,000 ms |
delta values are server implementation defaults and MUST NOT be exposed in protocol headers.¶
Each service SHOULD register with the
Intent Ledger at onboarding and be issued a GUID
(service_ledger_id) that is included in all
ledger entries for that service. This enables
cross-service querying while maintaining service-level
isolation.¶
The normative requirement (Section 9.3) is that each service maintains a durable, locally queryable Intent Ledger. This section describes a recommended local-first, batch-sync architecture that satisfies that requirement without placing the ledger on the critical path of request processing. Implementations MAY choose a different architecture provided the normative requirements are met.¶
For highly critical services, the intent payload and the ledger entry SHOULD be co-located in the same durable store so the atomic write required by Section 9.3 can be satisfied without a distributed transaction. For less critical services, a temporary co-located copy is sufficient for Phase1 and Phase2 lifecycle management, with the ledger entry propagated to the Central Ledger via event publish.¶
Phase 1 received
|
v
Persist as single unit of work:
- Intent payload (durable store)
- Ledger record (Local Ledger, phase: WAITING_CONFIRM)
|
v
200 OK returned to client
|
v (async background batch job)
Local Ledger --> Central Ledger (eventually consistent)
Where a Central Ledger is deployed, its management application MAY trigger an on-demand pull from any service's Local Ledger. This is intended for incident investigation, where the latest data is required immediately without waiting for the next scheduled batch sync. Access controls for on-demand pull are discussed in Section 13.5.¶
The following table summarizes typical operational modes for the recommended architecture:¶
| Scenario | Ledger Used | Trigger |
|---|---|---|
| Normal operation | Local Ledger only | Per phase transition |
| Retry-inspection query | Local Ledger | Client query before retry |
| Routine audit | Central Ledger | Batch sync (scheduled) |
| Incident investigation | Central Ledger | On-demand pull from management app |
| Compliance reporting | Central Ledger | Batch sync (scheduled) |
DTT-2PHP-Client-Correlation-ID and
DTT-2PHP-Server-Correlation-ID values
MUST be treated as opaque identifiers.
Implementations SHOULD use UUIDv4
or equivalent cryptographically random values to prevent
enumeration or prediction of correlation IDs by
unauthorized parties.¶
A malicious actor in possession of both
DTT-2PHP-Client-Correlation-ID and
DTT-2PHP-Server-Correlation-ID could attempt to
submit a spoofed Phase2 confirmation.
Implementations MUST authenticate
Phase2 confirmation requests using the same
authentication mechanism applied to Phase1
requests. The server MUST verify that
the authenticated identity of the Phase2 requester
matches that of the Phase1 requester.¶
Replay of a Phase2 confirmation is a normal, expected behavior in 2PHP-DTT and is not by itself an attack. Phase2 confirmations are idempotent within the TTL window (Section 8.1) and are rejected after TTL expiry (Section 8.2). This design allows legitimate clients to safely re-send Phase2 in the face of transient network loss without duplicating server-side effects, and bounds the window in which any captured Phase2 request remains useful to a party that possesses both correlation identifiers.¶
Because a re-sent Phase2 within TTL is honored, an unauthenticated party in possession of both correlation identifiers could re-drive the server's idempotent response. This is a confidentiality-of-identifiers concern rather than a duplication concern. Implementations MUST authenticate Phase2 requests under the same authentication mechanism used for Phase1 (see Section 13.2) and SHOULD pair Phase2 requests with short-lived credentials or request signing where the deployment threat model warrants it.¶
The intent payload persisted during Phase1 may contain sensitive data. Implementations MUST ensure that persisted payloads are protected at rest using appropriate encryption mechanisms consistent with the sensitivity of the data.¶
The Central Ledger aggregates intent records across all services. Access to the Central Ledger MUST be restricted to authorized audit, operations, and compliance consumers. The on-demand pull mechanism (Section 12.6) MUST be protected by appropriate authentication and authorization controls.¶
All 2PHP exchanges MUST be conducted over TLS (HTTPS). Use of 2PHP over unencrypted HTTP is NOT RECOMMENDED.¶
This document requests registration of the following HTTP field names in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" defined in [RFC9110], Section16.3.1:¶
| Field Name | Status | Reference |
|---|---|---|
DTT-2PHP-Enabled
|
Experimental | This document |
DTT-2PHP-Client-Correlation-ID
|
Experimental | This document |
DTT-2PHP-Auto-Confirm
|
Experimental | This document |
DTT-2PHP-Requested-TTL
|
Experimental | This document |
DTT-2PHP-Server-Correlation-ID
|
Experimental | This document |
DTT-2PHP-Phase-State
|
Experimental | This document |
DTT-2PHP-TTL
|
Experimental | This document |
DTT-2PHP-PONR-Deadline
|
Experimental | This document |
DTT-2PHP-Resource-ID
|
Experimental | This document |
DTT-2PHP-Message
|
Experimental | This document |