FastAPI service that drafts AI Procurement Decision Cards (Kinetic Gain Protocol Suite spec #11) from a buyer rubric and vendor Suite documents. Optional audit-stream-py integration via AUDIT_STREAM_URL env var.
Project description
procurement-decision-api
The machine that produces buyer-side AI procurement decisions, schema-conformant and ready to publish.
A FastAPI service that ingests a buyer's evaluation rubric plus a set of vendor Kinetic Gain Protocol Suite declarations and returns a draft AI Procurement Decision Card (spec #11 of the Suite). The Decision Card is the canonical machine-readable carrier for NIST AI RMF-aligned procurement outcomes under OMB M-24-10 — see the crosswalk doc.
The cross-ecosystem bridge
This is the first repo that composes the Kinetic Gain Protocol Suite with the Decision Intelligence Engines portfolio:
Vendor publishes: Buyer publishes (this service produces):
───────────────────────── ────────────────────────────────────────
AEO Protocol Card ┐
Tool Disclosure │
Clinical AI Card ├──> AI Procurement Decision Card
Student AI Disclosure │ (status / rubric / conditions /
Agent Card │ documents reviewed / rationale)
…the other six specs… ┘
Quick start
pip install procurement-decision-api
procurement-decision-api # listens on http://0.0.0.0:8088
Or via Docker:
docker run -p 8088:8088 ghcr.io/mizcausevic-dev/procurement-decision-api:latest
Then draft a decision:
curl -s http://localhost:8088/decisions/draft \
-H 'content-type: application/json' \
-d '{
"decision_id": "SPRINGFIELD-DEC-2026-001",
"buyer": {
"name": "Springfield Unified School District",
"type": "school-district",
"jurisdiction": "US-CA"
},
"decision_maker": {
"role": "Director of Educational Technology",
"name": "Dr. Jane Doe",
"authority": "Board Resolution 2026-04"
},
"vendor_name": "AcmeTutor Inc.",
"product_name": "AcmeTutor 3.0",
"vendor_id": "https://acmetutor.example/.well-known/aeo.json",
"fetch_targets": [
{ "type": "aeo", "url": "https://acmetutor.example/.well-known/aeo.json" },
{ "type": "tutor-card", "url": "https://acmetutor.example/.well-known/tutor-card.json" },
{ "type": "student-ai-disclosure", "url": "https://acmetutor.example/.well-known/student-ai-disclosure.json" }
],
"policy_uris": [
"https://springfield.edu/.well-known/aup.json"
],
"rubric": [
{ "id": "ferpa-compliance", "result": "pass", "weight": 1.0 },
{ "id": "coppa-compliance", "result": "pass", "weight": 1.0 },
{ "id": "no-training-on-student-data", "result": "pass-with-condition", "weight": 1.0,
"notes": "Disclosure asserts no-training; require contractual confirmation." },
{ "id": "bias-audit-completed", "result": "partial", "weight": 0.8,
"notes": "Audit current but due for refresh by 2026-09." }
],
"conditions": [
{ "id": "no-training-restriction",
"description": "Vendor SHALL NOT use Springfield USD student-provided content for model training.",
"enforcement": "contractual" },
{ "id": "bias-audit-refresh",
"description": "Vendor SHALL deliver a refreshed third-party bias audit by 2026-12-01.",
"enforcement": "audit" }
]
}' | jq
The response includes:
draft— the full, schema-conformant Decision Card (ready to sign + publish at/.well-known/decisions/<id>.json)documents_fetched[]— each vendor URL with its retrieval timestamp + sha256 content hashfetch_errors[]— per-target retrieval errors (the draft doesn't fail wholesale on one missing URL)inferred_status—trueif the service inferred the decision status from the rubric
What the service does
- Fetches every URL in
fetch_targetsconcurrently with httpx, capped at 2 MB / 10 s per document, and computes a canonical sha256 hash over each (sorted keys, no whitespace). - Infers
decision.statusfrom the rubric if you didn't supplyproposed_status. The inference rules:- Any
fail→rejected-with-remediation - Any
partialorpass-with-condition→approved-with-conditions - All
pass→approved - Empty / all
n/a→pending
- Any
- Composes a default rationale from the rubric results if you didn't supply
rationale_template. - Validates the Decision Card against the same conditional rules the upstream zod schema enforces:
status∈ {approved-with-conditions,rejected-with-remediation} →conditionsmust be non-emptystatus=withdrawn→withdrawalblock requiredpublication.is_public=true→publication_urirequired
- Returns the Draft Decision Card. Review, edit, sign, publish.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | / |
Service info + relevant links |
| GET | /healthz |
Liveness probe (always 200 if the process is running) |
| POST | /decisions/draft |
Produce a Draft Decision Card |
| POST | /decisions/validate |
Validate an existing Decision Card against the v0.1 schema |
| GET | /docs |
Interactive OpenAPI documentation (Swagger UI) |
| GET | /openapi.json |
Machine-readable API schema |
Why this matters
AI procurement under OMB M-24-10 and NIST AI RMF requires agencies to publish reviewable decisions about vendor AI systems. Today, those decisions sit in PDFs and procurement databases — invisible to vendors trying to win future RFPs and invisible to citizens whose data is being processed.
The AI Procurement Decision Card spec defines a machine-readable carrier for those decisions. This service is the tool that produces them at scale: a reviewer fills in the rubric, points at the vendor's published declarations, and gets back a schema-valid card ready to publish at /.well-known/decisions/<decision_id>.json.
For procurement teams, this means a decision becomes a queryable, searchable, audit-friendly artifact — and the vendor's published declarations are cited by URL and content hash, so any drift after the decision is detectable.
Architecture
┌────────────────────────────────────────────────────────────┐
│ FastAPI app (lifespan-managed) │
│ │
│ POST /decisions/draft │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────┐ │
│ │ fetcher.fetch_documents (async, httpx) │ │
│ │ - timeout 10s per doc │ │
│ │ - 2 MB size cap │ │
│ │ - canonical sha256 hash │ │
│ │ - per-target error collection │ │
│ └────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────┐ │
│ │ rubric.infer_status │ │
│ │ rubric.compose_rationale │ │
│ │ rubric.weighted_score │ │
│ └────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────┐ │
│ │ drafter.draft_decision_card │ │
│ │ - validates conditional rules │ │
│ │ - assembles history events │ │
│ └────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ DraftResponse │
└────────────────────────────────────────────────────────────┘
Pydantic v2 models mirror the JSON Schema 2020-12 spec exactly, including the conditional rules (which run as @model_validator(mode="after") hooks).
Development
git clone https://github.com/mizcausevic-dev/procurement-decision-api
cd procurement-decision-api
pip install -e ".[dev]"
# Run the test suite (mocks the vendor HTTP layer; no internet required)
pytest -q
# Lint, format, typecheck
ruff check src tests
ruff format src tests
mypy src
# Run the service
python -m procurement_decision_api
# or
uvicorn procurement_decision_api.app:app --reload --port 8088
Composability
This service composes naturally with the rest of the Kinetic Gain ecosystem:
- Input documents can be fetched directly from any vendor's
/.well-known/paths, or validated first viakg-validate-actionin your CI. - Output Decision Cards can be inspected by
mcp-kinetic-gain(tools:decision_card_inspect,decision_card_validate). - Inline validation in the browser is available at validator.kineticgain.com — paste the produced draft, get inline error markers.
License
MIT. The Kinetic Gain Protocol Suite specifications this service produces are also MIT; reference implementations like mcp-kinetic-gain are AGPL-3.0.
Related
- Spec repo:
ai-procurement-decision-spec - Hosted validator: validator.kineticgain.com
- MCP server:
mcp-kinetic-gain— install withnpx -y mcp-kinetic-gain - GitHub Action:
kg-validate-action - NIST AI RMF crosswalk: suite.kineticgain.com/docs/nist-rmf-crosswalk.md
- Apex: kineticgain.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file procurement_decision_api-0.1.1.tar.gz.
File metadata
- Download URL: procurement_decision_api-0.1.1.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23ba3e358a31b2a4c045f16e5076597a9bd028f0b44c85247b645688b99dcf75
|
|
| MD5 |
50f99e7a762f24279ca277fa2957863a
|
|
| BLAKE2b-256 |
b06f0af95cc6d69d891024206a5950c8fb46ebdee8d44ecc813a9b60beea4a2b
|
Provenance
The following attestation bundles were made for procurement_decision_api-0.1.1.tar.gz:
Publisher:
publish.yml on mizcausevic-dev/procurement-decision-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
procurement_decision_api-0.1.1.tar.gz -
Subject digest:
23ba3e358a31b2a4c045f16e5076597a9bd028f0b44c85247b645688b99dcf75 - Sigstore transparency entry: 1549195649
- Sigstore integration time:
-
Permalink:
mizcausevic-dev/procurement-decision-api@7e7240a1a7b207a52d43868f4657c503ed5b5dcd -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/mizcausevic-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e7240a1a7b207a52d43868f4657c503ed5b5dcd -
Trigger Event:
push
-
Statement type:
File details
Details for the file procurement_decision_api-0.1.1-py3-none-any.whl.
File metadata
- Download URL: procurement_decision_api-0.1.1-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c66d3106c9ae64f1e2ed6d1bb4ad91334dd67dea7e0060e4478440a49196510
|
|
| MD5 |
a5bd1e44d09c0c11938265236023ef30
|
|
| BLAKE2b-256 |
002dc9d74a6f3924a3174612ec224bbfac796f62fdaa3be3d174eb81e5f928b2
|
Provenance
The following attestation bundles were made for procurement_decision_api-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on mizcausevic-dev/procurement-decision-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
procurement_decision_api-0.1.1-py3-none-any.whl -
Subject digest:
8c66d3106c9ae64f1e2ed6d1bb4ad91334dd67dea7e0060e4478440a49196510 - Sigstore transparency entry: 1549195724
- Sigstore integration time:
-
Permalink:
mizcausevic-dev/procurement-decision-api@7e7240a1a7b207a52d43868f4657c503ed5b5dcd -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/mizcausevic-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e7240a1a7b207a52d43868f4657c503ed5b5dcd -
Trigger Event:
push
-
Statement type: