# UNDF: UNDF-2026-000000235
Fixes pyramid-0005: registry.py Introspector.relate()/unrelate() — list-backed relationship tracking with O(n) membership and removal.

--- a/src/pyramid/registry.py
+++ b/src/pyramid/registry.py

@@ DEFECT pyramid-0005: Introspector.relate()/unrelate() lines 185-199

 class Introspector:
     def __init__(self):
         self._categories = {}
-        self._refs = {}                # introspectable → list of related — CWE-407
+        self._refs = {}                # introspectable → list of related (preserved for related())
+        self._refs_set = {}            # FIX pyramid-0005: introspectable → set for O(1) ops

     def relate(self, *pairs):
         introspectables = self._get_intrs_by_pairs(pairs)
         relatable = ((x, y) for x in introspectables for y in introspectables)
         for x, y in relatable:
             L = self._refs.setdefault(x, [])
-            if x is not y and y not in L:     # O(n) list scan — CWE-407
+            S = self._refs_set.setdefault(x, set())
+            if x is not y and y not in S:     # O(1) set lookup — fixed
                 L.append(y)
+                S.add(y)

     def unrelate(self, *pairs):
         introspectables = self._get_intrs_by_pairs(pairs)
         relatable = ((x, y) for x in introspectables for y in introspectables)
         for x, y in relatable:
             L = self._refs.get(x, [])
-            if y in L:                        # O(n) list scan — CWE-407
-                L.remove(y)                   # O(n) list removal — CWE-407
+            S = self._refs_set.get(x, set())
+            if y in S:                        # O(1) set lookup — fixed
+                L.remove(y)                   # O(n) but confirmed; one call per unrelate
+                S.discard(y)

# NOTE: _refs list is kept for related() return value (callers may rely on list type).
# _refs_set shadow provides O(1) dedup in relate() and O(1) guard in unrelate().
