Skip to content

Latest commit

 

History

History
2649 lines (2599 loc) · 355 KB

File metadata and controls

2649 lines (2599 loc) · 355 KB
Status FROZEN
Document version 2.0.0
Source brief ./ISA.md
Project audit-grade-rag
Prepared by Codex
Prepared on 2026-05-11
ISC count 51
Workflow GoalMode MasterPRD Phase 1-5 rebuild

Audit-Grade RAG — Master PRD

§0. Frontmatter and ISA Lock

  • Author: Codex.
  • Created: 2026-05-11.
  • Status: FROZEN.
  • Codex model: GPT-5.5 lineage.
  • Codex reasoning effort: high.
  • ISA source: ./ISA.md.
  • ISC count at freeze: 51.
  • Estimated scope: XL.
  • The ISA criteria are the only acceptance anchors. No PRD-local acceptance IDs replace them.
  • The PRD expands depth only. Breadth changes require an ISA append before PRD edits.
  • Reconciliation command: bun ~/.claude/skills/GoalMode/Tools/ReconcileCheck.ts ISA.md docs/MASTER_PRD.md.
  • Implementation status lives in matching ISA and PRD checkboxes plus §13 progress notes.

§1. Problem

§1.1 North Star Lifted From ISA.Goal

Deliver a self-hostable, open-source-auditable RAG application that ingests one configurable corpus, answers operator questions with per-claim citations to retrieved chunks, records every (query, retrieved-chunks, generated-answer, model-version, prompt-version, embedding-model-version, seed, timestamp, user) tuple to a hash-chained append-only SQLite audit ledger, replays any past answer bit-for-bit on demand, scores groundedness / citation-accuracy / refusal-correctness against a versioned adversarial golden set with all three metrics ≥ acceptance threshold, and emits a regulator-shaped EU AI Act §50 transparency-disclosure PDF + sealed-ledger artifact, all behind a German-language operator console — ready for a DACH-regulated-industry pilot deployment without a single hand-edit to the audit story.

§1.2 Problem Lifted From ISA.Problem

Off-the-shelf retrieval-augmented-generation products (LangChain Cloud, LlamaIndex Cloud, Vectara, the major US hyperscaler RAG offerings) ship as "ask your documents" demos: a chunker, a vector store, a model, a chat UI. They do not ship the artifacts a regulated DACH organisation — Bank, Versicherung, pharmazeutisches Unternehmen, Behörde — needs to put a RAG system into production under BaFin MaRisk, EU AI Act, DSGVO, GxP, or EBA-Leitlinien scrutiny: chunk-level provenance attached to every retrieved span, an immutable hash-chained audit ledger every regulator can replay, deterministic re-execution of any past answer bit-for-bit (frozen seed + frozen model version + frozen prompt version), an evaluation harness with adversarial cases that distinguishes "groundedness" from "fluent hallucination", and a regulator-shaped report (initially: EU AI Act §50 transparency disclosure) that compliance can hand to an auditor without translating engineer-shaped logs into compliance-shaped narratives by hand. The pattern in the German market today is either "we don't ship RAG to production because compliance won't sign off" or "we built a one-off internal tool whose audit story is whatever the team had time to build, which is rarely enough." There is no credible open-source-first project filling the gap; the few commercial vendors who claim "compliance-grade RAG" charge enterprise prices for what is largely a slide-deck claim, not a reproducible-from-source system. This project is the engineer-built reference implementation that closes the gap, scoped to one corpus + one regulator-shaped report for v1 so that the PRD-able scope is finite and the result is demo-able to both engineering interviewers (G3 / Festanstellung evidence) and prospective customers (G6 / commercial PAI).

§1.3 Audience Stories

  • Compliance officer: asks a regulated-domain question and sees every answer claim tied to an exact chunk and source location.
  • Operator: diagnoses ingestion, retrieval, generation, validation, ledger, replay, and report failures from the console without reading raw infrastructure logs.
  • Auditor: receives a sealed artifact whose hash chain, signatures, citations, and report claims can be verified from source-controlled code.
  • Engineering lead: can run the full gate and prove that grounding, citation accuracy, refusal correctness, replay, and report determinism are enforced.
  • Pilot sponsor: can install the product on-prem, ingest a real corpus, and run a supervised DACH-regulated workflow without hand-building the audit story.

§2. Vision

§2.1 Vision Lifted From ISA.Vision

A self-hostable Hono SSR application at audit-grade-rag.example.local where a compliance officer pastes a question, the operator console shows the answer with every claim citation-linked to the exact chunk in the exact source PDF page, the audit trail panel shows the SHA-256 hash chain entry that records the (query, retrieved chunks, generated answer, model version, prompt version, seed, timestamp, user) tuple, the "Replay" button reproduces the answer bit-for-bit from that ledger entry six months later, the "Generate AI Act §50 disclosure" button emits a regulator-shaped PDF the BaFin/BaSt/Aufsichtsbehörde can read without translation, and the eval-harness dashboard shows current groundedness / citation-accuracy / refusal-correctness scores against a versioned golden set with adversarial cases. Euphoric surprise: a Sparkasse compliance team that previously told their developers "RAG is forbidden until compliance signs off" runs this against a sample BaFin-Rundschreiben corpus on Monday, generates the §50 disclosure on Tuesday, and on Wednesday the Bereichsleiter-Compliance asks engineering to deploy it across the whole Beratungsabteilung — because the audit story is no longer hand-waving but an open-source-auditable system the Innenrevision can read.

§2.2 Instrumented End State

  • The operator can authenticate without passwords and recover only through a rate-limited email bootstrap path.
  • The operator can ingest a filesystem corpus and inspect document, page, chunk, embedding, and snapshot state.
  • The operator can ask a question and inspect the hybrid retrieval evidence before trusting the answer.
  • The answer panel refuses unsupported questions and blocks uncited claims before they reach the operator.
  • The audit panel shows the row ID, previous hash, signature key, model version, prompt version, embedding version, corpus snapshot, seed, outcome, and timestamp for the latest material event.
  • The replay flow distinguishes pass, named drift, and unsupported provider behavior.
  • The report flow emits PDF, JSON, and sealed ledger excerpt for exactly the chosen window.
  • The evaluation dashboard shows current thresholds and tag-level failures without hiding empty-set or fixture problems.
  • The deployment path remains self-host-first and does not require SaaS dependencies beyond configured LLM calls.

§3. Out of Scope

§3.1 ISA.OutOfScope Lift

  • No multi-tenant SaaS in v1. Single-tenant self-host only. The audit story is dramatically simpler when one organisation owns the data, the keys, and the ledger; multi-tenant data-residency, tenant key isolation, and per-tenant audit-export are deferred to v2.
  • No billing, usage metering, or per-seat licensing. v1 is licensable as a one-time-fee or commercial-friendly OSS license; per-seat metering is a separate concern when SaaS lands.
  • No SSO / SAML / OIDC in v1. Operator console uses email + WebAuthn passkey only. Enterprise SSO is the second-most-requested integration but adds materially to the auth attack surface; v1.1 ships SSO via a single battle-tested library (Auth.js + Auth0/Authentik adapter), not a homegrown stack.
  • No custom embedding training. v1 ships with one open-source default (bge-m3 recommended; jina-embeddings-v3 as the alternative for German-heavy corpora) behind a provider-pluggable interface so a customer can swap to their own on-prem model. Training pipelines are out of scope.
  • No multi-corpus federation. v1 is one corpus per deployment. Cross-corpus queries, federation routers, and cross-corpus citation reconciliation are explicitly out of scope.
  • No multi-language operator UI in v1. Operator console is German-only at launch; corpus content can be multilingual via the embedding model. English UI is v1.1.
  • No native iOS / Android / desktop applications. Web only.
  • No alternative regulator report formats in v1. The PRD ships exactly one: EU AI Act §50 transparency disclosure. BaFin MaRisk AT 4.4-style summary, EBA-Leitlinien evidence packs, and FDA 21 CFR Part 11 attestations are added one-at-a-time post-v1, each behind its own ISC pack.
  • No real-time collaborative answer drafting. The operator console is a single-user-at-a-time tool in v1; collaborative review is out of scope.
  • No automatic doc-ingestion from email / SharePoint / Confluence. v1 ingests from a watched filesystem directory; integration adapters are v1.1+.
  • No model-fine-tuning in scope. The product is RAG-with-rigorous-grounding; fine-tuning a base model on the corpus is a different engineering project and would change the audit story (a fine-tuned model is itself an in-scope artifact under EU AI Act high-risk classification).
  • No retrieval over images or audio in v1. Text + tables in PDFs, DOCX, and Markdown are the supported corpus types. OCR for scanned PDFs is in scope (via tesseract); image-to-text retrieval is not.

§3.2 Boundary Versions

  • v1 ships one tenant and one corpus; v2 may consider multi-tenant isolation only after the single-tenant ledger story is mature.
  • v1 ships German operator UI; v1.1 may add English UI after the German copy is complete.
  • v1 ships one EU AI Act §50 report; later regulator packs must arrive through new ISA criteria.
  • v1 ingests local files; enterprise connectors are deferred because each connector changes provenance and egress evidence.
  • v1 supports provider-pluggable models; model training, fine-tuning, and image or audio retrieval are separate projects.

§4. Architecture

§4.1 Architecture Invariants

  • Every runtime path that can affect an answer passes through the audit boundary before returning operator-visible state.
  • Retrieval state is snapshot-bound. A query cannot mix chunks from two corpus snapshots.
  • Corpus, prompt, model, embedding, seed, and provider profile versions are immutable inputs to answer generation.
  • Post-generation validation is a hard gate. The UI never receives an answer with uncited assertions.
  • SQLite is the default audit ledger because the sealed single-file handoff is part of the regulator story.
  • Postgres 16 plus pgvector is the retrieval store. Dense vectors are not emulated in memory.
  • BM25 and dense retrieval are peers. Reciprocal-rank fusion is the only v1 merge path.
  • Reports are generated from ledger rows and deterministic templates, never from ad hoc UI state.
  • The operator console is a work surface, not marketing. It defaults to dense evidence panels and German operational copy.
  • The build system is a product surface because CI, checks, README install, and branch protection are ISC-scored.

§4.2 Feature Map From ISA.Features

name description satisfies depends_on parallelizable
feat/auth-passkey Magic-link bootstrap + WebAuthn passkey for operator ISC-1..6 yes
feat/corpus-ingest PDF/DOCX/Markdown ingestion with chunking, embedding, pgvector indexing ISC-7..11 yes
feat/retrieval-hybrid BM25 + dense retrieval with RRF and OutOfCorpus signal ISC-12..15 feat/corpus-ingest no
feat/generation-cited Prompt template + citation parser + post-generation validator + regeneration loop ISC-16..20 feat/retrieval-hybrid no
feat/audit-ledger Hash-chained SQLite audit ledger with verify CLI and Ed25519 signing ISC-21..26 yes
feat/replay-tool Bit-equal replay against ledger entries; ReplayDriftError on drift ISC-27..29 feat/audit-ledger, feat/generation-cited no
feat/eval-harness Adversarial golden set + scorer + threshold gate; integrated into check:full ISC-30..34 feat/generation-cited yes
feat/regulator-report EU AI Act §50 PDF + JSON + sealed-excerpt zip via Typst ISC-35..38 feat/audit-ledger, feat/eval-harness no
feat/operator-console Hono SSR operator UI: query / chunks / answer / audit / replay / report ISC-39..43 feat/auth-passkey, feat/generation-cited, feat/regulator-report no
feat/dsgvo-baseline Logger redaction, deletion tombstones, residency doc, egress allowlist ISC-44..47 yes
feat/devloop GoalMode-style guardrail stack: TS strict, Biome, ESLint, knip, lefthook, CI, pnpm check:full ISC-48..51 first (gates everything else)

§4.3 Module Ownership

  • Identity, session, and operator console: owns features/auth, features/session, features/operator-console, lib/security; serves ISC-1, ISC-2, ISC-3, ISC-4, ISC-5, ISC-6.
  • Corpus ingestion and indexing: owns features/ingest, features/corpus, features/embedding, lib/postgres; serves ISC-7, ISC-8, ISC-9, ISC-10, ISC-11.
  • Retrieval: owns features/retrieval, features/search, lib/postgres, lib/ranking; serves ISC-12, ISC-13, ISC-14, ISC-15.
  • Generation and per-claim citation: owns features/generation, features/citations, features/prompts, lib/llm; serves ISC-16, ISC-17, ISC-18, ISC-19, ISC-20.
  • Audit ledger: owns features/audit-ledger, features/audit-export, lib/sqlite, lib/signing; serves ISC-21, ISC-22, ISC-23, ISC-24, ISC-25, ISC-26.
  • Replay: owns features/replay, features/artifact-registry, features/audit-ledger; serves ISC-27, ISC-28, ISC-29.
  • Eval harness: owns features/eval, features/scoring, features/golden-set, lib/metrics; serves ISC-30, ISC-31, ISC-32, ISC-33, ISC-34.
  • Regulator report (EU AI Act §50): owns features/reporting, features/typst, features/audit-export; serves ISC-35, ISC-36, ISC-37, ISC-38.
  • Operator console UI: owns app/console, features/operator-console, features/source-viewer, lib/csp; serves ISC-39, ISC-40, ISC-41, ISC-42, ISC-43.
  • DSGVO / compliance baseline: owns lib/logger, features/privacy, features/data-residency, lib/egress; serves ISC-44, ISC-45, ISC-46, ISC-47.
  • Build, test, ship (GoalMode contract): owns .github/workflows, lefthook.yml, package.json, docs/MASTER_PRD.md; serves ISC-48, ISC-49, ISC-50, ISC-51.

§4.4 Runtime Flow

  • Auth flow: /auth/operator verifies bootstrap or recovery state, binds a WebAuthn credential, writes a strict session cookie, and refuses password state.
  • Ingestion flow: file walk, extraction, OCR, tokenization, chunk persistence, embedding, HNSW index update, snapshot finalization, and dry-run reporting are one transactional workflow with failed snapshots never becoming active.
  • Query flow: session check, active snapshot binding, BM25 top-50, dense top-50, RRF merge, low-relevance refusal, generation, citation parsing, validation, ledger append, response render.
  • Ledger flow: canonical payload construction, previous-hash lookup, SHA-256 row ID, Ed25519 signature, append-only SQLite insert, verification and export.
  • Replay flow: load ledger row, resolve frozen artifacts, re-run against the original snapshot, compare bytes, ledger pass or drift, return named outcome.
  • Eval flow: read non-empty golden set, run pinned tuple, compute three threshold metrics and tag breakdowns, fail the command when any threshold falls below target.
  • Report flow: select window, read only in-window ledger rows, seal excerpt, render Typst PDF and JSON, hash outputs, ledger report event.

