Every render carries its receipt. Every receipt is verifiable.
Indago does not ask you to trust it. It journals every render and every emit as a chained SHA-256 event you can replay. indago_journal(op=verify) walks the chain in milliseconds and returns either intact:true with a head_hash, or pinpoints the seq where the chain was tampered.
SHA-256, append-only, local.
Each journal record carries: seq, ts, event_type, a typed payload, the prev_hash of the prior record, and its own hash over the canonical JSON of all of the above. The file is append-only. op=head returns the current head. op=verify walks from seq=1 forward and recomputes every link.
Every render is a typed event.
Inputs in. HTML out. Both hashed.
Every call to indago_report appends a report.rendered event. Payload includes template, the typed payload's matrix_sha256 (or chart_matrix_shas[] / package_sha256 / etc.), and the SHA-256 of the rendered HTML.
Every claim chained.
Every call to indago_finding_emit appends a finding.emitted event with the finding_sha256 chained to the prior render. The emit is rejected if evidence_chunk_id doesn't resolve in the index — the anti-fabrication rail.
One call, full replay.
indago_journal(op=verify) walks every record, recomputes the chain, returns intact:true · records_verified:N · head_hash:<hex>. If a record was edited, returns tampered_at_seq:<n> · expected:<hex> · actual:<hex>.
No citation without a resolvable chunk.
indago_finding_emit(evidence_chunk_id=…) rejects with HTTP 422 if the chunk id doesn't resolve in the current index. qa-with-citations rewrites inline [chunk_id] markers in the answer body into clickable chips that scroll to the matching evidence row — readers can verify each load-bearing sentence in one click. Hallucinated citations are not just discouraged; they are blocked at the API boundary.
Same query, same answer.
Every API response carries a _provenance envelope:
Re-run with the same engine, the same git sha and the same index state — you'll get the same hit set, ranked the same way. If any of those three drift, the response advertises it; you choose whether to rerun or to accept the drift with a recorded diff.
Drops into the binder.
The validation-binder renderer (Pro tier) bundles journal segments, render events, finding events and chunk-resolved evidence into a control-framework-shaped HTML+PDF artifact. The binder accepts any control-framework label the customer chooses — these are renderer labels on the binder, not separate registered scan plugins. The receipts are the same; the framing changes per artifact. Reference mappings we document out of the box:
- 21 CFR Part 11 — electronic records / electronic signatures (ALCOA+). Framework label.
- SOC 2 — CC7/CC8 (change-management, audit trail). Framework label.
- ISO 27001 / 27002 — A.5/A.8/A.12 (information integrity, logging). Framework label.
- NIS2 · GDPR Art. 32 — integrity, traceability of processing. Framework label; the registered GDPR clause-scan is
compliance.law.missing-clause-gdpr. - GxP · GLP — investigator-facing reproducibility binder. Framework label.
The control framework is the customer's decision; Indago supplies the receipts. Registered compliance scans today: compliance.law.missing-clause-gdpr, compliance.law.missing-clause-hipaa, compliance.law.missing-clause-sox, compliance.law.outdated-reference.eu.law. Other frameworks listed above are binder-renderer labels with chunk-resolved evidence — not separate scan engines.
In one paragraph.
Renders are journaled with the SHA-256 of their typed payloads and rendered HTML. Findings are emitted with chunk-id-resolution gates and chained finding_sha256. The journal is append-only and locally verifiable with op=verify. Every API response carries an engine_version + git_sha + index_state_hash envelope. The customer can replay any deliverable end-to-end without trusting the vendor.