From a2e89251a3672b170ea8a43c3c2202af38eb33f3 Mon Sep 17 00:00:00 2001 From: Albert Mavashev Date: Thu, 30 Jul 2026 08:27:51 -0400 Subject: [PATCH 1/3] Publish recovery conformance evidence --- .github/workflows/ci.yml | 14 +++++++++++++- .github/workflows/python-publish.yml | 14 +++++++++++++- AUDIT.md | 5 +++++ README.md | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39baf14..636aaf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: runcycles/cycles-protocol - ref: 594631c14710da08ad5e00125d899d642213c296 + ref: b27d7cb38a8f2bd915dea64e4369a2b91f31008c path: .cycles-protocol persist-credentials: false - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -34,4 +34,16 @@ jobs: run: >- python .cycles-protocol/scripts/run_client_recovery_conformance.py --claim durable + --report-json recovery-conformance.json + --implementation runcycles/cycles-client-python + --implementation-commit ${{ github.sha }} + --evidence-url https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} --adapter python scripts/recovery_conformance_adapter.py + - name: Upload recovery conformance evidence + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: recovery-conformance-${{ github.sha }} + path: recovery-conformance.json + if-no-files-found: error + retention-days: 90 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index d705bb0..1c3c4ff 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: runcycles/cycles-protocol - ref: 594631c14710da08ad5e00125d899d642213c296 + ref: b27d7cb38a8f2bd915dea64e4369a2b91f31008c path: .cycles-protocol persist-credentials: false - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 @@ -39,7 +39,19 @@ jobs: run: >- python .cycles-protocol/scripts/run_client_recovery_conformance.py --claim durable + --report-json recovery-conformance.json + --implementation runcycles/cycles-client-python + --implementation-commit ${{ github.sha }} + --evidence-url https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} --adapter python scripts/recovery_conformance_adapter.py + - name: Upload recovery conformance evidence + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: recovery-conformance-${{ github.sha }} + path: recovery-conformance.json + if-no-files-found: error + retention-days: 90 build: name: Build distributions diff --git a/AUDIT.md b/AUDIT.md index 82674ec..f13201b 100644 --- a/AUDIT.md +++ b/AUDIT.md @@ -1,5 +1,10 @@ # Cycles Protocol v0.1.25 — Client (Python) Audit +**Date:** 2026-07-30 (no runtime change — durable recovery conformance now +emits the profile 0.3 machine-readable evidence report, uploads it from both +CI and release workflows even on failure, and links the public SDK matrix from +the README. The report binds all 12 shared scenarios and their exact native +tests to the SDK commit, protocol commit, catalog digest, and Actions run.), **Date:** 2026-07-27 (v0.5.0 — durable commit retries: on-disk pending-commit journal with next-run replay, bounded atexit flush, and `POST /v1/events` recovery for commits that land after reservation expiry; async retry-task GC fix; `retry_enabled=False` now journals instead of silently dropping. Review hardening: per-identity journal partitioning (tenant-keyed when configured — rotation-safe), 429 transient with `Retry-After` incl. first-attempt commits (no more release-on-429), 401/403 retained, `0700`/`0600` journal permissions, process-wide flush deadline; round 3: first-attempt 401/403 journaled (not released), Retry-After persisted across restarts, PBKDF2 30k rounds, unique journal temp files. See the dated entry below. 491 tests pass at 100% coverage.), 2026-07-10 (v0.5.0 — `TENANT_CLOSED` + `LIMIT_EXCEEDED` error-code support. `TENANT_CLOSED` per runtime spec v0.1.25.13 (`cycles-protocol-v0.yaml`, runcycles/cycles-protocol#125): `ErrorCode.TENANT_CLOSED` enum member, `TenantClosedError` subclass wired into the lifecycle error-code→exception mapping (reservation-creation surfaces), `CyclesProtocolError.is_tenant_closed()` helper. `LIMIT_EXCEEDED` per runtime spec v0.1.25.12 (revision 2026-07-04, HTTP 429 rate limiting): enum-only member matching the `BUDGET_FROZEN`/`BUDGET_CLOSED` pattern, classified retryable at both the enum and exception layers (429 is transient; previously it fell through to `UNKNOWN`, which happened to be retryable, so semantics are unchanged — now typed). Enum reordered to mirror spec declaration order. Both purely additive; previously both codes fell through the `ErrorCode.from_string` forward-compat path to `UNKNOWN`. See the dated entries at the end of this file. 398 tests pass at 100% coverage.), 2026-07-09 (README + docstring transport-error documentation fix, no version bump — see the dated entry at the end of this file. `CyclesTransportError` is exported but never raised by the SDK; README and its docstring now describe the actual `status == -1` surfacing.), diff --git a/README.md b/README.md index fefd339..33d9693 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![PyPI](https://img.shields.io/pypi/v/runcycles)](https://pypi.org/project/runcycles/) [![PyPI Downloads](https://img.shields.io/pypi/dm/runcycles)](https://pypi.org/project/runcycles/) [![CI](https://github.com/runcycles/cycles-client-python/actions/workflows/ci.yml/badge.svg)](https://github.com/runcycles/cycles-client-python/actions) +[![Recovery conformance](https://img.shields.io/github/actions/workflow/status/runcycles/cycles-client-python/ci.yml?branch=main&label=recovery%20conformance)](https://runcycles.io/protocol/sdk-recovery-conformance) [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/runcycles/cycles-client-python/actions) From d386a0649ec752f0cc9306046a1ba39e7a93bf76 Mon Sep 17 00:00:00 2001 From: Albert Mavashev Date: Thu, 30 Jul 2026 08:38:29 -0400 Subject: [PATCH 2/3] Pin evidence to the source commit --- .github/workflows/ci.yml | 4 ++-- .github/workflows/python-publish.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 636aaf1..eb982f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,14 @@ jobs: --claim durable --report-json recovery-conformance.json --implementation runcycles/cycles-client-python - --implementation-commit ${{ github.sha }} + --implementation-commit ${{ github.event.pull_request.head.sha || github.sha }} --evidence-url https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} --adapter python scripts/recovery_conformance_adapter.py - name: Upload recovery conformance evidence if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: recovery-conformance-${{ github.sha }} + name: recovery-conformance-${{ github.event.pull_request.head.sha || github.sha }} path: recovery-conformance.json if-no-files-found: error retention-days: 90 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1c3c4ff..3d37426 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -41,14 +41,14 @@ jobs: --claim durable --report-json recovery-conformance.json --implementation runcycles/cycles-client-python - --implementation-commit ${{ github.sha }} + --implementation-commit ${{ github.event.pull_request.head.sha || github.sha }} --evidence-url https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} --adapter python scripts/recovery_conformance_adapter.py - name: Upload recovery conformance evidence if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: recovery-conformance-${{ github.sha }} + name: recovery-conformance-${{ github.event.pull_request.head.sha || github.sha }} path: recovery-conformance.json if-no-files-found: error retention-days: 90 From a0225800abc125d5de351c2470685b573ff5bd44 Mon Sep 17 00:00:00 2001 From: Albert Mavashev Date: Thu, 30 Jul 2026 08:43:02 -0400 Subject: [PATCH 3/3] Pin the normalized evidence runner --- .github/workflows/ci.yml | 2 +- .github/workflows/python-publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb982f6..96610d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: runcycles/cycles-protocol - ref: b27d7cb38a8f2bd915dea64e4369a2b91f31008c + ref: bc12e1fc4b17e272614b63d5e3cb0bea408885af path: .cycles-protocol persist-credentials: false - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 3d37426..281aceb 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: runcycles/cycles-protocol - ref: b27d7cb38a8f2bd915dea64e4369a2b91f31008c + ref: bc12e1fc4b17e272614b63d5e3cb0bea408885af path: .cycles-protocol persist-credentials: false - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0