AISOURCEOFTRUTH.COM
OPENSPEC PLAN · FOR YOUR CODING AGENT

Trace an incident to the prompt

Your agent writes these files into openspec/changes/integrate-aisot-incident-records/ in your repo, runs openspec validate integrate-aisot-incident-records, and works the task list. The setup guide explains each step for people.

language: http · python · typescript   with: CommitOps · RepoOps

OPENSPEC/CHANGES/INTEGRATE-AISOT-INCIDENT-RECORDS/PROPOSAL.MD
# Proposal: Trace an incident to the prompt

## Why
After an outage, the account of what caused it shifts as people revise notes. An incident record fixes what was known and when, and links the cause to the agent session and prompt behind it.

## What Changes
- The incident bundle stays private; its hash becomes the record's artifact.
- `incident` carries id, time, title and severity. `attribution` carries commit, PR, session, prompt hash and model.
- Find it by incident id later.


## Capabilities
### New Capabilities
- `incident-records`: An incident record naming the commit, PR, session and prompt hash, fixed before the story changes.

## 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}`.
- No PromptReports product is required.
- Source of this plan: https://aisourceoftruth.com/use-cases/incident-to-prompt (CC0). Regenerate it with `curl -H 'Accept: application/json' 'https://aisourceoftruth.com/use-cases/incident-to-prompt/openspec?lang=python'`.
OPENSPEC/CHANGES/INTEGRATE-AISOT-INCIDENT-RECORDS/DESIGN.MD
# Design: Trace an incident to the prompt

## Context
Engineering platforms, SRE teams and coding-agent vendors. After an outage, the account of what caused it shifts as people revise notes. An incident record fixes what was known and when, and links the cause to the agent session and prompt behind it.

## Where it sits in your agent
Publish from the incident tool when the incident is declared, then again with attribution when the cause is known. Both records stay.

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`.

## 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()
```

## What this does not prove
- Attribution is your statement. The record fixes when you made it, not that it is right.
OPENSPEC/CHANGES/INTEGRATE-AISOT-INCIDENT-RECORDS/TASKS.MD
# Tasks: Trace an incident to the prompt

## 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 Publish the incident: Post an incident record: `incident: { id, occurred_at, severity }` and `attribution: { commit, pr_ref, session_id, prompt_hash, model }`. `developer` is a handle or hash, never personal data. (`POST /v1/records`)
- [ ] 2.2 Link the cause: Put the PR's provenance record digest in `lineage`, so the incident sits downstream of the change that caused it. (`POST /v1/records`)
- [ ] 2.3 Find it later: Query by incident id. (`GET /v1/records?ref={ref}`)

## 3. Verify against the live registry
- [ ] 3.1 Publish the incident: The record is findable by the incident id.
- [ ] 3.2 Link the cause: The PR record's lineage lists the incident.
- [ ] 3.3 Find it later: Every record for the incident comes back.

## 4. Done when
- [ ] 4.1 Each incident has a fixed public timeline and a link to its cause.
OPENSPEC/CHANGES/INTEGRATE-AISOT-INCIDENT-RECORDS/SPECS/INCIDENT-RECORDS/SPEC.MD
# incident-records Specification

## ADDED Requirements

### Requirement: Incidents are recorded
The incident tool SHALL publish an incident record when an incident is declared and SHALL publish attribution when the cause is known.

#### Scenario: Cause found
- **WHEN** the cause of an incident is identified
- **THEN** a record with the attribution block is published and linked to the causing change
$ curl -H 'Accept: application/json' https://aisourceoftruth.com/use-cases/incident-to-prompt/openspec?lang=python # this page is a rendering of the API. Reproduce it as data.