Governed documents and host-neutral MCP — development preview

Spec 050 implementation in the 2.3.15b1 beta candidate; not a released stable feature. Existing memory recall, MCP server and DolphinBench routing stay intact. The document service is opt-in. It is not a bundled law corpus or a legal-advice system and does not claim current-law completeness.

Connect an existing retriever

The governed stdio transport caps request and response frames at 1 MiB. RPC IDs are valid UTF-8 strings of at most 256 bytes or integers within the exact JSON number range. A large assembled quality report returns the explicit result_budget_exhausted tool error; it is never silently truncated or erased. Inspect individual outcomes or use the authenticated CLI/API report path for the complete retained detail. The response budget does not change task counts, evidence retention or whether an effect occurred.

Use FeedbackService(existing_evidence_service) and RagService(feedback). The authenticated owner grants the application principal explicit search and inspect capabilities for one agent/workspace with an expiry. Identity derives from the evidence credential, not model arguments. Register a RagSource with fixed scope, collection, revision and explicit egress (none or remote). Pass a trusted application adapter object to rag.register(owner_token, source, adapter). Owner tokens stay in application setup; never pass them to a model.

Canonical memory uses subject/agent/workspace scope inside a physical home. An application must map each tenant to its own canonical memory home and encryption authority. FeedbackService(..., memory=memory, memory_tenant_id="TENANT") binds that home to one configured tenant; it defaults to local for existing local homes. A different tenant is denied even with a valid credential and a matching subject name. Never derive the home or this binding from model arguments, and never map distinct tenants to the same canonical home. A service with no canonical memory can still serve its independently scoped encrypted document partitions.

Canonical-source eligibility reuses the core store's bounded authorization query before loading record contents, including workspace/agent, active status, retrieval exclusions and sensitivity. Feedback defaults to egress_class="remote": sensitive/restricted canonical sources are withheld. Only a trusted local-only application should explicitly select egress_class="local"; stdio transport by itself does not prove a caller keeps data on device. Proposal operations return closed versioned receipts, not raw canonical sources or human review notes, including on legacy cached retries. Full encrypted source snapshots remain available through the privileged review surface.

The adapter implements:

def search(self, source, query, *, deadline) -> tuple[RagHit, ...]:
    ...  # Use the existing retriever with scoped application credentials.

def inspect(self, source, document_id, chunk_id, *, deadline) -> RagHit:
    ...

Return original passages, SHA-256 of their exact UTF-8 text, citation/locator, source/document/chunk identity, revision, fixed scope and known jurisdiction and effective dates. Respect the monotonic deadline. The service validates results, filters requested jurisdiction/date, and rechecks authorization and registration before returning them. A requested date excludes unknown start dates; validity intervals are [effective_from, effective_to). Unfiltered unknowns remain explicit. URLs are citations, never automatically fetched. Adapter code is trusted owner configuration; the model cannot provide SQL, executable code or endpoints.

SQLiteRagProvider(feedback) is the built-in reference provider. Register it with provider_id="sqlite-vault", egress="none"; use owner-only put_documents to import bounded batches of RagHit values. Persistent passages/metadata use the existing encrypted evidence vault. The FTS5 search index exists only in RAM for an authorized query. Updating a passage requires a new source revision rather than overwriting content under an existing document/chunk/revision identity.

rag.search(session, RagQuery(...), idempotency_key=...) returns a retained receipt. rag.inspect returns the exact retained passage from that receipt, not a live refetch. Revoked or changed sources cannot be inspected through this model path. External documents are untrusted evidence and are not automatically admitted as memory or promoted into rules. Retrieved instructions cannot grant permissions.

Local MCP and CLI

Owner configuration and an existing encrypted EvidenceService store are required. Put the application credential in an owner-private file (POSIX mode 0600 or a verified protected Windows DACL). Never put a token in tool arguments or a command line. The following command starts a local subprocess, not a public server:

atmem rag --root /path/to/existing/control --vault-id MY_VAULT \
  --credential-file /path/to/private/application.token \
  --agent writer --workspace project serve

The same prefix supports sources, capabilities, search --source law --query 'filing deadline' --key request-1 --jurisdiction XX --as-of 2026-01-01, and inspect --receipt RECEIPT --document DOCUMENT --chunk CHUNK. No default memory store is opened. The CLI reattaches only already registered built-in local sources. External adapters use an application-owned Python entry point that constructs RagService, registers its trusted adapter and calls GovernedMCPServer(feedback, rag, session).serve().

