Skip to content
Merged
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
17 changes: 17 additions & 0 deletions changelogs/cycles-protocol-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ New entries are added directly to this file. See `scripts/validate_changelogs.py

---

## v0.1.25.2 — 2026-06-12

_(revision 2026-06-12 — clarify `cycles_evidence` non-attestation + fix the url join)_

- **`cycles_evidence_url` join fix**: `server_id` is already the canonical base
URL *including* `/v1` (e.g. `https://cycles.example.com/v1`), so the URL is
`{server_id}/evidence/{evidence_id}` — NOT `{server_id}/v1/evidence/...` (which
double-prefixed `/v1`). Documented normatively on the field.
- **Non-attestation of `cycles_evidence`**: stated explicitly that the ref is
transport metadata, NOT part of the attested payload. The `evidence_id` is
computed over the pre-evidence-ref response; the `ReservationCreateResponseMirror`
in `drafts/cycles-evidence-v0.1.yaml` keeps `additionalProperties: false` and
omits `cycles_evidence` so the content hash is never self-referential. Servers
MUST compute `evidence_id` before stamping the ref onto the wire response.

---

## v0.1.25.1 — 2026-06-12

_(revision 2026-06-12 — surface `cycles_evidence` on the reserve response)_
Expand Down
20 changes: 18 additions & 2 deletions cycles-protocol-v0.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: Cycles Budget Authority API
version: 0.1.25.1
version: 0.1.25.2
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0
Expand Down Expand Up @@ -513,6 +513,17 @@
offline. Because signing/storage is async, the envelope MAY be served
shortly after this response — consumers SHOULD treat a transient `404`
from `getEvidence` as not-yet-available and retry.


TRANSPORT METADATA, NOT ATTESTED: `cycles_evidence` is added to the
response for the caller's convenience and is NOT part of the evidence
the envelope attests. The `evidence_id` is computed over the operation
response WITHOUT this field — the envelope's `payload.<artifact>.response`
mirror (`drafts/cycles-evidence-v0.1.yaml`) keeps `additionalProperties:
false` and omits `cycles_evidence` precisely so the content hash is
never self-referential. Implementations MUST compute `evidence_id`
before stamping `cycles_evidence` onto the response, and MUST NOT
include `cycles_evidence` in the attested payload.
required: [evidence_id, cycles_evidence_url]
properties:
evidence_id:
Expand All @@ -522,14 +533,19 @@
cycles_evidence_url:
type: string
format: uri
description: 'Absolute URL of the signed envelope: `{server_id}/v1/evidence/{evidence_id}`.'
description: >-
Absolute URL of the signed envelope, formed as
`{server_id}/evidence/{evidence_id}`. Note `server_id` is already the
canonical deployment base INCLUDING the `/v1` prefix (e.g.
`https://cycles.example.com/v1`), so the join adds only
`/evidence/{evidence_id}` — it MUST NOT re-add `/v1`.

IdempotencyKey:

Check warning on line 543 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
minLength: 1
maxLength: 256

ErrorCode:

Check warning on line 548 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
enum:
- INVALID_REQUEST
Expand All @@ -548,7 +564,7 @@
- MAX_EXTENSIONS_EXCEEDED
- INTERNAL_ERROR

ErrorResponse:

Check warning on line 567 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [error, message, request_id]
additionalProperties: false
Expand Down Expand Up @@ -583,7 +599,7 @@
type: object
additionalProperties: true

DecisionEnum:

Check warning on line 602 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
enum: [ALLOW, ALLOW_WITH_CAPS, DENY]

Expand Down Expand Up @@ -676,7 +692,7 @@
the companion-specs publication model does not use cross-spec
$ref.

Amount:

Check warning on line 695 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [unit, amount]
additionalProperties: false
Expand Down Expand Up @@ -758,7 +774,7 @@
maxLength: 256
maxProperties: 16

Action:

Check warning on line 777 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [kind, name]
additionalProperties: false
Expand Down Expand Up @@ -816,7 +832,7 @@
minimum: 0

# ---- Decide (optional) ----
DecisionRequest:

Check warning on line 835 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [idempotency_key, subject, action, estimate]
additionalProperties: false
Expand All @@ -833,7 +849,7 @@
type: object
additionalProperties: true

DecisionResponse:

Check warning on line 852 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [decision]
additionalProperties: false
Expand Down Expand Up @@ -901,7 +917,7 @@
description: Reservation lifecycle state (v1+ may add additional terminal states).
enum: [ACTIVE, COMMITTED, RELEASED, EXPIRED]

ReservationCreateRequest:

Check warning on line 920 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [idempotency_key, subject, action, estimate]
additionalProperties: false
Expand Down Expand Up @@ -1058,7 +1074,7 @@
until reconciled (debt repaid below overdraft_limit, or is_over_limit cleared by operator).
Defaults to false when absent.

ReservationCreateResponse:

Check warning on line 1077 in cycles-protocol-v0.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required: [decision, affected_scopes]
additionalProperties: false
Expand Down
10 changes: 10 additions & 0 deletions drafts/cycles-evidence-v0.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,16 @@ components:
The dry_run-vs-reservation_id-and-expires_at_ms rules
(canonical L981 and L1404) span request and response, so they
live at the `ReservePayload` level rather than here.

