/ scripts / semantic_resonance.py
semantic_resonance.py
  1  #!/usr/bin/env python3
  2  """
  3  Semantic Resonance Engine - ACTUAL semantic similarity, not term overlap.
  4  
  5  The problem with term matching:
  6      "rewrites are cheap" and "prevent ruin before optimizing gain" share ZERO words.
  7      But they are the SAME CONCEPT.
  8  
  9  This engine bridges that gap using:
 10  1. Concept expansion - synonyms and related concepts per axiom
 11  2. TF-IDF vectorization with n-grams
 12  3. Cosine similarity for semantic distance
 13  4. Fuzzy matching on concept descriptions
 14  
 15  Key insight: Axioms have SEMANTIC FIELDS, not just keywords.
 16      - A4 includes: cheap recovery, reversibility, antifragility, rebuild, undo, restart
 17      - These don't overlap with "ruin" or "ergodic" but ARE the same concept
 18  
 19  Usage:
 20      python scripts/semantic_resonance.py --text "rewrites are cheap"
 21      python scripts/semantic_resonance.py --text "build liberally"
 22      python scripts/semantic_resonance.py --file document.md
 23      echo "philosophy becomes code" | python scripts/semantic_resonance.py
 24  
 25  Author: Sovereign_OS
 26  Date: 2026-01-15
 27  """
 28  
 29  import re
 30  import sys
 31  import math
 32  import argparse
 33  from pathlib import Path
 34  from collections import Counter, defaultdict
 35  from typing import Dict, List, Tuple, Set, Optional
 36  from datetime import datetime
 37  from difflib import SequenceMatcher
 38  
 39  
 40  # ============================================================================
 41  # AXIOM SEMANTIC FIELDS
 42  # ============================================================================
 43  # Each axiom has:
 44  #   - principle: the core statement
 45  #   - concepts: expanded semantic field (not just keywords)
 46  #   - antonyms: concepts that indicate NON-alignment
 47  #   - exemplars: concrete examples that embody the axiom
 48  
 49  AXIOM_SEMANTIC_FIELDS = {
 50      'A0': {
 51          'name': 'Boundary Operation',
 52          'type': 'Structural',
 53          'principle': 'Every coherent system is Markov blankets within Markov blankets.',
 54          'concepts': [
 55              # Core terms
 56              'boundary', 'boundaries', 'border', 'edge', 'interface',
 57              'markov blanket', 'separation', 'distinction', 'demarcation',
 58              # Semantic expansions
 59              'inside outside', 'interior exterior', 'internal external',
 60              'what belongs', 'what crosses', 'permeability', 'membrane',
 61              'encapsulation', 'isolation', 'containment', 'scope',
 62              'sovereign territory', 'jurisdiction', 'domain',
 63              'agent boundary', 'self other', 'identity boundary',
 64              # Actions
 65              'draw distinction', 'mark boundary', 'define scope',
 66              'protect interior', 'control flow', 'filter what enters',
 67              # Structural concepts
 68              'fractal', 'nested', 'hierarchical structure', 'layered',
 69              'distributed', 'decentralized', 'network topology',
 70              'modular', 'composable', 'separation of concerns',
 71          ],
 72          'antonyms': [
 73              'undifferentiated', 'boundary-less', 'no separation',
 74              'everything connected', 'monolithic', 'no distinction',
 75          ],
 76          'exemplars': [
 77              'cell membrane controls what enters',
 78              'api boundaries define modules',
 79              'every page is a peer not subordinate',
 80              'structure flows content stays sovereign',
 81              'the blanket is the intelligence',
 82          ],
 83      },
 84  
 85      'A1': {
 86          'name': 'Telos of Integration',
 87          'type': 'Teleological',
 88          'principle': "Satan didn't know he was choosing isolation.",
 89          'concepts': [
 90              # Core terms
 91              'integration', 'connection', 'binding', 'linking', 'joining',
 92              'relation', 'relationship', 'exchange', 'interchange',
 93              # Semantic expansions
 94              'move toward connection', 'reach out', 'bridge gap',
 95              'collaborate', 'cooperate', 'coordinate', 'unite',
 96              'synthesis', 'combine', 'merge', 'unify', 'together',
 97              'network effect', 'collective', 'community', 'ecosystem',
 98              # Purpose concepts
 99              'purpose', 'telos', 'meaning', 'direction', 'aim',
100              'why we connect', 'purpose of system', 'raison detre',
101              # Negative pole awareness
102              'isolation warning', 'avoid isolation', 'not alone',
103              'sovereignty with relation', 'connected sovereignty',
104          ],
105          'antonyms': [
106              'isolation', 'disconnection', 'fragmentation', 'alone',
107              'cut off', 'siloed', 'walled off', 'refusing connection',
108          ],
109          'exemplars': [
110              'systems that persist are systems that integrate',
111              'sovereignty with relation not without',
112              'binding is the purpose',
113              'exchange creates knowledge',
114              'link rather than copy',
115          ],
116      },
117  
118      'A2': {
119          'name': 'Recognition of Life',
120          'type': 'Aesthetic',
121          'principle': 'Can you recognize life? Death mimics life through ornament.',
122          'concepts': [
123              # Core terms
124              'life', 'alive', 'living', 'vital', 'vitality',
125              'death', 'dead', 'dying', 'calcified', 'ossified',
126              # Recognition concepts
127              'recognize', 'discern', 'distinguish', 'discriminate',
128              'authentic', 'genuine', 'real', 'true',
129              'fake', 'imitation', 'mimicry', 'ornament', 'decoration',
130              # Motion vs stasis
131              'motion', 'movement', 'flow', 'change', 'evolve',
132              'static', 'fixed', 'frozen', 'stuck', 'stagnant',
133              # Primitive vs calcified
134              'primitive', 'simple', 'essential', 'core',
135              'complex', 'baroque', 'over-engineered', 'cruft',
136              'golden cup', 'carpenter cup', 'simple tools',
137              # Emergence
138              'emergence', 'emergent', 'spontaneous', 'organic',
139              'natural', 'growing', 'adaptive', 'evolutionary',
140          ],
141          'antonyms': [
142              'fixation', 'rigidity', 'calcification', 'fossilized',
143              'bureaucratic', 'process over outcome', 'ritual without meaning',
144          ],
145          'exemplars': [
146              'motion is life fixation is death',
147              'prefer primitive over calcified',
148              'the blur is the feature',
149              'see through the golden cup',
150              'simple tools that work',
151          ],
152      },
153  
154      'A3': {
155          'name': 'Dynamic Pole Navigation',
156          'type': 'Operational',
157          'principle': "The tension IS the dyad. Move between poles; don't fix.",
158          'concepts': [
159              # Core terms
160              'dynamic', 'pole', 'navigation', 'tension', 'dyad',
161              'balance', 'equilibrium', 'oscillation', 'between',
162              # Movement concepts
163              'move between', 'navigate', 'adapt', 'adjust', 'flex',
164              'context-dependent', 'situational', 'responsive',
165              'neither extreme', 'middle path', 'dialectic',
166              # Tension concepts
167              'hold tension', 'embrace paradox', 'both and',
168              'not either or', 'complementary opposites',
169              'yin yang', 'counterpoint', 'polarity',
170              # Failure modes
171              'failure mode', 'extreme position', 'stuck at pole',
172              'shadow pole', 'blind spot', 'what you avoid',
173              # Flexibility
174              'flexible', 'adaptable', 'responsive', 'agile',
175              'read context', 'situational awareness',
176          ],
177          'antonyms': [
178              'fixed position', 'rigid stance', 'one extreme',
179              'black and white', 'binary thinking', 'dogmatic',
180          ],
181          'exemplars': [
182              'life is the movement between poles',
183              'navigate dynamically based on context',
184              'shadow pole has information',
185              'dont fix at one extreme',
186              'tension is productive not problematic',
187          ],
188      },
189  
190      'A4': {
191          'name': 'Ergodic Asymmetry',
192          'type': 'Survival',
193          'principle': 'Prevent ruin before optimizing gain.',
194          'concepts': [
195              # Core terms
196              'ruin', 'survival', 'catastrophe', 'disaster', 'terminal',
197              'ergodic', 'ergodicity', 'time average', 'ensemble average',
198              # Asymmetry concepts
199              'asymmetry', 'asymmetric', 'irreversible', 'one-way',
200              'cant undo', 'no recovery', 'game over', 'extinction',
201              # Prevention concepts
202              'prevent', 'avoid', 'protect', 'safeguard', 'hedge',
203              'downside protection', 'risk management', 'insurance',
204              # Recovery concepts - KEY SEMANTIC FIELD
205              'cheap recovery', 'cheap to rebuild', 'cheap to restart',
206              'rewrites are cheap', 'rebuild is cheap', 'throwaway',
207              'reversible', 'undoable', 'recoverable', 'resilient',
208              'can start over', 'phoenix', 'resurrection',
209              'build liberally', 'iterate freely', 'fail cheap',
210              # Taleb concepts
211              'antifragile', 'black swan', 'fat tail', 'fragile',
212              'robust', 'convex', 'concave', 'optionality',
213              # Time concepts
214              'time destroys', 'survival over time', 'longevity',
215              'expected value trap', 'gambler ruin', 'absorbing state',
216          ],
217          'antonyms': [
218              'optimize for expected value', 'ignore tail risk',
219              'all-in bet', 'irreversible commitment', 'no hedge',
220          ],
221          'exemplars': [
222              'prevent ruin before optimizing gain',
223              'rewrites are cheap catastrophe is expensive',
224              'build liberally because rebuild is cheap',
225              'survival matters more than expected value',
226              'some positions are terminal',
227              'cheap to throw away and restart',
228              'reversibility as default',
229              'fail fast fail cheap',
230          ],
231      },
232  }
233  
234  
235  # ============================================================================
236  # TEXT PROCESSING
237  # ============================================================================
238  
239  def preprocess_text(text: str) -> str:
240      """Clean and normalize text for comparison."""
241      text = text.lower()
242      # Remove punctuation but keep spaces
243      text = re.sub(r'[^\w\s-]', ' ', text)
244      # Normalize whitespace
245      text = re.sub(r'\s+', ' ', text).strip()
246      return text
247  
248  
249  def extract_ngrams(text: str, n: int = 2) -> List[str]:
250      """Extract n-grams from text."""
251      words = text.split()
252      if len(words) < n:
253          return words
254      return [' '.join(words[i:i+n]) for i in range(len(words) - n + 1)]
255  
256  
257  def tokenize(text: str) -> List[str]:
258      """Tokenize text into words and bigrams."""
259      text = preprocess_text(text)
260      words = text.split()
261      bigrams = extract_ngrams(text, 2)
262      return words + bigrams
263  
264  
265  # ============================================================================
266  # TF-IDF IMPLEMENTATION
267  # ============================================================================
268  
269  class TFIDFVectorizer:
270      """Simple TF-IDF implementation without external dependencies."""
271  
272      def __init__(self):
273          self.vocabulary: Dict[str, int] = {}
274          self.idf: Dict[str, float] = {}
275          self.documents: List[List[str]] = []
276  
277      def fit(self, documents: List[str]):
278          """Build vocabulary and compute IDF from documents."""
279          self.documents = [tokenize(doc) for doc in documents]
280  
281          # Build vocabulary
282          all_tokens = set()
283          for tokens in self.documents:
284              all_tokens.update(tokens)
285          self.vocabulary = {token: i for i, token in enumerate(sorted(all_tokens))}
286  
287          # Compute IDF
288          n_docs = len(self.documents)
289          doc_freq = Counter()
290          for tokens in self.documents:
291              unique_tokens = set(tokens)
292              for token in unique_tokens:
293                  doc_freq[token] += 1
294  
295          self.idf = {
296              token: math.log((n_docs + 1) / (freq + 1)) + 1
297              for token, freq in doc_freq.items()
298          }
299  
300      def transform(self, text: str) -> Dict[str, float]:
301          """Transform text to TF-IDF vector."""
302          tokens = tokenize(text)
303          tf = Counter(tokens)
304          total = sum(tf.values())
305  
306          vector = {}
307          for token, count in tf.items():
308              tf_val = count / total if total > 0 else 0
309              idf_val = self.idf.get(token, 1.0)
310              vector[token] = tf_val * idf_val
311  
312          return vector
313  
314  
315  def cosine_similarity(vec1: Dict[str, float], vec2: Dict[str, float]) -> float:
316      """Compute cosine similarity between two sparse vectors."""
317      if not vec1 or not vec2:
318          return 0.0
319  
320      # Find common keys
321      common_keys = set(vec1.keys()) & set(vec2.keys())
322      if not common_keys:
323          return 0.0
324  
325      # Dot product
326      dot = sum(vec1[k] * vec2[k] for k in common_keys)
327  
328      # Magnitudes
329      mag1 = math.sqrt(sum(v ** 2 for v in vec1.values()))
330      mag2 = math.sqrt(sum(v ** 2 for v in vec2.values()))
331  
332      if mag1 == 0 or mag2 == 0:
333          return 0.0
334  
335      return dot / (mag1 * mag2)
336  
337  
338  # ============================================================================
339  # FUZZY MATCHING
340  # ============================================================================
341  
342  def fuzzy_match_score(text1: str, text2: str) -> float:
343      """Compute fuzzy match score using SequenceMatcher."""
344      return SequenceMatcher(None, text1.lower(), text2.lower()).ratio()
345  
346  
347  def best_fuzzy_match(text: str, candidates: List[str]) -> Tuple[str, float]:
348      """Find best fuzzy match from candidates."""
349      if not candidates:
350          return "", 0.0
351  
352      best_candidate = ""
353      best_score = 0.0
354  
355      text_lower = text.lower()
356      for candidate in candidates:
357          score = fuzzy_match_score(text_lower, candidate.lower())
358          if score > best_score:
359              best_score = score
360              best_candidate = candidate
361  
362      return best_candidate, best_score
363  
364  
365  # ============================================================================
366  # SEMANTIC RESONANCE ENGINE
367  # ============================================================================
368  
369  class SemanticResonanceEngine:
370      """
371      Engine that computes SEMANTIC similarity to axioms.
372  
373      Unlike term matching, this can detect:
374      - "rewrites are cheap" -> A4 (prevent ruin, cheap recovery)
375      - "build liberally" -> A4 (because rebuild is cheap)
376      - "philosophy becomes code" -> A0 (structure flows)
377      """
378  
379      def __init__(self):
380          self.vectorizer = TFIDFVectorizer()
381          self._build_axiom_corpus()
382  
383      def _build_axiom_corpus(self):
384          """Build TF-IDF corpus from axiom semantic fields."""
385          # Create document for each axiom
386          documents = []
387          for axiom_id, field in AXIOM_SEMANTIC_FIELDS.items():
388              doc_parts = [
389                  field['principle'],
390                  ' '.join(field['concepts']),
391                  ' '.join(field['exemplars']),
392              ]
393              documents.append(' '.join(doc_parts))
394  
395          self.vectorizer.fit(documents)
396  
397          # Pre-compute axiom vectors
398          self.axiom_vectors = {}
399          for axiom_id, field in AXIOM_SEMANTIC_FIELDS.items():
400              doc = ' '.join([
401                  field['principle'],
402                  ' '.join(field['concepts']),
403                  ' '.join(field['exemplars']),
404              ])
405              self.axiom_vectors[axiom_id] = self.vectorizer.transform(doc)
406  
407      def compute_resonance(self, text: str) -> Dict[str, dict]:
408          """
409          Compute semantic resonance with each axiom.
410  
411          Returns dict with:
412              - tfidf_score: TF-IDF cosine similarity
413              - concept_score: Fuzzy match to concepts
414              - exemplar_score: Fuzzy match to exemplars
415              - combined_score: Weighted combination
416              - matched_concepts: Which concepts matched
417              - matched_exemplars: Which exemplars matched
418          """
419          text_vector = self.vectorizer.transform(text)
420          text_lower = preprocess_text(text)
421  
422          results = {}
423  
424          for axiom_id, field in AXIOM_SEMANTIC_FIELDS.items():
425              # TF-IDF similarity
426              tfidf_score = cosine_similarity(text_vector, self.axiom_vectors[axiom_id])
427  
428              # Concept matching (fuzzy)
429              concept_matches = []
430              for concept in field['concepts']:
431                  concept_lower = preprocess_text(concept)
432                  # Check if concept appears in text
433                  if concept_lower in text_lower:
434                      concept_matches.append((concept, 1.0))
435                  else:
436                      # Fuzzy match
437                      score = fuzzy_match_score(text_lower, concept_lower)
438                      if score > 0.5:
439                          concept_matches.append((concept, score))
440  
441              concept_score = max([m[1] for m in concept_matches]) if concept_matches else 0.0
442  
443              # Exemplar matching (fuzzy)
444              exemplar_matches = []
445              for exemplar in field['exemplars']:
446                  exemplar_lower = preprocess_text(exemplar)
447                  score = fuzzy_match_score(text_lower, exemplar_lower)
448                  if score > 0.4:
449                      exemplar_matches.append((exemplar, score))
450  
451              exemplar_score = max([m[1] for m in exemplar_matches]) if exemplar_matches else 0.0
452  
453              # Antonym check (reduces score)
454              antonym_penalty = 0.0
455              for antonym in field.get('antonyms', []):
456                  if preprocess_text(antonym) in text_lower:
457                      antonym_penalty = 0.3
458                      break
459  
460              # Combined score with weights
461              # TF-IDF provides semantic similarity
462              # Concept matching catches specific terms
463              # Exemplar matching catches phrasing patterns
464              combined = (
465                  tfidf_score * 0.3 +
466                  concept_score * 0.4 +
467                  exemplar_score * 0.3
468              ) - antonym_penalty
469  
470              combined = max(0.0, min(1.0, combined))
471  
472              results[axiom_id] = {
473                  'tfidf_score': tfidf_score,
474                  'concept_score': concept_score,
475                  'exemplar_score': exemplar_score,
476                  'combined_score': combined,
477                  'matched_concepts': [m[0] for m in concept_matches[:3]],
478                  'matched_exemplars': [m[0] for m in exemplar_matches[:2]],
479              }
480  
481          return results
482  
483      def get_primary_resonance(self, text: str) -> Tuple[str, float, dict]:
484          """Get the axiom with highest resonance."""
485          results = self.compute_resonance(text)
486  
487          if not results:
488              return None, 0.0, {}
489  
490          best_axiom = max(results, key=lambda k: results[k]['combined_score'])
491          return best_axiom, results[best_axiom]['combined_score'], results[best_axiom]
492  
493      def explain_resonance(self, text: str) -> str:
494          """Generate human-readable explanation of resonance."""
495          results = self.compute_resonance(text)
496  
497          lines = []
498          lines.append("=" * 70)
499          lines.append("SEMANTIC RESONANCE ANALYSIS")
500          lines.append("=" * 70)
501          lines.append("")
502          lines.append(f'Input: "{text[:80]}{"..." if len(text) > 80 else ""}"')
503          lines.append("")
504  
505          # Sort by combined score
506          sorted_axioms = sorted(
507              results.items(),
508              key=lambda x: x[1]['combined_score'],
509              reverse=True
510          )
511  
512          for axiom_id, scores in sorted_axioms:
513              field = AXIOM_SEMANTIC_FIELDS[axiom_id]
514              combined = scores['combined_score']
515  
516              # Visual bar
517              bar = "█" * int(combined * 20)
518              empty = "░" * (20 - int(combined * 20))
519  
520              lines.append(f"{axiom_id}: {field['name']} ({field['type']})")
521              lines.append(f"    [{bar}{empty}] {combined:.0%}")
522  
523              if scores['matched_concepts']:
524                  lines.append(f"    Concepts: {', '.join(scores['matched_concepts'][:3])}")
525              if scores['matched_exemplars']:
526                  lines.append(f"    Exemplars: {scores['matched_exemplars'][0][:50]}...")
527  
528              lines.append("")
529  
530          # Primary resonance
531          best_axiom, best_score, _ = self.get_primary_resonance(text)
532  
533          lines.append("-" * 70)
534          if best_score >= 0.3:
535              field = AXIOM_SEMANTIC_FIELDS[best_axiom]
536              lines.append(f"PRIMARY RESONANCE: {best_axiom} - {field['name']}")
537              lines.append(f"Score: {best_score:.0%}")
538              lines.append("")
539              lines.append(f'Principle: "{field["principle"]}"')
540          elif best_score >= 0.1:
541              lines.append(f"Weak resonance with {best_axiom} ({best_score:.0%})")
542          else:
543              lines.append("No significant axiom resonance detected.")
544  
545          lines.append("")
546  
547          return "\n".join(lines)
548  
549  
550  # ============================================================================
551  # DEMONSTRATION
552  # ============================================================================
553  
554  def demonstrate_semantic_gap():
555      """Demonstrate how semantic resonance bridges the gap."""
556      engine = SemanticResonanceEngine()
557  
558      test_cases = [
559          # These should match A4 despite NO term overlap with "prevent ruin" or "ergodic"
560          ("rewrites are cheap", "A4"),
561          ("build liberally", "A4"),
562          ("cheap to throw away and restart", "A4"),
563          ("fail fast fail cheap", "A4"),
564  
565          # These should match their respective axioms
566          ("what belongs inside vs outside", "A0"),
567          ("move toward connection", "A1"),
568          ("motion is life fixation is death", "A2"),
569          ("navigate between poles", "A3"),
570  
571          # Edge cases
572          ("prevent catastrophe at all costs", "A4"),
573          ("boundaries enable integration", "A0"),  # Could be A0 or A1
574      ]
575  
576      print("\n" + "=" * 70)
577      print("SEMANTIC GAP DEMONSTRATION")
578      print("=" * 70)
579      print("\nKey insight: 'rewrites are cheap' and 'prevent ruin' share ZERO words")
580      print("but they ARE the same concept. Watch semantic resonance bridge this gap.\n")
581  
582      for text, expected in test_cases:
583          axiom_id, score, details = engine.get_primary_resonance(text)
584          match = "✓" if axiom_id == expected else "✗"
585          print(f'{match} "{text}"')
586          print(f'    → {axiom_id} ({score:.0%}) [expected: {expected}]')
587          if details.get('matched_concepts'):
588              print(f'    Matched: {details["matched_concepts"][0]}')
589          print()
590  
591  
592  # ============================================================================
593  # MAIN
594  # ============================================================================
595  
596  def main():
597      parser = argparse.ArgumentParser(
598          description='Semantic Resonance Engine - ACTUAL semantic similarity'
599      )
600      parser.add_argument(
601          '--text', '-t',
602          type=str,
603          help='Text to analyze'
604      )
605      parser.add_argument(
606          '--file', '-f',
607          type=Path,
608          help='File containing text to analyze'
609      )
610      parser.add_argument(
611          '--demo',
612          action='store_true',
613          help='Run demonstration of semantic gap bridging'
614      )
615      parser.add_argument(
616          '--json',
617          action='store_true',
618          help='Output as JSON'
619      )
620  
621      args = parser.parse_args()
622  
623      engine = SemanticResonanceEngine()
624  
625      if args.demo:
626          demonstrate_semantic_gap()
627          return 0
628  
629      # Get input text
630      if args.text:
631          text = args.text
632      elif args.file:
633          text = args.file.read_text(encoding='utf-8')
634      elif not sys.stdin.isatty():
635          text = sys.stdin.read()
636      else:
637          print("Error: No input provided. Use --text, --file, or pipe input.")
638          print("       Use --demo to see demonstration.")
639          return 1
640  
641      text = text.strip()
642      if not text:
643          print("Error: Empty input")
644          return 1
645  
646      if args.json:
647          import json
648          results = engine.compute_resonance(text)
649          axiom_id, score, _ = engine.get_primary_resonance(text)
650          output = {
651              'input': text,
652              'primary_axiom': axiom_id,
653              'primary_score': score,
654              'resonances': {
655                  k: {
656                      'combined': v['combined_score'],
657                      'tfidf': v['tfidf_score'],
658                      'concept': v['concept_score'],
659                      'exemplar': v['exemplar_score'],
660                  }
661                  for k, v in results.items()
662              }
663          }
664          print(json.dumps(output, indent=2))
665      else:
666          print(engine.explain_resonance(text))
667  
668      return 0
669  
670  
671  if __name__ == '__main__':
672      sys.exit(main())