§4.5 Per-ISC Architecture Directives

  • ISC-1 architecture directive: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login.
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-2 architecture directive: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email).
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-3 architecture directive: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h.
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-4 architecture directive: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1.
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-5 architecture directive: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema.
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-6 architecture directive: Anti: No anonymous query path. GET /api/query without a session returns 401.
    • Owning module set: features/auth, features/session, features/operator-console, lib/security.
    • Runtime boundary: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Operator surface: /auth/operator; /console.
    • Persistent evidence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Primary risk controlled: password fallback, anonymous access, and untranslated operator states.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-7 architecture directive: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres.
    • Owning module set: features/ingest, features/corpus, features/embedding, lib/postgres.
    • Runtime boundary: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Operator surface: /console/corpus; /console/audit.
    • Persistent evidence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Primary risk controlled: in-memory indexing, lossy provenance, and replay-breaking snapshot mutation.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-8 architecture directive: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128.
    • Owning module set: features/ingest, features/corpus, features/embedding, lib/postgres.
    • Runtime boundary: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Operator surface: /console/corpus; /console/audit.
    • Persistent evidence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Primary risk controlled: in-memory indexing, lossy provenance, and replay-breaking snapshot mutation.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-9 architecture directive: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay.
    • Owning module set: features/ingest, features/corpus, features/embedding, lib/postgres.
    • Runtime boundary: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Operator surface: /console/corpus; /console/audit.
    • Persistent evidence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Primary risk controlled: in-memory indexing, lossy provenance, and replay-breaking snapshot mutation.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-10 architecture directive: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against.
    • Owning module set: features/ingest, features/corpus, features/embedding, lib/postgres.
    • Runtime boundary: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Operator surface: /console/corpus; /console/audit.
    • Persistent evidence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Primary risk controlled: in-memory indexing, lossy provenance, and replay-breaking snapshot mutation.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-11 architecture directive: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing.
    • Owning module set: features/ingest, features/corpus, features/embedding, lib/postgres.
    • Runtime boundary: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Operator surface: /console/corpus; /console/audit.
    • Persistent evidence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Primary risk controlled: in-memory indexing, lossy provenance, and replay-breaking snapshot mutation.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-12 architecture directive: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20).
    • Owning module set: features/retrieval, features/search, lib/postgres, lib/ranking.
    • Runtime boundary: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Operator surface: /console retrieved-chunks panel.
    • Persistent evidence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Primary risk controlled: single-mode vector search, cross-snapshot leakage, and hallucination-prone low-relevance answers.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-13 architecture directive: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload.
    • Owning module set: features/retrieval, features/search, lib/postgres, lib/ranking.
    • Runtime boundary: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Operator surface: /console retrieved-chunks panel.
    • Persistent evidence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Primary risk controlled: single-mode vector search, cross-snapshot leakage, and hallucination-prone low-relevance answers.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-14 architecture directive: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query.
    • Owning module set: features/retrieval, features/search, lib/postgres, lib/ranking.
    • Runtime boundary: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Operator surface: /console retrieved-chunks panel.
    • Persistent evidence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Primary risk controlled: single-mode vector search, cross-snapshot leakage, and hallucination-prone low-relevance answers.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-15 architecture directive: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response.
    • Owning module set: features/retrieval, features/search, lib/postgres, lib/ranking.
    • Runtime boundary: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Operator surface: /console retrieved-chunks panel.
    • Persistent evidence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Primary risk controlled: single-mode vector search, cross-snapshot leakage, and hallucination-prone low-relevance answers.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-16 architecture directive: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl).
    • Owning module set: features/generation, features/citations, features/prompts, lib/llm.
    • Runtime boundary: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Operator surface: /console answer panel; /console/source.
    • Persistent evidence: prompt_templates, generation_traces, claims, claim_citations.
    • Primary risk controlled: prompt-only grounding, uncited claims, and silent regeneration loops.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-17 architecture directive: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists.
    • Owning module set: features/generation, features/citations, features/prompts, lib/llm.
    • Runtime boundary: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Operator surface: /console answer panel; /console/source.
    • Persistent evidence: prompt_templates, generation_traces, claims, claim_citations.
    • Primary risk controlled: prompt-only grounding, uncited claims, and silent regeneration loops.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-18 architecture directive: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator.
    • Owning module set: features/generation, features/citations, features/prompts, lib/llm.
    • Runtime boundary: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Operator surface: /console answer panel; /console/source.
    • Persistent evidence: prompt_templates, generation_traces, claims, claim_citations.
    • Primary risk controlled: prompt-only grounding, uncited claims, and silent regeneration loops.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-19 architecture directive: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger.
    • Owning module set: features/generation, features/citations, features/prompts, lib/llm.
    • Runtime boundary: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Operator surface: /console answer panel; /console/source.
    • Persistent evidence: prompt_templates, generation_traces, claims, claim_citations.
    • Primary risk controlled: prompt-only grounding, uncited claims, and silent regeneration loops.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-20 architecture directive: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted.
    • Owning module set: features/generation, features/citations, features/prompts, lib/llm.
    • Runtime boundary: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Operator surface: /console answer panel; /console/source.
    • Persistent evidence: prompt_templates, generation_traces, claims, claim_citations.
    • Primary risk controlled: prompt-only grounding, uncited claims, and silent regeneration loops.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-21 architecture directive: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature.
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-22 architecture directive: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited).
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-23 architecture directive: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row.
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-24 architecture directive: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row.
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-25 architecture directive: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip.
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-26 architecture directive: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse.
    • Owning module set: features/audit-ledger, features/audit-export, lib/sqlite, lib/signing.
    • Runtime boundary: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Operator surface: /console audit-trail panel; /console/history.
    • Persistent evidence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Primary risk controlled: mutable ledger writes, unsigned rows, and regulator artifacts that cannot be verified.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-27 architecture directive: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer.
    • Owning module set: features/replay, features/artifact-registry, features/audit-ledger.
    • Runtime boundary: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Operator surface: /console/history replay button; /console replay result panel.
    • Persistent evidence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Primary risk controlled: non-deterministic replay, unnamed drift, and unledgered regulator actions.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-28 architecture directive: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer.
    • Owning module set: features/replay, features/artifact-registry, features/audit-ledger.
    • Runtime boundary: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Operator surface: /console/history replay button; /console replay result panel.
    • Persistent evidence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Primary risk controlled: non-deterministic replay, unnamed drift, and unledgered regulator actions.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-29 architecture directive: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when.
    • Owning module set: features/replay, features/artifact-registry, features/audit-ledger.
    • Runtime boundary: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Operator surface: /console/history replay button; /console replay result panel.
    • Persistent evidence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Primary risk controlled: non-deterministic replay, unnamed drift, and unledgered regulator actions.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-30 architecture directive: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical.
    • Owning module set: features/eval, features/scoring, features/golden-set, lib/metrics.
    • Runtime boundary: pnpm eval; pnpm check:full.
    • Operator surface: /console/eval.
    • Persistent evidence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Primary risk controlled: empty golden sets, vanity metrics, and thresholds not wired into the full gate.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-31 architecture directive: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
    • Owning module set: features/eval, features/scoring, features/golden-set, lib/metrics.
    • Runtime boundary: pnpm eval; pnpm check:full.
    • Operator surface: /console/eval.
    • Persistent evidence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Primary risk controlled: empty golden sets, vanity metrics, and thresholds not wired into the full gate.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-32 architecture directive: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero.
    • Owning module set: features/eval, features/scoring, features/golden-set, lib/metrics.
    • Runtime boundary: pnpm eval; pnpm check:full.
    • Operator surface: /console/eval.
    • Persistent evidence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Primary risk controlled: empty golden sets, vanity metrics, and thresholds not wired into the full gate.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-33 architecture directive: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract.
    • Owning module set: features/eval, features/scoring, features/golden-set, lib/metrics.
    • Runtime boundary: pnpm eval; pnpm check:full.
    • Operator surface: /console/eval.
    • Persistent evidence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Primary risk controlled: empty golden sets, vanity metrics, and thresholds not wired into the full gate.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-34 architecture directive: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures.
    • Owning module set: features/eval, features/scoring, features/golden-set, lib/metrics.
    • Runtime boundary: pnpm eval; pnpm check:full.
    • Operator surface: /console/eval.
    • Persistent evidence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Primary risk controlled: empty golden sets, vanity metrics, and thresholds not wired into the full gate.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-35 architecture directive: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window.
    • Owning module set: features/reporting, features/typst, features/audit-export.
    • Runtime boundary: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Operator surface: /console/reports.
    • Persistent evidence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Primary risk controlled: HTML-rendered nondeterminism, window leakage, and compliance prose detached from ledger evidence.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-36 architecture directive: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt.
    • Owning module set: features/reporting, features/typst, features/audit-export.
    • Runtime boundary: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Operator surface: /console/reports.
    • Persistent evidence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Primary risk controlled: HTML-rendered nondeterminism, window leakage, and compliance prose detached from ledger evidence.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-37 architecture directive: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version).
    • Owning module set: features/reporting, features/typst, features/audit-export.
    • Runtime boundary: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Operator surface: /console/reports.
    • Persistent evidence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Primary risk controlled: HTML-rendered nondeterminism, window leakage, and compliance prose detached from ledger evidence.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-38 architecture directive: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window.
    • Owning module set: features/reporting, features/typst, features/audit-export.
    • Runtime boundary: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Operator surface: /console/reports.
    • Persistent evidence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Primary risk controlled: HTML-rendered nondeterminism, window leakage, and compliance prose detached from ledger evidence.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-39 architecture directive: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written.
    • Owning module set: app/console, features/operator-console, features/source-viewer, lib/csp.
    • Runtime boundary: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Operator surface: /console; /console/history; /console/reports.
    • Persistent evidence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Primary risk controlled: third-party scripts, inaccessible controls, and UI states that hide audit failure.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-40 architecture directive: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift.
    • Owning module set: app/console, features/operator-console, features/source-viewer, lib/csp.
    • Runtime boundary: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Operator surface: /console; /console/history; /console/reports.
    • Persistent evidence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Primary risk controlled: third-party scripts, inaccessible controls, and UI states that hide audit failure.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-41 architecture directive: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download.
    • Owning module set: app/console, features/operator-console, features/source-viewer, lib/csp.
    • Runtime boundary: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Operator surface: /console; /console/history; /console/reports.
    • Persistent evidence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Primary risk controlled: third-party scripts, inaccessible controls, and UI states that hide audit failure.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-42 architecture directive: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks).
    • Owning module set: app/console, features/operator-console, features/source-viewer, lib/csp.
    • Runtime boundary: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Operator surface: /console; /console/history; /console/reports.
    • Persistent evidence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Primary risk controlled: third-party scripts, inaccessible controls, and UI states that hide audit failure.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-43 architecture directive: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'.
    • Owning module set: app/console, features/operator-console, features/source-viewer, lib/csp.
    • Runtime boundary: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Operator surface: /console; /console/history; /console/reports.
    • Persistent evidence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Primary risk controlled: third-party scripts, inaccessible controls, and UI states that hide audit failure.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-44 architecture directive: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only.
    • Owning module set: lib/logger, features/privacy, features/data-residency, lib/egress.
    • Runtime boundary: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Operator surface: /console/settings/privacy.
    • Persistent evidence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Primary risk controlled: PII in logs, uncontrolled egress, and deletion that breaks the audit chain.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-45 architecture directive: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window.
    • Owning module set: lib/logger, features/privacy, features/data-residency, lib/egress.
    • Runtime boundary: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Operator surface: /console/settings/privacy.
    • Persistent evidence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Primary risk controlled: PII in logs, uncontrolled egress, and deletion that breaks the audit chain.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-46 architecture directive: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress.
    • Owning module set: lib/logger, features/privacy, features/data-residency, lib/egress.
    • Runtime boundary: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Operator surface: /console/settings/privacy.
    • Persistent evidence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Primary risk controlled: PII in logs, uncontrolled egress, and deletion that breaks the audit chain.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-47 architecture directive: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1.
    • Owning module set: lib/logger, features/privacy, features/data-residency, lib/egress.
    • Runtime boundary: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Operator surface: /console/settings/privacy.
    • Persistent evidence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Primary risk controlled: PII in logs, uncontrolled egress, and deletion that breaks the audit chain.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-48 architecture directive: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0.
    • Owning module set: .github/workflows, lefthook.yml, package.json, docs/MASTER_PRD.md.
    • Runtime boundary: pnpm check:fast; pnpm check:full; pnpm build.
    • Operator surface: README setup path; GitHub checks.
    • Persistent evidence: CI status checks, branch-protection rule, README install script.
    • Primary risk controlled: unchecked commits, green local stubs with failing CI, and install docs that do not boot the product.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-49 architecture directive: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push.
    • Owning module set: .github/workflows, lefthook.yml, package.json, docs/MASTER_PRD.md.
    • Runtime boundary: pnpm check:fast; pnpm check:full; pnpm build.
    • Operator surface: README setup path; GitHub checks.
    • Persistent evidence: CI status checks, branch-protection rule, README install script.
    • Primary risk controlled: unchecked commits, green local stubs with failing CI, and install docs that do not boot the product.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-50 architecture directive: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console.
    • Owning module set: .github/workflows, lefthook.yml, package.json, docs/MASTER_PRD.md.
    • Runtime boundary: pnpm check:fast; pnpm check:full; pnpm build.
    • Operator surface: README setup path; GitHub checks.
    • Persistent evidence: CI status checks, branch-protection rule, README install script.
    • Primary risk controlled: unchecked commits, green local stubs with failing CI, and install docs that do not boot the product.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.
  • ISC-51 architecture directive: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side.
    • Owning module set: .github/workflows, lefthook.yml, package.json, docs/MASTER_PRD.md.
    • Runtime boundary: pnpm check:fast; pnpm check:full; pnpm build.
    • Operator surface: README setup path; GitHub checks.
    • Persistent evidence: CI status checks, branch-protection rule, README install script.
    • Primary risk controlled: unchecked commits, green local stubs with failing CI, and install docs that do not boot the product.
    • Failure handling: return a typed product error, ledger the material outcome where applicable, and surface German operator copy when the operator can act.
    • Observability: ordinary logs carry only metadata, while content-bearing evidence belongs to the ledger or test fixture.
    • Implementation note: no in-memory substitute may satisfy this criterion when the ISA names Postgres, pgvector, SQLite, Typst, WebAuthn, or CI.

