> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reflections.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# System invariants

> Non-negotiable rules, complexity budgets, and release blockers that govern the Reflections platform.

System invariants are rules that must hold true at all times. Violating any of them blocks a release. They are enforced through a combination of lint rules, architecture guard scripts, file-scan tests, and CI gates.

## Non-negotiables

These nine rules define the platform's safety and correctness boundaries. Every change to the codebase is evaluated against them.

<Steps>
  <Step title="The system prompt is not a database">
    User-specific knowledge belongs in the knowledge graph, not hardcoded into LLM system prompts.
    The system prompt provides instructions; the retrieval pipeline provides context.
  </Step>

  <Step title="Learning is gated: candidate, eval, approval, apply">
    No extracted fact becomes active truth without passing through evaluation. Facts enter as
    `candidate`, are scored and evaluated, and only transition to `active` after approval and patch
    application.
  </Step>

  <Step title="Evidence is untrusted text">
    All evidence retrieved from the knowledge graph is treated as untrusted. An injection warning is
    appended when evidence is included in LLM context to prevent prompt injection via stored
    content.
  </Step>

  <Step title="Roles are server-derived">
    The API derives user roles from authenticated sessions. Client role claims are never trusted.
    The role hierarchy is: `viewer` \< `operator` \< `admin` \< `owner`.
  </Step>

  <Step title="Realtime path is read-only for truth tables">
    The realtime plane (API + brain-core) may read facts, entities, chunks, and sources but must
    never write to them. This is enforced by import restrictions on `@reflection/db/queries/admin`.
  </Step>

  <Step title="Facts are append-only">
    Facts use temporal validity (`valid_from`, `valid_to`) and supersession (`supersedes_fact_id`)
    instead of destructive updates. Old facts are never deleted — they are superseded.
  </Step>

  <Step title="No process.env outside designated files">
    Environment variable access is restricted to `packages/shared/src/env.ts` (backend) and
    `apps/web/src/lib/env.ts` (frontend). All other code imports from `@reflection/shared/env`.
  </Step>

  <Step title="No deep imports">
    Code must import from package entrypoints (`@reflection/db/queries/read`), never from internal
    paths (`@reflection/db/src/queries/facts.ts`).
  </Step>

  <Step title="Every external input is Zod-validated">
    All data entering the system — API request bodies, webhook payloads, event data, query
    parameters — is validated through Zod schemas defined in `@reflection/schemas`.
  </Step>
</Steps>

<Warning>
  The **eval gate** (rule 2) and **read-only realtime** (rule 5) are the two invariants most likely
  to cause production incidents if violated. Both are enforced at multiple layers — ESLint,
  architecture guard, and dedicated file-scan tests — to prevent accidental bypass.
</Warning>

## Ingestion lifecycle authority

The ingestion pipeline has its own set of invariants that govern how source processing state is tracked:

1. **`source_ingestions` is the only runtime authority** for ingestion lifecycle state. No other table drives lifecycle branching.
2. **Lifecycle semantics are defined once** in `@reflection/schemas` (`ingestion-lifecycle.ts`). Workers, DB query modules, and API status mapping all consume this shared kernel.
3. **`ingest_runs` is telemetry-only** — it exists for observability and compatibility but must not drive lifecycle branching decisions.

## Voice tool role policy

Voice tools — the server-tool callbacks that the voice provider calls during a conversation — follow strict role-based access:

1. **Mutation-capable tools** require `operator` role or above (`operator`, `admin`, `owner`).
2. **Viewer and visitor sessions** are retrieval-only by design.
3. **Tool-requested learning intents** flow through the async ingestion/eval gate. The realtime path does not directly mutate truth tables, even when a tool requests it.

## Complexity budget

The project operates under a "minimum viable abstraction" posture. These hard rules prevent unnecessary complexity from entering the codebase:

<AccordionGroup>
  <Accordion title="Hard rules">
    1. No new infrastructure component without a measured bottleneck.
    2. No generic abstraction until at least 3 concrete call sites exist.
    3. No second implementation path for the same responsibility.
    4. No LLM entity extraction in the realtime path.
    5. No cross-layer shortcuts around boundaries.
    6. No placeholder comments (`TODO`, `FIXME`, `HACK`) in source files.
    7. Max cyclomatic complexity of 20 per function (enforced by ESLint).
  </Accordion>

  <Accordion title="PR rejection triggers">
    A pull request is rejected if it:

    * Adds indirection without materially reducing duplication or coupling.
    * Introduces speculative extension points for hypothetical future use.
    * Expands scope beyond the current milestone gate.
    * Violates any non-negotiable invariant.
  </Accordion>
</AccordionGroup>

## Definition of done

Every change must meet these criteria before merging:

* Failing tests written first for changed behavior (test-driven development).
* `pnpm lint`, `pnpm typecheck`, `pnpm test`, and `pnpm build` pass for the touched scope.
* No focused or skipped tests (`test.only`, `test.skip`) in committed code.
* No placeholder comments (`TODO`, `FIXME`, `HACK`).

## Release blockers

Any of the following conditions blocks a release:

* A boundary violation against any non-negotiable invariant.
* A failing safety or invariant regression test.
* An undocumented complexity increase that violates the complexity budget.

<Info>
  The enforcement matrix — which invariants are checked by ESLint, the architecture guard, and
  file-scan tests — is documented in the repository's `AGENTS.md`. Each invariant is covered by at
  least two independent enforcement mechanisms to prevent single-point bypass.
</Info>

## Related pages

* [Two-plane architecture](/architecture/two-plane-architecture) — the execution model that invariants protect.
* [Boundary matrix](/architecture/boundaries) — per-plane allowed and forbidden operations.
* [Knowledge graph](/architecture/knowledge-graph) — how the temporal fact model and eval gate work in practice.
