Build with the local Soterias SDK. Get started with Python and TypeScript.
SoteriasDocsBuild
Workflows

Evidence and protected reads

This continuation belongs to build Tasks29–30, covering original features41 and14. It is a native Rust component with Python/TypeScript helpers and a constrained MCP quotation tool. Full Tasks29–30 and production acceptance remain open. This page describes the matching evidence pilot: Python0.1.4, native0.1.0rc5 and TypeScript/MCP0.1.0-rc.5.

The immediately runnable full programs are workflow.py and workflow.mjs. types.mts additionally checks the actual public TypeScript signatures. Install the matching binary SDK, then download the programs linked above:

Terminal
python -m pip install "soterias==0.1.4"
npm install @soterias/core@0.1.0-rc.5

Run:

Terminal
python workflow.py
node workflow.mjs

Each creates a fresh temporary directory by default. An optional first argument selects a new host-owned directory. Neither command contacts Gmail, an LLM or a cloud account. They write synthetic invoice bytes, encrypted retained sources, actual SQLite records and an explicit checkpoint, and preserve those files for inspection. The disposable example passphrase is public fixture material. Production operators supply their own protected unlock and keep the checkpoint independently from the mutable evidence directory; the adjacent checkpoint in this example is not rollback protection against its owner.

Expected final JSON includes status: "PASS", semantic_truth: "not_established", model_calls: 0, provider_tokens: null, a quotation proof, the measured program elapsed time and its retained directory. Zero model calls describes these programs, not estimated calls or tokens saved. Python and Node's pure_check objects must match exactly. Encrypted-store identities and whole program elapsed times may differ. Debug native modules are not performance benchmarks or final package acceptance.

Python usage

Python
from soterias import SourceStore, Citation

# This code runs in the trusted host, outside the agent's context.
store = SourceStore.create("new-private-evidence", passphrase=host_unlock,
                           tenant_id="engagement-42", store_id="sources")
source = store.ingest_file("approved-invoice.txt", media="utf8_text",
                           permitted_uses=["transaction-testing"])
evidence = store.evidence(principal="assigned-auditor", purpose="transaction-testing")
evidence.register_source(source, identity="invoice-42", revision="v1",
                         readers=["assigned-auditor"],
                         stale_after_ms=host_expiry, retain_until_ms=host_retention)
save_independent_checkpoint(store.checkpoint())

# Offsets are explicit original Unicode scalar positions, end exclusive.
citation = Citation(source, start=35, end=45, quote="120.00 EUR")
result = evidence.verify(citation)
fact = evidence.extract_quote(citation)
save_independent_checkpoint(store.checkpoint())
checked = evidence.check_fact(fact)

# Interpretations remain candidates. Model confidence cannot grant trust.
interpretation = evidence.extract_interpretation(
    "The transaction is valid", citations=[citation],
    uncertainty=["purchase-order-not-yet-corroborated"],
)
save_independent_checkpoint(store.checkpoint())
evidence.revoke_source(source)  # Only the original profile publisher may revoke.
save_independent_checkpoint(store.checkpoint())
store.close()

This shorter extract uses application-owned unlock, retention, source selection and checkpoint storage. Those are integration inputs, not functions implemented by the SDK. Run the linked full program for a self-contained working version.

TypeScript usage

TypeScript
import {SourceStore, Citation} from '@soterias/core';

const store = SourceStore.create({directory: 'new-private-evidence',
  passphrase: hostUnlock, tenantId: 'engagement-42', storeId: 'sources'});
const source = store.ingestFile('approved-invoice.txt', {
  media: 'utf8_text', permittedUses: ['transaction-testing'],
});
const evidence = store.evidence({principal: 'assigned-auditor', purpose: 'transaction-testing'});
evidence.registerSource(source, {identity: 'invoice-42', revision: 'v1',
  readers: ['assigned-auditor'], staleAfterMs: hostExpiry, retainUntilMs: hostRetention});
saveIndependentCheckpoint(store.checkpoint());
const citation = new Citation(source, {start: 35n, end: 45n, quote: '120.00 EUR'});
evidence.verify(citation);
const fact = evidence.extractQuote(citation);
saveIndependentCheckpoint(store.checkpoint());
const result = evidence.checkFact(fact);
store.close();

JavaScript string indices count UTF-16 code units. Use Array.from(text).length for Unicode scalar counts or explicitly set unit: 'utf8_byte' and compute with Buffer.byteLength. Neither unit means grapheme clusters. é and e followed by a combining accent differ; CRLF/LF, whitespace, confusables, truncation and split UTF-8 codepoints are never normalized or silently repaired.

What is verified

