Decision Provenance Record
Specification v0.1
Abstract
This specification defines two interoperable data structures for cryptographically verifiable AI decision evidence: the Decision Provenance Record (DPR v0.1) — a signed, tamper-evident record of a single AI-driven consequential decision — and the EvidenceChain v1 — a hash-linked, append-only sequence of agent action records.
These structures satisfy the evidentiary requirements of ECOA / Regulation B §1002.9, US Treasury AI Risk Management Framework (March 2026), DORA Article 8(1), EU AI Act Article 12, Colorado AI Act SB 24-205 §6, and DIFC Regulation 10.
For counsel and examiners: A GateFrame DPR is not a log file. It is a signed record — produced at the exact moment of decision, cryptographically sealed, tamper-evident by construction. Any modification to any field after signing is cryptographically detectable. Verification is independent: the examiner calls GET /dpr/{id}/verify without trusting GateFrame's servers.
1. Cryptographic Primitives
Algorithms
All signatures use Ed25519 (RFC 8032). All hashes use SHA-256 (FIPS 180-4). All hash chains use binary Merkle tree construction. All binary encodings use lowercase hexadecimal.
Canonical Serialization
Before signing or hashing, a record MUST be serialized as UTF-8 encoded JSON with keys sorted lexicographically, no whitespace, and these fields excluded: signature, record_hash, merkle_position.
canonical = json.dumps(
{k: v for k, v in record.items()
if k not in ("signature", "record_hash", "merkle_position")},
sort_keys=True,
separators=(",", ":"),
default=str
).encode("utf-8")
Record Hash
record_hash = SHA-256(canonical_bytes).hex() # 64-char hex string
Signature
signature = Ed25519_Sign(private_key, bytes.fromhex(record_hash)).hex() # 128-char hex
Chain Link
First record: prev_hash = null. Subsequent records: prev_hash = record_hash of previous record.
2. Decision Provenance Record (DPR v0.1)
Schema
| Field | Type | Description |
|---|---|---|
| decision_id | string (UUID v4) | Unique identifier for this decision record |
| dpr_version | "0.1" | Specification version. Embedded in every record. |
| created_at | ISO 8601 UTC | Timestamp at moment of decision, not post-hoc |
| decision | deny | approve | approve_with_conditions | refer | The AI decision |
| decision_confidence | float [0,1] | Model confidence score |
| model_id | string | Identifier of the AI model that produced the decision |
| model_version | string | Model version at time of decision |
| algorithm_type | string | Algorithm family (e.g. GradientBoostedTree) |
| authorized_by | string | Role or identifier who authorized the model deployment |
| authorized_at | ISO 8601 UTC | When the model deployment was authorized |
| policy_version | string | Version of the reason code library applied |
| model_operator_id | string | Identifier of the model operator (may differ from lender) |
| executing_institution_id | string | Institution that issued the adverse action |
| delegation_present | boolean | True when model operator ≠ executing institution |
| adverse_action_reasons | array | Ranked Reg B reason codes (see §2.2) |
| application_id | string | Applicant's application reference |
| input_hash | SHA-256 hex | Hash of the input SHAP values and applicant context |
| reg_b_compliant | boolean | Whether reason codes satisfy §1002.9(b)(2) |
| record_hash | SHA-256 hex (64 chars) | Hash of the canonical DPR content |
| signature | Ed25519 hex (128 chars) | Signature over record_hash bytes |
Adverse Action Reason Object
| Field | Type | Description |
|---|---|---|
| rank | integer 1–4 | Ranking by SHAP weight (1 = highest adverse impact) |
| reg_b_code | string | Official Reg B Appendix C reason code number |
| gateframe_code_id | string (GF-XXX) | GateFrame internal code identifier |
| consumer_text | string | Required consumer-facing reason text (§1002.9(b)(2)) |
| examiner_description | string | Technical description for examiner review |
| reg_b_citation | string | Full regulatory citation |
| shap_feature | string | SHAP feature name that mapped to this reason code |
| shap_weight | float | SHAP feature importance weight |
3. EvidenceChain v1
An EvidenceChain is an ordered, hash-linked sequence of AgentAction records. Each record includes the SHA-256 hash of the previous record, creating a chain where tampering with any record invalidates every subsequent record.
Chain Verification
For each record at index i, a verifier MUST assert:
- Hash integrity:
SHA-256(canonical(record)) == record.record_hash - Chain link: if
i > 0, thenrecord.prev_hash == records[i-1].record_hash - Signature:
Ed25519_Verify(public_key, record.record_hash, record.signature) == True
The chain is valid if and only if all three assertions pass for every record.
4. Regulatory Mapping
| Framework | Key DPR Fields | Requirement Satisfied |
|---|---|---|
| ECOA / Reg B | adverse_action_reasons, authorized_by, delegation_present | §1002.9(b)(2) specific reason codes, authority chain |
| US Treasury AI RMF | record_hash, signature, model_id | Control 4.2 — tamper-evident AI decision records |
| DORA Art. 8(1) | prev_hash, chain verification, authorized_by | ICT risk documentation, independent verifiability |
| EU AI Act Art. 12 | dpr_version, created_at, model_id | High-risk AI system record-keeping |
| Colorado AI Act §6 | adverse_action_reasons, decision, reg_b_compliant | Algorithmic decision disclosure |
| DIFC Reg 10 | Full DPR + chain verification endpoint | AI governance documentation for DFSA examination |
5. Verification Protocol
Online Verification (Recommended for Examiners)
Two endpoints available. Use the DPR registry for individual decisions; use the chain endpoint for ExaminerPack bundles.
GET https://gateframe-api.netlify.app/dpr/{decision_id}/verify
Response:
{
"valid": true,
"hash_verified": true,
"signature_present": true,
"decision_id": "...",
"record_hash": "...",
"regulatory_basis": ["US Treasury AI RMF Control 4.2", "Reg B §1002.9", "DORA Art. 8(1)"]
}
Chain verification (ExaminerPack)
POST https://gateframe-api.netlify.app/agentseal/chain/verify · /sign/batch
X-API-Key: gf-demo-key-2026
Content-Type: application/json
{ "chain_export": <ExaminerPack JSON from export.py or /evidence-pack> }
Response:
{
"valid": true,
"action_count": 3,
"verified_at": "2026-04-24T10:00:00Z",
"broken_at": null,
"signer_key_fingerprint": "a3f9c2e1b4d80012",
"chain_hash_root": "e3b0c44298fc1c14...",
"verification_log": [
{"seq": 0, "hash_valid": true, "sig_valid": true, "link_valid": true},
{"seq": 1, "hash_valid": true, "sig_valid": true, "link_valid": true},
{"seq": 2, "hash_valid": true, "sig_valid": true, "link_valid": true}
]
}
Offline Verification (No GateFrame Server Trust Required)
Obtain the public key from GET /agentseal/health. Then:
1. Reconstruct canonical JSON (sort keys, no whitespace, exclude signature/record_hash) 2. derived_hash = SHA-256(canonical_bytes).hex() 3. Assert derived_hash == record.record_hash 4. Assert Ed25519_Verify(public_key, bytes.fromhex(record_hash), bytes.fromhex(signature))
Trust model: GateFrame is the notary, not the author. The institution's General Counsel authors the reason code library. GateFrame signs the application of that library to a specific decision. Liability for the reason text remains with counsel — GateFrame provides the signing infrastructure and independent verifiability.
6. API Authentication
Authentication Scheme
All API endpoints (except /, /health, /agentseal/health) require an X-API-Key header.
curl -H "X-API-Key: gf-demo-key-2026" \
https://gateframe-api.netlify.app/validate/
| Key Type | Access | Rate Limit |
|---|---|---|
Demo key: gf-demo-key-2026 | All endpoints, evaluation only | 100 req/day per IP |
| Pilot key (per institution) | Full access, audit logging | Negotiated per pilot SLA |
Pilot keys: contact shankar@gateframe.io. Keys are institution-scoped and logged for audit purposes.
7. Security & Data Handling
Data Processing
- SHAP values and decision records are processed in AWS Lambda (us-east-1). No data is retained beyond the request unless explicitly stored via
POST /dpr/. - DPR records stored via the registry endpoint are persisted in SQLite on the Lambda instance. Records are not transmitted to third parties.
- No PII is required by any GateFrame endpoint. Application IDs are client-generated references; GateFrame does not process applicant personal data.
- The Ed25519 signing key is stored as an encrypted environment variable in AWS Lambda. It is never logged or transmitted.
Uptime & SLA (Pilot)
- Target availability: 99.5% during pilot period
- Response time: Sub-200ms for all signing operations (p95)
- Support: Email response within 24 business hours during pilot
- Production SLA: Negotiated per enterprise contract. SOC 2 Type I in progress (Month 2).
Note on SQLite in Lambda: The current DPR registry uses SQLite in /tmp — ephemeral storage that resets on cold starts. For production pilots, DPR persistence will be migrated to a managed PostgreSQL instance. This migration is scheduled for Month 2 of the funded sprint.
8. Reference Implementation
| Resource | URL |
|---|---|
| Live API | gateframe-api.netlify.app/docs |
| SDK | pip install agentseal |
| Tamper proof demo | gateframe-demo.netlify.app/tamper |
| Evidence pack preview | gateframe-demo.netlify.app/evidence-pack |
| Verification portal | gateframe-verification.netlify.app |
| Chain verify endpoint | POST https://gateframe-api.netlify.app/agentseal/chain/verify · /sign/batch — accepts full ExaminerPack JSON, returns per-record verification log |
| Spec (this page) | dpr-spec.netlify.app |
9. Conformance
An implementation is conformant with this specification if:
- Records produced by the implementation pass the verification protocol in §5
- The canonical serialization in §1 is followed exactly
- The
dpr_versionfield is present and set to"0.1"in every record - Every record includes
record_hash(SHA-256, 64-char hex) andsignature(Ed25519, 128-char hex)
GateFrame Inc. · shankar@gateframe.io · gateframe.io
Apache 2.0 License — specification only. Reference implementation is proprietary.
Priority date: April 22, 2026 · Version: DPR v0.1 · EvidenceChain v1