Skip to content

Production checklist

This page lists what to check before your integration goes live. Each item says what to do and why.

  1. Handle keys safely. Call Alvia from your server, keep keys in a secret manager and use a separate production project. See Keys.
  2. Test the memory policy. Check allowed facts, excluded words, paraphrases and mixed conversations before the first production write. See Writes.
  3. Prove isolation. Show that one project’s key cannot reach another’s memories and that your server chooses each user’s scope. See Prove isolation and recovery behavior.
  4. Retry only what can succeed. Back off with jitter and bound your attempts. See Retries.
  5. Set timeouts and fallbacks. Decide what the application does without context. See Latency and capacity.
  6. Monitor. Log each call’s outcome and watch your allowances. See Monitoring.
  • Follow the key rules. Call Alvia from your server only, keep keys in a secret manager, and use one key for each service and environment. See Keep keys safe in Authentication.
  • Use separate projects for production and testing. Test data then never reaches your production context. See Projects and scope.
  • Rotate before expiry. Choose a key lifetime that fits your deployment and replace it before it expires. For keys without an expiration, set your own rotation schedule. See Rotate a key in Authentication.

Before the first production write or backfill, run the policy checks in Filter memories. Use an allowed fact as a positive control, then test restricted words, meaning paraphrases and mixed conversations. Verify the policy against the formed memories: a 202 confirms acceptance, and the memories show what was kept.

  • Send occurred_at when the information is not new. Imported records, delayed queues and backfills must carry the time the information was stated or observed. See Point-in-Time Reasoning and change over time.
  • Send times with the user’s offset. Relative dates such as “yesterday” resolve on that day.
  • Write in the background. A write returns 202 before formation runs, so your user does not need to wait for it.
  • Read a new memory after formation. Formation finishes in less than a minute, so a new memory is readable shortly after the write.
  • Set a project memory policy. Exclude sensitive information by keyword and meaning before importing conversations. Remove secrets, system prompts and tool output in your application too. See Filter memories.
  • Use context for prompts, and recall when you need an ID. See Read memories.
  • Send scope on every read that serves one user. A read without scope covers the whole project.
  • Treat “no context” as a normal result. Context returns 404 and recall returns "status": "not_found" when Alvia has no context for the question right now; a later call can return one. Your application should still respond.
  • Set a timeout on every call. Decide what your application does without context.

Retry a request only when a later attempt can succeed:

Status Retry What to do
400, 401, 404, 409, 413, 415 No Fix the request, the key or the account state first.
429 with a reason Not until the reset A monthly allowance is used up. Retry-After gives the seconds until it resets.
429 without a reason Yes Wait for the seconds in Retry-After, then retry.
502, 503, 504 Yes Wait for Retry-After when present; otherwise back off.
500 A few times Back off. If it continues, report it with the response body.
Network error or timeout Yes Back off.

Back off with growing, random waits: for example 1, 2, 4 and 8 seconds, each with up to a second of random jitter, then stop. Jitter keeps many clients from retrying at the same moment.

retry.py
import random
import time
import requests
RETRY_STATUSES = {429, 500, 502, 503, 504}
def call_alvia(method: str, url: str, **kwargs) -> requests.Response:
"""Sends a request, retrying responses a later attempt can fix."""
for attempt in range(5):
try:
response = requests.request(
method, url, timeout=30, **kwargs
)
except (requests.ConnectionError, requests.Timeout):
if attempt == 4:
raise
else:
status = response.status_code
reason = None
if status == 429:
try:
problem = response.json()
if isinstance(problem, dict):
reason = problem.get("reason")
except ValueError:
pass # An intermediary may return HTML.
used_up = isinstance(reason, str) and reason in {
"monthly_read_quota_reached",
"monthly_write_quota_reached",
}
if (
status not in RETRY_STATUSES
or used_up
or attempt == 4
):
return response
try:
wait = float(response.headers.get("Retry-After", ""))
except ValueError:
wait = None # Absent or an HTTP date: back off.
if wait is not None:
time.sleep(max(wait, 0))
continue
time.sleep(2**attempt + random.random())
raise RuntimeError("unreachable")

Retry only requests that failed: network errors, 5xx responses and 429 responses without a reason (after the wait in Retry-After). A 202 means Alvia accepted the write, so do not send it again. When you retry, send the same content, scope and occurred_at. Each accepted request uses writes. See Retries in Store memories.

Choose each timeout from the time your application can afford to wait. Measure context, recall and search separately under representative load: context writes an answer, while recall and search return memory records. When facts conflict, rely on resolved context rather than the first search hit.

Decide each fallback before going live. An interactive support screen can start the context read alongside the CRM lookup and show verified CRM data if the context deadline passes. A refund workflow should hold a consequential case for review when required context is unavailable. Cancel work your application no longer needs, and bound both request attempts and total retry time.

A write’s response time measures acceptance, not formation. Measure separately how long a synthetic accepted write takes to become readable. Do not poll on every user keystroke or block a conversation while formation runs: an application that must acknowledge a new preference at once should use its current interaction state until formation finishes.

Rate limits and monthly allowances apply to the whole account, across every project and key, so pace batch jobs to leave room for live traffic and plan test projects into the same capacity. Budget reads per interaction, and slow down before RateLimit-Remaining reaches zero. See Rate limits.

  1. Measure expected concurrent interactions, reads per interaction and write volume.
  2. Compare sustained request rates and bursts with Rate limits, and leave capacity for live traffic.
  3. Run a bounded worker queue for imports, with backpressure and a way to stop a backfill.
  4. Preserve each conversation’s original date and test the policy before a bulk submission.
  5. Track accepted submissions separately from memories formed; accepted text can form no memory.

Import each conversation once. Keep a submission record in your application, so a restarted backfill resumes where it stopped and sends nothing twice.

  • Log the operation, duration, HTTP status, error code and reason. Use an opaque correlation ID. Do not log keys, raw request bodies, generated context or customer scopes containing PII.
  • Count misses separately from failures. Context 404, recall not_found and empty lists can be valid results. Alert separately on authentication failures, 429 and 5xx responses.
  • Measure end-to-end latency in your application. Server-Timing on REST memory calls reports Alvia’s processing time; measure the full round trip in your application.
  • Track usage. Alvia-Usage on those calls reports the reads and writes the request used, and facts formed later add to the total usage the dashboard shows.
  • Review calls in the activity log. A project’s Activity page in the dashboard lists each API-key call with its operation, status and scope, and the query text and ranked results of reads, for 90 days. See Security.
  • Watch remaining allowance and stored-memory capacity in the dashboard. See Limits and allowances.
  • Tolerate additive response changes. Ignore fields you do not use and handle unfamiliar categories and reasons. See Errors.

Before production, use invented data in separate projects A and B. Store a distinct fact in each, then verify that A’s key cannot retrieve, forget or give feedback on B’s memory ID. Test your application’s user A and user B sessions too: the server must select their scope, regardless of scope values supplied by a client. Keys within one project do not provide user-level access control.

Test missing context, expired credentials, a 429, a timeout after an accepted write and a restarted import job. Verify the intended fallback and bounded retries in each case. For a forget test, capture the memory ID first, forget it, then verify get, list, recall, search and context as described in Manage memories. Forgetting is permanent, so confirm before you forget. Keep the project’s retained-data and erasure procedure in your operational review. See Security.