# ADR-045: Organization Members as Authoritative SQL Table, BelongsToEdge as Derived ## Status Accepted ## Context OQ-23 asked whether `BelongsToEdge` in the ACL graph should be derived (materialized from `organization_members`) or primary (ACL graph is the source of truth). The ACL graph needs `BelongsToEdge` for traversal-based permission evaluation (ADR-034). The hub needs `organization_members` for fast SQL lookups ("list all members of org X", FK constraints on cascading behavior). Two sources of truth for the same data creates a consistency risk. ## Decision `organization_members` is the authoritative SQL table. `BelongsToEdge` in the ACL graph is derived. When org membership changes, the consumer (hub) writes to `organization_members` first, then creates or removes the corresponding `BelongsToEdge` in the ACL graph instance. The ACL edge mirrors the SQL table; it does not define it. If the two fall out of sync, the SQL table is the source of truth. An audit/reconciliation process can re-derive ACL edges from the SQL table. ## Consequences **Positive:** - Clear authority — one write path for membership, one derived read path for ACL traversal - FK constraints on `organization_members` work (cascade delete when org or account is removed) - Fast indexed lookups for membership lists — no graph traversal needed - ACL evaluator can still traverse `BelongsToEdge` for permission resolution - Reconciliation is straightforward — scan `organization_members`, compare against ACL edges, fix discrepancies **Negative:** - Dual-write contract — the consumer must write both places. If the ACL edge write fails after the SQL write, they're out of sync. - The ACL graph is not self-contained for org membership — it depends on an external table ## References - ADR-034: ACL as metagraph - ADR-041: Identity tables in storage package - OQ-23: BelongsToEdge derivation (now resolved)