Evidence an investigator can take to court
Your agent writes these files into openspec/changes/integrate-aisot-evidence-records/ in your repo, runs openspec validate integrate-aisot-evidence-records, and works the task list. The setup guide explains each step for people.
language: http · python · typescript with: none fits this use case
OPENSPEC/CHANGES/INTEGRATE-AISOT-EVIDENCE-RECORDS/PROPOSAL.MD
# Proposal: Evidence an investigator can take to court
## Why
Screenshots and exports are easy to challenge. Recording each item by hash as it is collected fixes when it existed, and an amend-only chain shows every later change.
## What Changes
- Each evidence item gets an evidence record with `case_id` and `item_id`, by hash only.
- An amendment is a new record whose `amends` names the earlier one.
- The case exports as a bundle with proofs and timestamps.
## Capabilities
### New Capabilities
- `evidence-records`: Hash-only evidence records for cases such as prediction-market fraud, amendments that point back, and an export with proofs and timestamps.
## Impact
- External service: AI Source of Truth at https://aisourceoftruth.com. Reads are anonymous. Writes need a publisher key pair you generate, a client id and secret from registration, and a token from `/oauth/token`.
- Routes used: `POST /v1/records`, `GET /v1/records?ref={ref}`, `POST /v1/export`.
- No PromptReports product is required.
- Source of this plan: https://aisourceoftruth.com/use-cases/evidence-for-court (CC0). Regenerate it with `curl -H 'Accept: application/json' 'https://aisourceoftruth.com/use-cases/evidence-for-court/openspec?lang=python'`.
OPENSPEC/CHANGES/INTEGRATE-AISOT-EVIDENCE-RECORDS/DESIGN.MD
# Design: Evidence an investigator can take to court
## Context
Investigators, fraud teams and lawyers, for example in prediction-market fraud cases. Screenshots and exports are easy to challenge. Recording each item by hash as it is collected fixes when it existed, and an amend-only chain shows every later change.
## Where it sits in your agent
Publish from the capture tool, so an item cannot enter the case folder without a record.
Over MCP, point the agent at `https://aisourceoftruth.com/mcp` (Streamable HTTP, JSON-RPC 2.0; read tools need no token). The tools this change uses: `publish_record`, `search_records`, `export_bundle`.
## Decisions
- Treat the registry as a source of facts about records, never about the world. Show what it says, with the digest, and do not turn a verdict into a quality score.
- If the registry cannot be reached, treat the answer as unknown (the same as `check`), never as `rely`, and retry later.
- Keep content private: send hashes. Never put personal data in a record; it is public and permanent.
- Keep the private key and client secret in your secret store. Rotate keys at `POST /v1/keys`; a revoked key cannot sign.
## Setup and signing helper
```python
# pip install requests cryptography
import base64, json, os, uuid
import requests
from cryptography.hazmat.primitives.serialization import load_pem_private_key
AISOT = os.environ.get("AISOT_ORIGIN", "https://aisourceoftruth.com")
KEY = load_pem_private_key(open(os.environ["AISOT_KEY_PEM"], "rb").read(), password=None) # Ed25519
def token():
r = requests.post(f"{AISOT}/oauth/token", json={
"grant_type": "client_credentials",
"client_id": os.environ["AISOT_CLIENT_ID"],
"client_secret": os.environ["AISOT_CLIENT_SECRET"],
})
r.raise_for_status()
return r.json()["access_token"] # lasts 60 minutes
def signed_post(path, body, content_type="application/json", token=token):
raw = json.dumps(body, separators=(",", ":")).encode()
sig = base64.urlsafe_b64encode(KEY.sign(raw)).rstrip(b"=").decode()
headers = {"Content-Type": content_type, "X-AISOT-Signature": sig, "Idempotency-Key": str(uuid.uuid4())}
if token:
headers["Authorization"] = f"Bearer {token()}"
headers["X-AISOT-Key-Id"] = os.environ["AISOT_KEY_ID"]
r = requests.post(f"{AISOT}{path}", data=raw, headers=headers)
r.raise_for_status()
return r.json()
```
## Calls
### POST /v1/records
append a signed record; the answer carries its digest and inclusion proof.
```python
answer = signed_post("/v1/records", record, content_type="application/vnd.aisot.record+json")
```
### GET /v1/records?ref={ref}
every record carrying a handle such as a PR, incident or case id.
```python
r = requests.get(f"{AISOT}/v1/records?ref={ref}", headers={"Accept": "application/json"})
r.raise_for_status()
answer = r.json()
```
### POST /v1/export
an offline bundle with proofs and timestamps for up to 100 records.
```python
r = requests.post(f"{AISOT}/v1/export", json={"digests":["{digest}"]})
r.raise_for_status()
answer = r.json()
```
## What this does not prove
- Records prove existence and order, not what the evidence means or that it is admissible.
OPENSPEC/CHANGES/INTEGRATE-AISOT-EVIDENCE-RECORDS/TASKS.MD
# Tasks: Evidence an investigator can take to court
## 1. Configure
- [ ] 1.1 Set `AISOT_ORIGIN=https://aisourceoftruth.com` in the agent's environment.
- [ ] 1.2 Generate an Ed25519 key pair, register the publisher (`POST /v1/publishers`), and store `AISOT_CLIENT_ID`, `AISOT_CLIENT_SECRET`, `AISOT_KEY_ID` and the private key as secrets.
- [ ] 1.3 Mint a token at `/oauth/token` and confirm `GET /v1/me` answers with your publisher id.
- [ ] 1.4 Optional: add the MCP server `https://aisourceoftruth.com/mcp` to the agent's MCP config.
## 2. Build
- [ ] 2.1 Record on capture: Hash each item when captured and publish an evidence record: `evidence: { case_id, item_id, kind, captured_at }`. Content stays with you. (`POST /v1/records`)
- [ ] 2.2 Amend, never edit: For a corrected item, publish a new record with `amends` naming the old record. (`POST /v1/records`)
- [ ] 2.3 List the case: List every record for the case by its case id. (`GET /v1/records?ref={ref}`)
- [ ] 2.4 Export: Export the case for a regulator or a court. (`POST /v1/export`)
## 3. Verify against the live registry
- [ ] 3.1 Record on capture: Each captured item has a record.
- [ ] 3.2 Amend, never edit: The case chain shows the amendment linked to the original.
- [ ] 3.3 List the case: The count matches your evidence log.
- [ ] 3.4 Export: The bundle verifies offline.
## 4. Done when
- [ ] 4.1 Every item has a fixed capture time and an unbroken amendment chain.
OPENSPEC/CHANGES/INTEGRATE-AISOT-EVIDENCE-RECORDS/SPECS/EVIDENCE-RECORDS/SPEC.MD
# evidence-records Specification ## ADDED Requirements ### Requirement: Items are recorded on capture The capture tool SHALL publish a hashes-only evidence record for each item when it is captured. #### Scenario: Capture - **WHEN** an item is captured - **THEN** an evidence record with its case id exists ### Requirement: Amend only A change to an item SHALL be a new record with `amends`, never a replacement. #### Scenario: Correction - **WHEN** an item is corrected - **THEN** a new record amends the original and both stay listed
$ curl -H 'Accept: application/json' https://aisourceoftruth.com/use-cases/evidence-for-court/openspec?lang=python # this page is a rendering of the API. Reproduce it as data.