From 78ac2da58c71a035c1806d451184d52378c7c819 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 21 Oct 2026 14:41:53 +0200 Subject: [PATCH 1/2] feat: expose payment approval decision fields for FinCrime v3 Signed-off-by: Saurabh Jain --- CHANGELOG.md | 6 ++++++ axonflow/__init__.py | 4 ++++ axonflow/_version.py | 2 +- axonflow/types.py | 24 ++++++++++++++++++++++++ pyproject.toml | 2 +- tests/test_pep.py | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2b6fce..2723826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 and tag v{X.Y.Z}. The release workflow's preflight checks the section header matches the tag. --> +## [9.5.0] - 2026-10-21: Decision API approval retry fields + +### Added + +- Decision API payment approval wire fields: exact `target.server`, request `approval_id`, and response `pending_approval` and consumed `approval_id`. A hold is never an allow verdict; retry only after human approval and forward the payment only on an allow verdict for the spent approval. + ## [9.4.0] - 2026-09-14: decision provenance, the PEP capability handshake, typed policy authoring, and the simulation family deprecated The first Python SDK release carrying these entries sends the PEP capability handshake, which a platform reads from v10.4.0, and reaches `/api/v1/typed-policies`, which needs a v11.0.0 platform. Upgrade the SDK before the platform: from v11.0.0, `decide` refuses a client that does not declare redaction, including one that sends no handshake, wherever the organization has a redact override. Against an older platform this release works unchanged. diff --git a/axonflow/__init__.py b/axonflow/__init__.py index 7d355b6..c302cd0 100644 --- a/axonflow/__init__.py +++ b/axonflow/__init__.py @@ -246,7 +246,9 @@ CreateBudgetRequest, DecideRequest, DecideResponse, + DecisionApprovalRetry, DecisionCallerIdentity, + DecisionPendingApproval, DecisionProvenance, DecisionTarget, DynamicPolicyInfo, @@ -400,6 +402,8 @@ # Decision Mode PEP contract (ADR-056, #2563) "DecideRequest", "DecideResponse", + "DecisionApprovalRetry", + "DecisionPendingApproval", "DecisionProvenance", "LegacyValidatorAction", "PolicyIdentity", diff --git a/axonflow/_version.py b/axonflow/_version.py index 3236f04..3de3aaf 100644 --- a/axonflow/_version.py +++ b/axonflow/_version.py @@ -1,3 +1,3 @@ """Single source of truth for the AxonFlow SDK version.""" -__version__ = "9.4.0" +__version__ = "9.5.0" diff --git a/axonflow/types.py b/axonflow/types.py index fbde01c..890f36b 100644 --- a/axonflow/types.py +++ b/axonflow/types.py @@ -665,6 +665,7 @@ class DecisionTarget(BaseModel): type: str | None = Field(default=None, description='"llm" | "tool" | "agent".') model: str | None = Field(default=None, description="When type=llm.") provider: str | None = Field(default=None, description="When type=llm.") + server: str | None = Field(default=None, description="When type=tool.") tool: str | None = Field(default=None, description="When type=tool.") @@ -682,6 +683,27 @@ class DecideRequest(BaseModel): target: DecisionTarget = Field(default_factory=DecisionTarget) user_token: str | None = Field(default=None) context: dict[str, Any] | None = Field(default=None) + approval_id: str | None = Field( + default=None, description="Approved hold spent by an exact retry" + ) + + +class DecisionApprovalRetry(BaseModel): + """The header or body field that names a held call on retry.""" + + header: str + argument: str | None = None + body_field: str | None = None + + +class DecisionPendingApproval(BaseModel): + """A call held for a person's review; this is never an allow verdict.""" + + approval_id: str + status: str + plane: str + expires_at: datetime | None = None + retry: DecisionApprovalRetry class DecideResponse(DecisionProvenance): @@ -707,6 +729,8 @@ class DecideResponse(DecisionProvenance): policy_identities: list[PolicyIdentity] | None = Field(default=None) policy_packs: list[str] | None = Field(default=None) document_version: int | None = Field(default=None) + pending_approval: DecisionPendingApproval | None = Field(default=None) + approval_id: str | None = Field(default=None) class PlanStep(BaseModel): diff --git a/pyproject.toml b/pyproject.toml index 64ac9d2..d948b25 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "axonflow" -version = "9.4.0" +version = "9.5.0" description = "AxonFlow Python SDK - Enterprise AI Governance in 3 Lines of Code" readme = "README.md" license = {text = "MIT"} diff --git a/tests/test_pep.py b/tests/test_pep.py index 5e029d9..e3a9e47 100644 --- a/tests/test_pep.py +++ b/tests/test_pep.py @@ -153,6 +153,43 @@ async def test_decide_omits_none_fields_on_wire( assert "user_token" not in body # None excluded assert "context" not in body + @pytest.mark.asyncio + async def test_payment_hold_and_approved_retry_wire( + self, client: AxonFlow, httpx_mock: HTTPXMock + ) -> None: + httpx_mock.add_response(url=DECIDE_URL, json={ + "verdict": "needs_approval", "pending_approval": { + "approval_id": "hold-1", "status": "pending", "plane": "decide", + "retry": {"header": "X-Axonflow-Approval-Id", "body_field": "approval_id"}, + }, + }) + httpx_mock.add_response(url=DECIDE_URL, json={ + "verdict": "allow", "approval_id": "hold-1", + }) + request = DecideRequest( + stage="tool", query="Retry failed disbursement", + target={ + "type": "tool", + "server": "payment-ops", + "tool": "payment-ops.retry_disbursement", + }, + ) + held = await client.decide(request) + assert held.verdict == "needs_approval" + assert held.pending_approval is not None + assert held.pending_approval.approval_id == "hold-1" + assert held.pending_approval.retry.body_field == "approval_id" + request.approval_id = held.pending_approval.approval_id + allowed = await client.decide(request) + assert allowed.verdict == "allow" + assert allowed.approval_id == "hold-1" + import json as _json + + sent = [_json.loads(item.content) for item in httpx_mock.get_requests()] + assert sent[0]["target"]["server"] == "payment-ops" + assert "approval_id" not in sent[0] + assert sent[1]["approval_id"] == "hold-1" + # --------------------------------------------------------------------------- # fulfill_request() — the fail-closed core From 197b871147b73a1fff72afccd87eb8edce1cb796 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 21 Oct 2026 15:23:51 +0200 Subject: [PATCH 2/2] chore(contract): pin v11.2 payment approval wire shape Advance the derived OpenAPI snapshot to merged platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4 and refresh the baseline after reviewing its drift delta. The pin exposes the Decision API approval fields carried by this SDK release. Signed-off-by: Saurabh Jain --- tests/fixtures/openapi/README.md | 10 +- tests/fixtures/openapi/agent-api.yaml | 75 ++++++++----- tests/fixtures/openapi/masfeat-api.yaml | 4 +- tests/fixtures/openapi/orchestrator-api.yaml | 68 ++++++----- tests/fixtures/openapi/policy-api.yaml | 4 +- tests/fixtures/wire_shape_baseline.json | 112 +++++++++++++++---- 6 files changed, 174 insertions(+), 99 deletions(-) diff --git a/tests/fixtures/openapi/README.md b/tests/fixtures/openapi/README.md index 3e43064..50483ab 100644 --- a/tests/fixtures/openapi/README.md +++ b/tests/fixtures/openapi/README.md @@ -7,7 +7,7 @@ It reads the schema declarations under `components.schemas` and the names of eac The four files here hold exactly that, and nothing else. `scripts/snapshot_openapi_schemas.py` derives them from the platform's `docs/api/*.yaml` at platform commit -`36e0e96b7e5c16626d394272b727b533f2b94a04`, the v11.0.0 candidate. It works on the YAML node +`ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4`, the merged platform source for the v11.2.0 train. It works on the YAML node graph, so every declaration survives in source order, including a schema declared twice in one file and a declaration with no properties. A loader that counts in-file duplicates reads the same thing here as from the source. The script drops descriptions, types, paths and the `info` block; @@ -23,10 +23,10 @@ spec. | File | sha256 of the source spec | |---|---| -| `agent-api.yaml` | `49bd1b145cd3b2d29e8cc8de240cc184d4f5d24f83b6c546894d1f0a682a032a` | -| `masfeat-api.yaml` | `2d49d6af2d5b1510b373c01fce1df2b712b32766b14d477652797746c52147e7` | -| `orchestrator-api.yaml` | `b173c9bec456e4af3aa09c63306e503caa73ca0cf61da3dfaa7b21453dcd1188` | -| `policy-api.yaml` | `090730a359bf242b6ed5c1a0d63a2831c749583bd957cc3ecc64c99ead5514b7` | +| `agent-api.yaml` | `617e6236f91dd7716baaab8e2f22ef24f1713ebfd4938cc52a60a3368e3acb1a` | +| `masfeat-api.yaml` | `eb224773c2a14fc6a84a630b652b17e010a4776da28529b13e173b002d2d4756` | +| `orchestrator-api.yaml` | `a1f96d929ff35acb1204ce5ba3c6e605b8f91d93e7fa62a2fa8a760ea8486860` | +| `policy-api.yaml` | `a1a7aff59d759033f99721a40d942e8750c6026d69f9efb0edf66016f0069ae9` | Each file's header repeats its source path, commit and digest. diff --git a/tests/fixtures/openapi/agent-api.yaml b/tests/fixtures/openapi/agent-api.yaml index 3ff2e7c..f8c0d50 100644 --- a/tests/fixtures/openapi/agent-api.yaml +++ b/tests/fixtures/openapi/agent-api.yaml @@ -1,6 +1,6 @@ # GENERATED by scripts/snapshot_openapi_schemas.py - do not edit. -# Source: docs/api/agent-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04 -# Source sha256: 49bd1b145cd3b2d29e8cc8de240cc184d4f5d24f83b6c546894d1f0a682a032a +# Source: docs/api/agent-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4 +# Source sha256: 617e6236f91dd7716baaab8e2f22ef24f1713ebfd4938cc52a60a3368e3acb1a # Schema declarations and property names only; see tests/fixtures/openapi/README.md. components: schemas: @@ -18,6 +18,7 @@ components: "capabilities": {} "sdk_compatibility": {} "plugin_compatibility": {} + "upstream": {} "PlatformCapability": properties: "name": {} @@ -103,17 +104,6 @@ components: "enabled_override": {} "override_reason": {} "expires_at": {} - "CreateOverrideResponse": - properties: - "id": {} - "policy_id": {} - "policy_type": {} - "expires_at": {} - "ttl_seconds": {} - "requested_ttl": {} - "clamped": {} - "clamped_reason": {} - "created_at": {} "TestPatternRequest": properties: "pattern": {} @@ -165,6 +155,16 @@ components: "skip_llm": {} "context": {} "media": {} + "PolicyTestResponse": + properties: + "blocked": {} + "reason": {} + "triggered_policies": {} + "checks_performed": {} + "processing_time_ms": {} + "engine": {} + "subject_type": {} + "policy_bundle": {} "ClientResponse": properties: "success": {} @@ -173,18 +173,21 @@ components: "plan_id": {} "metadata": {} "error": {} + "code": {} "blocked": {} "block_reason": {} - "approval_request_id": {} "policy_info": {} "budget_info": {} "media_analysis": {} "engine": {} "subject_type": {} "policy_bundle": {} + "policy_packs": {} "legacy_validators": {} + "response_plane": {} "PolicyEvaluationInfo": properties: + "matched_policies": {} "policies_evaluated": {} "static_checks": {} "processing_time": {} @@ -205,7 +208,6 @@ components: "context_id": {} "approved_data": {} "policies": {} - "approval_request_id": {} "rate_limit": {} "expires_at": {} "block_reason": {} @@ -225,8 +227,17 @@ components: "pep_id": {} "audience": {} "capabilities": {} + "PendingApproval": + properties: + "approval_id": {} + "status": {} + "plane": {} + "expires_at": {} + "retry": {} + "ApprovalHoldReason": {} "DecideRequest": properties: + "approval_id": {} "stage": {} "caller_identity": {} "target": {} @@ -248,6 +259,8 @@ components: "tool": {} "DecideResponse": properties: + "pending_approval": {} + "approval_id": {} "verdict": {} "decision_id": {} "trace_id": {} @@ -426,6 +439,7 @@ components: "license_expiry": {} "MCPQueryRequest": properties: + "approval_id": {} "client_id": {} "license_key": {} "user_token": {} @@ -448,6 +462,7 @@ components: "engine": {} "subject_type": {} "policy_bundle": {} + "policy_packs": {} "legacy_validators": {} "PolicyInfo": properties: @@ -458,7 +473,6 @@ components: "processing_time_ms": {} "matched_policies": {} "exfiltration_check": {} - "dynamic_policy_info": {} "ExplainPolicy": properties: "policy_id": {} @@ -496,25 +510,11 @@ components: "tool_signature": {} "ExfiltrationCheckInfo": properties: - "exceeded": {} - "limit_type": {} "rows_returned": {} "row_limit": {} "bytes_returned": {} "byte_limit": {} - "DynamicPolicyInfo": - properties: - "policies_evaluated": {} - "matched_policies": {} - "orchestrator_reachable": {} - "processing_time_ms": {} - "DynamicPolicyMatch": - properties: - "policy_id": {} - "policy_name": {} - "policy_type": {} - "action": {} - "message": {} + "within_limits": {} "PolicyMatchInfo": properties: "policy_id": {} @@ -524,6 +524,7 @@ components: "action": {} "MCPExecuteRequest": properties: + "approval_id": {} "client_id": {} "license_key": {} "user_token": {} @@ -546,9 +547,11 @@ components: "engine": {} "subject_type": {} "policy_bundle": {} + "policy_packs": {} "legacy_validators": {} "MCPCheckInputRequest": properties: + "approval_id": {} "client_id": {} "user_token": {} "tenant_id": {} @@ -562,6 +565,8 @@ components: "content_type": {} "MCPCheckInputResponse": properties: + "pending_approval": {} + "approval_id": {} "allowed": {} "block_reason": {} "policies_evaluated": {} @@ -573,7 +578,13 @@ components: "override_existing_id": {} "redacted": {} "redacted_statement": {} + "redacted_parameters": {} "redaction_evaluated": {} + "engine": {} + "subject_type": {} + "policy_bundle": {} + "policy_packs": {} + "legacy_validators": {} "MCPCheckOutputRequest": properties: "client_id": {} @@ -599,6 +610,7 @@ components: "engine": {} "subject_type": {} "policy_bundle": {} + "policy_packs": {} "legacy_validators": {} "ConnectorRefreshResponse": properties: @@ -646,6 +658,7 @@ components: "window": {} "resets_at": {} "upgrade": {} + "code": {} "DecisionEntry": properties: "id": {} diff --git a/tests/fixtures/openapi/masfeat-api.yaml b/tests/fixtures/openapi/masfeat-api.yaml index ba5c354..c262b19 100644 --- a/tests/fixtures/openapi/masfeat-api.yaml +++ b/tests/fixtures/openapi/masfeat-api.yaml @@ -1,6 +1,6 @@ # GENERATED by scripts/snapshot_openapi_schemas.py - do not edit. -# Source: docs/api/masfeat-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04 -# Source sha256: 2d49d6af2d5b1510b373c01fce1df2b712b32766b14d477652797746c52147e7 +# Source: docs/api/masfeat-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4 +# Source sha256: eb224773c2a14fc6a84a630b652b17e010a4776da28529b13e173b002d2d4756 # Schema declarations and property names only; see tests/fixtures/openapi/README.md. components: schemas: diff --git a/tests/fixtures/openapi/orchestrator-api.yaml b/tests/fixtures/openapi/orchestrator-api.yaml index 46f9a9a..2befa34 100644 --- a/tests/fixtures/openapi/orchestrator-api.yaml +++ b/tests/fixtures/openapi/orchestrator-api.yaml @@ -1,6 +1,6 @@ # GENERATED by scripts/snapshot_openapi_schemas.py - do not edit. -# Source: docs/api/orchestrator-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04 -# Source sha256: b173c9bec456e4af3aa09c63306e503caa73ca0cf61da3dfaa7b21453dcd1188 +# Source: docs/api/orchestrator-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4 +# Source sha256: a1f96d929ff35acb1204ce5ba3c6e605b8f91d93e7fa62a2fa8a760ea8486860 # Schema declarations and property names only; see tests/fixtures/openapi/README.md. components: schemas: @@ -17,6 +17,23 @@ components: "separation_of_duties": {} "tier_established": {} "reserved": {} + "TemplateOmissionReport": + properties: + "omitted": {} + "modified": {} + "of": {} + "message": {} + "TypedAuthoringActivation": + properties: + "kind": {} + "root": {} + "digest": {} + "previous_digest": {} + "document_id": {} + "document_version": {} + "actor": {} + "at": {} + "reason": {} "AuthoringFinding": properties: "code": {} @@ -129,6 +146,10 @@ components: "provider_info": {} "processing_time": {} "media_analysis": {} + "engine": {} + "subject_type": {} + "policy_bundle": {} + "verdict": {} "PolicyEvaluationResult": properties: "allowed": {} @@ -142,9 +163,6 @@ components: "evaluation_error": {} "segments_resolved": {} "applied_policies_detail": {} - "override_applied": {} - "override_id": {} - "override_reason": {} "preferred_provider": {} "allowed_providers": {} "routing_reason": {} @@ -190,6 +208,10 @@ components: "metadata": {} "error": {} "policy_info": {} + "engine": {} + "subject_type": {} + "policy_bundle": {} + "verdict": {} "complexity": {} "domain": {} "parallel": {} @@ -234,6 +256,7 @@ components: "next_step_name": {} "step_result": {} "total_steps": {} + "ignored_foreign_gate_rows": {} "workflow_id": {} "RollbackPlanResponse": properties: @@ -491,6 +514,9 @@ components: "approval_url": {} "policies_evaluated": {} "policies_matched": {} + "engine": {} + "subject_type": {} + "policy_bundle": {} "cached": {} "decision_source": {} "retry_context": {} @@ -671,35 +697,6 @@ components: "approval_status": {} "paused_at_step": {} "paused_reason": {} - "MCPDynamicPolicyMatch": - properties: - "policy_id": {} - "policy_name": {} - "policy_type": {} - "action": {} - "reason": {} - "MCPPolicyEvaluationRequest": - properties: - "tenant_id": {} - "organization_id": {} - "user_id": {} - "user_role": {} - "segment_ids": {} - "connector_name": {} - "operation": {} - "statement": {} - "parameters": {} - "request_time": {} - "client_ip": {} - "metadata": {} - "MCPPolicyEvaluationResponse": - properties: - "allowed": {} - "block_reason": {} - "policies_evaluated": {} - "matched_policies": {} - "processing_time_ms": {} - "metadata": {} "RBIAISystemSummary": properties: "total_systems": {} @@ -742,6 +739,7 @@ components: properties: "success": {} "error": {} + "MultiAgentStepRefusal": {} "TripletErrorResponse": properties: "error": {} @@ -1495,6 +1493,7 @@ components: "pii_types": {} "has_extracted_text": {} "extracted_text_length": {} + "scanned": {} "estimated_cost_usd": {} "warnings": {} "structured_warnings": {} @@ -1607,7 +1606,6 @@ components: "created_at": {} "revoked_at": {} "revoked_by": {} - "CreateOverrideResponse": {} "OverrideSummary": {} "OverrideDetail": {} "DecisionListResponse": diff --git a/tests/fixtures/openapi/policy-api.yaml b/tests/fixtures/openapi/policy-api.yaml index 4717159..0b0bdda 100644 --- a/tests/fixtures/openapi/policy-api.yaml +++ b/tests/fixtures/openapi/policy-api.yaml @@ -1,6 +1,6 @@ # GENERATED by scripts/snapshot_openapi_schemas.py - do not edit. -# Source: docs/api/policy-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04 -# Source sha256: 090730a359bf242b6ed5c1a0d63a2831c749583bd957cc3ecc64c99ead5514b7 +# Source: docs/api/policy-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4 +# Source sha256: a1a7aff59d759033f99721a40d942e8750c6026d69f9efb0edf66016f0069ae9 # Schema declarations and property names only; see tests/fixtures/openapi/README.md. components: schemas: diff --git a/tests/fixtures/wire_shape_baseline.json b/tests/fixtures/wire_shape_baseline.json index 09b4469..95a1c7c 100644 --- a/tests/fixtures/wire_shape_baseline.json +++ b/tests/fixtures/wire_shape_baseline.json @@ -118,6 +118,7 @@ "status", "tier", "timestamp", + "upstream", "version" ], "orchestrator-api.yaml": [ @@ -148,6 +149,30 @@ "timestamp" ] }, + "PendingApproval": { + "agent-api.yaml": [ + "approval_id", + "expires_at", + "plane", + "retry", + "status" + ], + "orchestrator-api.yaml": [ + "approval_status", + "created_at", + "decision", + "decision_reason", + "plan_id", + "policies_matched", + "step_id", + "step_index", + "step_input", + "step_name", + "step_type", + "workflow_id", + "workflow_name" + ] + }, "UpdatePolicyRequest": { "orchestrator-api.yaml": [ "action", @@ -173,7 +198,7 @@ ] } }, - "openapi_specs_sha": "36e0e96b7e5c16626d394272b727b533f2b94a04", + "openapi_specs_sha": "ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4", "per_model_drift": { "AISystemRegistry": { "note": "deprecated-pending-removal: getaxonflow/axonflow-enterprise#3254 pin-advance batch (dataclass binding, #3262). sdk_only lists the LEGACY spellings the parser reads first-for-compatibility before falling back to the real v9.13.0 wire names (now spec-declared), here business_owner/customer_impact/model_complexity/human_reliance (real wire: owner_email/risk_rating_impact/risk_rating_complexity/risk_rating_reliance), plus deprecated fiction technical_owner (never served on 9.x). spec_only fields (data_sources/model_type/version/deployment_date/last_assessment_date/next_assessment_due/updated_by) are informational coverage gaps (PR #224). Legacy spellings burn down in the next major.", @@ -236,7 +261,9 @@ "note": "acknowledged-spec-superset: the v11.0.0-candidate spec declares `approval_request_id` on ClientResponse; the SDK does not model it yet - additive optional field, no break. Tracked in axonflow-enterprise#1704.", "sdk_only": [], "spec_only": [ - "approval_request_id" + "code", + "policy_packs", + "response_plane" ] }, "CreateStaticPolicyRequest": { @@ -268,13 +295,6 @@ "policy_version_at_decision" ] }, - "DecisionTarget": { - "note": "acknowledged-spec-superset: the v9.13.0 spec declares optional `server` on DecisionTarget (two-field (server, tool) identity contract, epic #2905 / platform #2904); the SDK does not yet model it there - additive optional, no break.", - "sdk_only": [], - "spec_only": [ - "server" - ] - }, "DynamicPolicy": { "note": "acknowledged-sdk-superset: the SDK declares optional `organization_id` on DynamicPolicy, which the v9.13.0 pin declared and the v11.0.0-candidate spec does not. An absent optional field parses as None, so nothing breaks; whether the SDK drops it is tracked in axonflow-enterprise#1704.", "sdk_only": [ @@ -282,17 +302,11 @@ ], "spec_only": [] }, - "DynamicPolicyMatch": { - "note": "deprecated-pending-removal: `reason` is marked DEPRECATED + 'Removed in v7' on its Field() docstring; the canonical wire field is `message` (already present, matches spec).", - "sdk_only": [ - "reason" - ], - "spec_only": [] - }, "ExfiltrationCheckInfo": { "note": "deprecated-pending-removal: `within_limits` is marked DEPRECATED + 'Removed in v7' on its Field() docstring; the canonical wire fields are `exceeded` + `limit_type` (already present, match spec).", "sdk_only": [ - "within_limits" + "exceeded", + "limit_type" ], "spec_only": [] }, @@ -316,13 +330,49 @@ "trigger_conditions" ] }, + "MCPCheckInputRequest": { + "sdk_only": [], + "spec_only": [ + "approval_id" + ] + }, + "MCPCheckInputResponse": { + "sdk_only": [], + "spec_only": [ + "approval_id", + "engine", + "legacy_validators", + "pending_approval", + "policy_bundle", + "policy_packs", + "redacted_parameters", + "subject_type" + ] + }, "MCPCheckOutputResponse": { "note": "acknowledged-sdk-superset: the former `redaction_evaluated` entry resolved - the v9.13.0 spec declares it (#2865/#2866). SDK still declares decision-context fields `policy_matches`/`redacted_message` (Plugin Batch 1, v7.1.0 cycle) ahead of the spec; tracked in #1745.", "sdk_only": [ "policy_matches", "redacted_message" ], - "spec_only": [] + "spec_only": [ + "policy_packs" + ] + }, + "PlanResponse": { + "sdk_only": [], + "spec_only": [ + "engine", + "policy_bundle", + "subject_type", + "verdict" + ] + }, + "PolicyEvaluationInfo": { + "sdk_only": [], + "spec_only": [ + "matched_policies" + ] }, "PolicyEvaluationResult": { "note": "acknowledged-spec-superset: the v11.0.0-candidate spec declares allowed_providers/applied_policies_detail/evaluation_error/override_applied/override_id/override_reason/preferred_provider/routing_reason/segments_resolved/severity/severity_policy_id on PolicyEvaluationResult; the SDK does not model them yet - additive server-side surface, no break. Newly visible with the v11.0.0-candidate pin; tracked in axonflow-enterprise#1704.", @@ -331,9 +381,6 @@ "allowed_providers", "applied_policies_detail", "evaluation_error", - "override_applied", - "override_id", - "override_reason", "preferred_provider", "routing_reason", "segments_resolved", @@ -373,6 +420,12 @@ ], "spec_only": [] }, + "ResumePlanResponse": { + "sdk_only": [], + "spec_only": [ + "ignored_foreign_gate_rows" + ] + }, "StaticPolicy": { "note": "acknowledged-sdk-superset: the SDK declares optional `organization_id` on StaticPolicy, which the v9.13.0 pin declared and the v11.0.0-candidate spec does not. An absent optional field parses as None, so nothing breaks; whether the SDK drops it is tracked in axonflow-enterprise#1704.", "sdk_only": [ @@ -385,7 +438,16 @@ "sdk_only": [], "spec_only": [ "approval_enqueue", - "approval_id" + "approval_id", + "engine", + "policy_bundle", + "subject_type" + ] + }, + "TemplateOmissionReport": { + "sdk_only": [], + "spec_only": [ + "modified" ] }, "UnifiedStepStatus": { @@ -419,6 +481,7 @@ "AuthZENResponse", "AuthZENResponseContext", "AuthZENSubject", + "AuthoringFinding", "Budget", "BudgetAlert", "BudgetCheckRequest", @@ -438,8 +501,7 @@ "DecisionExplanation", "DecisionTarget", "DynamicPolicy", - "DynamicPolicyInfo", - "DynamicPolicyMatch", + "EditionConstructReport", "ExecutionSnapshot", "ExecutionSummary", "ExfiltrationCheckInfo", @@ -493,9 +555,11 @@ "StaticPolicy", "StepGateRequest", "StepGateResponse", + "TemplateOmissionReport", "TimelineEntry", "TokenUsage", "ToolContext", + "TypedAuthoringDocumentRequest", "UnifiedStepStatus", "UpdatePlanRequest", "UpdatePlanResponse",