Invariant Reference

Parallax formalizes correctness as numbered invariants across all specs. Every code change should be checked against the invariants it might affect. Invariants are referenced in commit messages using their codes.

Data Model Invariants (INV-01..08)

From specs/01-data-model.md:

CodeInvariant
INV-01Every entity has a non-empty _type, _class, and entity key.
INV-02EntityId is deterministic: same (account_id, type, key) always produces the same ID.
INV-03Every relationship's from_id and to_id reference entities that exist in the committed graph.
INV-04No two entities in the same account share (type, key).
INV-05No two relationships share (from_id, class, to_id) unless explicitly keyed with derive_with_key.
INV-06Timestamps are monotonically increasing per node.
INV-07Property types are stable within an entity type across versions (no type changes).
INV-08Property values are flat — no nested objects or arrays-of-objects.

Storage Engine Invariants (INV-S01..S08)

From specs/02-storage-engine.md:

CodeInvariant
INV-S01A committed write is never lost, even after a crash.
INV-S02A read snapshot never observes a partial write.
INV-S03Snapshots are monotonically increasing — a newer snapshot always supersedes an older one.
INV-S04WAL entries are append-only and immutable after write.
INV-S05A WAL entry with a CRC mismatch is treated as corrupt; recovery stops at the last valid entry.
INV-S06MemTable flush is atomic: either all entries move to a segment or none do.
INV-S07Segment files are immutable after creation. Compaction produces new segments, never modifies old ones.
INV-S08An entity with _deleted = true must never appear in query results.

Graph Engine Invariants (INV-G01..G06)

From specs/03-graph-engine.md:

CodeInvariant
INV-G01GraphReader<'snap> references cannot outlive their snapshot (enforced by the borrow checker).
INV-G02Traversal never follows edges to deleted entities.
INV-G03BFS traversal visits each entity at most once (no infinite loops in cyclic graphs).
INV-G04Shortest path returns None when no path exists; it never returns an incorrect path.
INV-G05Blast radius computation is bounded by max_depth (default: 4).
INV-G06Coverage gap analysis only returns entities of target_type that have no qualifying neighbor.

Query Language Invariants (INV-Q01..Q06)

From specs/04-query-language.md:

CodeInvariant
INV-Q01PQL parsing is deterministic: the same query string always produces the same AST.
INV-Q02A query never returns results from entities that do not satisfy all specified filters.
INV-Q03LIMIT n applied to a query returns at most n results.
INV-Q04A query that times out returns an error, not a partial result.
INV-Q05FIND SHORTEST PATH FROM A TO B returns the minimum-hop path or None; never a longer path.
INV-Q06FIND BLAST RADIUS FROM X DEPTH n returns only entities reachable within n hops.

Connector SDK Invariants (INV-C01..C06)

From specs/05-integration-sdk.md:

CodeInvariant
INV-C01A sync commit is atomic: either all entities/relationships land or none do.
INV-C02Entities from connector A are never deleted by a sync from connector B.
INV-C03Entity IDs are deterministic from (account_id, type, key) — same as INV-02.
INV-C04A relationship in a sync batch whose from_id or to_id does not exist (in batch or graph) is rejected.
INV-C05Step dependencies form a DAG — circular step dependencies are rejected at connector load time.
INV-C06A failed step does not prevent independent steps from running.

API Surface Invariants (INV-A01..A06)

From specs/06-api-surface.md:

CodeInvariant
INV-A01All write endpoints require authentication when an API key is configured.
INV-A02API key comparison uses constant-time equality to prevent timing attacks.
INV-A03Every committed write is visible to subsequent reads on the same server instance.
INV-A04Query responses are paginated; no single response exceeds the configured max_results limit.
INV-A05Every request has a X-Request-Id header (generated or propagated) for tracing.
INV-A06The /v1/health endpoint is exempt from authentication.

Policy Engine Invariants (INV-P01..P06)

From specs/08-policy-engine.md:

CodeInvariant
INV-P01A policy rule with an invalid PQL query is rejected at load time, not at evaluation time.
INV-P02Policy evaluation never modifies the graph. It is read-only.
INV-P03A rule that errors during evaluation is recorded as an error, not as a pass or fail.
INV-P04Posture score is computed from all loaded rules, including errored ones (they count as failures).
INV-P05Framework mapping (CIS, NIST, PCI-DSS) is metadata on rules; it does not affect evaluation logic.
INV-P06Policy rules are validated against the PQL parser before being accepted into the rule set.

How to Use This Reference

When modifying code, ask: Which invariants does this change touch?

Reference affected invariants in your commit message:

fix(ingest): reject dangling relationships at commit time (INV-C04, INV-03)
feat(store): implement WAL CRC32C verification (INV-S05)
refactor(graph): bound traversal depth to prevent unbounded BFS (INV-G03)

When adding new behavior, ask: Does this require a new invariant? If yes, add it to the appropriate spec file and to this reference page.