diff --git a/glyphs/super_registry.py b/glyphs/super_registry.py new file mode 100644 index 0000000..fef9eaf --- /dev/null +++ b/glyphs/super_registry.py @@ -0,0 +1,315 @@ +"""Supercharged Glyph Registry (LedoGlyph600) + +Registry for 600-glyph supercharged dataset with: +- 112 superpowers per glyph +- frequency signatures (praw: P, R, A, W) +- contributor inheritance (lineage) +- symbolic anatomy (originalMetrics) +- activation envelopes (activation modes) +- resonance profiles (activation signatures) +- extended metadata (governance, routing, storage) + +Data source: /mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json +""" + +from typing import Optional, List, Dict, Any +import json +from pathlib import Path + +# Module-level cache +_glyphs: Optional[Dict[str, dict]] = None +_glyph_ids: Optional[List[str]] = None +_loaded = False +_load_path: Optional[Path] = None + + +def load_all_supercharged(path: Optional[str] = None) -> None: + """Load all 600 supercharged glyphs from JSON file. + + Lazy-loads and caches glyphs in module-level variables. + Validates that exactly 600 glyphs are present. + + Args: + path: Optional path to LedoGlyph600.json file. + Defaults to /mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json + + Raises: + FileNotFoundError: If file doesn't exist + ValueError: If glyph count != 600 + json.JSONDecodeError: If JSON is malformed + """ + global _glyphs, _glyph_ids, _loaded, _load_path + + if _loaded: + return + + # Resolve path + if path is None: + path = "/mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json" + + filepath = Path(path) + if not filepath.exists(): + raise FileNotFoundError(f"Supercharged glyph file not found: {filepath}") + + _load_path = filepath + + # Load JSON + with open(filepath) as f: + data = json.load(f) + + # Extract glyphs + if isinstance(data, dict) and "glyphs" in data: + glyph_list = data["glyphs"] + elif isinstance(data, list): + glyph_list = data + else: + raise ValueError("Invalid glyph data structure") + + # Validate count + if len(glyph_list) != 600: + raise ValueError(f"Expected 600 glyphs, got {len(glyph_list)}") + + # Build cache dict by ID + _glyphs = {} + for glyph in glyph_list: + glyph_id = glyph.get("id") + if glyph_id: + _glyphs[glyph_id] = glyph + + # Build ID list + _glyph_ids = sorted(list(_glyphs.keys())) + + _loaded = True + + +def get_super(glyph_id: str) -> Optional[dict]: + """Get a single supercharged glyph by ID. + + Returns all fields: id, name, category, period, band, originalMetrics, + praw, score, lineage, activation, routing, storage, governance. + + Args: + glyph_id: Glyph ID (e.g. "G001") + + Returns: + Glyph dict with all supercharged fields, or None if not found + """ + if not _loaded: + load_all_supercharged() + + return _glyphs.get(glyph_id) if _glyphs else None + + +def list_super_ids() -> List[str]: + """List all supercharged glyph IDs (sorted). + + Returns: + List of 600 glyph IDs + """ + if not _loaded: + load_all_supercharged() + + return _glyph_ids[:] if _glyph_ids else [] + + +def search_super( + query: str, + *, + fields: Optional[List[str]] = None, + limit: int = 20 +) -> List[dict]: + """Search supercharged glyphs by query across specified fields. + + Performs case-insensitive substring matching on string fields and + numeric fields converted to strings. + + Args: + query: Search string (case-insensitive substring match) + fields: List of field names to search. + Defaults to ['id', 'name', 'category'] + limit: Maximum results to return (default 20) + + Returns: + List of matching glyph dicts (up to limit) + """ + if not _loaded: + load_all_supercharged() + + if not _glyphs: + return [] + + if fields is None: + fields = ["id", "name", "category"] + + query_lower = query.lower() + results = [] + + for glyph_id in _glyph_ids: + glyph = _glyphs[glyph_id] + + # Search in specified fields + for field in fields: + value = glyph.get(field) + if value is None: + continue + + # Convert to string for matching + if isinstance(value, str): + if query_lower in value.lower(): + results.append(glyph) + break + elif isinstance(value, (int, float)): + if query_lower in str(value).lower(): + results.append(glyph) + break + + # Stop if we've hit limit + if len(results) >= limit: + break + + return results[:limit] + + +def super_stats() -> dict: + """Get statistics about the supercharged glyph registry. + + Validates registry integrity and returns metadata. + + Returns: + Dict with keys: + - total_glyphs: Count of glyphs (should be 600) + - fields_present: List of all field names found across glyphs + - sample_ids: First 5 glyph IDs + - categories: List of all unique categories + - loaded: Whether registry is loaded + - load_path: Path to data file + """ + if not _loaded: + load_all_supercharged() + + if not _glyphs: + return { + "total_glyphs": 0, + "fields_present": [], + "sample_ids": [], + "categories": [], + "loaded": False, + "load_path": None, + } + + # Collect all field names + all_fields = set() + all_categories = set() + + for glyph in _glyphs.values(): + all_fields.update(glyph.keys()) + category = glyph.get("category") + if category: + all_categories.add(category) + + return { + "total_glyphs": len(_glyphs), + "fields_present": sorted(list(all_fields)), + "sample_ids": _glyph_ids[:5] if _glyph_ids else [], + "categories": sorted(list(all_categories)), + "loaded": _loaded, + "load_path": str(_load_path) if _load_path else None, + } + + +def get_super_field(glyph_id: str, field_path: str, default: Any = None) -> Any: + """Get a nested field from a supercharged glyph. + + Supports dot-notation for nested fields (e.g. "activation.score", + "praw.P", "lineage.signature"). + + Args: + glyph_id: Glyph ID + field_path: Field path (supports dots for nesting) + default: Default value if not found + + Returns: + Field value or default + """ + glyph = get_super(glyph_id) + if glyph is None: + return default + + # Handle nested paths + parts = field_path.split(".") + value = glyph + + for part in parts: + if isinstance(value, dict): + value = value.get(part) + if value is None: + return default + else: + return default + + return value + + +def list_super_by_category(category: str) -> List[dict]: + """List all supercharged glyphs in a category. + + Args: + category: Category name (e.g. "neural", "harmonic") + + Returns: + List of matching glyphs + """ + if not _loaded: + load_all_supercharged() + + if not _glyphs: + return [] + + return [g for g in _glyphs.values() if g.get("category") == category] + + +def get_super_by_band(band: int) -> List[dict]: + """List all supercharged glyphs in a frequency band. + + Args: + band: Band number + + Returns: + List of matching glyphs sorted by band + """ + if not _loaded: + load_all_supercharged() + + if not _glyphs: + return [] + + return sorted( + [g for g in _glyphs.values() if g.get("band") == band], + key=lambda g: g.get("id", "") + ) + + +def get_glyphs_by_score_range(min_score: int, max_score: int) -> List[dict]: + """List glyphs with scores in the given range. + + Args: + min_score: Minimum score (inclusive) + max_score: Maximum score (inclusive) + + Returns: + List of glyphs sorted by score descending + """ + if not _loaded: + load_all_superchattracted() + + if not _glyphs: + return [] + + return sorted( + [ + g for g in _glyphs.values() + if min_score <= g.get("score", 0) <= max_score + ], + key=lambda g: g.get("score", 0), + reverse=True + ) diff --git a/tests/test_supercharged_registry.py b/tests/test_supercharged_registry.py new file mode 100644 index 0000000..dbc619f --- /dev/null +++ b/tests/test_supercharged_registry.py @@ -0,0 +1,400 @@ +#!/usr/bin/env python3 +"""Tests for Supercharged Glyph Registry (LedoGlyph600) + +Tests verify: +- load_all_supercharged loads exactly 600 glyphs +- get_super returns correct glyph data +- list_super_ids returns all glyph IDs +- search_super works across supercharged fields +- super_stats reports correct metadata +- Helper functions work correctly +""" + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path.cwd())) + +from glyphs.super_registry import ( + load_all_supercharged, + get_super, + list_super_ids, + search_super, + super_stats, + get_super_field, + list_super_by_category, + get_super_by_band, + get_glyphs_by_score_range, +) + + +def test_load_all_supercharged(): + """Test loading all 600 supercharged glyphs.""" + load_all_supercharged() + stats = super_stats() + + if stats["total_glyphs"] != 600: + print(f"FAIL: Expected 600 glyphs, got {stats['total_glyphs']}") + return False + + if not stats["loaded"]: + print("FAIL: Registry not marked as loaded") + return False + + print(f"PASS: Loaded 600 glyphs") + return True + + +def test_get_super(): + """Test retrieving individual glyphs by ID.""" + load_all_supercharged() + ids = list_super_ids() + + if not ids: + print("FAIL: No glyph IDs available") + return False + + # Test first glyph + first_id = ids[0] + glyph = get_super(first_id) + + if glyph is None: + print(f"FAIL: Could not get glyph {first_id}") + return False + + # Check required fields + required_fields = ["id", "name", "category", "band", "score"] + for field in required_fields: + if field not in glyph: + print(f"FAIL: Glyph missing field: {field}") + return False + + if glyph["id"] != first_id: + print(f"FAIL: Glyph ID mismatch: {glyph['id']} != {first_id}") + return False + + print(f"PASS: Retrieved glyph {first_id} with all required fields") + return True + + +def test_get_super_nonexistent(): + """Test retrieving non-existent glyph returns None.""" + load_all_supercharged() + glyph = get_super("NONEXISTENT") + + if glyph is not None: + print("FAIL: Should return None for nonexistent glyph") + return False + + print("PASS: Returns None for nonexistent glyph") + return True + + +def test_list_super_ids(): + """Test listing all glyph IDs.""" + load_all_supercharged() + ids = list_super_ids() + + if len(ids) != 600: + print(f"FAIL: Expected 600 IDs, got {len(ids)}") + return False + + if ids != sorted(ids): + print("FAIL: IDs are not sorted") + return False + + if not all(isinstance(id, str) for id in ids): + print("FAIL: Not all IDs are strings") + return False + + print(f"PASS: Listed 600 sorted glyph IDs") + return True + + +def test_search_super_basic(): + """Test basic search functionality.""" + load_all_supercharged() + + # Search by ID + results = search_super("G001", fields=["id"]) + if len(results) == 0: + print("FAIL: Could not find G001") + return False + + if results[0]["id"] != "G001": + print("FAIL: First result is not G001") + return False + + print(f"PASS: Found G001 by ID search") + return True + + +def test_search_super_case_insensitive(): + """Test case-insensitive search.""" + load_all_supercharged() + + # Get a known glyph + first_glyph = get_super("G001") + if first_glyph is None: + print("FAIL: Could not load reference glyph") + return False + + name = first_glyph.get("name", "").lower() + if not name: + print("FAIL: Reference glyph has no name") + return False + + # Search with uppercase + results = search_super(name.upper(), fields=["name"]) + if len(results) == 0: + print(f"FAIL: Case-insensitive search failed for {name.upper()}") + return False + + print(f"PASS: Case-insensitive search works") + return True + + +def test_search_super_limit(): + """Test search limit parameter.""" + load_all_supercharged() + + # Search for common category + results = search_super("", fields=["category"], limit=5) + + # Note: empty query won't match, but we can test limit on real results + ids = list_super_ids() + + # Search for first 10 IDs with limit + for test_id in ids[:10]: + results = search_super(test_id, limit=3) + if len(results) > 3: + print(f"FAIL: Got {len(results)} results, limit was 3") + return False + + print("PASS: Search limit respected") + return True + + +def test_super_stats(): + """Test statistics reporting.""" + load_all_supercharged() + stats = super_stats() + + # Verify stats keys + required_keys = [ + "total_glyphs", + "fields_present", + "sample_ids", + "categories", + "loaded", + "load_path", + ] + + for key in required_keys: + if key not in stats: + print(f"FAIL: Missing stats key: {key}") + return False + + # Verify values + if stats["total_glyphs"] != 600: + print(f"FAIL: total_glyphs != 600") + return False + + if not isinstance(stats["fields_present"], list): + print("FAIL: fields_present is not a list") + return False + + if not isinstance(stats["sample_ids"], list): + print("FAIL: sample_ids is not a list") + return False + + # Check supercharged fields are present + supercharged_fields = [ + "id", + "name", + "activation", + "lineage", + "praw", + "originalMetrics", + ] + + missing = [f for f in supercharged_fields if f not in stats["fields_present"]] + if missing: + print(f"FAIL: Missing supercharged fields: {missing}") + return False + + if stats["loaded"] != True: + print("FAIL: loaded should be True") + return False + + if stats["sample_ids"] != list_super_ids()[:5]: + print("FAIL: sample_ids mismatch") + return False + + print(f"PASS: Stats complete with {len(stats['categories'])} categories") + return True + + +def test_get_super_field(): + """Test nested field retrieval.""" + load_all_supercharged() + + glyph = get_super("G001") + if glyph is None: + print("FAIL: Could not load G001") + return False + + # Test direct field + name = get_super_field("G001", "name") + if name != glyph["name"]: + print(f"FAIL: Direct field mismatch") + return False + + # Test nested field (if present) + if "activation" in glyph: + score = get_super_field("G001", "activation.score") + if score != glyph.get("activation", {}).get("score"): + print(f"FAIL: Nested field mismatch") + return False + + # Test default value + missing = get_super_field("G001", "nonexistent.field", default="DEFAULT") + if missing != "DEFAULT": + print(f"FAIL: Default value not returned") + return False + + print("PASS: Nested field retrieval works") + return True + + +def test_list_super_by_category(): + """Test filtering by category.""" + load_all_supercharged() + + stats = super_stats() + categories = stats.get("categories", []) + + if not categories: + print("SKIP: No categories found") + return True + + # Test first category + category = categories[0] + glyphs = list_super_by_category(category) + + if len(glyphs) == 0: + print(f"FAIL: No glyphs found in category {category}") + return False + + # Verify all returned glyphs are in that category + for glyph in glyphs: + if glyph.get("category") != category: + print(f"FAIL: Glyph in wrong category") + return False + + print(f"PASS: Found {len(glyphs)} glyphs in category '{category}'") + return True + + +def test_get_super_by_band(): + """Test filtering by frequency band.""" + load_all_supercharged() + + # Get first glyph to find a band + first = get_super(list_super_ids()[0]) + if first is None: + print("FAIL: Could not load first glyph") + return False + + band = first.get("band") + glyphs = get_super_by_band(band) + + if len(glyphs) == 0: + print(f"FAIL: No glyphs found in band {band}") + return False + + # Verify all are in same band + for glyph in glyphs: + if glyph.get("band") != band: + print(f"FAIL: Glyph in wrong band") + return False + + print(f"PASS: Found {len(glyphs)} glyphs in band {band}") + return True + + +def test_get_glyphs_by_score_range(): + """Test filtering by score range.""" + load_all_supercharged() + + glyphs = get_glyphs_by_score_range(100, 200) + + if len(glyphs) == 0: + print("SKIP: No glyphs in score range 100-200") + return True + + # Verify all are in range and sorted + prev_score = float('inf') + for glyph in glyphs: + score = glyph.get("score", 0) + if not (100 <= score <= 200): + print(f"FAIL: Glyph score {score} out of range") + return False + + if score > prev_score: + print(f"FAIL: Results not sorted descending") + return False + + prev_score = score + + print(f"PASS: Found {len(glyphs)} glyphs in score range [100-200]") + return True + + +def main_test(): + print("[TEST SUITE] test_supercharged_registry.py") + print() + + tests = [ + ("Load all supercharged", test_load_all_supercharged), + ("Get single glyph", test_get_super), + ("Get nonexistent glyph", test_get_super_nonexistent), + ("List all glyph IDs", test_list_super_ids), + ("Search by ID", test_search_super_basic), + ("Case-insensitive search", test_search_super_case_insensitive), + ("Search limit", test_search_super_limit), + ("Statistics reporting", test_super_stats), + ("Get nested field", test_get_super_field), + ("Filter by category", test_list_super_by_category), + ("Filter by band", test_get_super_by_band), + ("Filter by score range", test_get_glyphs_by_score_range), + ] + + passed = 0 + failed = 0 + skipped = 0 + + for name, test_func in tests: + print(f"Running: {name}...", end=" ") + try: + result = test_func() + if result is True: + passed += 1 + elif result is None: + skipped += 1 + print("SKIP") + continue + else: + failed += 1 + except Exception as e: + print(f"FAIL: {e}") + failed += 1 + + print() + print(f"Results: {passed} passed, {failed} failed, {skipped} skipped") + + return 0 if failed == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main_test())