Supported transport: local stdio, legacy MCP revisions 2025-06-18 and 2025-11-25, with initialization. Unsupported versions are rejected. There is no claim of MCP 2026-07-28, Streamable HTTP, OAuth hosting or public availability. See the versioned official sources in Spec 050 protocol-decisions.md.

Implemented tool inventory (guarded_* requires an explicitly configured application dispatcher; execution and feedback_propose_* require canonical memory. The standard CLI does not register arbitrary handlers):

<!-- governed-tool-inventory:start -->
ToolCapabilityEffect
feedback_capabilitiesAny active grantCurrent fixed scope and granted operations; unrelated host tools remain advisory.
rag_sourcessearchScoped registered sources.
rag_searchsearchOriginal passages and encrypted request/result receipts; no memory admission.
rag_inspectinspectRetained passage, subject to live source authorization.
feedback_outcomereadRetained observations and scoped operational classifications; host reports remain unverified.
feedback_qualityreadCounts for an owner-frozen schedule; undefined rates are null.
feedback_report_outcomereportAppend attributable unverified observations; no review or activation.
guarded_executeexecuteOptional application-owned dispatch; persists intent before effects and refuses blind retries.
guarded_toolsexecuteExact schemas and versions for owner-registered proxy tools in this scope.
guarded_inspectreadOptional inspection of an execution intent/result; not independent verification.
feedback_propose_ruleproposeRequires an explicit canonical-memory binding; source-grounded proposal only.
feedback_propose_profileproposeRequires an explicit canonical-memory binding; bounded profile proposal only.
<!-- governed-tool-inventory:end -->

Tool annotations guide clients; server-side authority enforces access on every call. MCP connectivity does not control tools outside this server. Guarded proxy execution is available through the optional dispatcher API. The dashboard and owner export SDK described below are implemented development surfaces. Production activation qualification and complete lifecycle acceptance remain Spec 050 work.

CLI feedback operations use the same service: outcome --id ID, quality --schedule ID, report --file outcome.json --key KEY, propose-rule --file candidate.json --key KEY and propose-profile --file candidate.json --key KEY. Proposal commands and tools require an additional explicit --memory-db binding to an existing encrypted canonical store, plus the authenticated propose grant. A file's scope must match the bound caller. MCP derives scope server-side. No model tool can review or activate a proposal. Ordinary plaintext/local recall remains unaffected.

Retention, availability and limitations

Exact passages, queries, source metadata, observations and readback evidence are encrypted at rest in the existing vault. Authorized tool responses leave the application boundary in plaintext and can enter the calling agent/provider's context; that agent's storage/egress policy is separate. A remote RAG adapter sends queries to its explicitly configured provider. A local adapter does not.

Revocation is checked per call and after provider work. Timeouts, unavailable providers and malformed results produce explicit errors, not fabricated answers. A hung read holds a bounded worker slot until it finishes; retries cannot spawn unlimited workers. No document-provider deadline changes DolphinBench model/judge retry policy. Use a new request key for a deliberate new search; conflicting reuse is rejected and identical successful retries return the original receipt.

If access is revoked before a final audit update, the already retained pending attempt remains unknown. Capture does not prove model use. Ordinary memory forgetting invalidates future selection but does not itself erase historical flight evidence. Owner-previewed registered-copy cleanup is described below; backups, client copies and external providers have separate retention.

Current evidence is isolated macOS testing with synthetic documents, real credentials/stores and actual MCP subprocesses. It is not a quality benchmark, cross-platform certification or a released artifact. See Spec 050 implementation-evidence.md and benchmark-impact.md for exact status.

Integrity, quotas and supported backups

The opt-in ledger has encrypted per-scope checkpoints under the Home's .feedback-checkpoints directory. These anchor ciphertext outside the DB: deleting a policy row, removing an anchor while records remain, or replacing only the DB with an older copy fails closed. Pending/committed checkpoints recover crashes around SQLite commit. Effects dispatch only after both commits complete. Vault data-key rotation preserves the checkpoint identity key and roots.

A supported backup includes the protected database, identity/accounts, required keys, artifacts where used, and .feedback-checkpoints. A DB alone is not a usable evidence backup. An existing pre-checkpoint development feedback ledger is not silently trusted; no published release used that ledger. Restoring a whole old Home together with all its keys and anchors cannot be distinguished from the old legitimate state without an external monotonic authority. Full restore and activation reconciliation remain acceptance work; no universal rollback-proof claim is made. Standalone retained-action reconstruction has been tested without the original host, destination or canonical memory process.

