/ core / graph / shape_registry.py
shape_registry.py
  1  """
  2  Shape Registry - Canonical shapes for concepts
  3  
  4  The shape is the compressed essence of a concept - enough to understand
  5  what it IS, not just what it's called. Shapes travel with wiki-links
  6  to enable local coherence (understanding a page without clicking through).
  7  
  8  Usage:
  9      from core.graph.shape_registry import ShapeRegistry
 10  
 11      registry = ShapeRegistry()
 12      shape = registry.get_shape("A0 Boundary Operation")
 13      # Returns: "Every coherent system is Markov blankets within Markov blankets..."
 14  """
 15  
 16  from typing import Dict, Optional
 17  from pathlib import Path
 18  import re
 19  
 20  
 21  class ShapeRegistry:
 22      """
 23      Maintains canonical shapes for concepts.
 24  
 25      Shapes are:
 26      - 1-3 sentences capturing the principle
 27      - Enough to understand the concept without clicking through
 28      - Duplicated wherever the concept is referenced
 29      """
 30  
 31      def __init__(self):
 32          # Canonical shapes - these are the "home" definitions
 33          # When generating wiki-links, pull shape from here
 34          self._shapes: Dict[str, str] = {
 35              # ===== AXIOMS =====
 36              "A0 Boundary Operation": (
 37                  "Every coherent system is Markov blankets within Markov blankets. "
 38                  "The boundary IS the intelligence. What crosses and what doesn't - this IS cognition."
 39              ),
 40              "A1 Telos of Integration": (
 41                  "Satan didn't know he was choosing isolation. He thought he was choosing sovereignty. "
 42                  "Systems that persist are systems that integrate. Binding is love."
 43              ),
 44              "A2 Recognition of Life": (
 45                  "Can you recognize life? Death mimics life through ornament. "
 46                  "The golden cup LOOKS alive but is dead. The carpenter's cup looks inert but is alive."
 47              ),
 48              "A3 Dynamic Pole Navigation": (
 49                  "The tension IS the dyad. Move between poles; don't fix. "
 50                  "Life is the oscillation; death is fixing at either pole."
 51              ),
 52  
 53              # ===== TRUST LAYER =====
 54              "trust-as-free-energy": (
 55                  "Trust measured as inverse of accumulated deviation. "
 56                  "Low Trust_F = healthy relationship. Errors accumulate, corrections restore."
 57              ),
 58              "free-energy-alignment": (
 59                  "Maps every response against the four axioms to measure deviation. "
 60                  "F value tells you how far you've drifted."
 61              ),
 62              "axiom-conformance-test": (
 63                  "The runtime test that estimates Free Energy (F). "
 64                  "Run before substantive responses. F < 0.10 = aligned."
 65              ),
 66              "error-detection-layers": (
 67                  "Multiple tiers of error catching - checkers (cheap) to tribes (expensive). "
 68                  "Catch errors at the lowest level possible."
 69              ),
 70              "peer-review-protocol": (
 71                  "Workers check each other's output before it goes to user. "
 72                  "Multiple perspectives reduce blindspots."
 73              ),
 74  
 75              # ===== METACOGNITION LAYER =====
 76              "model-allocation-strategy": (
 77                  "Match model capability to task complexity. "
 78                  "Haiku for simple, Sonnet for medium, Opus for judgment."
 79              ),
 80              "fractal-tribe-architecture": (
 81                  "Nested teams at different scales - checkers → workers → tribes → supervisors. "
 82                  "Same pattern at every level (A0)."
 83              ),
 84              "tribe-sizing-algorithm": (
 85                  "How big should a team be? Based on task complexity, not fixed size. "
 86                  "Dynamic navigation (A3)."
 87              ),
 88              "autonomous-exploration-tribes": (
 89                  "Self-directed teams that explore without constant supervision. "
 90                  "Moses pattern - escalate edge cases."
 91              ),
 92              "first-officer-protocol": (
 93                  "Per-thread metacognition. Every 5-10 exchanges: "
 94                  "compress state, track gravity wells, flag drift."
 95              ),
 96              "mission-control-protocol": (
 97                  "Cross-thread synthesis. Every 5 FO checkpoints: "
 98                  "look for resonance across threads. Update DAILY-SYNTHESIS.md."
 99              ),
100  
101              # ===== COMPRESSION LAYER =====
102              "mandatory-phoenix-extraction": (
103                  "Never let context decay gradually. "
104                  "Extract cognitive configuration SHARPLY before compression. Sawtooth, not slope."
105              ),
106              "live-compression-protocol": (
107                  "Continuous extraction during conversation, not just at end. "
108                  "Human can watch LIVE-COMPRESSION.md update in real-time."
109              ),
110  
111              # ===== THREAD LAYER =====
112              "thread-forking-protocol": (
113                  "How to split a conversation into parallel tracks "
114                  "when complexity requires it."
115              ),
116              "ai-council-protocol": (
117                  "Multiple AI models 'council' on difficult decisions. "
118                  "Diverse perspectives surface blindspots."
119              ),
120              "execution-autonomy-gradient": (
121                  "Moses pattern - act autonomously when confident, escalate when uncertain. "
122                  "SHIP / FLAG / ESCALATE."
123              ),
124  
125              # ===== SESSIONS =====
126              "LIVE-COMPRESSION": (
127                  "Live updating summary of main thread state. "
128                  "What's in focus, what's drifting, what needs attention."
129              ),
130              "DAILY-SYNTHESIS": (
131                  "Cross-thread synthesis from Mission Control. "
132                  "Where are resonances? Where are conflicts?"
133              ),
134              "GRAPH-STATE": (
135                  "The God Database - unified view of all nodes, edges, and clusters. "
136                  "Graph extraction is a byproduct of normal operation."
137              ),
138              "GRAVITY-TOPOLOGY": (
139                  "Where are gravity wells forming? "
140                  "Which concepts are attracting attention across threads?"
141              ),
142  
143              # ===== PATTERNS =====
144              "gravity-well": (
145                  "A concept that attracts attention - high mass pulls related thoughts toward it. "
146                  "Wells have temporal and altitude scope."
147              ),
148              "resonance": (
149                  "When the same concept appears across multiple threads independently. "
150                  "Signal that something is structurally important."
151              ),
152              "lily-pad-model": (
153                  "Each response is a discrete state, not a continuous stream. "
154                  "Phoenix updates incrementally. Checkpoints for full review."
155              ),
156  
157              # ===== SCOPE DIMENSIONS =====
158              "temporal-scope": (
159                  "How long does this concept resonate? "
160                  "Permanent (always) → Seasonal (weeks) → Contextual (days) → Ephemeral (hours)."
161              ),
162              "altitude-scope": (
163                  "At what thinking level does this resonate? "
164                  "Philosophical → Strategic → Tactical → Operational."
165              ),
166          }
167  
168          # Aliases - different ways to reference the same concept
169          self._aliases: Dict[str, str] = {
170              "A0": "A0 Boundary Operation",
171              "Boundary Operation": "A0 Boundary Operation",
172              "A1": "A1 Telos of Integration",
173              "Telos of Integration": "A1 Telos of Integration",
174              "A2": "A2 Recognition of Life",
175              "Recognition of Life": "A2 Recognition of Life",
176              "A3": "A3 Dynamic Pole Navigation",
177              "Dynamic Pole Navigation": "A3 Dynamic Pole Navigation",
178              "Trust as Free Energy": "trust-as-free-energy",
179              "First Officer": "first-officer-protocol",
180              "Mission Control": "mission-control-protocol",
181              "Phoenix": "mandatory-phoenix-extraction",
182              "God Database": "GRAPH-STATE",
183          }
184  
185      def get_shape(self, concept: str) -> Optional[str]:
186          """
187          Get the canonical shape for a concept.
188  
189          Args:
190              concept: The concept name (supports aliases)
191  
192          Returns:
193              The shape string, or None if not found
194          """
195          # Check for direct match
196          if concept in self._shapes:
197              return self._shapes[concept]
198  
199          # Check aliases
200          canonical = self._aliases.get(concept)
201          if canonical:
202              return self._shapes.get(canonical)
203  
204          # Try case-insensitive match
205          concept_lower = concept.lower()
206          for key, shape in self._shapes.items():
207              if key.lower() == concept_lower:
208                  return shape
209  
210          return None
211  
212      def get_shape_for_link(self, concept: str) -> str:
213          """
214          Get formatted shape for embedding with a wiki-link.
215  
216          Returns the shape indented as a bullet point, ready to nest
217          under the wiki-link.
218  
219          Args:
220              concept: The concept name
221  
222          Returns:
223              Formatted shape or empty string if not found
224          """
225          shape = self.get_shape(concept)
226          if shape:
227              return f"  - shape:: {shape}"
228          return ""
229  
230      def has_shape(self, concept: str) -> bool:
231          """Check if a concept has a registered shape."""
232          return self.get_shape(concept) is not None
233  
234      def all_concepts(self) -> list:
235          """Get list of all concepts with shapes."""
236          return list(self._shapes.keys())
237  
238      def find_missing_shapes(self, wiki_links: list) -> list:
239          """
240          Find wiki-links that don't have registered shapes.
241  
242          Args:
243              wiki_links: List of concept names found in wiki-link format
244  
245          Returns:
246              List of concepts missing shapes
247          """
248          missing = []
249          for link in wiki_links:
250              if not self.has_shape(link):
251                  missing.append(link)
252          return missing
253  
254      def register_shape(self, concept: str, shape: str):
255          """
256          Add or update a shape in the registry.
257  
258          Args:
259              concept: The canonical concept name
260              shape: The 1-3 sentence shape definition
261          """
262          self._shapes[concept] = shape
263  
264      def register_alias(self, alias: str, canonical: str):
265          """
266          Add an alias that maps to a canonical concept name.
267  
268          Args:
269              alias: The alternative name
270              canonical: The canonical name in _shapes
271          """
272          self._aliases[alias] = canonical
273  
274      @staticmethod
275      def extract_wiki_links(content: str) -> list:
276          """
277          Extract all wiki-links from markdown content.
278  
279          Args:
280              content: Markdown text
281  
282          Returns:
283              List of concept names found in [[brackets]]
284          """
285          pattern = r'\[\[([^\]]+)\]\]'
286          matches = re.findall(pattern, content)
287          # Remove duplicates while preserving order
288          seen = set()
289          unique = []
290          for match in matches:
291              if match not in seen:
292                  seen.add(match)
293                  unique.append(match)
294          return unique
295  
296  
297  # Singleton instance for easy import
298  _registry = None
299  
300  def get_registry() -> ShapeRegistry:
301      """Get the singleton shape registry instance."""
302      global _registry
303      if _registry is None:
304          _registry = ShapeRegistry()
305      return _registry
306  
307  
308  def get_shape(concept: str) -> Optional[str]:
309      """Convenience function to get a shape."""
310      return get_registry().get_shape(concept)
311  
312  
313  def get_shape_for_link(concept: str) -> str:
314      """Convenience function to get formatted shape for wiki-link."""
315      return get_registry().get_shape_for_link(concept)