feat(wcp): retry_context + idempotency_key (#1673 P1+P2)#144
Merged
saurabhjain1592 merged 7 commits intomainfrom Apr 21, 2026
Merged
feat(wcp): retry_context + idempotency_key (#1673 P1+P2)#144saurabhjain1592 merged 7 commits intomainfrom
saurabhjain1592 merged 7 commits intomainfrom
Conversation
Implements the Python SDK side of the WCP retry_context + idempotency_key wire contract (#1673 Phase 1 + Phase 2): - RetryContext pydantic model + PriorCompletionStatus enum mirroring §3 of the contract. Exposed on StepGateResponse.retry_context. - StepGateResponse.cached / .decision_source kept, marked [DEPRECATED] in field descriptions. - step_gate() takes a keyword-only `include_prior_output: bool = False` argument. When True, the SDK sends ?include_prior_output=true. - idempotency_key on StepGateRequest and MarkStepCompletedRequest (both max_length=255). - IdempotencyKeyMismatchError exception, re-exported from axonflow top-level. Raised by step_gate and mark_step_completed when the platform returns 409 with error.code == "IDEMPOTENCY_KEY_MISMATCH". Exposes workflow_id, step_id, expected_idempotency_key, received_idempotency_key. - Unit tests for all six shapes in §6.8 of the contract, plus a second 409 test on the gate call path. CHANGELOG entry under [Unreleased]; no version bump (version bumps land in the same PR once platform v7.3.0 is tagged). Refs: technical-docs/WCP_RETRY_IDEMPOTENCY_WIRE_CONTRACT.md on feat/1673-retry-context-and-idempotency-key in axonflow-enterprise.
Contract §3 specifies the field as "string or null" — platform returns null when the caller never supplied a key. The pydantic model was typed as `str = Field(default="")`, which would raise ValidationError on null from the platform. - Change type to `str | None = Field(default=None)` to accept null. - Add a new unit test that exercises the null-from-platform case.
Contract §3 was updated (platform session): idempotency_key is always emitted as a string, "" when the caller never supplied a key. Not null, not omitted. - Revert RetryContext.idempotency_key from `str | None = None` to `str = Field(default="")` so the pydantic model matches the wire. - Drop the now-invalid null-from-platform test. - Existing null-preservation test from the earlier commit is retired since the platform no longer emits null on this field. Cross-referenced against TS SDK fix `a31e770` which applied the same contract alignment.
Raw-SDK example exercising both phases end-to-end against a running v7.3.0 enterprise stack: - retry_context invariants on first gate (counters, status, first==last, last_decision first-call invariant) - re-gate post-complete (gate_count=2, completion_count=1, prior_completion_status="completed", prior_output_available=True) - agent-crash simulation (gate without complete → "gated_not_completed") - include_prior_output=True opt-in populates retry_context.prior_output - retry_context.idempotency_key echo on gate with key - IdempotencyKeyMismatchError typed raise with workflow_id / step_id / expected / received all populated - Complete with matching key succeeds Every assertion fails the process on mismatch. Ran green against platform on feat/1673-retry-context-and-idempotency-key.
…_idempotency example ruff's default S101 (asserts) and E501 (line length) reject the E2E-validation example file the platform session landed in 8d9aa78. These are intentional for a self-verifying script — asserts are the verification mechanism, and the long assertion labels are the diagnostics printed on failure. - Per-file-ignore entry in pyproject.toml for S101/E501 scoped to just examples/wcp_retry_idempotency.py (not all examples — other example files should keep the stricter defaults). - Also ran ruff format on the file for consistency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the Python SDK side of the WCP retry_context + idempotency_key wire contract for axonflow-enterprise#1673 (Phase 1 + Phase 2). Contract: WCP_RETRY_IDEMPOTENCY_WIRE_CONTRACT.md.
RetryContextpydantic model +PriorCompletionStatusenum (onStepGateResponse.retry_context).cached/decision_sourcepreserved, marked[DEPRECATED]in field descriptions.step_gate(..., include_prior_output=False)— new keyword-only arg sends?include_prior_output=true.idempotency_keyonStepGateRequestandMarkStepCompletedRequest(max_length=255).IdempotencyKeyMismatchErrorexported fromaxonflow, raised from bothstep_gateandmark_step_completedon 409IDEMPOTENCY_KEY_MISMATCH.[Unreleased]CHANGELOG entry. No version bump until platform v7.3.0 tag is cut.Coordination
E2E_EXAMPLES_TESTING_WORKFLOW.md(CLAUDE.md hard rule feat: Contract Testing & Integration Test CI #6).Test plan
tests/test_retry_context_idempotency.py— 7/7 green