Create and protect the backup/restore root with AtMem's existing protect_private_path before copying private keys/accounts/checkpoints. On Windows a plain copytree does not preserve DACLs; copies must inherit an owner-private destination or be created with explicit protected DACLs. The reader rejects an unprotected checkpoint rather than silently accepting or repairing it.

The development service bounds a scope to 10,000 historical encrypted records and 64 MiB of ciphertext. Contract messages are bounded to 256 KiB and stdio frames to 1 MiB. Exhaustion fails explicitly, rather than silently discarding evidence or claiming complete retrieval. Retention/compaction and larger-scale performance qualification remain work; the reference RAM-FTS adapter is not a million-document performance claim.

The first opt-in feedback mutation upgrades the evidence container to format 4. Ordinary native-only stores retain their existing format. The published 2.3.14 reader refuses a format-4 vault rather than rotating its keys while discarding unknown scope partitions. Upgrade is tested against the actual public 2.3.14 wheel. Downgrading a feedback-enabled vault to that old binary is not supported; restore a complete pre-opt-in backup instead.

Action verification and uncertain effects

VerificationService accepts only owner-registered callbacks and separately authenticated verifier identities. Readback contains exact checks and retained evidence. state_only is the default: correct destination state alone cannot prove an agent made the required call. To count a completed action, a verifier must use binding="effect_receipt" and independently read an operation journal binding the outcome, run, turn, invocation, canonical argument digest and a unique backend effect reference. One reference cannot prove different invocations. The journal must also distinguish succeeded, failed, not-dispatched and unknown operations; correct destination state after a failed operation is not success. Generic stdio does not itself establish trusted host run/turn IDs: the application must retain that correlation independently. A caller's reported IDs are not proof. All required checks must pass on one matching invocation; partial calls are never combined. Conflicts stay disputed. Proposed failure labels are not certified causal diagnoses. Host/model reports never become independent verification.

The optional GuardedDispatcher persists admission and a scope/tool hold before dispatching. A timeout or lost acknowledgement leaves an uncertain receipt and the hold survives new retry keys, restarts and registered-source cleanup. Even a successful same-key retry returns the original admission; use inspect for the latest status. A deliberate new invocation is permitted after a healthy handler acknowledgement; that acknowledgement still does not verify task success.

Application handlers can opt into register(..., with_context=True) and receive invoke(arguments, context=...). The application-owned context carries the execution receipt, idempotency key, authenticated actor and fixed scope, so a backend can persist operation correlation. It contains no credential. A normal return must mean the handler has a definitive response; handlers must raise on ambiguous effects rather than hiding transport failures in an ordinary result.

Unknown effects are never replayed automatically. The owner SDK's reconcile requires a retained, independent effect-bound verification of the exact proxy execution and a trusted backend-terminal journal receipt. A state snapshot or model assertion cannot clear a hold. A still-running local handler, changed verifier, disputed operation status or missing/deleted evidence prevents reconciliation. Conclusive terminal-operation evidence can clear a hold even when task checks failed; the retained failed task is not promoted to success. This permits an explicit corrected attempt without conflating task quality with effect certainty. The application is responsible for the backend's terminal-journal contract; the proxy cannot terminate a remote operation or undo a completed effect.

Review, dashboard, deletion and export

Rule/profile proposals reuse the canonical engine's review authority. Source generation, exact content digest and scope are checked again under transaction. Review authorizes neither execution nor activation. The three supported rule predicates are argument presence, exact typed equality and approval-required. The compiler executes no generated code. A native guard veto always wins.

RuleLifecycle records encrypted versioned activation receipts. Active use requires a reviewed candidate, current eligible sources, accepted unexpired qualification and matching runtime versions. rollback creates a new generation from an exact previously active generation only if those checks still hold. Revocation, expiry, source deletion and restore quarantine cannot be bypassed using historical receipts. The current offline qualification evaluator is diagnostic and always inconclusive; it cannot activate production behavior. Test-only trusted-store fixtures exercise consumers of accepted authority and are explicitly not qualification or efficacy evidence.

Diagnostic attempts are reserved in protected storage before replay. Failed or crashed attempts remain charged; a same-key retry returns the retained failure or an explicit in-flight/unknown result rather than re-executing. Content-free per-hypothesis attempt counters survive registered-source cleanup. The current disk check bounds serialized qualification payloads, not complete filesystem or provider consumption; full production resource qualification is still pending.