§5. Data Model

§5.1 Storage Boundaries

  • Postgres stores corpus, chunk, embedding, retrieval, prompt metadata, provider metadata, operator metadata, and relational product state.
  • pgvector stores vector(1024) embeddings for the default bge-m3 profile and uses HNSW cosine indexes.
  • SQLite WAL stores the append-only audit ledger, default export state, and single-file regulator evidence.
  • Filesystem fixtures store attribution-cleared corpus excerpts, Typst templates, prompt templates, and golden-set JSONL.
  • Secrets stay outside the database schema and are referenced through deployment configuration fingerprints.
  • PII-bearing operator mappings are separable from immutable ledger rows through tombstone hashes.
  • Query text, answer text, and retrieved chunk text are content evidence and are never duplicated into ordinary INFO logs.
  • Every table that supports replay has an immutable version or digest field.
  • Every report artifact has a digest so byte-determinism can be tested without opening the PDF.
  • Every schema migration that affects answer generation increments an artifact version or records an explicit compatibility note.

§5.2 Core Tables and Files

  • operators: internal operator identity, status, locale, role, creation timestamp.
  • operator_identities: email hash, encrypted email for recovery, deletion tombstone, operator mapping.
  • webauthn_credentials: credential ID, public key, sign count, transports, backup flags, last-used timestamp.
  • sessions: session ID, operator ID, created, last seen, idle expiry, absolute expiry, user-agent hash, IP hash.
  • magic_link_challenges: email hash, challenge hash, expiry, consumed timestamp, creation IP hash, recovery purpose.
  • corpora: single configured corpus, active snapshot pointer, display metadata.
  • corpus_snapshots: immutable sequence, snapshot hash, embedding model version, chunker version, finalized state.
  • source_documents: logical source path, type, title, corpus ID.
  • document_revisions: immutable content hash, extracted text hash, OCR flag, warnings, byte size, snapshot ID.
  • document_pages: page text, page hash, page number, character count.
  • chunks: stable chunk ID, snapshot ID, document revision ID, page range, char range, token range, chunk text, chunk hash.
  • chunk_embeddings: chunk FK, embedding model version, dimension, vector, embedding hash, HNSW index.
  • bm25_terms: snapshot-bound lexical index rows for BM25 candidate generation.
  • retrieval_traces: query hash, snapshot ID, vector candidates, BM25 candidates, RRF candidates, final chunks, top-K, low-score flag.
  • prompt_templates: family, semantic version, filesystem path, template hash, retirement state.
  • provider_profiles: model ID, model version, endpoint kind, replay capability, config hash.
  • generation_traces: prompt, provider, seed, temperature, request hash, response hash, validation status.
  • claims: claim index, claim text hash, validation status.
  • claim_citations: claim ID, chunk ID, citation role, extracted marker.
  • audit_ledger_entries: SQLite append-only table with canonical payload, row hash, previous hash, signature, and material answer metadata.
  • audit_exports: export window, SQLite artifact digest, signature digest, zip digest.
  • eval/golden/v<N>.jsonl: golden question cases with expected outcome, expected chunks, and tags.
  • eval_runs: pinned tuple, scores, per-tag breakdown, pass or fail status.
  • report_artifacts: report kind, time window, template version, output digests, generator identity.
  • operator_deletion_tombstones: deletion timestamp, original user hash, tombstone hash, retention policy reference.

§5.3 Per-ISC Data Contracts

  • ISC-1 data contract: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login.
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-2 data contract: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email).
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-3 data contract: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h.
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-4 data contract: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1.
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-5 data contract: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema.
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-6 data contract: Anti: No anonymous query path. GET /api/query without a session returns 401.
    • Required persistence: operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/auth/operator-passkey.ts must include at least one success case and one boundary case for this criterion.
  • ISC-7 data contract: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres.
    • Required persistence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf must include at least one success case and one boundary case for this criterion.
  • ISC-8 data contract: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128.
    • Required persistence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf must include at least one success case and one boundary case for this criterion.
  • ISC-9 data contract: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay.
    • Required persistence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf must include at least one success case and one boundary case for this criterion.
  • ISC-10 data contract: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against.
    • Required persistence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf must include at least one success case and one boundary case for this criterion.
  • ISC-11 data contract: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing.
    • Required persistence: corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf must include at least one success case and one boundary case for this criterion.
  • ISC-12 data contract: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20).
    • Required persistence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts must include at least one success case and one boundary case for this criterion.
  • ISC-13 data contract: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload.
    • Required persistence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts must include at least one success case and one boundary case for this criterion.
  • ISC-14 data contract: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query.
    • Required persistence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts must include at least one success case and one boundary case for this criterion.
  • ISC-15 data contract: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response.
    • Required persistence: retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts must include at least one success case and one boundary case for this criterion.
  • ISC-16 data contract: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl).
    • Required persistence: prompt_templates, generation_traces, claims, claim_citations.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl must include at least one success case and one boundary case for this criterion.
  • ISC-17 data contract: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists.
    • Required persistence: prompt_templates, generation_traces, claims, claim_citations.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl must include at least one success case and one boundary case for this criterion.
  • ISC-18 data contract: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator.
    • Required persistence: prompt_templates, generation_traces, claims, claim_citations.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl must include at least one success case and one boundary case for this criterion.
  • ISC-19 data contract: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger.
    • Required persistence: prompt_templates, generation_traces, claims, claim_citations.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl must include at least one success case and one boundary case for this criterion.
  • ISC-20 data contract: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted.
    • Required persistence: prompt_templates, generation_traces, claims, claim_citations.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl must include at least one success case and one boundary case for this criterion.
  • ISC-21 data contract: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature.
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-22 data contract: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited).
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-23 data contract: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row.
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-24 data contract: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row.
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-25 data contract: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip.
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-26 data contract: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse.
    • Required persistence: audit_ledger_entries, audit_exports, ed25519_key_config.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite must include at least one success case and one boundary case for this criterion.
  • ISC-27 data contract: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer.
    • Required persistence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift must include at least one success case and one boundary case for this criterion.
  • ISC-28 data contract: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer.
    • Required persistence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift must include at least one success case and one boundary case for this criterion.
  • ISC-29 data contract: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when.
    • Required persistence: replay_runs, artifact_snapshots, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift must include at least one success case and one boundary case for this criterion.
  • ISC-30 data contract: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical.
    • Required persistence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act must include at least one success case and one boundary case for this criterion.
  • ISC-31 data contract: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
    • Required persistence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act must include at least one success case and one boundary case for this criterion.
  • ISC-32 data contract: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero.
    • Required persistence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act must include at least one success case and one boundary case for this criterion.
  • ISC-33 data contract: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract.
    • Required persistence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act must include at least one success case and one boundary case for this criterion.
  • ISC-34 data contract: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures.
    • Required persistence: eval/golden/v.jsonl, eval_runs, eval_results.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act must include at least one success case and one boundary case for this criterion.
  • ISC-35 data contract: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window.
    • Required persistence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ must include at least one success case and one boundary case for this criterion.
  • ISC-36 data contract: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt.
    • Required persistence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ must include at least one success case and one boundary case for this criterion.
  • ISC-37 data contract: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version).
    • Required persistence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ must include at least one success case and one boundary case for this criterion.
  • ISC-38 data contract: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window.
    • Required persistence: report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ must include at least one success case and one boundary case for this criterion.
  • ISC-39 data contract: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written.
    • Required persistence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html must include at least one success case and one boundary case for this criterion.
  • ISC-40 data contract: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift.
    • Required persistence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html must include at least one success case and one boundary case for this criterion.
  • ISC-41 data contract: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download.
    • Required persistence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html must include at least one success case and one boundary case for this criterion.
  • ISC-42 data contract: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks).
    • Required persistence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html must include at least one success case and one boundary case for this criterion.
  • ISC-43 data contract: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'.
    • Required persistence: ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html must include at least one success case and one boundary case for this criterion.
  • ISC-44 data contract: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only.
    • Required persistence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md must include at least one success case and one boundary case for this criterion.
  • ISC-45 data contract: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window.
    • Required persistence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md must include at least one success case and one boundary case for this criterion.
  • ISC-46 data contract: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress.
    • Required persistence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md must include at least one success case and one boundary case for this criterion.
  • ISC-47 data contract: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1.
    • Required persistence: operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md must include at least one success case and one boundary case for this criterion.
  • ISC-48 data contract: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0.
    • Required persistence: CI status checks, branch-protection rule, README install script.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/meta/check-full.test.ts, .github/workflows/ci.yml must include at least one success case and one boundary case for this criterion.
  • ISC-49 data contract: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push.
    • Required persistence: CI status checks, branch-protection rule, README install script.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/meta/check-full.test.ts, .github/workflows/ci.yml must include at least one success case and one boundary case for this criterion.
  • ISC-50 data contract: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console.
    • Required persistence: CI status checks, branch-protection rule, README install script.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/meta/check-full.test.ts, .github/workflows/ci.yml must include at least one success case and one boundary case for this criterion.
  • ISC-51 data contract: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side.
    • Required persistence: CI status checks, branch-protection rule, README install script.
    • Integrity rule: data written for this criterion is immutable unless the ISA explicitly allows rotation, recovery, or tombstoning.
    • Version rule: any value that can affect answer bytes, citation state, retrieval order, report bytes, or replay result has a digest or semantic version.
    • Migration rule: schema changes include forward migration, rollback notes for local development, and a test fixture proving old rows remain readable where replay depends on them.
    • Privacy rule: content stays in the ledger or corpus store, while ordinary logs use hashes and IDs only.
    • Constraint rule: database constraints reject impossible states before application code can ledger them.
    • Fixture rule: tests/meta/check-full.test.ts, .github/workflows/ci.yml must include at least one success case and one boundary case for this criterion.

§6. APIs, CLIs, and Runtime Contracts

§6.1 API Envelope

  • Successful JSON responses include ok: true, data, request_id, and ledger_entry_id when a material event was recorded.
  • Failed JSON responses include ok: false, error.code, error.message_de, error.message_en, request_id, and retryable.
  • Auth failures use 401 for missing session and 403 for authenticated but unauthorized access.
  • Validation failures use 422 and include field-level details without echoing secrets or query text into logs.
  • Conflict states use 409 when a snapshot, replay artifact, or report window changed during the operation.
  • CLI commands write machine-readable JSON on --json and human-readable German-first output by default where an operator sees it.
  • CLI commands exit non-zero for failed thresholds, drift, tamper detection, invalid input, empty golden set, or missing required artifact.
  • All content-bearing API calls require a session except unauthenticated bootstrap and recovery paths.
  • The backend never trusts client-supplied corpus snapshot IDs for active queries without server-side binding.
  • The backend uses centralized request validation at Hono boundaries before calling feature modules.

§6.2 Canonical Endpoints and Commands

  • GET /auth/operator: render German bootstrap or passkey-login shell.
  • POST /api/auth/magic-link/request: request a 10-minute bootstrap or recovery challenge.
  • POST /api/auth/magic-link/consume: consume a valid challenge and proceed to passkey binding when needed.
  • POST /api/auth/webauthn/register/options: create registration options for first login.
  • POST /api/auth/webauthn/register/verify: verify and persist a passkey.
  • POST /api/auth/webauthn/authenticate/options: create authentication options for subsequent logins.
  • POST /api/auth/webauthn/authenticate/verify: verify assertion and mint session.
  • POST /api/query: run retrieval, generation, citation validation, ledger append, and response render.
  • GET /api/audit/:entryId: read a ledger-backed event summary for the authenticated operator.
  • POST /api/audit/:entryId/replay: run replay and ledger its outcome.
  • POST /api/report/eu-ai-act-50: generate the PDF, JSON, and sealed audit excerpt for a time window.
  • GET /api/eval/latest: return latest eval metrics and tag breakdowns.
  • pnpm ingest --corpus <dir>: ingest a filesystem corpus into Postgres and pgvector.
  • pnpm ingest --dry-run --corpus <dir>: report counts and estimated index size without writes.
  • audit-verify <ledger.sqlite>: verify hash chain and Ed25519 signatures.
  • audit-replay <ledger.sqlite> <entry-id>: replay a ledgered answer or return named drift.
  • pnpm eval: run golden questions and enforce groundedness, citation accuracy, and refusal thresholds.
  • pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir>: produce deterministic report artifacts.
  • pnpm check:fast: run the local commit gate.
  • pnpm check:full: run the full done-contract gate.