The original Task29 store already commits exact original SHA256, complete source metadata, encrypted payloads, parser versions and transformation lineage. This continuation adds immutable source profiles and source-version uniqueness, exact readers, effective/freshness/retention bounds and append-only revocations in the same authenticated storage history. Every dependent citation/fact check reloads current pinned state. A revoked ancestor invalidates derived evidence; children cannot widen reader sets or validity/retention bounds. Traversal is bounded to eight generations and128 checks per operation; inputs are bounded to16KiB,16 parent/citation/readers and4096-byte candidate claims.

One (identity, revision) can be registered only once per tenant/store. Each retained SourceRef receives one profile. A later capture/version is ingested as a new source manifest, including its capture time. There is no mutable "latest" alias, silent replacement, source-ID reuse or automatic current-pin discovery. Original storage bytes and existing selector contracts are unchanged.

verify_quote(..., current_file=...) additionally rehashes the whole actual current file. Without current_file, it verifies retained historical bytes. The repository's freshness interval is an independently declared host policy; it does not inspect the current external file or establish external truth. SourceStore.check_quote / checkQuote compare only caller-owned bytes and say so in the returned report. They are useful after an admitted read, but do not authenticate that read or replace its original signed receipts.

extract_quote accepts only a literal claim equal to one verified citation. extract_interpretation remains explicitly a model interpretation. Descendants cannot remove their parents' uncertainty or relabel an interpretation as a verbatim quotation. check_fact rechecks every source and parent. A missing fact is unknown; a malformed, forged, inaccessible, stale or revoked proof refuses with a fixed error. A successful report includes the fact commitment, actual storage anchor, principal/use/time, verifier version and deterministic digest. The digest is not a signature. quotation_truth: true means only exact textual provenance. It does not assert that the invoice, transaction, calculation or model's interpretation is financially true. General semantic TrustedFact promotion/corroboration and policy-provider integration remain open.

MCP usage

The existing protected document MCP factory retains its native credential, warrant, policy, scoped approval, one-use broker admission and original receipt checks. Its new read-only verify_protected_quote tool accepts a previously returned request SHA256, relative selection offsets, exact text and unit:

JSON
{"name":"verify_protected_quote","arguments":{
  "inputSha256":"SHA256_FROM_THE_PRIOR_PROTECTED_READ",
  "start":"0","end":"7","quote":"invoice","unit":"unicode_codepoint"
}}

Call execute_protected_operation with your host-prepared signed read request first. The quotation tool checks only this exact credential's retained successful UTF-8 read. It rechecks the credential, compares bytes in Rust and binds its report to the original response SHA256, full source hash and selected byte range. It does not dispatch another read, replay an effect, accept a filesystem path, choose a principal/time, register a source, revoke evidence, mint trust or approve anything. Its report is unsigned historical DATA. Keep and independently verify the original read receipts. A new read requires fresh broker admission.

Accounting use and remaining boundaries

Workflow Evidence use Separate required verifier/action
Transaction testing Retain the scoped invoice/PO versions and cite exact amounts, dates and transaction IDs. Revocation/freshness invalidate dependent candidate facts. Corroborate the records under an explicit rule; dispatch only broker-authorized reads and separately approved workpaper changes.
Recalculation Retain the exact source rate, cost, useful life and calculation period with units and unresolved interpretation. Run independently tested decimal/date calculations; retain calculation provenance and independently verify the result. A quote match does not verify arithmetic.
Control testing Cite the exact control description, sampled evidence and exception wording for the assigned engagement. Test the actual operating control; keep exceptions uncertain until reviewed; approve only the relevant broker-bound workpaper action.

SourceStore and EvidenceRepository are privileged cooperative host APIs. The host authenticates principal, purpose and clock; caller labels are not an authentication mechanism. Code holding the owner/key can use the lower-level source APIs. Do not expose this owner, passphrase or profile operations to an untrusted agent. The opt-in UTF-8 broker route holds an OS disclosure lease across admission and dispatch, checks the exact request principal against live source and ancestor permissions/revocation, and rechecks freshness at dispatch. Revocation returns evidence_source_busy while a read lease is outstanding; after revocation commits, later reads refuse, including unused signed approvals. Binary routes reject this binding explicitly. Arbitrary agent OS isolation, logical PDF text/page/OCR mapping, semantic promotion, complete platform packaging, independent audit and full release gates remain separate requirements.

Trusted host setup binds the same source owner on the executor and separate reviewer before preparing/reviewing the operation:

Python
executor.configure_document_evidence(tool_id="accounting.lookup", action="lookup",
                                     store=store, source=source)
reviewer.configure_document_evidence(tool_id="accounting.lookup", action="lookup",
                                     store=store, source=source)

