Skip to content

Commit f0beb54

Browse files
authored
feat(protocol): surface cycles_evidence on ErrorResponse (v0.1.25.5) (#109)
Adds the optional `cycles_evidence` field (CyclesEvidenceRef) to ErrorResponse, closing the last gap in the lifecycle binding loop (decide / reserve / commit / release / error). The `error` artifact wraps any 4xx/5xx ErrorResponse from the four core runtime endpoints and is the canonical home for non-dry reserve denials (insufficient budget surfaces as HTTP 409 BUDGET_EXCEEDED, not a 200 with decision: DENY) — the highest-signal evidence an APS receipt can bind to. Surfacing the ref in-band lets a denied caller bind its own signed receipt to the denial and fetch the envelope via getEvidence. The field is CyclesEvidenceRef, identical to the four success responses; TRANSPORT METADATA, NOT attested — the `error` artifact's payload.error.response mirror (drafts/cycles-evidence-v0.1.yaml) keeps additionalProperties: false and omits it, so the content hash is never self-referential. Present when the server emitted an `error` envelope for this response; absent when emission is disabled or for errors raised before evidence could be emitted. Additive + non-breaking. - cycles-protocol-v0.yaml: info.version 0.1.25.4 -> 0.1.25.5; cycles_evidence on ErrorResponse. - drafts/cycles-evidence-v0.1.yaml: DELIBERATE OMISSION note on ErrorResponseMirror (matches the other four mirrors). - cycles-spec-index.yaml: runtime_base 0.1.25.5, spec_index 0.1.30. - changelogs/cycles-protocol-v0.md: v0.1.25.5 entry. - merged/: regenerated.
1 parent abea4d3 commit f0beb54

5 files changed

Lines changed: 68 additions & 4 deletions

File tree

changelogs/cycles-protocol-v0.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ New entries are added directly to this file. See `scripts/validate_changelogs.py
66

77
---
88

9+
## v0.1.25.5 — 2026-06-13
10+
11+
_(revision 2026-06-13 — surface `cycles_evidence` on the error response)_
12+
13+
- Adds the optional `cycles_evidence` field (`CyclesEvidenceRef`) to
14+
`ErrorResponse`, closing the last gap in the lifecycle binding loop
15+
(decide / reserve / commit / release / **error**). The `error` artifact wraps
16+
any 4xx/5xx `ErrorResponse` from the four core runtime endpoints and is the
17+
canonical home for non-dry reserve denials — insufficient budget surfaces as
18+
HTTP 409 `BUDGET_EXCEEDED`, NOT a 200 with `decision: DENY` (see
19+
§ReservationCreateResponse.decision) — which the evidence draft calls the
20+
highest-signal evidence an APS receipt can bind to. Surfacing the ref in-band
21+
lets a denied caller bind its own signed receipt to the denial and fetch the
22+
envelope via `getEvidence`. The field is `CyclesEvidenceRef`, identical in
23+
shape/semantics to the four success responses; it is TRANSPORT METADATA, NOT
24+
attested (the `error` artifact's `payload.error.response` mirror in
25+
`drafts/cycles-evidence-v0.1.yaml` keeps `additionalProperties: false` and
26+
omits it, so the content hash is never self-referential). Present when the
27+
server emitted an `error` envelope for this response; absent when emission is
28+
disabled or for errors raised before evidence could be emitted (e.g. request
29+
validation / auth failures). Additive + non-breaking.
30+
31+
---
32+
933
## v0.1.25.4 — 2026-06-13
1034

1135
_(revision 2026-06-13 — surface `cycles_evidence` on the decide response)_

cycles-protocol-v0.yaml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.1.0
22
info:
33
title: Cycles Budget Authority API
4-
version: 0.1.25.4
4+
version: 0.1.25.5
55
license:
66
name: Apache 2.0
77
url: https://www.apache.org/licenses/LICENSE-2.0
@@ -598,6 +598,23 @@ components:
598598
details:
599599
type: object
600600
additionalProperties: true
601+
cycles_evidence:
602+
$ref: '#/components/schemas/CyclesEvidenceRef'
603+
description: >-
604+
Reference to the CyclesEvidence envelope emitted for this error
605+
(artifact_type `error`). Present when the server emitted an `error`
606+
CyclesEvidence record for this response — most importantly the
607+
non-dry reserve denials that surface as HTTP 409 `BUDGET_EXCEEDED`
608+
(and the other live denial codes), which are the highest-signal
609+
evidence an APS receipt can bind to. A denied caller reads
610+
`evidence_id` to bind its own signed receipt to this denial, then
611+
fetches the envelope at `cycles_evidence_url` (see `getEvidence`).
612+
Absent when evidence emission is disabled on the server, or for
613+
errors raised before evidence could be emitted (e.g. request
614+
validation / auth failures). TRANSPORT METADATA, NOT ATTESTED — as
615+
with the success responses, `evidence_id` is computed over the
616+
`ErrorResponse` body WITHOUT this field (the `error` artifact's
617+
`payload.error.response` mirror omits it); see `CyclesEvidenceRef`.
601618
602619
DecisionEnum:
603620
type: string

cycles-spec-index.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ spec_family:
6363
isolation; SDK generators and validator pipelines need a merged artifact.
6464
The merge_recipes section below defines how to produce those artifacts.
6565
current_versions:
66-
base_runtime: "0.1.25.4" # + cycles_evidence ref on reserve/commit/release responses (additive)
66+
base_runtime: "0.1.25.5" # + cycles_evidence ref on ErrorResponse (denial evidence, additive)
6767
base_runtime_semantic_base: "0.1.25" # frozen wire baseline — evidence revisions are additive, 0.1.25 clients stay compatible
6868
base_governance: "0.1.25.33" # + webhook lifecycle EventTypes and per-row Event emission on webhook operations
6969
base_governance_semantic_base: "0.1.25.9" # frozen wire baseline
7070
extension_runtime: "0.1.26" # untouched — no Event/ErrorResponse redeclaration
7171
extension_governance: "0.1.27" # trace_id on redeclared ErrorResponse
7272
action_kinds: "0.1.27" # trace_id on redeclared ErrorResponse
73-
spec_index: "0.1.29" # runtime_base editorial → 0.1.25.4 (+ decide cycles_evidence)
73+
spec_index: "0.1.30" # runtime_base editorial → 0.1.25.5 (+ cycles_evidence on ErrorResponse)
7474

7575
# ---------------------------------------------------------------------------
7676
# CANONICAL DOCUMENTS
@@ -85,7 +85,7 @@ documents:
8585

8686
- id: runtime_base
8787
file: cycles-protocol-v0.yaml
88-
version: "0.1.25.4" # editorial: + cycles_evidence on reserve/commit/release/decide responses
88+
version: "0.1.25.5" # editorial: + cycles_evidence on reserve/commit/release/decide/error responses
8989
semantic_base: "0.1.25" # frozen wire baseline — evidence fields are additive/optional
9090
role: base
9191
conformance: normative

drafts/cycles-evidence-v0.1.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,17 @@ components:
959959
Mirror of `cycles-protocol-v0.yaml#/components/schemas/ErrorResponse`
960960
— the body of any 4xx/5xx response from the four core
961961
runtime endpoints.
962+
963+
DELIBERATE OMISSION — `cycles_evidence`: as with the
964+
reserve/commit/release/decision mirrors, the canonical
965+
`ErrorResponse` carries an optional `cycles_evidence` ref
966+
(added in `cycles-protocol-v0.yaml` v0.1.25.5 so a denied
967+
caller gets the `error` envelope id in-band) but it is
968+
TRANSPORT METADATA, NOT attested; `additionalProperties: false`
969+
forbids it here. The `evidence_id` is computed over this
970+
pre-evidence-ref response, so the content hash an `error`
971+
envelope's `payload.error.response` carries is never
972+
self-referential.
962973
required: [error, message, request_id]
963974
additionalProperties: false
964975
properties:

merged/cycles-openapi-protocol-merged.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,18 @@ components:
202202
details:
203203
type: object
204204
additionalProperties: true
205+
cycles_evidence:
206+
$ref: '#/components/schemas/CyclesEvidenceRef'
207+
description: Reference to the CyclesEvidence envelope emitted for this error (artifact_type
208+
`error`). Present when the server emitted an `error` CyclesEvidence record for this response
209+
— most importantly the non-dry reserve denials that surface as HTTP 409 `BUDGET_EXCEEDED`
210+
(and the other live denial codes), which are the highest-signal evidence an APS receipt can
211+
bind to. A denied caller reads `evidence_id` to bind its own signed receipt to this denial,
212+
then fetches the envelope at `cycles_evidence_url` (see `getEvidence`). Absent when evidence
213+
emission is disabled on the server, or for errors raised before evidence could be emitted
214+
(e.g. request validation / auth failures). TRANSPORT METADATA, NOT ATTESTED — as with the
215+
success responses, `evidence_id` is computed over the `ErrorResponse` body WITHOUT this field
216+
(the `error` artifact's `payload.error.response` mirror omits it); see `CyclesEvidenceRef`.
205217
DecisionEnum:
206218
type: string
207219
enum:

0 commit comments

Comments
 (0)