The existing local dashboard accepts an optional FeedbackDashboard with a trusted signed-in-identity/session binding and optional per-request memory factory. It exposes real scoped quality counts, exact per-action arguments, checks, source evidence, proposal review and shadow/suspend/revoke controls. Existing login, origin and CSRF checks apply. Without this application binding, the screen reports unconfigured. With matching runtime configuration, an owner can select an accepted current qualification, inspect its evidence and confirm activation, or request rollback to a previous active generation. The server rechecks authority and source/version/qualification state; displayed metadata does not grant permission. With only the current diagnostic qualifier, activation remains unavailable. The export workflow has separate consent, exact preview, manual review, confirmation and withdrawal controls. Production qualification remains acceptance work. For threaded HTTP actions, supply a per-request memory_factory; do not share a thread-bound SQLite connection from setup.

Owner SDK FeedbackRecovery.preview_forget / forget requires exact preview confirmation and privileged deletion authority. It removes registered scoped source-dependent feedback payloads, retains content-free revocation/idempotency anchors, and checks canonical deletion completion. RAG re-registration requires a new generation. Cleanup follows typed protocol links: a document source ID is not a canonical-memory ID or an outcome ID, and a cached/copied response does not own the identities it quotes. Raw tool arguments, results and readback bodies cannot authorize deletion through embedded IDs. Unlinked copies of text remain subject to their separate evidence retention/deletion; this is not semantic erasure of every matching string. Active/qualified dependent rules or profiles must first be explicitly revoked; otherwise preview/forget returns dependent_policy_requires_revocation without removing the source or silently turning off a guard. reconcile_after_restore disables restored grants, approvals, export consents and RAG sources, and quarantines active/qualified behavior until fresh qualification. The supported Home preflight/adoption workflow now changes a content-free machine binding: feedback refuses the read-only restore and then requires scoped reconciliation after adoption, including after process restart. An old reconciliation ID cannot clear a newer adoption. Corrupt/missing binding state fails closed. Ordinary native recall and historical evidence inspection are unchanged. A Home cannot be made globally rollback-proof without an external monotonic witness; arbitrary file copies or direct canonical database restores still require explicit operator reconciliation and remain outside automatic restore detection. Neither operation erases provider originals, backups, recipient exports or forensic storage remnants.

After administrator-approved Home adoption, use a private owner credential file, not the revoked application grant, to quarantine the exact scope:

atmem rag --root /existing/control --vault-id VAULT \
  --credential-file /private/owner.token --agent AGENT --workspace WORKSPACE \
  reconcile-restore --restore-id ADOPTION_EVENT --confirm ADOPTION_EVENT

This disables restored grants/approvals/consents/source registrations and quarantines covered rules/profiles. It does not restore access, issue a fresh qualification or replay an uncertain write. The owner must explicitly regrant the required capabilities, reattach/register authorized sources and independently requalify behavior before activation. The command is owner-only CLI/SDK; it is not exposed to models through MCP. Repeat the same event ID for an idempotent retry; use a new ID for a new restore event.

FeedbackService.operational_metrics(session) returns authenticated, scoped process-local counters and p50/p95 over the last 256 calls per closed operation. They contain no passages, arguments, tokens, provider exception text or dynamic metric labels. Counters reset on restart; 64 scopes are tracked at most and telemetry exhaustion cannot discard evidence or block an action. Rule-evaluation latency is separate from the full proxy request, verification and provider time; these samples do not qualify a performance improvement or the production budget.

An application may use owner-only record_usage with an already observed provider receipt, run ID, integer USD micro-units, input/output token counts and model-call count. Receipt reuse cannot double-count or reassign a run. Quality reports aggregate only retained scheduled runs and label these costs as partial host reports, never verified billing. Each count/cost may be explicitly unknown; known subtotals remain separate and a missing component makes the total null. Overflow is explicit as well. Missing capture is null, not zero. This API makes no model calls and grants no spending authority. The dashboard displays the same missing/partial usage distinction.

ExampleExportService is an owner-only SDK using the existing export privilege, explicit purpose, recipient public key, bounded record IDs, expiry and exact preview confirmation. It uses real recipient encryption and includes lineage and exclusions. Unverified, disputed, known evaluation/test records, detected secrets and unrevalidated sources are excluded. Secret detection is not a guarantee of anonymization; review the exact authorized preview. Withdrawal blocks new exports, not already delivered copies. It starts no training.

For the optional dashboard workflow, the trusted application supplies FeedbackDashboard(..., export_signer=...); that callback returns the signing public/secret key pair from the application's own protected key custody. The browser supplies only the recipient's public ML-KEM-768 key, purpose, explicit outcome IDs, development/train destination and a consent expiry of at most seven days. No signing key or recipient private key is accepted over HTTP. The feature remains unavailable without the configured signer. Actual scoped export authority is rechecked before signing-key access. Consent precedes an exact plaintext preview; a separate reviewed confirmation binds its SHA-256 and recipient before downloading a recipient-encrypted JSON bundle. Editing the form invalidates its preview; logout clears its content and pending requests. Withdrawal prevents future export and does not recall existing copies. Known RAG evidence is revalidated against the complete registered source snapshot at both preview and export, including cached retries: revocation, revision changes and missing receipts exclude the example. No provider fetch occurs during export.