DELIBERATE OMISSION — `cycles_evidence`: the canonical response
carries an optional `cycles_evidence` ref (`evidence_id` +
`cycles_evidence_url`), but it is TRANSPORT METADATA and is NOT
attested by this envelope, so it is intentionally absent here and
`additionalProperties: false` FORBIDS it in the attested payload.
The `evidence_id` is computed over this pre-evidence-ref response;
including the ref would make the content hash self-referential.
Servers MUST compute `evidence_id` before stamping `cycles_evidence`
onto the wire response.
required: [decision, affected_scopes]
additionalProperties: false
properties:
Expand Down
17 changes: 8 additions & 9 deletions merged/cycles-openapi-protocol-merged.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,10 @@
CyclesEvidenceRef:
type: object
additionalProperties: false
description: Reference to the CyclesEvidence envelope emitted for an operation. The `evidence_id`
is the sha256 content hash of the JCS-canonical envelope and is computed SYNCHRONOUSLY at decision
time, so it is returned on the operation response even though the envelope is Ed25519-signed and
stored ASYNCHRONOUSLY. A caller (e.g. an APS gateway) binds its own signed receipt to this evidence
by recording `evidence_id`, then fetches the envelope at `cycles_evidence_url` (see `getEvidence`)
to verify it offline. Because signing/storage is async, the envelope MAY be served shortly after
this response — consumers SHOULD treat a transient `404` from `getEvidence` as not-yet-available
and retry.
description: |-
Reference to the CyclesEvidence envelope emitted for an operation. The `evidence_id` is the sha256 content hash of the JCS-canonical envelope and is computed SYNCHRONOUSLY at decision time, so it is returned on the operation response even though the envelope is Ed25519-signed and stored ASYNCHRONOUSLY. A caller (e.g. an APS gateway) binds its own signed receipt to this evidence by recording `evidence_id`, then fetches the envelope at `cycles_evidence_url` (see `getEvidence`) to verify it offline. Because signing/storage is async, the envelope MAY be served shortly after this response — consumers SHOULD treat a transient `404` from `getEvidence` as not-yet-available and retry.

TRANSPORT METADATA, NOT ATTESTED: `cycles_evidence` is added to the response for the caller's convenience and is NOT part of the evidence the envelope attests. The `evidence_id` is computed over the operation response WITHOUT this field — the envelope's `payload.<artifact>.response` mirror (`drafts/cycles-evidence-v0.1.yaml`) keeps `additionalProperties: false` and omits `cycles_evidence` precisely so the content hash is never self-referential. Implementations MUST compute `evidence_id` before stamping `cycles_evidence` onto the response, and MUST NOT include `cycles_evidence` in the attested payload.
required:
- evidence_id
- cycles_evidence_url
Expand All @@ -144,12 +140,15 @@
cycles_evidence_url:
type: string
format: uri
description: 'Absolute URL of the signed envelope: `{server_id}/v1/evidence/{evidence_id}`.'
description: Absolute URL of the signed envelope, formed as `{server_id}/evidence/{evidence_id}`.
Note `server_id` is already the canonical deployment base INCLUDING the `/v1` prefix (e.g.
`https://cycles.example.com/v1`), so the join adds only `/evidence/{evidence_id}` — it MUST
NOT re-add `/v1`.
IdempotencyKey:

Check warning on line 147 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
minLength: 1
maxLength: 256
ErrorCode:

Check warning on line 151 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
enum:
- INVALID_REQUEST
Expand All @@ -170,7 +169,7 @@
- ACTION_QUOTA_EXCEEDED
- ACTION_KIND_NOT_ALLOWED
- ACTION_KIND_DENIED
ErrorResponse:

Check warning on line 172 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- error
Expand Down Expand Up @@ -203,7 +202,7 @@
details:
type: object
additionalProperties: true
DecisionEnum:

Check warning on line 205 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: string
enum:
- ALLOW
Expand Down Expand Up @@ -284,7 +283,7 @@
servers MUST default to "desc". Servers that do not recognize the parameter MUST ignore it without
error (additive-parameter guarantee). This schema is carried inline in each spec of the family
(protocol + governance); the companion-specs publication model does not use cross-spec $ref.
Amount:

Check warning on line 286 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- unit
Expand Down Expand Up @@ -367,7 +366,7 @@
type: string
maxLength: 256
maxProperties: 16
Action:

Check warning on line 369 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- kind
Expand Down Expand Up @@ -416,7 +415,7 @@
cooldown_ms:
type: integer
minimum: 0
DecisionRequest:

Check warning on line 418 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- idempotency_key
Expand All @@ -436,7 +435,7 @@
metadata:
type: object
additionalProperties: true
DecisionResponse:

Check warning on line 438 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- decision
Expand Down Expand Up @@ -497,7 +496,7 @@
- COMMITTED
- RELEASED
- EXPIRED
ReservationCreateRequest:

Check warning on line 499 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- idempotency_key
Expand Down Expand Up @@ -644,7 +643,7 @@
capped the charge. When true, ALL new reservations against this scope are blocked with 409
OVERDRAFT_LIMIT_EXCEEDED until reconciled (debt repaid below overdraft_limit, or is_over_limit
cleared by operator). Defaults to false when absent.
ReservationCreateResponse:

Check warning on line 646 in merged/cycles-openapi-protocol-merged.yaml

View workflow job for this annotation

GitHub Actions / Lint sources, check merge drift, lint merged artifacts

schema-must-have-description Top-level schemas in components should have a description
type: object
required:
- decision
Expand Down