The TypeScript equivalents are configureDocumentEvidence({toolId, action, store, source}). MCP trusted construction accepts evidenceBindings: [{toolId, action, store, source}] in openDocumentMcpFactory / listenDocumentHttp options. These are host configuration, never tool arguments. Bind explicitly after each reopen and retain the source owner until the executor/reviewer closes. Existing ordinary v4 routes retain their previous scope and do not implicitly claim this evidence enforcement. Setup fails closed for missing/duplicate routes, unsupported binary bindings or an already enabled outcome-verification profile. Source profiles, checkpoint custody and the enclosing authenticated broker remain trusted deployment configuration; the SDK does not sandbox its owning host.

Implementation: Rust repository, quotation verifier, native lifecycle tests, and legacy comparison.

Full Python program

Python
"""Actual local encrypted evidence lifecycle; no model or external account required."""
from __future__ import annotations
import json
import os
from pathlib import Path
import sys
import tempfile
import time
from soterias import Citation, FactReference, SourceStore, SourceStoreError


def main() -> None:
    started = time.perf_counter_ns()
    root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(tempfile.mkdtemp(prefix="soterias-evidence-"))
    root.mkdir(parents=True, exist_ok=True)
    original = root / "invoice.txt"
    text = "Invoice INV-42: café 😀; amount 120.00 EUR.\n"
    original.write_bytes(text.encode("utf-8"))
    # Disposable local example secret, deliberately not a production credential.
    unlock = b"disposable-local-evidence-example"
    store = SourceStore.create(root / "store", passphrase=unlock, tenant_id="demo", store_id="audit")
    now = time.time_ns() // 1_000_000
    source = store.ingest_file(original, media="utf8_text", permitted_uses=["transaction-testing"], captured_at_ms=now)
    # Production hosts protect the checkpoint independently from the store itself.
    checkpoint_path = root / "checkpoint.json"
    checkpoint_path.write_bytes(store.checkpoint())
    evidence = store.evidence(principal="auditor", purpose="transaction-testing")
    evidence.register_source(source, identity="invoice-42", revision="v1", readers=["auditor"],
                             stale_after_ms=now + 60_000, retain_until_ms=now + 120_000)
    checkpoint_path.write_bytes(store.checkpoint())
    quoted = "120.00 EUR"
    start = text.index(quoted)  # Python Unicode scalar indices, not UTF-8 bytes.
    citation = Citation(source, start=start, end=start + len(quoted), quote=quoted)
    assert evidence.verify(citation)["status"] == "verified"
    proof = store.verify_quote(source, purpose="transaction-testing", start=start,
                               end=start + len(quoted), quote=quoted, current_file=original)
    literal = evidence.extract_quote(citation)
    (root / "fact-id.txt").write_text(literal.digest, encoding="ascii")
    checkpoint_path.write_bytes(store.checkpoint())
    checked = evidence.check_fact(literal)
    assert checked["report"]["quotation_truth"] == "true"
    assert checked["report"]["semantic_truth"] == "not_established"
    interpretation = evidence.extract_interpretation("The transaction is valid", citations=[citation])
    checkpoint_path.write_bytes(store.checkpoint())
    assert evidence.check_fact(interpretation)["report"]["quotation_truth"] == "unknown"
    assert evidence.check_fact(FactReference("0" * 64))["truth"] == "unknown"
    try:
        store.evidence(principal="other-agent", purpose="transaction-testing").verify(citation)
    except SourceStoreError as error:
        assert error.code == "evidence_use_denied"
    else:
        raise AssertionError("reader permission was not enforced")
    original.write_bytes((text + "changed outside quote\n").encode("utf-8"))
    try:
        store.verify_quote(source, purpose="transaction-testing", start=start,
                           end=start + len(quoted), quote=quoted, current_file=original)
    except SourceStoreError as error:
        assert error.code == "evidence_original_changed"
    else:
        raise AssertionError("whole-current-source mutation was not refused")
    # Historical provenance remains explicit and does not assert a current original.
    assert evidence.verify(citation)["status"] == "verified"
    store.close()
    with SourceStore.open(root / "store", passphrase=unlock, checkpoint=checkpoint_path.read_bytes()) as reopened:
        evidence = reopened.evidence(principal="auditor", purpose="transaction-testing")
        assert evidence.check_fact(literal)["report"]["quotation_truth"] == "true"
        evidence.revoke_source(source)
        checkpoint_path.write_bytes(reopened.checkpoint())
        try:
            evidence.check_fact(literal)
        except SourceStoreError as error:
            assert error.code == "evidence_source_revoked"
        else:
            raise AssertionError("revocation did not invalidate dependent fact")
    pure = SourceStore.check_quote(text.encode("utf-8"), start=start, end=start + len(quoted), quote=quoted)
    print(json.dumps({"status": "PASS", "runtime": "python", "mode": "cooperative_host_integrity",
                      "quotation_proof": proof["digest"], "pure_check": pure,
                      "elapsed_ms": (time.perf_counter_ns() - started) / 1_000_000,
                      "model_calls": 0, "provider_tokens": None,
                      "semantic_truth": "not_established", "root": os.fspath(root)}))


