Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions docs/specification/shopping/cart/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,17 +475,7 @@ operations unless otherwise noted.

### Specific Header Requirements

* **UCP-Agent**: All requests **MUST** include the `UCP-Agent` header
containing the platform profile URI using Dictionary Structured Field syntax
([RFC 8941](https://datatracker.ietf.org/doc/html/rfc8941){target="_blank"}).
Format: `profile="https://platform.example/profile"`.
* **Idempotency-Key**: Operations that modify state **SHOULD** support
idempotency. When provided, the server **MUST**:
1. Store the key with the operation result for at least 24 hours.
2. Return the cached result for duplicate keys whose request body matches the original.
3. Return `409 Conflict` if the key is reused with a mismatched body.
See [Message Signatures — Idempotency Key Requirements](../../signatures.md#replay-protection)
for the full payload-matching contract.
{{ header_requirements('ucp_agent', 'idempotency_key') }}

## Protocol Mechanics

Expand Down
5 changes: 1 addition & 4 deletions docs/specification/shopping/catalog/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,10 +518,7 @@ operations unless otherwise noted.

### Specific Header Requirements

* **UCP-Agent**: All requests **MUST** include the `UCP-Agent` header
containing the platform profile URI using Dictionary Structured Field syntax
([RFC 8941](https://datatracker.ietf.org/doc/html/rfc8941){target="_blank"}).
Format: `profile="https://platform.example/profile"`.
{{ header_requirements('ucp_agent') }}

## Error Handling

Expand Down
12 changes: 1 addition & 11 deletions docs/specification/shopping/checkout/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -1301,17 +1301,7 @@ operations unless otherwise noted.

### Specific Header Requirements

* **UCP-Agent**: All requests **MUST** include the `UCP-Agent` header
containing the platform profile URI using Dictionary Structured Field syntax
([RFC 8941](https://datatracker.ietf.org/doc/html/rfc8941){target="_blank"}).
Format: `profile="https://platform.example/profile"`.
* **Idempotency-Key**: Operations that modify state **SHOULD** support
idempotency. When provided, the server **MUST**:
1. Store the key with the operation result for at least 24 hours.
2. Return the cached result for duplicate keys whose request body matches the original.
3. Return `409 Conflict` if the key is reused with a mismatched body.
See [Message Signatures — Idempotency Key Requirements](../../signatures.md#replay-protection)
for the full payload-matching contract.
{{ header_requirements('ucp_agent', 'idempotency_key') }}

## Protocol Mechanics

Expand Down
10 changes: 1 addition & 9 deletions docs/specification/shopping/order/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,7 @@ Returns the current-state snapshot of an order.

### Specific Header Requirements

**UCP-Agent** (required on all requests):

Platform identification using
[RFC 8941 Dictionary](https://www.rfc-editor.org/rfc/rfc8941#name-dictionaries){ target="_blank" }
syntax:

```http
UCP-Agent: profile="https://platform.example/.well-known/ucp"
```
{{ header_requirements('ucp_agent') }}

## Message Signing

Expand Down
29 changes: 29 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,35 @@ def resolve_structure(schema, root):
f"Error processing OpenAPI: {e}{get_error_context()}"
) from e

# --- Shared "Specific Header Requirements" prose ---
HEADER_REQUIREMENTS = {
"ucp_agent": (
"* **UCP-Agent**: All requests **MUST** include the `UCP-Agent` header\n"
" containing the platform profile URI using Dictionary Structured Field syntax\n"
' ([RFC 8941](https://datatracker.ietf.org/doc/html/rfc8941){target="_blank"}).\n'
' Format: `profile="https://platform.example/profile"`.'
),
"idempotency_key": (
"* **Idempotency-Key**: Operations that modify state **SHOULD** support\n"
" idempotency. When provided, the server **MUST**:\n"
" 1. Store the key with the operation result for at least 24 hours.\n"
" 2. Return the cached result for duplicate keys whose request body matches the original.\n"
" 3. Return `409 Conflict` if the key is reused with a mismatched body.\n"
" See [Message Signatures — Idempotency Key Requirements](/specification/signatures/#replay-protection)\n"
" for the full payload-matching contract."
),
}

@env.macro
def header_requirements(*keys):
"""Render shared 'Specific Header Requirements' bullets by key."""
try:
return "\n".join(HEADER_REQUIREMENTS[k] for k in keys)
except KeyError as exc:
raise ValueError(
f"Unknown header requirement {exc}{get_error_context()}."
)

# --- MACRO 4: For HTTP Headers ---
@env.macro
def header_fields(operation_id, file_name):
Expand Down
Loading