telos-receipt
The canonical unsigned integrity-hash receipt contract for TELOS AI Labs.
One receipt envelope, spoken by both ends of the trust loop:
- telos-mcp mints a receipt when its governance scorer scores an action.
- telos-trust-surface serves and verifies receipts other agents fetch.
Because both import this package, a receipt minted by the scorer verifies on the trust surface unchanged, no translation, no second shape to keep in sync.
Pure stdlib, zero dependencies, offline, key-free.
The envelope
{
"receipt_version": "telos/0.1-unsigned",
"kind": "action_governed",
"agent_id": "...",
"payload": { "...": "..." },
"issued_at": "<iso8601>",
"integrity_hash": "sha256:<hex over canonical payload>",
"covered_fields": "payload (canonical JSON, sort_keys, compact separators)",
"signing_status": "unsigned_integrity_hash",
"signature": null,
"engine": "telos v0.1 (unsigned integrity-hash; no governance engine wired)"
}
Canonical form, stated exactly (independent verifiers MUST match all six or payloads will falsely mismatch): keys sorted, compact separators (, :), NaN/Infinity refused, and ASCII-escaped output (Python json.dumps default ensure_ascii=True: non-ASCII characters serialize as \uXXXX escapes, including UTF-16 surrogate pairs for astral characters). A verifier emitting raw UTF-8 will compute a different hash on any non-ASCII payload. Two further rules govern numbers, because the action receipt carries floats:
- Number formatting. Floats serialize as Python's shortest round-trip
repr(equivalently the ECMAScript Number-to-String algorithm):0.1emits0.1, not0.10000000000000001. A non-Python verifier MUST reproduce that exact formatting or any float-bearing payload will mismatch. - Number type is significant. JSON has a single number type, but this contract preserves the payload's Python type:
1(int) and1.0(float) are distinct inputs producing distinct hashes. A reimplementation that collapses1.0to1cannot reproduce a float-typed hash.build_action_receiptputs floats (composite_score,scores) into the payload, so this rule is load-bearing for action receipts.
Known-answer vectors
Recomputed from this package on CPython 3.11 / 3.12 / 3.14 (byte-identical on all three). Each entry is the exact ASCII-escaped canonical JSON that compute_integrity_hash produces (the string that is UTF-8 encoded and SHA-256'd), followed by the hash it returns. Copy the escaped string verbatim. The second vector is a non-ASCII payload (e + combining accent U+0301, Cyrillic, and an astral emoji), shown as its escaped canonical form because that is what actually gets hashed:
{"action":"wrote_file","path":"demo.txt"}
sha256:acd144a9dc2a2d19c13d1ef5119759ae963c406d7e980b017e00cb163517f692
{"msg":"cafe\u0301 \u043c\u0438\u0440 \ud83d\ude80"}
sha256:f9c77a03300b6507b66feccb530a6e3ed9eb0fe80f27c3a269559de15d0a0911
{"composite_score":0.1,"scores":{"purpose":0.9,"scope":0.8}}
sha256:3d3fbf211d5c93140e5a55713c571544718b1d59c581e19e134a74664b025f54
{"v":1}
sha256:afbf9d0f3560b0fd7795e81c42a0a79ee6b6fc67e064f77826aee642cad28d91
{"v":1.0}
sha256:f3c8be97307d38261061fa08e74365e54a239cddb1d189f3bea18022adbe2f35
The float payload exercises rule 5; the last two vectors differ by number type alone (rule 6).
What the integrity hash does and does not tell you
- Does: confirm the
payloadmatches theintegrity_hashrecorded in the receipt (it detects alteration of the payload relative to that hash). - Does NOT: prove who issued it, when, or that the payload+hash pair was not minted fresh. Anyone can compute the same hash over any payload. Authorship and time need a signature, which this contract does not provide yet.
verify_receipt checks the payload-to-hash binding ONLY. It does not read, trust,
or validate a receipt's signature or signing_status fields; its result always
reports signature_verified: false and the library's own unsigned
signing_status constant, never the receipt's self-declared value.
Going live (no schema break)
Two internals flip; the shape does not move:
- The governance engine flips stub → real (real verdicts/scores in the payload).
- The signer flips null → real:
signatureis filled andsigning_statuschanges. Every field already exists.
API
from telos_receipt import build_receipt, build_action_receipt, verify_receipt
r = build_action_receipt(
action_name="write_file",
action_params={"path": "/tmp/x"},
agent_id="agent-alpha",
verdict="EXECUTE",
composite_score=0.81,
scores={"purpose": 0.9, "scope": 0.8},
pa_id="pa::agent-alpha::v1",
)
assert verify_receipt(r)["match"] is True
Release files for telos-receipt 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| telos_receipt-0.1.0.tar.gz | 12.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| telos_receipt-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.8 kB
Release files / telos_receipt-0.1.0.tar.gz
| Download URL | telos_receipt-0.1.0.tar.gz |
|---|---|
| Size | 12.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
87f1dd537ca36467c3ecc1d89ae3fea4634b5dc9181214d7cbdbedd549a33ed8
|
|
BLAKE2b-256 checksum How to use checksums |
8db6c88b7bf2ada260a5df3bff7055ad97dbb9802f460e09cbb556425abafd57
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|
Release files / telos_receipt-0.1.0-py3-none-any.whl
| Download URL | telos_receipt-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
04463263f6868cdca33f9514aae4de5304a1b7179d2f1cab5654376488707255
|
|
BLAKE2b-256 checksum How to use checksums |
3e5216ce4c6ad10edf385c4774eb7ad4dc6d8545e19f7bb20fb2e16aca2d4fd3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|