§6.3 Per-ISC Runtime Contracts

  • ISC-1 runtime contract: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login.
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-2 runtime contract: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email).
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-3 runtime contract: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h.
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-4 runtime contract: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1.
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-5 runtime contract: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema.
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-6 runtime contract: Anti: No anonymous query path. GET /api/query without a session returns 401.
    • Entry points: /auth/operator; /api/auth/webauthn/*; /api/query.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-7 runtime contract: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres.
    • Entry points: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-8 runtime contract: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128.
    • Entry points: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-9 runtime contract: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay.
    • Entry points: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-10 runtime contract: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against.
    • Entry points: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-11 runtime contract: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing.
    • Entry points: pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-12 runtime contract: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20).
    • Entry points: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-13 runtime contract: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload.
    • Entry points: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-14 runtime contract: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query.
    • Entry points: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-15 runtime contract: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response.
    • Entry points: /api/query; retrieveHybrid(query, snapshotId, topK).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-16 runtime contract: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl).
    • Entry points: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-17 runtime contract: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists.
    • Entry points: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-18 runtime contract: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator.
    • Entry points: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-19 runtime contract: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger.
    • Entry points: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-20 runtime contract: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted.
    • Entry points: /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-21 runtime contract: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature.
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-22 runtime contract: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited).
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-23 runtime contract: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row.
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-24 runtime contract: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row.
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-25 runtime contract: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip.
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-26 runtime contract: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse.
    • Entry points: audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-27 runtime contract: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer.
    • Entry points: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-28 runtime contract: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer.
    • Entry points: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-29 runtime contract: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when.
    • Entry points: audit-replay <ledger.sqlite> ; /api/audit/:id/replay.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-30 runtime contract: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical.
    • Entry points: pnpm eval; pnpm check:full.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-31 runtime contract: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
    • Entry points: pnpm eval; pnpm check:full.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-32 runtime contract: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero.
    • Entry points: pnpm eval; pnpm check:full.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-33 runtime contract: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract.
    • Entry points: pnpm eval; pnpm check:full.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-34 runtime contract: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures.
    • Entry points: pnpm eval; pnpm check:full.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-35 runtime contract: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window.
    • Entry points: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-36 runtime contract: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt.
    • Entry points: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-37 runtime contract: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version).
    • Entry points: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-38 runtime contract: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window.
    • Entry points: pnpm report --format=eu-ai-act-50 --since= --until= --out=.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-39 runtime contract: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written.
    • Entry points: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-40 runtime contract: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift.
    • Entry points: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-41 runtime contract: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download.
    • Entry points: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-42 runtime contract: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks).
    • Entry points: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-43 runtime contract: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'.
    • Entry points: /console; /api/query; /api/audit/:id/replay; /api/report.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-44 runtime contract: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only.
    • Entry points: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-45 runtime contract: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window.
    • Entry points: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-46 runtime contract: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress.
    • Entry points: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-47 runtime contract: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1.
    • Entry points: /api/operator/delete; logger.info(event); egressAllowlist.assert(host).
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-48 runtime contract: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0.
    • Entry points: pnpm check:fast; pnpm check:full; pnpm build.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-49 runtime contract: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push.
    • Entry points: pnpm check:fast; pnpm check:full; pnpm build.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-50 runtime contract: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console.
    • Entry points: pnpm check:fast; pnpm check:full; pnpm build.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.
  • ISC-51 runtime contract: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side.
    • Entry points: pnpm check:fast; pnpm check:full; pnpm build.
    • Authentication: require an authenticated operator unless this criterion is the explicit bootstrap or recovery path.
    • Request validation: reject malformed inputs before side effects and never coerce security-sensitive fields silently.
    • Success response: include stable IDs and enough metadata for the console, tests, and ledger verification to correlate the action.
    • Error response: use a typed code, German operator copy, and a retryability flag.
    • Audit response: ledger material events before returning success; for blocked paths, ledger the block rather than pretending no event happened.
    • Idempotency: repeat safe reads without mutation; repeat writes only through explicit idempotency keys or content hashes.
    • Backpressure: fail closed on unavailable Postgres, pgvector, SQLite ledger, Typst, model provider, or golden-set dependencies.

§7. UI

§7.1 UI Principles

  • The console is German-first and operational, with dense but readable evidence surfaces.
  • The first viewport after login is the actual query workspace, not a landing page.
  • The answer panel cannot hide citation validation failures, low-relevance refusals, replay drift, or report generation errors.
  • Retrieved chunks use collapsible panels with stable dimensions so score changes do not shift the layout during inspection.
  • Citation pills are buttons with accessible names and deterministic keyboard order.
  • Source previews preserve page number, character offset, chunk ID, and highlight state.
  • Audit rows show digest and signature metadata in a compact panel suitable for copying into a runbook.
  • Report windows use real date-time controls and show the exact included ledger sequence range before generation.
  • WCAG 2.2 AA is a release requirement, not a later polish task.
  • CSP is visible through headers and tests, not merely listed in documentation.

§7.2 Page and Component Map

  • /auth/operator: email bootstrap, passkey registration, passkey authentication, recovery states, rate-limit messages.
  • /console: query box, answer panel, retrieved chunks, audit trail, active snapshot badge, latest eval badge.
  • /console/source/:docId: source PDF or text page view with cited char offset highlighted.
  • /console/history: ledger-row list, replay action, pass or drift details.
  • /console/reports: EU AI Act §50 window picker, generation status, artifact download.
  • /console/eval: latest metrics, tag breakdown, failing case summaries.
  • /console/settings/privacy: operator deletion, residency note, provider configuration fingerprints.
  • CitationPill: inline answer citation control.
  • RetrievedChunkPanel: chunk metadata, score, method, text excerpt, source link.
  • AuditTrailPanel: row ID, previous hash, signature, versions, outcome.
  • ReplayResultPanel: pass, drift, unsupported, or error state with diff when available.
  • ReportWindowForm: time-window picker and artifact status.

§7.3 Per-ISC UI Contracts

  • ISC-1 UI contract: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login.
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-2 UI contract: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email).
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-3 UI contract: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h.
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-4 UI contract: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1.
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-5 UI contract: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema.
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-6 UI contract: Anti: No anonymous query path. GET /api/query without a session returns 401.
    • Primary surface: /auth/operator; /console.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-7 UI contract: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres.
    • Primary surface: /console/corpus; /console/audit.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-8 UI contract: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128.
    • Primary surface: /console/corpus; /console/audit.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-9 UI contract: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay.
    • Primary surface: /console/corpus; /console/audit.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-10 UI contract: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against.
    • Primary surface: /console/corpus; /console/audit.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-11 UI contract: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing.
    • Primary surface: /console/corpus; /console/audit.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-12 UI contract: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20).
    • Primary surface: /console retrieved-chunks panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-13 UI contract: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload.
    • Primary surface: /console retrieved-chunks panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-14 UI contract: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query.
    • Primary surface: /console retrieved-chunks panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-15 UI contract: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response.
    • Primary surface: /console retrieved-chunks panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-16 UI contract: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl).
    • Primary surface: /console answer panel; /console/source.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-17 UI contract: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists.
    • Primary surface: /console answer panel; /console/source.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-18 UI contract: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator.
    • Primary surface: /console answer panel; /console/source.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-19 UI contract: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger.
    • Primary surface: /console answer panel; /console/source.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-20 UI contract: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted.
    • Primary surface: /console answer panel; /console/source.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-21 UI contract: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature.
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-22 UI contract: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited).
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-23 UI contract: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row.
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-24 UI contract: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row.
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-25 UI contract: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip.
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-26 UI contract: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse.
    • Primary surface: /console audit-trail panel; /console/history.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-27 UI contract: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer.
    • Primary surface: /console/history replay button; /console replay result panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-28 UI contract: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer.
    • Primary surface: /console/history replay button; /console replay result panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-29 UI contract: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when.
    • Primary surface: /console/history replay button; /console replay result panel.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-30 UI contract: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical.
    • Primary surface: /console/eval.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-31 UI contract: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
    • Primary surface: /console/eval.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-32 UI contract: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero.
    • Primary surface: /console/eval.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-33 UI contract: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract.
    • Primary surface: /console/eval.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-34 UI contract: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures.
    • Primary surface: /console/eval.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-35 UI contract: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window.
    • Primary surface: /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-36 UI contract: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt.
    • Primary surface: /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-37 UI contract: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version).
    • Primary surface: /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-38 UI contract: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window.
    • Primary surface: /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-39 UI contract: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written.
    • Primary surface: /console; /console/history; /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-40 UI contract: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift.
    • Primary surface: /console; /console/history; /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-41 UI contract: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download.
    • Primary surface: /console; /console/history; /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-42 UI contract: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks).
    • Primary surface: /console; /console/history; /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-43 UI contract: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'.
    • Primary surface: /console; /console/history; /console/reports.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-44 UI contract: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only.
    • Primary surface: /console/settings/privacy.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-45 UI contract: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window.
    • Primary surface: /console/settings/privacy.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-46 UI contract: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress.
    • Primary surface: /console/settings/privacy.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-47 UI contract: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1.
    • Primary surface: /console/settings/privacy.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-48 UI contract: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0.
    • Primary surface: README setup path; GitHub checks.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-49 UI contract: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push.
    • Primary surface: README setup path; GitHub checks.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-50 UI contract: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console.
    • Primary surface: README setup path; GitHub checks.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.
  • ISC-51 UI contract: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side.
    • Primary surface: README setup path; GitHub checks.
    • German copy: include success, empty, validation, blocked, rate-limited, and failure states when the operator can see the behavior.
    • Keyboard path: every actionable control for this criterion is reachable, labelled, and operable without pointer input.
    • Screen-reader path: panels expose headings, landmarks, live-region updates only for state changes, and no duplicate unlabeled icon buttons.
    • Evidence path: when this criterion writes or reads evidence, the UI shows the relevant ID, digest, timestamp, or source link.
    • Failure path: the UI distinguishes user-correctable input errors from system faults, drift, refusal, blocked generation, and unavailable dependencies.

§7.5 Live-Provider Integration Tests

§7.5.1 Claude CLI OAuth LLM Provider Live Integration

  • Declared provider category: LLM provider.
  • Declared provider keyword: Claude CLI OAuth for local GoalMode evidence; Anthropic SDK/API for deployable API-key environments.
  • Served ISC-N: ISC-16, ISC-17, ISC-18, ISC-19, ISC-20, ISC-27, ISC-28, ISC-29, ISC-44, ISC-47, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/anthropic.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, the installed claude command must use the local Claude Code OAuth session and the test must call claude -p --output-format json --json-schema using claude-sonnet-4-6 unless CLAUDE_MODEL overrides it.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and the CLI is absent, OAuth is unavailable, the model is unavailable, or the structured JSON envelope lacks structured_output, the test fails with the provider name and failed stage in the error text.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a live call occurred.
  • Product obligation: no deterministic development profile may be used as evidence for this L4 row. The Anthropic SDK/API adapter remains a deployable-provider path and is not required merely to prove local /goal live behavior.

§7.5.2 bge-m3 Embedding Model Live Integration

  • Declared provider category: Embedding model.
  • Declared provider keyword: bge-m3.
  • Served ISC-N: ISC-7, ISC-8, ISC-11, ISC-12, ISC-13, ISC-14, ISC-15, ISC-31, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/bge-m3.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, BGE_M3_EMBEDDING_ENDPOINT may point at an OpenAI-compatible embedding endpoint serving model bge-m3; if it is absent, the live test self-provisions a local TEI BAAI/bge-m3 container and persists the cold model cache under ignored .live-cache/bge-m3. BGE_M3_API_KEY is optional for deployments that require bearer auth.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and the configured or self-provisioned endpoint is unreachable, returns non-2xx, returns no numeric vector, or cannot finish TEI startup within the declared timeout, the test fails with the provider name and last endpoint/container error.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a live model invocation occurred.
  • Product obligation: deterministic local vectors remain a development profile only and cannot satisfy this L4 row.

§7.5.3 pgvector Vector Store Live Integration

  • Declared provider category: Vector store.
  • Declared provider keyword: pgvector.
  • Served ISC-N: ISC-7, ISC-8, ISC-9, ISC-10, ISC-11, ISC-12, ISC-13, ISC-14, ISC-15, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/pgvector.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, DATABASE_URL must point at Postgres 16 with the pgvector extension available.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and Postgres is absent, pgvector cannot be created or found, or vector distance SQL fails, the test fails with the provider name and connection setting in the error text.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a live store query occurred.
  • Product obligation: array math or local JSON vectors cannot satisfy this L4 row.

§7.5.4 Typst PDF Renderer Live Integration

  • Declared provider category: PDF renderer.
  • Declared provider keyword: Typst.
  • Served ISC-N: ISC-35, ISC-36, ISC-37, ISC-38, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/typst.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, the typst binary must be on PATH and support deterministic PDF compilation with the pinned report template path.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and the binary is absent, compilation exits non-zero, or the output is not a PDF byte stream, the test fails with the provider name and binary requirement in the error text.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a live renderer invocation occurred.
  • Product obligation: a text file shaped like PDF output cannot satisfy this L4 row.

§7.5.5 WebAuthn Auth Library Live Integration

  • Declared provider category: Auth library.
  • Declared provider keyword: WebAuthn.
  • Served ISC-N: ISC-1, ISC-2, ISC-3, ISC-5, ISC-6, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/webauthn.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, Node WebCrypto must support an ES256 challenge-signature round trip matching the passkey verification profile.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and ES256 key generation, challenge signing, or signature verification fails, the test fails with the provider name and ceremony stage in the error text.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a passkey ceremony occurred.
  • Product obligation: password state or email-only auth cannot satisfy this L4 row.

§7.5.6 Hono SSR UI Framework Live Integration

  • Declared provider category: UI framework.
  • Declared provider keyword: Hono.
  • Served ISC-N: ISC-39, ISC-40, ISC-41, ISC-42, ISC-43, ISC-48, ISC-49.
  • L4 test file: tests/integration-live/hono-ssr.spec.ts.
  • Execution contract: pnpm test:integration:live invokes this test through the integration-live Vitest project, and pnpm check:full chains that script after L2 integration.
  • Environment contract: when RUN_LIVE_TESTS=1, the hono package must resolve locally and the real Hono HTTP app must render the operator-console SSR route with a self-only CSP.
  • Fail-loud rule: if RUN_LIVE_TESTS=1 and Hono is absent, the app cannot instantiate, console landmarks are missing, or CSP drifts from default-src 'self', the test fails with the provider name and route evidence in the error text.
  • Non-live contract: when RUN_LIVE_TESTS is not 1, the test records a structured disabled-gate assertion; it does not pretend a UI framework invocation occurred.
  • Product obligation: the chosen UI framework for v1 is Hono SSR strings, not a separate Next.js runtime.

§8. Test Strategy

§8.1 ISA Test Strategy Lift

ISC Type Check Threshold Tool
ISC-1..6 integration Test-driven Hono routes against ephemeral SQLite All ISC-1..6 pass Vitest + supertest + sqlite-tmp
ISC-7..11 integration Run ingestion against a fixture corpus, assert chunk count + embedding count + index reachability Counts match fixture expectations Vitest + pg-tmp + tesseract fixture
ISC-12..15 integration Pinned-corpus retrieval; assert top-K identity for known queries; assert OutOfCorpus on adversarial query Match golden expected_chunks Vitest + pinned corpus snapshot
ISC-16..20 integration + unit + L4 Unit-test the citation-validator on crafted provider outputs; integration-test full generate→validate→regenerate path; local L4 calls Claude Code CLI OAuth with --output-format json --json-schema when RUN_LIVE_TESTS=1; deployable API-key adapters stay explicit and configurable Validator rejects all uncited crafted cases; live call returns a cited-answer-capable response payload Vitest + Claude CLI structured-output live call
ISC-21..26 integration + unit Hash-chain unit tests on synthetic rows; integration tests writing real rows; tamper test that flips one byte audit-verify exits 0 clean, non-zero tampered Vitest + ts-node + sqlite-tmp
ISC-27..29 integration + L4 Replay a freshly-written ledger row; replay against drifted (manually-edited) prompt version → expect ReplayDriftError; L4 verifies replay metadata against the configured Claude CLI OAuth or deployable LLM provider profile when RUN_LIVE_TESTS=1 Byte-equal on clean replay; named drift on dirty; live profile metadata is explicit and ledgerable Vitest + SQLite + provider-profile live check
ISC-30..34 unit + integration Eval harness self-tests on a 5-question fixture; thresholds enforced; empty-set rejected Thresholds met, empty rejected Vitest
ISC-35..38 integration Generate report; re-generate; diff bytes; out-of-window ledger row test Byte-identical re-runs; window honored Vitest + Typst CLI + sha256sum
ISC-39..43 e2e agent-browser-driven flow: login → query → see citations → replay → generate report → CSP scan Full flow green; CSP report shows zero violations agent-browser + custom e2e harness
ISC-44..47 unit + integration + L4 Logger redaction unit tests; deletion-tombstone integration test; egress-allowlist test against the configured LLM provider endpoint contract when RUN_LIVE_TESTS=1 No PII in INFO logs; tombstone preserves chain; only configured LLM-host egress Vitest + live provider egress probe
ISC-48..51 meta / CI pnpm check:full on a clean clone; CI workflow run on PR; install-instructions test on a clean container Exit 0 on all GitHub Actions + Docker

§8.2 Test Pyramid Rules

  • L1 unit tests cover pure validation, parsing, scoring, hashing, canonicalization, ranking, redaction, and deterministic template functions.
  • L2 integration tests use real owned boundaries: Postgres with pgvector, SQLite WAL, filesystem fixtures, CLI spawns, Typst, and Hono route handlers.
  • L3 end-to-end tests drive the real console through the browser harness and assert operator-visible behavior.
  • Tests do not use .skip, .only, xit, xdescribe, or it.todo.
  • L2 and L3 tests do not mock owned databases, filesystem writes, CLI commands, or ledger verification.
  • External LLM calls may use a deterministic provider profile where replay byte-equality is required, but the provider profile must be explicit and ledgered.
  • Eval fixtures live in-repo and must include attribution-cleared German regulatory text excerpts under corpus-fixtures/.
  • The golden set may be small for v1 but cannot be empty and must include ambiguous, out-of-corpus, contradictory, multi-hop, and numerical tags.
  • pnpm check:full is the only completion gate; pnpm check:fast is the commit gate.
  • pnpm build is a separate done-contract proof and cannot be inferred from tests.

§8.3 Per-ISC Test Recipes

  • ISC-1 detailed test recipe: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-2 detailed test recipe: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-3 detailed test recipe: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-4 detailed test recipe: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-5 detailed test recipe: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-6 detailed test recipe: Anti: No anonymous query path. GET /api/query without a session returns 401.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/auth/operator-passkey.ts.
    • L2: exercise /auth/operator; /api/auth/webauthn/*; /api/query against the real owned dependencies and assert persisted evidence in operators, operator_identities, webauthn_credentials, sessions, magic_link_challenges.
    • L3: drive /auth/operator; /console or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-7 detailed test recipe: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf.
    • L2: exercise pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW against the real owned dependencies and assert persisted evidence in corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • L3: drive /console/corpus; /console/audit or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-8 detailed test recipe: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf.
    • L2: exercise pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW against the real owned dependencies and assert persisted evidence in corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • L3: drive /console/corpus; /console/audit or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-9 detailed test recipe: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf.
    • L2: exercise pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW against the real owned dependencies and assert persisted evidence in corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • L3: drive /console/corpus; /console/audit or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-10 detailed test recipe: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf.
    • L2: exercise pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW against the real owned dependencies and assert persisted evidence in corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • L3: drive /console/corpus; /console/audit or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-11 detailed test recipe: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from corpus-fixtures/eu-ai-act, tests/fixtures/ingest/scanned.pdf.
    • L2: exercise pnpm ingest --corpus ; pnpm ingest --dry-run; Postgres pgvector HNSW against the real owned dependencies and assert persisted evidence in corpus_snapshots, source_documents, document_revisions, chunks, chunk_embeddings.
    • L3: drive /console/corpus; /console/audit or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-12 detailed test recipe: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts.
    • L2: exercise /api/query; retrieveHybrid(query, snapshotId, topK) against the real owned dependencies and assert persisted evidence in retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • L3: drive /console retrieved-chunks panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-13 detailed test recipe: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts.
    • L2: exercise /api/query; retrieveHybrid(query, snapshotId, topK) against the real owned dependencies and assert persisted evidence in retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • L3: drive /console retrieved-chunks panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-14 detailed test recipe: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts.
    • L2: exercise /api/query; retrieveHybrid(query, snapshotId, topK) against the real owned dependencies and assert persisted evidence in retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • L3: drive /console retrieved-chunks panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-15 detailed test recipe: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, tests/fixtures/retrieval/pinned-corpus.ts.
    • L2: exercise /api/query; retrieveHybrid(query, snapshotId, topK) against the real owned dependencies and assert persisted evidence in retrieval_traces, chunks, chunk_embeddings, bm25_terms.
    • L3: drive /console retrieved-chunks panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-16 detailed test recipe: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl.
    • L2: exercise /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks) against the real owned dependencies and assert persisted evidence in prompt_templates, generation_traces, claims, claim_citations.
    • L3: drive /console answer panel; /console/source or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-17 detailed test recipe: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl.
    • L2: exercise /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks) against the real owned dependencies and assert persisted evidence in prompt_templates, generation_traces, claims, claim_citations.
    • L3: drive /console answer panel; /console/source or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-18 detailed test recipe: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl.
    • L2: exercise /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks) against the real owned dependencies and assert persisted evidence in prompt_templates, generation_traces, claims, claim_citations.
    • L3: drive /console answer panel; /console/source or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-19 detailed test recipe: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl.
    • L2: exercise /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks) against the real owned dependencies and assert persisted evidence in prompt_templates, generation_traces, claims, claim_citations.
    • L3: drive /console answer panel; /console/source or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-20 detailed test recipe: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/generation/uncited-output.json, prompts/answer/v3.tmpl.
    • L2: exercise /api/query; prompts/answer/v3.tmpl; validateClaims(response, chunks) against the real owned dependencies and assert persisted evidence in prompt_templates, generation_traces, claims, claim_citations.
    • L3: drive /console answer panel; /console/source or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-21 detailed test recipe: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-22 detailed test recipe: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-23 detailed test recipe: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-24 detailed test recipe: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-25 detailed test recipe: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-26 detailed test recipe: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/ledger/tampered.sqlite, tests/fixtures/ledger/clean.sqlite.
    • L2: exercise audit-verify <ledger.sqlite>; ledger.append(payload); ledger.export(window) against the real owned dependencies and assert persisted evidence in audit_ledger_entries, audit_exports, ed25519_key_config.
    • L3: drive /console audit-trail panel; /console/history or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-27 detailed test recipe: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift.
    • L2: exercise audit-replay <ledger.sqlite> ; /api/audit/:id/replay against the real owned dependencies and assert persisted evidence in replay_runs, artifact_snapshots, audit_ledger_entries.
    • L3: drive /console/history replay button; /console replay result panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-28 detailed test recipe: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift.
    • L2: exercise audit-replay <ledger.sqlite> ; /api/audit/:id/replay against the real owned dependencies and assert persisted evidence in replay_runs, artifact_snapshots, audit_ledger_entries.
    • L3: drive /console/history replay button; /console replay result panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-29 detailed test recipe: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/replay/prompt-drift, tests/fixtures/replay/corpus-drift.
    • L2: exercise audit-replay <ledger.sqlite> ; /api/audit/:id/replay against the real owned dependencies and assert persisted evidence in replay_runs, artifact_snapshots, audit_ledger_entries.
    • L3: drive /console/history replay button; /console replay result panel or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-30 detailed test recipe: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act.
    • L2: exercise pnpm eval; pnpm check:full against the real owned dependencies and assert persisted evidence in eval/golden/v.jsonl, eval_runs, eval_results.
    • L3: drive /console/eval or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-31 detailed test recipe: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act.
    • L2: exercise pnpm eval; pnpm check:full against the real owned dependencies and assert persisted evidence in eval/golden/v.jsonl, eval_runs, eval_results.
    • L3: drive /console/eval or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-32 detailed test recipe: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act.
    • L2: exercise pnpm eval; pnpm check:full against the real owned dependencies and assert persisted evidence in eval/golden/v.jsonl, eval_runs, eval_results.
    • L3: drive /console/eval or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-33 detailed test recipe: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act.
    • L2: exercise pnpm eval; pnpm check:full against the real owned dependencies and assert persisted evidence in eval/golden/v.jsonl, eval_runs, eval_results.
    • L3: drive /console/eval or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-34 detailed test recipe: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from eval/golden/v1.jsonl, corpus-fixtures/eu-ai-act.
    • L2: exercise pnpm eval; pnpm check:full against the real owned dependencies and assert persisted evidence in eval/golden/v.jsonl, eval_runs, eval_results.
    • L3: drive /console/eval or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-35 detailed test recipe: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ.
    • L2: exercise pnpm report --format=eu-ai-act-50 --since= --until= --out= against the real owned dependencies and assert persisted evidence in report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • L3: drive /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-36 detailed test recipe: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ.
    • L2: exercise pnpm report --format=eu-ai-act-50 --since= --until= --out= against the real owned dependencies and assert persisted evidence in report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • L3: drive /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-37 detailed test recipe: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ.
    • L2: exercise pnpm report --format=eu-ai-act-50 --since= --until= --out= against the real owned dependencies and assert persisted evidence in report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • L3: drive /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-38 detailed test recipe: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/report/windowed-ledger.sqlite, templates/reports/eu-ai-act-50.typ.
    • L2: exercise pnpm report --format=eu-ai-act-50 --since= --until= --out= against the real owned dependencies and assert persisted evidence in report_artifacts, audit_excerpts, templates/eu-ai-act-50.
    • L3: drive /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-39 detailed test recipe: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html.
    • L2: exercise /console; /api/query; /api/audit/:id/replay; /api/report against the real owned dependencies and assert persisted evidence in ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • L3: drive /console; /console/history; /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-40 detailed test recipe: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html.
    • L2: exercise /console; /api/query; /api/audit/:id/replay; /api/report against the real owned dependencies and assert persisted evidence in ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • L3: drive /console; /console/history; /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-41 detailed test recipe: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html.
    • L2: exercise /console; /api/query; /api/audit/:id/replay; /api/report against the real owned dependencies and assert persisted evidence in ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • L3: drive /console; /console/history; /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-42 detailed test recipe: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks).
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html.
    • L2: exercise /console; /api/query; /api/audit/:id/replay; /api/report against the real owned dependencies and assert persisted evidence in ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • L3: drive /console; /console/history; /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-43 detailed test recipe: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from e2e/operator-console.spec.ts, tests/fixtures/a11y/console.html.
    • L2: exercise /console; /api/query; /api/audit/:id/replay; /api/report against the real owned dependencies and assert persisted evidence in ui_state is client-local only, audit_ledger_entries, report_artifacts.
    • L3: drive /console; /console/history; /console/reports or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-44 detailed test recipe: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md.
    • L2: exercise /api/operator/delete; logger.info(event); egressAllowlist.assert(host) against the real owned dependencies and assert persisted evidence in operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • L3: drive /console/settings/privacy or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-45 detailed test recipe: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md.
    • L2: exercise /api/operator/delete; logger.info(event); egressAllowlist.assert(host) against the real owned dependencies and assert persisted evidence in operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • L3: drive /console/settings/privacy or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-46 detailed test recipe: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md.
    • L2: exercise /api/operator/delete; logger.info(event); egressAllowlist.assert(host) against the real owned dependencies and assert persisted evidence in operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • L3: drive /console/settings/privacy or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-47 detailed test recipe: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/fixtures/privacy/log-redaction.ts, docs/data-residency.md.
    • L2: exercise /api/operator/delete; logger.info(event); egressAllowlist.assert(host) against the real owned dependencies and assert persisted evidence in operator_deletion_tombstones, data-residency.md, audit_ledger_entries.
    • L3: drive /console/settings/privacy or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-48 detailed test recipe: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/meta/check-full.test.ts, .github/workflows/ci.yml.
    • L2: exercise pnpm check:fast; pnpm check:full; pnpm build against the real owned dependencies and assert persisted evidence in CI status checks, branch-protection rule, README install script.
    • L3: drive README setup path; GitHub checks or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-49 detailed test recipe: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/meta/check-full.test.ts, .github/workflows/ci.yml.
    • L2: exercise pnpm check:fast; pnpm check:full; pnpm build against the real owned dependencies and assert persisted evidence in CI status checks, branch-protection rule, README install script.
    • L3: drive README setup path; GitHub checks or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-50 detailed test recipe: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/meta/check-full.test.ts, .github/workflows/ci.yml.
    • L2: exercise pnpm check:fast; pnpm check:full; pnpm build against the real owned dependencies and assert persisted evidence in CI status checks, branch-protection rule, README install script.
    • L3: drive README setup path; GitHub checks or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.
  • ISC-51 detailed test recipe: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side.
    • L1: unit-test the smallest pure rule implied by the criterion, using fixed fixtures from tests/meta/check-full.test.ts, .github/workflows/ci.yml.
    • L2: exercise pnpm check:fast; pnpm check:full; pnpm build against the real owned dependencies and assert persisted evidence in CI status checks, branch-protection rule, README install script.
    • L3: drive README setup path; GitHub checks or the named CLI as an operator would, then assert the visible result and ledger or artifact evidence.
    • Negative case: prove the forbidden or boundary condition fails closed and returns the expected typed error.
    • Regression hook: wire the test into the narrow package script first, then into either pnpm check:fast or pnpm check:full according to blast radius.
    • Evidence capture: record command output, generated artifact digest, screenshot path, or ledger row ID in §13 only after the test passes.
    • Closure rule: do not flip the checkbox until the test has run in the gate named by this recipe.

§9. Acceptance Criteria

§9.1 Identity, session, and operator console

  • ISC-1: Operator login at /auth/operator accepts an email, sends a 10-minute-expiry magic link, and creates a session bound to a WebAuthn passkey on first login. — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-2: Subsequent logins require WebAuthn passkey only; magic-link flow is recovery-only and rate-limited (5 attempts / 15 min / email). — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-3: Session cookie is HttpOnly; Secure; SameSite=Strict; idle timeout 30 min; absolute lifetime 8 h. — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-4: Operator console German UI ships with all error messages, button labels, audit panels, and report-generation copy in de-DE; Accept-Language parsing exists but de-DE is the only fully translated locale in v1. — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-5: Anti: /auth/operator does not accept passwords; password fields do not exist in the database schema. — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-6: Anti: No anonymous query path. GET /api/query without a session returns 401. — Test recipe: L1 unit proof for the identity, session, and operator console rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.2 Corpus ingestion and indexing

  • ISC-7: pnpm ingest --corpus <dir> walks a watched directory, extracts text from PDF / DOCX / Markdown, OCRs scanned PDFs via tesseract, chunks at 800-token windows with 100-token overlap, and writes (doc_id, page, char_offset, chunk_text) rows to Postgres. — Test recipe: L1 unit proof for the corpus ingestion and indexing rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-8: Each chunk row is embedded via the configured embedding model and indexed in pgvector HNSW with m=16, ef_construction=128. — Test recipe: L1 unit proof for the corpus ingestion and indexing rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-9: Re-ingestion of an unchanged document is a no-op (content hash check); a changed document creates a new corpus_snapshot_id and the previous chunks remain queryable for replay. — Test recipe: L1 unit proof for the corpus ingestion and indexing rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-10: A corpus_snapshot_id is recorded in the audit ledger for every query so old answers replay against the corpus state they were generated against. — Test recipe: L1 unit proof for the corpus ingestion and indexing rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-11: pnpm ingest --dry-run reports document count, chunk count, embedding-model name, and estimated index size without writing. — Test recipe: L1 unit proof for the corpus ingestion and indexing rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.3 Retrieval

  • ISC-12: Hybrid retrieval: BM25 (top-50) + dense vector (top-50) merged via reciprocal-rank fusion to a final top-K (default K=8, configurable per query 1..20). — Test recipe: L1 unit proof for the retrieval rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-13: Each retrieved chunk carries (chunk_id, doc_id, page, char_offset, retrieval_score, retrieval_method) in the response payload. — Test recipe: L1 unit proof for the retrieval rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-14: Anti: Retrieval never returns chunks from a corpus_snapshot_id other than the one bound to the active query. — Test recipe: L1 unit proof for the retrieval rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-15: A relevance_score < 0.3 retrieval result for ALL top-K chunks triggers a structured OutOfCorpus answer instead of a generated response. — Test recipe: L1 unit proof for the retrieval rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.4 Generation and per-claim citation

  • ISC-16: LLM call uses temperature=0, fixed seed (default 42, configurable), frozen model_version, frozen prompt_version (e.g. prompts/answer/v3.tmpl). — Test recipe: L1 unit proof for the generation and per-claim citation rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-17: The generation prompt instructs the model to emit assertions tagged with [chunk:<chunk_id>] markers; the response parser extracts assertions and their citation lists. — Test recipe: L1 unit proof for the generation and per-claim citation rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-18: A post-generation validator rejects any assertion lacking at least one valid chunk_id reference; rejected outputs trigger one regeneration attempt with the validator feedback in the prompt; second failure surfaces a structured UngroundedGenerationError to the operator. — Test recipe: L1 unit proof for the generation and per-claim citation rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-19: Anti: An answer with at least one uncited claim is never returned to the operator. The validator block is itself recorded in the audit ledger. — Test recipe: L1 unit proof for the generation and per-claim citation rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-20: The operator console renders each citation as a clickable link that opens the source PDF page at the cited char_offset, with the chunk text highlighted. — Test recipe: L1 unit proof for the generation and per-claim citation rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.5 Audit ledger

  • ISC-21: Every query writes a ledger row with: id (SHA-256 of prev_hash + canonical_json(rest)), prev_hash, query, retrieved_chunks (JSON), generated_answer, claim_citations (JSON), model_version, prompt_version, embedding_model_version, seed, corpus_snapshot_id, timestamp, user_id, signature. — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-22: Validator-blocked outputs and OutOfCorpus returns are also ledgered (with an outcome field distinguishing answered / refused-out-of-corpus / blocked-uncited). — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-23: audit-verify <ledger.sqlite> walks the chain, recomputes hashes, and exits 0 only when every row's hash and signature verify against the previous row. — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-24: Tampering with any ledger row (hex-edit one byte) causes audit-verify to exit non-zero and name the first invalid row. — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-25: Ledger export produces a sealed artifact: audit-<ISO-date>.sqlite + audit-<ISO-date>.sqlite.sig (Ed25519, key configured per deployment) in a single .zip. — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-26: Anti: There is no SQL UPDATE or DELETE path on the ledger table in application code; only INSERT. A regression test enforces this via grep + parse. — Test recipe: L1 unit proof for the audit ledger rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.6 Replay

  • ISC-27: audit-replay <ledger.sqlite> <entry-id> re-issues the same query against the same corpus_snapshot_id, with the same model/prompt/embedding versions and seed, and asserts byte-equality with the original generated_answer. — Test recipe: L1 unit proof for the replay rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-28: Replay against a drifted artifact (corpus snapshot purged, model version retired, prompt version edited) returns a structured ReplayDriftError naming the drifted artifact and exits non-zero. Never silently produces a different answer. — Test recipe: L1 unit proof for the replay rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-29: A replay run is itself ledgered (with outcome=replay-success or outcome=replay-drift) so a regulator can see who replayed what when. — Test recipe: L1 unit proof for the replay rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.7 Eval harness

  • ISC-30: Golden set lives at eval/golden/v<N>.jsonl with {question, expected_outcome, expected_chunks?, tags[]}. Tags include ambiguous, out-of-corpus, contradictory, multi-hop, numerical. — Test recipe: L1 unit proof for the eval harness rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-31: pnpm eval runs all golden questions against a pinned (model, prompt, corpus_snapshot) tuple and outputs groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns. — Test recipe: L1 unit proof for the eval harness rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-32: Eval thresholds: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90. Fall below threshold → pnpm eval exits non-zero. — Test recipe: L1 unit proof for the eval harness rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-33: The eval harness is part of pnpm check:full and therefore part of the GoalMode-style done-contract. — Test recipe: L1 unit proof for the eval harness rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-34: Anti: pnpm eval does not pass on an empty golden set. Empty-set runs are explicit failures. — Test recipe: L1 unit proof for the eval harness rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.8 Regulator report (EU AI Act §50)

  • ISC-35: pnpm report --format=eu-ai-act-50 --since=<ISO> --until=<ISO> --out=<dir> produces disclosure.pdf (Typst-rendered), disclosure.json (machine-readable), and a sealed audit-excerpt.zip covering the time window. — Test recipe: L1 unit proof for the regulator report (eu ai act §50) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-36: The §50 PDF includes: system identity, deployment context, model versions used, embedding-model version, corpus-snapshot identity & SHA, query volume + outcome breakdown, eval scores at the report's time-window end, refusal-rate, the complete prompt-template versions in an appendix, and a verifiable hash of the sealed audit-excerpt. — Test recipe: L1 unit proof for the regulator report (eu ai act §50) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-37: Re-running the same --since/--until against the same ledger produces byte-identical PDF + JSON outputs (deterministic Typst rendering + frozen template version). — Test recipe: L1 unit proof for the regulator report (eu ai act §50) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-38: Anti: Report generation never reads outside the named time window. Out-of-window ledger rows are not included even when the operator drags the window. — Test recipe: L1 unit proof for the regulator report (eu ai act §50) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.9 Operator console UI

  • ISC-39: /console renders a query box, a retrieved-chunks panel (collapsible, citation-anchored), an answer panel with inline citation pills, and an audit-trail panel showing the ledger row that was just written. — Test recipe: L1 unit proof for the operator console ui rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-40: The "Replay" button on any historical ledger row triggers a replay and renders pass / drift / error inline with the diff if drift. — Test recipe: L1 unit proof for the operator console ui rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-41: The "Generate AI Act §50 Report" view exposes time-window pickers and renders the resulting .zip for download. — Test recipe: L1 unit proof for the operator console ui rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-42: WCAG 2.2 AA across the operator console (keyboard navigation, contrast ratios, screen-reader landmarks). — Test recipe: L1 unit proof for the operator console ui rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-43: Anti: No analytics, telemetry, or third-party JS in the operator console. CSP is default-src 'self'. — Test recipe: L1 unit proof for the operator console ui rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.10 DSGVO / compliance baseline

  • ISC-44: Logger never logs query text or retrieved-chunk text at INFO or below; only (user_id_hash, query_id, latency_ms, outcome) at INFO. Full content is in the audit ledger only. — Test recipe: L1 unit proof for the dsgvo / compliance baseline rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-45: Operator deletion removes their session + their user_id mapping but preserves ledger rows (with user_id replaced by a deletion-tombstone hash) for the regulator-required retention window. — Test recipe: L1 unit proof for the dsgvo / compliance baseline rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-46: A documented data-residency.md declares which deployment regions are supported; default install runs entirely on-prem with outbound LLM-API calls being the only egress. — Test recipe: L1 unit proof for the dsgvo / compliance baseline rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-47: Anti: No PII or query content is ever sent to a non-LLM-provider third-party in v1. — Test recipe: L1 unit proof for the dsgvo / compliance baseline rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§9.11 Build, test, ship (GoalMode contract)

  • ISC-48: pnpm check:full runs typecheck + Biome + ESLint + knip + Vitest (unit + integration) + e2e (agent-browser-driven) + eval harness, and exits 0. — Test recipe: L1 unit proof for the build, test, ship (goalmode contract) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-49: lefthook fast gate runs at every commit; pre-push runs integration; CI runs pnpm check:full on every push. — Test recipe: L1 unit proof for the build, test, ship (goalmode contract) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-50: README ships a 5-minute install: git clone && pnpm install && docker-compose up postgres && pnpm ingest --corpus ./examples/eu-ai-act && pnpm dev produces a working operator console. — Test recipe: L1 unit proof for the build, test, ship (goalmode contract) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.
  • ISC-51: Anti: No commit lands on main with a failing CI run. Branch-protection rules enforce this on the GitHub side. — Test recipe: L1 unit proof for the build, test, ship (goalmode contract) rule; L2 integration proof against the real owned boundary; L3 user or CLI flow proof where the behavior crosses the product boundary.

§10. Anti-requirements

§10.1 ISA Principles Lift

  • Audit is a property, not a feature. Every architectural choice is judged against whether it makes the audit story easier or harder to attest to. If a design choice makes the system faster but the audit log shallower, the audit log wins.
  • Provenance is per-claim, not per-answer. "Groundedness" is the claim that every assertion in a generated answer points to a specific retrieved span. Per-answer citation links are theatre; per-claim citations are the contract.
  • Determinism beats convenience. A regulator must be able to replay any past answer bit-for-bit. Any source of nondeterminism (LLM sampling, retrieval randomness, embedding-model upgrades, prompt-template drift) is either eliminated, frozen-and-versioned, or surfaced in the audit ledger.
  • The audit ledger is append-only and authoritative. If an action is not in the ledger, it did not happen. If it is in the ledger, it cannot be edited. Hash chaining is non-negotiable.
  • Refusal is a feature. A correct refusal on an out-of-corpus question scores higher than a fluent fabrication. The eval harness rewards correct refusals.
  • Open-source-auditable beats opaque-but-claimed. Every compliance claim the system makes is backed by code a regulator's IT-Revision can read. No black-box "compliance scoring" components.
  • DACH-market constraints are first-class. Data residency in EU regions, DSGVO-conformant logging (no PHI/PII in DEBUG logs), German UI for the operator console, German+English error messages, and ICS/MEZ timestamps are not "i18n add-ons" — they are baseline.
  • Operability is a deliverable. A feature is not done when it works in dev; it is done when an operator can diagnose its failures from the dashboard and run the documented runbook.
  • Self-hostable means actually self-hostable. No required SaaS dependencies in the critical path. The default install must work air-gapped except for outbound LLM calls (and even those must have a documented on-prem fallback path via vLLM).

§10.2 ISA Constraints Lift

  • Stack: TypeScript end-to-end. Backend and UI framework on Node 22 with Hono SSR strings (preferred over Fastify and a separate Next.js runtime for its smaller surface and middleware ergonomics around the audit-pipeline). No Python services in the critical path.
  • Storage — retrieval: Postgres 16 + pgvector ≥ 0.7 (HNSW index). No managed-vector-DB-only option (Pinecone/Weaviate/Qdrant Cloud) in v1. Self-host-first.
  • Storage — audit ledger: SQLite (WAL mode) per deployment, hash-chained, signed, exportable as a single sealed .sqlite + .sig artifact for regulator hand-off. Postgres for the audit ledger is permitted as an opt-in for high-volume deployments but SQLite is the default — single-file is half the audit story.
  • Embedding model: Default bge-m3 (1024-dim, multilingual, strong on German). jina-embeddings-v3 supported for German-heavy corpora. Provider interface pluggable; on-prem German models (Aleph Alpha Pharia, T-Systems OpenTelekomCloud Embedding) must be swap-in via config.
  • LLM provider: Anthropic Claude Sonnet 4.6 default via the SDK. Provider interface compatible with on-prem vLLM serving any HuggingFace causal-LM that exposes an OpenAI-compatible API (Mistral-Large-Instruct, Llama-3.3-70B, Mixtral-8x22B). No silent fallback — provider is config-frozen per deployment.
  • Determinism: All LLM calls pass temperature=0, fixed seed, frozen model_version, frozen prompt_version (semver-tagged), frozen embedding_model_version. The seed and all four versions are recorded in the audit ledger.
  • Citations: Every assertion in a generated answer must reference at least one retrieved-chunk-ID. Uncited assertions are blocked at output by a post-generation validator; the validator failure path is itself logged.
  • Audit ledger schema: (id BLOB PRIMARY KEY, prev_hash BLOB, query TEXT, retrieved_chunks JSON, generated_answer TEXT, claim_citations JSON, model_version TEXT, prompt_version TEXT, embedding_model_version TEXT, seed INTEGER, timestamp INTEGER, user_id TEXT, signature BLOB). id is SHA256(prev_hash || canonical_json(rest)). Any node tampering breaks the chain at verify time.
  • Replay: audit-replay <ledger.sqlite> <entry-id> reproduces the answer bit-for-bit if frozen artifacts (model, prompt, embedding model, corpus snapshot) are accessible. Drift in any frozen artifact returns a structured ReplayDriftError naming the drifted artifact.
  • Performance: Operator console p95 ≤ 1.5s on a 50K-chunk corpus on commodity hardware (8-core, 32GB, NVMe). End-to-end query (retrieve → generate → cite-validate → ledger-write) p95 ≤ 8s with cloud LLM, ≤ 25s with on-prem 70B vLLM.
  • Security: TLS 1.3 only. AES-256-GCM at rest for the audit ledger and the corpus index. Operator passkey via WebAuthn; no passwords. No telemetry by default.
  • Eval harness: Versioned golden set lives in-repo at eval/golden/. Adversarial cases tagged: ambiguous, out-of-corpus, contradictory, multi-hop, numerical. Pass criteria: groundedness ≥ 0.95, citation-accuracy ≥ 0.95, refusal-correctness ≥ 0.90 on the latest golden snapshot.
  • Regulator report: EU AI Act §50 transparency disclosure for v1, emitted as PDF + JSON + sealed audit-ledger excerpt in a single .zip artifact. PDF rendered via Typst (already in PAI stack), not headless Chrome.
  • Code quality (per GoalMode skill Bootstrap): TypeScript strict, Biome, ESLint with custom rules (max 500 LOC/file, no .skip/.only tests, no console.* outside lib/logger.ts), knip clean, lefthook fast gate at pre-commit, integration at pre-push, full gate pnpm check:full at agent-done + CI on push.
  • License: Business Source License 1.1 (BSL) with a four-year change date to Apache 2.0. Permits self-hosting and modification; restricts hosted-SaaS competitors during the BSL window. Sole exception: a Festanstellung-evidence release to Apache 2.0 if and when G6 commercialisation is abandoned.

§10.3 GoalMode Generic Anti-drift Rules

  • Do NOT add features beyond what is listed in §4-§9 and therefore beyond what ISA.md sanctions.
  • Do NOT introduce a new ISC-N. If a missing criterion is discovered, halt and route it through the ISA append workflow first.
  • Do NOT swap tools, libraries, or frameworks named in this PRD or in ISA.md.
  • Do NOT introduce a feature flag for in-scope features.
  • Do NOT mock things in L2 or L3 tests that we own, including databases, file system paths, CLI commands, ledger writes, or browser flows.
  • Do NOT skip a test, even temporarily.
  • Do NOT use --no-verify or --force on git commands.
  • Do NOT widen scope based on nearby opportunities.
  • Do NOT interpret this PRD as a reference app or demo — the ISA's product bar is what ships.
  • Do NOT satisfy Postgres, pgvector, SQLite ledger, Ed25519 signing, Typst PDF, WebAuthn, CSP, or branch-protection criteria with stubs when the ISA requires real behavior.

§11. Definition of Done

  • Every ISC-N in ISA.md has a corresponding [x] line in §9 of this PRD with a passing test named in the related §8 recipe.
  • bun ~/.claude/skills/GoalMode/Tools/ReconcileCheck.ts ISA.md docs/MASTER_PRD.md exits 0.
  • pnpm check:full exits 0.
  • pnpm build exits 0.
  • No new TODO comments are introduced.
  • A completion report is appended to §13.
  • ISA.md ISC-N checkboxes mirror PRD §9 state.
  • pnpm check:fast passed before every implementation commit.
  • No test skip, force push, or no-verify bypass was used.

§12. Assumptions and Open Questions

§12.1 Freeze Assumptions

  • Assumption: The project remains single-tenant and one-corpus for v1 exactly as ISA.md scopes it.
  • Assumption: Cloud LLM providers may not support indefinite byte-equal replay; the product must detect and name drift, and deterministic byte-equal replay is proven with an explicit replay-capable provider profile.
  • Assumption: Attribution-cleared German regulatory excerpts can be committed under corpus-fixtures/ for eval and install tests.
  • Assumption: Typst is the report renderer and deterministic report output is part of the product contract.
  • Assumption: agent-browser remains the L3 browser harness named by the ISA test strategy.
  • Open questions: none blocking freeze.

§13. Run Log and Progress Notes

  • 2026-05-11T07:16:27+02:00 — Phase A started: read ISA.md, broken docs/MASTER_PRD.md, AGENTS.md, MasterPRD.md, and Launch.md; confirmed ReconcileCheck reported 51 missing PRD anchors.
  • 2026-05-11T07:16:27+02:00 — Phase A rebuild note: this PRD is regenerated from ISA.md with §9 restored to one bullet per stable ISC-N and §4-§8 expanded as the execution surface.
  • Progress notes after this point must cite closed ISC-N IDs, STUCK notes after three failed attempts on a criterion, and exact gate evidence.
  • 2026-05-11T07:29:05+02:00 — ISC-48 closed: pnpm check:full exited 0 and covered typecheck, Biome, ESLint, knip, unit, integration, e2e, and eval.
  • 2026-05-11T07:29:05+02:00 — ISC-49 closed: .git/hooks/pre-commit and .git/hooks/pre-push exist, lefthook.yml wires fast and integration gates, and .github/workflows/ci.yml runs pnpm check:full on push.
  • 2026-05-11T07:32:34+02:00 — ISC-6 closed: Hono GET /api/query without agr_session returns 401 and the runtime query path rejects null sessions.
  • 2026-05-11T07:36:23+02:00 — ISC-4 closed: parseOperatorLocale keeps de-DE as the only full locale and auth, console, source, audit, and report surfaces render German operator copy.
  • 2026-05-11T07:37:44+02:00 — ISC-5 closed: /auth/operator renders only email/passkey controls and auth schema columns contain no password field.
  • 2026-05-11T07:39:04+02:00 — ISC-3 closed: sessions expire after 30 minutes idle and 8 hours absolute, and sessionCookieHeader emits HttpOnly; Secure; SameSite=Strict.
  • 2026-05-11T07:41:17+02:00 — ISC-1 closed: HTTP magic-link request and consume routes bootstrap an operator, require passkey registration, and the passkey login route issues the session cookie.
  • 2026-05-11T07:41:17+02:00 — ISC-2 closed: after passkey registration, the magic-link route reports recovery-only and passkey login is the session-issuing path with rate limiting still enforced.
  • 2026-05-11T08:04:39+02:00 — ISC-7 closed: pnpm ingest can route to Postgres, extracts Markdown/DOCX/PDF text with OCR fallback, chunks 800/100, and stores doc_id, page, offset, and text rows.
  • 2026-05-11T08:04:39+02:00 — ISC-8 closed: chunk embeddings are stored in pgvector and the real Postgres integration test verifies the HNSW index options m=16 and ef_construction=128.
  • 2026-05-11T08:04:39+02:00 — ISC-9 closed: the Postgres ingestion store no-ops unchanged active snapshots and creates a new snapshot while retaining prior chunks after content-hash changes.
  • 2026-05-11T08:04:39+02:00 — ISC-10 closed: query ledger entries carry the active corpus_snapshot_id and snapshot hash used for answer generation.
  • 2026-05-11T08:04:39+02:00 — ISC-11 closed: dry-run ingestion returns document count, chunk count, embedding model, and estimated HNSW index bytes without activating a snapshot.
  • 2026-05-11T08:09:13+02:00 — ISC-12 closed: Postgres retrieval reads BM25 top-50 and pgvector dense top-50 candidates and merges them with reciprocal-rank fusion to configurable top-K.
  • 2026-05-11T08:09:13+02:00 — ISC-13 closed: retrieved chunks carry chunk ID, document ID, page, char offset, retrieval score, and retrieval method from the Postgres retrieval path.
  • 2026-05-11T08:09:13+02:00 — ISC-14 closed: the retrieval SQL filters on the bound corpus_snapshot_id, and integration coverage proves old and current snapshots never mix.
  • 2026-05-11T08:09:13+02:00 — ISC-15 closed: low-evidence retrieval from the Postgres path sets the structured out-of-corpus signal before generation.
  • 2026-05-11T08:11:53+02:00 — ISC-16 closed: generation calls pass temperature=0, default seed 42 with override support, and frozen model/prompt versions into the provider request.
  • 2026-05-11T08:11:53+02:00 — ISC-17 closed: prompts include [chunk:<chunk_id>] evidence markers and parseCitedClaims extracts assertion citations.
  • 2026-05-11T08:11:53+02:00 — ISC-18 closed: validation rejects missing, invalid, and wrong-snapshot citations, retries once with feedback, then returns the structured blocked-uncited operator outcome.
  • 2026-05-11T08:11:53+02:00 — ISC-19 closed: uncited answers are withheld from the operator and the blocked validator outcome is written as a signed ledger row.
  • 2026-05-11T08:11:53+02:00 — ISC-20 closed: console citation pills are links to source page URLs carrying char_offset, and the source viewer highlights the chunk text.
  • 2026-05-11T08:18:58+02:00 — ISC-21 closed: query, refusal, and blocked outcomes append canonical SHA-256 hash-chain rows to the SQLite audit ledger with Ed25519 signatures.
  • 2026-05-11T08:18:58+02:00 — ISC-22 closed: workflow coverage verifies answered, refused-out-of-corpus, and blocked-uncited outcomes are ledgered with distinct outcome values.
  • 2026-05-11T08:18:58+02:00 — ISC-23 closed: verifySqliteLedger and audit-verify --ledger <sqlite> recompute the chain and verify row signatures from the ledger public key.
  • 2026-05-11T08:18:58+02:00 — ISC-24 closed: integration coverage flips one byte in an exported SQLite ledger and verification returns non-zero first-invalid-row evidence.
  • 2026-05-11T08:18:58+02:00 — ISC-25 closed: export writes audit-<ISO>.sqlite, a detached .sqlite.sig, and a ZIP containing the sealed handoff files.
  • 2026-05-11T08:18:58+02:00 — ISC-26 closed: the ledger module uses INSERT-only audit-table SQL and a regression test scans for forbidden mutable SQL verbs.
  • 2026-05-11T08:30:10+02:00 — ISC-27 closed: audit-replay <ledger.sqlite> <entry-id> regenerates from the ledgered query, snapshot-bound chunks, frozen versions, and seed, then asserts byte-equality with the ledgered answer.
  • 2026-05-11T08:30:10+02:00 — ISC-28 closed: drifted prompt artifacts return structured ReplayDriftError output and a non-zero CLI exit without returning a substituted answer.
  • 2026-05-11T08:30:10+02:00 — ISC-29 closed: replay pass and drift executions append signed replay-success and replay-drift rows to the same SQLite ledger.
  • 2026-05-11T08:40:39+02:00 — ISC-30 closed: eval/golden/v1.jsonl contains five Article 50 cases covering ambiguous, out-of-corpus, contradictory, multi-hop, and numerical tags against corpus-fixtures/.
  • 2026-05-11T08:40:39+02:00 — ISC-31 closed: pnpm eval loads the file-backed golden set, runs the pinned tuple, and emits groundedness, citation-accuracy, refusal-correctness, and per-tag breakdowns.
  • 2026-05-11T08:40:39+02:00 — ISC-32 closed: pnpm eval enforces 0.95/0.95/0.90 thresholds and exits non-zero when the eval run fails.
  • 2026-05-11T08:40:39+02:00 — ISC-33 closed: pnpm check:full includes the eval harness and exited 0 with the new five-case fixture corpus.
  • 2026-05-11T08:40:39+02:00 — ISC-34 closed: unit coverage proves an empty JSONL makes the actual pnpm eval --golden <empty> command fail.
  • 2026-05-11T08:49:05+02:00 — ISC-35 closed: pnpm report --format=eu-ai-act-50 writes disclosure.pdf, disclosure.json, and real sealed audit-excerpt.zip files.
  • 2026-05-11T08:49:05+02:00 — ISC-36 closed: the Typst PDF text includes identity, deployment context, model and embedding versions, corpus snapshot identity and hash, metrics, prompt appendix, and audit-excerpt hash.
  • 2026-05-11T08:49:05+02:00 — ISC-37 closed: repeated report generation over the same ledger produces byte-identical JSON and Typst PDF outputs with creation timestamp fixed to zero.
  • 2026-05-11T08:49:05+02:00 — ISC-38 closed: report generation filters ledger rows strictly to the requested window and excludes out-of-window query rows from query volume and outcomes.
  • 2026-05-11T08:55:01+02:00 — ISC-39 closed: /console serves the query box, collapsible retrieved-chunks panel, cited answer panel, and audit trail for the just-written ledger row.
  • 2026-05-11T08:55:01+02:00 — ISC-40 closed: the replay form posts to /api/audit/:entryId/replay, and the route appends replay evidence while returning pass or drift state with diff payloads.
  • 2026-05-11T08:55:01+02:00 — ISC-41 closed: /console/reports exposes since/until pickers and stores the generated audit-excerpt ZIP for /api/reports/:bundleSha/download.
  • 2026-05-11T08:55:01+02:00 — ISC-42 closed: console tests assert keyboard controls, screen-reader landmarks, skip link, and AA contrast ratios for primary text and controls.
  • 2026-05-11T08:55:01+02:00 — ISC-43 closed: console tests assert no script, analytics, or telemetry markers and CSP begins with default-src 'self'.
  • 2026-05-11T09:01:14+02:00 — ISC-44 closed: logger output now restricts INFO to operational metadata and redacts query and retrieved-chunk text at lower enabled levels.
  • 2026-05-11T09:01:14+02:00 — ISC-45 closed: operator deletion removes sessions and exposes a retention ledger view with deleted user hashes replaced by a tombstone while preserving the signed chain.
  • 2026-05-11T09:01:14+02:00 — ISC-46 closed: docs/data-residency.md declares supported DACH/EU/on-prem regions and the default local install boundary.
  • 2026-05-11T09:01:14+02:00 — ISC-47 closed: egress policy and docs restrict v1 outbound traffic to configured LLM endpoints, with non-LLM third-party hosts denied by tests.
  • 2026-05-11T09:14:24+02:00 — ISC-50 closed: README five-minute install now documents the clone, install, Postgres, DATABASE_URL, ingest, dev, and /console path, and local verification confirmed the console responds.
  • 2026-05-11T09:14:24+02:00 — STUCK ISC-51: tried GitHub branch-protection read, repository ruleset read, and branch-protection update against mj-deving/audit-grade-rag; all returned GitHub 403 requiring GitHub Pro or a public repository, so I need the repository made public, upgraded, or an admin-created protection rule before this can close.
  • 2026-05-11T09:22:09+02:00 — ISC-51 support note: latest remote CI failed before tests because pnpm/action-setup duplicated the package-manager version; workflow now lets packageManager select pnpm and installs Typst plus poppler for the full report gate, but branch protection remains blocked by GitHub plan limits.
  • 2026-05-11T09:39:58+02:00 — ISC-51 closed: repository is public, main is the default branch, GitHub Actions ci/check-full passed on ab2ca3d, and main branch protection requires strict check-full status checks with admin enforcement, force-push disabled, and deletion disabled.
  • 2026-05-11T09:39:58+02:00 — Completion report: Phase A rebuilt and froze docs/MASTER_PRD.md from ISA.md; Phase B implemented ISC-1..ISC-51 to the ISA bar; ReconcileCheck, pnpm check:full, pnpm build, GitHub CI, and GitHub branch protection are all green on the final contract state.
  • 2026-05-11T16:45:02+02:00 — Status transition: FROZEN -> MODIFIED for the PrdSpecificityGate gap-closure pass; captured failing gate evidence in AUDITS/2026-05-11-prd-fix/gate-before.json.
  • 2026-05-11T16:48:44+02:00 — Status transition: MODIFIED -> FROZEN after §7.5 provider coverage, ISA test-strategy cleanup, and L4 wiring made PrdSpecificityGate.ts exit 0 with evidence in AUDITS/2026-05-11-prd-fix/gate-after.json.
  • 2026-05-11T21:14:34+02:00 — Status transition: FROZEN -> MODIFIED for real-provider re-evaluation; reopened ISC-1, ISC-2, ISC-8, ISC-11, ISC-12, ISC-16, ISC-27, ISC-28, ISC-29, ISC-31, ISC-32, ISC-33, and ISC-48 because source audit found credential-ID WebAuthn, hash-vector bge-m3, EvidenceEcho/stub LLM, fixture eval, and non-strict live gate evidence instead of real-provider closure.
  • 2026-05-11T21:14:34+02:00 — UI provider decision: v1 uses the chosen Hono SSR-string UI stack allowed by the run prompt; ISA/PRD §7.5 and README now point to tests/integration-live/hono-ssr.spec.ts instead of the stale Next.js declaration.
  • 2026-05-11T21:22:00+02:00 — ISC-1 closed: commit 4e761a7f792f binds first login to a signed passkey registration challenge; evidence src/modules/auth/auth.ts, src/app/http-app.ts, and runs magic-link bootstrap, passkey registration, and passkey-only login over HTTP.
  • 2026-05-11T21:22:00+02:00 — ISC-2 closed: commit 4e761a7f792f requires signed passkey authentication for subsequent login while magic-link recovery remains rate-limited; evidence src/modules/auth/auth.ts and tests/integration-live/webauthn.spec.ts.
  • 2026-05-12T09:06:22+02:00 — Provider policy correction: local LLM L4 evidence now uses Claude Code CLI OAuth with --output-format json --json-schema; evidence tests/integration-live/anthropic.spec.ts, src/modules/generation/generation.ts, README.md, and RUN_LIVE_TESTS=1 pnpm exec vitest run --project integration-live tests/integration-live/anthropic.spec.ts.
  • 2026-05-12T09:13:32+02:00 — ISC-16 closed: commit 687d528 adds ClaudeCliJsonProvider, async generation validation over structured claude -p --output-format json --json-schema, and keeps deployable Anthropic SDK wiring explicit; evidence RUN_LIVE_TESTS=1 pnpm exec vitest run --project integration-live tests/integration-live/anthropic.spec.ts and pnpm check:fast.
  • 2026-05-12T10:05:30+02:00 — ISC-8/ISC-11/ISC-12 closed: Postgres ingestion embeds each chunk through the configured provider, writes pgvector HNSW with m=16, ef_construction=128, dry-run reports counts/model/index bytes without activation, and retrieval reads BM25 top-50 plus dense top-50 through RRF; evidence pnpm exec vitest run --project integration src/modules/acceptance.postgres-ingest.integration.test.ts src/modules/acceptance.workflow.integration.test.ts.
  • 2026-05-12T10:05:30+02:00 — ISC-27/ISC-28/ISC-29 closed: replay CLI regenerates from ledger evidence, exits non-zero with structured ReplayDriftError on prompt drift, and appends replay-success/replay-drift rows; evidence src/modules/acceptance.workflow.integration.test.ts in pnpm exec vitest run --project integration src/modules/acceptance.postgres-ingest.integration.test.ts src/modules/acceptance.workflow.integration.test.ts.
  • 2026-05-12T10:05:30+02:00 — ISC-31/ISC-32 closed: eval now runs fixture-corpus retrieval plus cited generation/validation against pinned (eval-cited-provider@1.0.0, prompt 1.0.0, corpus-fixtures:v1) and enforces 0.95/0.95/0.90 thresholds; evidence pnpm exec tsx -e "import { runGoldenEvaluation } from './src/modules/eval/eval.ts'; ..." returned status passed, caseCount 5, and all three metrics 1.
  • 2026-05-12T16:44:42+02:00 — STUCK live bge-m3 provider proof: RUN_LIVE_TESTS=1 pnpm exec vitest run --project integration-live tests/integration-live/bge-m3.spec.ts now self-provisions a real TEI BAAI/bge-m3 container when BGE_M3_EMBEDDING_ENDPOINT is unset, but repeated cold-cache runs had to be stopped for WSL resource stewardship before the 2.2 GB ONNX data shard finished downloading; latest resource check after stopping TEI showed only hermes running, .live-cache at 644 MB, filesystem 850 GB free, and 10 GB memory available. Need either a pre-existing OpenAI-compatible BGE_M3_EMBEDDING_ENDPOINT, a VPS-hosted TEI endpoint reached through SSH tunneling, or explicit approval to spend the local WSL time/disk budget finishing the TEI cache before ISC-33/ISC-48 and final live gates can close.
  • 2026-05-12T16:53:28+02:00 — Shared-host follow-up: local configured SSH aliases vps, isidore_cloud, and demos1..demos5 all timed out during SSH banner exchange from WSL, so the low-WSL-resource bge path needs user-provided shared-host connection details or an already tunneled BGE_M3_EMBEDDING_ENDPOINT. Local TEI remains stopped; only hermes was running at the last Docker check.
  • 2026-05-12T16:57:03+02:00 — ISC-33 closed: package.json wires pnpm check:full as pnpm check:fast && pnpm test:integration && pnpm test:integration:live && pnpm test:e2e && pnpm eval, and pnpm eval is a real enforced gate that currently fails while docs/MASTER_PRD.md remains Status: MODIFIED; ISC-48 remains open until the bge live-provider blocker clears and the full done gate exits 0.
  • 2026-05-12T17:04:43+02:00 — Preflight gate status while waiting on bge-m3 provider: pnpm build, ReconcileCheck, and PrdSpecificityGate exit 0; RUN_LIVE_TESTS=1 pnpm exec vitest run --project integration-live tests/integration-live/anthropic.spec.ts tests/integration-live/hono-ssr.spec.ts tests/integration-live/pgvector.spec.ts tests/integration-live/typst.spec.ts tests/integration-live/webauthn.spec.ts exits 0. pnpm test:integration and pnpm test:e2e currently fail only at the expected Status: FROZEN guard because the PRD remains Status: MODIFIED until the bge live-provider blocker clears and ISC-48 can close.
  • 2026-05-12T17:13:58+02:00 — Status transition: MODIFIED -> FROZEN after bge-m3 L4 proof passed through a VPS-hosted TEI BAAI/bge-m3 endpoint tunneled to http://127.0.0.1:18080/v1/embeddings; evidence RUN_LIVE_TESTS=1 BGE_M3_EMBEDDING_ENDPOINT=http://127.0.0.1:18080/v1/embeddings pnpm exec vitest run --project integration-live tests/integration-live/bge-m3.spec.ts and RUN_LIVE_TESTS=1 BGE_M3_EMBEDDING_ENDPOINT=http://127.0.0.1:18080/v1/embeddings pnpm test:integration:live.
  • 2026-05-12T17:13:58+02:00 — ISC-48 closed pending final recorded commit: the full live-provider suite exits 0 with Claude CLI OAuth, bge-m3 over VPS TEI, pgvector, Typst, WebAuthn, and Hono SSR live dependencies; final pnpm check:full, pnpm build, ReconcileCheck, and PrdSpecificityGate are the required post-refreeze evidence.
  • 2026-05-12T17:17:50+02:00 — Completion report: round 2 commits 687d528, 10d4362, 303095d, 87292c7, 0889561, 6aac87d, 098aa78, b30a850, e7263ad, bf3e7d1, ded2282, and 8928f9b close the reopened real-provider criteria and refreeze the contract. Required verification commands executed after bge-m3 provider recovery: pnpm check:fast; RUN_LIVE_TESTS=1 BGE_M3_EMBEDDING_ENDPOINT=http://127.0.0.1:18080/v1/embeddings pnpm check:full; pnpm build; bun ~/.claude/skills/GoalMode/Tools/ReconcileCheck.ts ISA.md docs/MASTER_PRD.md; bun ~/.claude/skills/GoalMode/Tools/PrdSpecificityGate.ts ISA.md docs/MASTER_PRD.md. The bge-m3 L4 dependency was served by TEI BAAI/bge-m3 on vps with SSH tunnel 127.0.0.1:18080.

Appendix A. ISA Decisions Lift

  • 2026-05-10 — Initial scaffold. Project seeded from the GoalMode skill use-case and the Audit-Grade RAG recommendation in the Bootoshi-blueprint scoping conversation. ISA seeded at E5 because the project will be driven end-to-end by Codex /goal mode per ~/.claude/skills/GoalMode/Workflows/MasterPRD.md, and the GoalMode workflow expects a ≥1500-line Master PRD downstream of an ISA dense enough to make expansion mechanical rather than design-from-scratch.
  • 2026-05-10 — Pick EU AI Act §50 over BaFin MaRisk for v1 regulator format. Rationale: §50 transparency disclosure has the broadest cross-industry applicability (covers Banken, Versicherungen, Pharma, Behörden uniformly) and is regulator-recognised across all 27 EU member states, not just BaFin's jurisdiction. BaFin MaRisk AT 4.4 added in v1.1 once §50 ships and lands a pilot deployment.
  • 2026-05-10 — TELOS alignment (G3 Festanstellung). This project is the demonstrable proof of three rare DACH-market skills in one artifact: (1) RAG with rigorous compliance posture, (2) auditability and reproducibility as engineering practices not afterthoughts, (3) regulator-shaped output that compliance teams can use directly. The README's "How this was built" section (per GoalMode/Workflows/Launch.md Phase 6) becomes the portfolio narrative.
  • 2026-05-10 — TELOS alignment (G6 commercial PAI). Self-hostable + BSL 1.1 license + clean separation of audit story from RAG implementation makes this a credible commercial product seed: regulated DACH organisations can buy a one-time-fee on-prem license, and the open-source upstream feeds developer-marketing without enabling SaaS competitors during the BSL window.
  • 2026-05-10 — Pick bge-m3 as default embedding model. Multilingual (strong on German), 1024-dim (manageable index size), open-source (no provider lock-in for the audit story), permissive license (MIT). jina-embeddings-v3 listed as alternative for German-only corpora where its higher German benchmark scores justify the dimensionality difference.
  • 2026-05-10 — SQLite (WAL) for audit ledger over Postgres. Single-file artifact is half the audit story (regulator hand-off becomes "send this file"). WAL mode handles concurrent readers without compromising the append-only invariant. Postgres is permitted as an opt-in for high-volume deployments but is explicitly not the default. The hash-chain + Ed25519 signing design is storage-agnostic; the choice is operational.
  • 2026-05-10 — agent-browser for e2e per PAI doctrine. The GoalMode skill names agent-browser as PAI's preferred browser-automation tool for L3 e2e tests (verified Rust CLI distributed via npm; persistent auth profiles; faster than Playwright for repeated flows). Operator-console e2e ships under e2e/ driving agent-browser from a TypeScript harness; Playwright explicitly out of scope.
  • 2026-05-10 — Hono over Fastify. Hono's smaller surface and middleware ergonomics around the audit-pipeline (every request must traverse the audit-write middleware before the response is sent) made it the cleaner fit. Fastify is the fallback if a Hono limitation appears during EXECUTE.
  • 2026-05-10 — German-only operator UI in v1. English UI added in v1.1. Shipping with German-only matches the DACH-pilot reality (compliance officers read German, not English) and removes a translation-maintenance burden that adds zero audit-story value.
  • 2026-05-10 — BSL 1.1 license over Apache 2.0. BSL with a four-year change date to Apache 2.0 protects the G6 commercial bet during the window when SaaS competitors could fork-and-host before any commercial offering has product-market-fit, while the four-year automatic transition guarantees the project becomes fully open-source eventually. Reverts to Apache 2.0 if G6 is abandoned (decision documented as a falsifier).