feat(pep): decide → fulfill → forward Decision Mode PEP (#2571)#59
Merged
Merged
Conversation
d684e9a to
d494ef4
Compare
Add the SDK analog of platform/shared/pep (ADR-056, epic #2563): a decide client that surfaces engine-fulfillable redact_pii obligations, plus a fulfill helper that discharges them by round-tripping content through the named engine endpoint (check-input) -- never by redacting locally. - decide() / fulfill_request() / decide_and_fulfill() / has_request_redaction() - DecideRequest/DecideResponse/Obligation/ObligationFulfillment + DecisionCallerIdentity/DecisionTarget types - redacted/redacted_statement/redaction_evaluated on MCPCheckInputResponse; redaction_evaluated on MCPCheckOutputResponse; content_type on check-input - AxonFlowError::ObligationNotFulfillable fail-closed signal; PEP constants - 22 unit tests (98.8% line cov on new code) + runtime-e2e against a real enterprise agent (decide->fulfill->masked, demo creds refused 401) Minor bump 0.5.0 -> 0.6.0 (additive, SDK semver decoupled from platform). Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
d494ef4 to
99bd849
Compare
…dence (#2571) R3 follow-up: - LOW: fulfill_request fails closed (ObligationNotFulfillable) on a self-contradictory engine response (redacted=true, empty/absent redacted_statement) instead of forwarding the unredacted original; adds a unit test. - MEDIUM: replace the stale runtime-e2e evidence log (captured at sdk_version 0.5.0, predating the shipped path) with a fresh capture against the 0.7.0 build + the real enterprise agent. Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
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.
Ports the Decision Mode PEP (decide → fulfill → forward) contract into the Rust SDK — the SDK analog of
platform/shared/pep(ADR-056, epic getaxonflow/axonflow-enterprise#2563, tracked by #2571). Cross-SDK parity with the Go (#181), TypeScript (#241), Python (#211), and Java SDK PRs; JSON wire field names are byte-identical.What's in it
New PEP surface on
AxonFlowClient:decide(DecideRequest) -> DecideResponse—POST /api/v1/decideover the client's existing HTTP Basic (org:license) auth. 401 →AxonFlowError::ApiError { status: 401 };denyis returned in the body (200), not an error.fulfill_request(&DecideResponse, &str) -> (String, bool)— discharges each request-phaseredact_piiobligation by POSTing to the obligation'scheck-inputendpoint and returning engine-redacted content. Fails closed (AxonFlowError::ObligationNotFulfillable, never the original) on: no request-phase fulfillment, unadvertised content-type, foreign endpoint, engine error/non-200, orredaction_evaluatedfalse/absent.decide_and_fulfill(DecideRequest) -> (verdict, content, DecideResponse)— one-call path; surfaces the fail-closed error so a caller cannot forward the unredacted query.has_request_redaction(&[Obligation]) -> bool.Types (
types::pep, re-exported from crate root):DecideRequest,DecideResponse,Obligation,ObligationFulfillment,DecisionCallerIdentity,DecisionTarget, plusMCPCheckInput/Output{Request,Response}. Addedcontent_typeto check-input request;redacted/redacted_statement/redaction_evaluatedto check-input response;redaction_evaluatedto check-output response — all#[serde(default)]so older platforms deserialize cleanly (fail-closed defaultfalse).AxonFlowError::ObligationNotFulfillable(String)— the fail-closed signal; non-retryable, not fail-open-eligible.No local redaction anywhere — fulfillment is always the engine round-trip.
Verification
cargo build/cargo clippy --all-targets -- -D warnings/cargo fmt --check— all green; zero new warnings vs clean tree.pep.rs98.8% lines,types/pep.rs100% (llvm-cov).decide_and_fulfillallow/deny/unfulfillable.runtime-e2e/decide_fulfill_obligation/) against a live enterprise agent, no mocks: decide → allow + obligation; fulfill → engine-masked (jo****************om/4**************1, neitherjohn.doe@example.comnor4111111111111111survives);decide_and_fulfillparity; demo creds refused 401. Evidence committed underEVIDENCE/.Versioning
Minor bump 0.6.0 → 0.7.0 (additive; SDK semver decoupled from platform). CHANGELOG updated. (NB: the brief said current was 0.6.0 → bump to 0.7.0, but the repo's latest released tag is
v0.5.0andCargo.tomlwas0.5.0; bumped from actual current.)No wire-shape baseline gate exists in this SDK, so none to regenerate.
Refs getaxonflow/axonflow-enterprise#2571, getaxonflow/axonflow-enterprise#2563