if __name__ == "__main__":
    main()

Full JavaScript program

JavaScript
// Actual native source/SQLite lifecycle. No external provider or model is invoked.
import assert from 'node:assert/strict';
import {mkdirSync,mkdtempSync,writeFileSync,readFileSync} from 'node:fs';
import {join} from 'node:path';
import {tmpdir} from 'node:os';
import {performance} from 'node:perf_hooks';
import {Citation,FactReference,SourceStore} from '@soterias/core';

const started=performance.now(),root=process.argv[2]??mkdtempSync(join(tmpdir(),'soterias-evidence-'));
mkdirSync(root,{recursive:true});
const original=join(root,'invoice.txt'),text='Invoice INV-42: café 😀; amount 120.00 EUR.\n';
writeFileSync(original,text);
const unlock=Buffer.from('disposable-local-evidence-example');
const store=SourceStore.create({directory:join(root,'store'),passphrase:unlock,tenantId:'demo',storeId:'audit'});
const now=Date.now(),source=store.ingestFile(original,{media:'utf8_text',permittedUses:['transaction-testing'],capturedAtMs:now});
const checkpoint=join(root,'checkpoint.json');writeFileSync(checkpoint,store.checkpoint());
let evidence=store.evidence({principal:'auditor',purpose:'transaction-testing'});
evidence.registerSource(source,{identity:'invoice-42',revision:'v1',readers:['auditor'],staleAfterMs:now+60_000,retainUntilMs:now+120_000});
writeFileSync(checkpoint,store.checkpoint());
const quoted='120.00 EUR';
// JS string indices are UTF-16. Explicitly convert to Unicode scalar indices.
const start=Array.from(text.slice(0,text.indexOf(quoted))).length,end=start+Array.from(quoted).length;
const citation=new Citation(source,{start,end,quote:quoted});
assert.equal(evidence.verify(citation).status,'verified');
const proof=store.verifyQuote(source,{purpose:'transaction-testing',start,end,quote:quoted,currentFile:original});
const literal=evidence.extractQuote(citation);writeFileSync(checkpoint,store.checkpoint());
writeFileSync(join(root,'fact-id.txt'),literal.digest);
const checked=evidence.checkFact(literal);
assert.equal(checked.report.quotation_truth,'true');assert.equal(checked.report.semantic_truth,'not_established');
const interpretation=evidence.extractInterpretation('The transaction is valid',{citations:[citation]});
writeFileSync(checkpoint,store.checkpoint());
assert.equal(evidence.checkFact(interpretation).report.quotation_truth,'unknown');
assert.equal(evidence.checkFact(new FactReference('0'.repeat(64))).truth,'unknown');
assert.throws(()=>store.evidence({principal:'other-agent',purpose:'transaction-testing'}).verify(citation),error=>error.code==='evidence_use_denied');
writeFileSync(original,text+'changed outside quote\n');
assert.throws(()=>store.verifyQuote(source,{purpose:'transaction-testing',start,end,quote:quoted,currentFile:original}),error=>error.code==='evidence_original_changed');
assert.equal(evidence.verify(citation).status,'verified');
store.close();
const reopened=SourceStore.open({directory:join(root,'store'),passphrase:unlock,checkpoint:readFileSync(checkpoint)});
try{
  evidence=reopened.evidence({principal:'auditor',purpose:'transaction-testing'});
  assert.equal(evidence.checkFact(literal).report.quotation_truth,'true');
  evidence.revokeSource(source);writeFileSync(checkpoint,reopened.checkpoint());
  assert.throws(()=>evidence.checkFact(literal),error=>error.code==='evidence_source_revoked');
}finally{reopened.close();unlock.fill(0);}
const pure=SourceStore.checkQuote(Buffer.from(text),{start,end,quote:quoted});
console.log(JSON.stringify({status:'PASS',runtime:'node',mode:'cooperative_host_integrity',quotation_proof:proof.digest,pure_check:pure,elapsed_ms:performance.now()-started,model_calls:0,provider_tokens:null,semantic_truth:'not_established',root}));

Typed semantic verification

Exact quotations establish provenance. For a separately host-pinned rule over typed claims and a complete corroborating source set, see Verify facts from multiple sources. These host operations do not automatically consume a signed human approval or produce a signed fact receipt.

Search guides, examples and API reference.