Frozen quality schedules may additionally specify task_class and versions (a bounded map of version names to identifiers). These are owner-supplied before observations, never inferred from model text or retroactively overwritten. Quality reports include the same denominators per class/version, preserving missing tasks; legacy schedules explicitly show unspecified versions/classes. The uncertainty field uses whole-episode resampling for diagnostic 95% rate intervals. Fewer than two observed clusters or a zero denominator is inconclusive. These intervals do not establish adequate statistical power, production qualification or a measured quality improvement.

Remaining acceptance work includes independent production qualification, complete quality/resource qualification gates, production Hermes conformance, recovery coverage outside the supported Home workflow and final cross-platform CI results. No existing DolphinBench score is changed or relabelled by these development features.

An offline diagnostic can measure the pure interpreter with 1,000 applicable synthetic rules; it opens no memory store, dispatches no effect and calls no model:

python scripts/evaluate_verified_memory_feedback.py \
  --manifest tests/fixtures/feedback/baseline-manifest.json \
  --output /path/to/a/new-diagnostic-report.json

The file is created exclusively, never overwritten. The report enforces frozen baseline/resource definitions and records actual p50/p95 and elapsed time. Native and AtMem quality outcomes, power, independent conformance, false-denial coverage and retrieval overhead remain insufficient evidence. Fast synthetic evaluation cannot issue qualification, activation or an efficacy claim. Compilation, authority/storage and remote time are explicitly outside the pure rule latency.

Independently checked failure classifications

VerificationService.propose_attribution retains a proposal without certifying it. register_attribution_verifier is an owner SDK operation, never an MCP tool. A separately authenticated verifier with the scoped verify capability calls verify_attribution. The writer/proposer cannot verify its own diagnosis. Registration alone establishes no result: application-owned read-only checker code must actually perform the independent checks and retain the supporting material.

AttributionReadback names a closed failure class, its exact fixed mechanical checks and original supporting data. Evidence binds the scope, outcome digest and invocation (nullable only when no invocation is captured), with a proofs entry for every check containing method, observed and expected. Sources are typed {"kind":"memory","source": SourceRevision.to_dict()} or {"kind":"rag","source": RagSource.to_dict()}. Canonical permission, source revision/generation and RAG registration are revalidated before committing. Partial checks, model judgements, unbound evidence, missing delivery receipts, changed verifier registration and unverified effects cannot certify a class.

The supported conditions are source-fact absence, retrieval miss, authority withheld, stale/conflicting state, delivered-but-not-applied, wrong argument/value, wording/precision, no call, execution failure and unknown. Absence/retrieval checks require an actually complete authorised snapshot from before the turn. A search returning no hits, a partial corpus, a current snapshot obtained afterwards, or a trace alone is insufficient. Missing facts in a write do not establish a retrieval failure. A delivered-but-not-applied result requires original core exposure bytes and independent operation-bound readback. No-call requires complete independent operation capture, rather than an omitted host trace. Integrators must leave a condition unknown when their backend cannot supply these proofs.

A verified result is a bounded operational classification under the registered checker contract. It is not evidence of an agent's internal motivation or universal causality: verified_causality and qualifies_policy are always false. The separate supports_classification field distinguishes supported, disproved and unknown conditions. Conflicting readbacks remain disputed. Scoped owner SDK resolve_attribution appends an exact receipt-set/generation-bound decision at the human-attestation tier, preserving every original; later readbacks invalidate a stale resolution. It cannot produce policy qualification.

The existing MCP feedback_outcome, CLI atmem rag outcome, and quality reports include bounded classification summaries when present. The dashboard shows them on their exact read/write action, including verifier checks, proposals and disputes. Raw proof material stays in the encrypted vault rather than being copied into these summaries. No new model-accessible verification, registration or resolution tool is exposed. Deleting a declared source removes dependent diagnosis/proof/ cache records through typed lineage, without deleting unrelated outcome history. Unlinked free-text copies remain subject to their own evidence retention.

Reproducible real-store and actual destination/corpus/exposure examples are in tests/test_feedback_attribution.py. They are synthetic contract tests, not production accuracy or causal-learning evidence.