Dev to Production — Upgrade Checklist¶
AEVUM_DEV=1 gives you a working Aevum engine with zero configuration.
Before you deploy, complete these five steps to replace every dev-mode default
with a production-grade equivalent.
Dev mode is never safe for production
AEVUM_DEV=1 grants consent to every subject and every operation for the
lifetime of the process. It uses an ephemeral in-memory sigchain that is
discarded on exit. Do not expose a dev-mode engine to real user data.
Step 1 — Remove AEVUM_DEV=1¶
Unset or delete the environment variable:
With AEVUM_DEV unset, the Engine raises a barrier error for any ingest or
query call that lacks a consent grant. Verify this:
engine = Engine()
result = engine.ingest(
data={"note": "test"},
provenance={"source_id": "svc", "chain_of_custody": ["svc"], "classification": 0},
purpose="my-app",
subject_id="user-1",
actor="my-agent",
)
assert result.status == "error"
assert result.data["error_code"] == "consent_required"
Step 2 — Grant explicit consent¶
Replace the auto-consent ledger with real consent grants. Each grant is per-subject, per-purpose, and time-bounded:
from aevum.core.consent.models import ConsentGrant
engine.add_consent_grant(ConsentGrant(
grant_id="grant-user1-support-2026",
subject_id="user-1",
grantee_id="support-agent",
operations=["ingest", "query"],
purpose="support-ticket-resolution",
classification_max=0,
granted_at="2026-01-01T00:00:00Z",
expires_at="2027-01-01T00:00:00Z",
))
Guidelines:
purposemust be specific and auditable. "any", "all", and empty string are rejected.expires_atis mandatory. Short-lived grants are preferable.- Grant one grant per subject/purpose pair, not a single catch-all grant.
- Store grants in your application database and reload them on restart.
Step 3 — Configure a persistent graph store¶
Dev mode uses InMemoryGraphStore — all data is lost on process exit.
For production, configure a persistent backend:
The persistent store maintains the sigchain across process restarts. The
session.start event written at Engine init will include a causation_id
linking to the last event of the previous session, creating a continuous
auditable chain.
Step 4 — Configure the policy engine¶
Dev mode uses NullPolicyEngine — all ABAC decisions are PERMIT.
For production, install Cedar (the default) or configure OPA:
Without a real policy engine, any principal can call any function on any resource. NullPolicyEngine logs a WARNING on first use to remind you.
Step 5 — Use an external signer¶
Dev mode uses InProcessSigner — the signing key lives in Python heap memory
alongside the agent process. This satisfies tamper-detection but not
tamper-prevention.
For regulated deployments (FDA 21 CFR §11.10(e), EU AI Act Art. 12, HIPAA §164.312(b)):
AWS KMS signing is not yet implemented. Use VaultTransitSigner or
implement the Signer protocol (see aevum.core.audit.signer.Signer).
Implement the Signer protocol and pass it to Sigchain:
from aevum.core.audit.signer import Signer
class MyKMSSigner(Signer):
def sign(self, digest: bytes) -> bytes: ...
def public_key_bytes(self) -> bytes: ...
@property
def key_id(self) -> str: ...
@property
def provenance(self) -> str:
return "my-kms"
engine = Engine(sigchain=Sigchain(signer=MyKMSSigner()))
Production checklist¶
Run through this before any deployment:
- [ ]
AEVUM_DEVis unset (not"", not"0"— unset) - [ ] Explicit consent grants loaded for all subjects
- [ ] Persistent graph store configured (Oxigraph or PostgreSQL)
- [ ] Cedar or OPA policy engine configured
- [ ] External signer configured (Vault Transit or equivalent)
- [ ]
engine.verify_sigchain()returnsTrueafter startup - [ ] No
NullPolicyEnginewarnings in logs - [ ] Consent required check passes (test with a subject that has no grant)
- [ ] Review THREAT_MODEL.md Assumption 4 — confirm storage assumptions hold
What dev mode never changes¶
These five absolute barriers are always active regardless of AEVUM_DEV:
- Crisis detection — ingested content is always screened
- Classification ceiling — results above actor clearance are always redacted
- Consent — in dev mode this is bypassed by
DevModeConsentLedger; in production it is enforced - Audit immutability — the ledger never allows deletion or overwrite
- Provenance — every ingest requires a
source_id
Never call barriers.py functions directly. Never monkeypatch them in production tests.