#!/usr/bin/env python3 """Fix broken wiki-links to map files by adding maps/ prefix. These links appear in Topics: sections of claim files. The target files exist in maps/ but the links use bare names without the path prefix. """ import os import re CODEX_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Map files that exist — link text (inside [[]]) → correct path prefix MAP_TARGETS = [ "livingip overview", "LivingIP architecture", "internet finance and decision markets", "attractor dynamics", "coordination mechanisms", "competitive advantage and moats", "collective agents", "living capital", "overview", "blockchain infrastructure and coordination", "analytical-toolkit", "metadao-decision-markets", "rio positions", ] # Verify all targets actually exist as map files for target in MAP_TARGETS: path = os.path.join(CODEX_ROOT, "maps", f"{target}.md") if not os.path.isfile(path): print(f"WARNING: maps/{target}.md does not exist — skipping") MAP_TARGETS.remove(target) # Build regex: match [[target]] but NOT [[maps/target]] (already fixed) # Case-insensitive for safety patterns = [] for target in MAP_TARGETS: escaped = re.escape(target) # Match [[target]] but not [[maps/target]] or [[anything/target]] pattern = re.compile( r'\[\[(' + escaped + r')\]\]', re.IGNORECASE ) patterns.append((target, pattern)) total_fixes = 0 files_fixed = 0 for dirpath, dirnames, filenames in os.walk(CODEX_ROOT): # Skip .git and ops directories rel = os.path.relpath(dirpath, CODEX_ROOT) if rel.startswith('.git') or rel.startswith('ops'): continue for fname in filenames: if not fname.endswith('.md'): continue filepath = os.path.join(dirpath, fname) try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() except (UnicodeDecodeError, OSError): continue original = content file_fixes = 0 for target, pattern in patterns: # Don't fix links that are already prefixed with maps/ # First check: does the file contain [[maps/target]]? Skip those. already_prefixed = re.compile( r'\[\[maps/' + re.escape(target) + r'\]\]', re.IGNORECASE ) def replace_bare_link(m): # Check if this is inside the maps/ directory itself # Map files can reference each other without prefix if os.path.relpath(filepath, CODEX_ROOT).startswith('maps/'): return m.group(0) # Don't touch links inside maps/ return f'[[maps/{m.group(1)}]]' content = pattern.sub(replace_bare_link, content) fixes_this_target = len(pattern.findall(original)) - len(pattern.findall(content)) if content != original: file_fixes = sum( len(p.findall(original)) - len(p.findall(content)) for _, p in patterns ) # Recount properly file_fixes = 0 for line_orig, line_new in zip(original.splitlines(), content.splitlines()): if line_orig != line_new: file_fixes += 1 with open(filepath, 'w', encoding='utf-8') as f: f.write(content) files_fixed += 1 total_fixes += file_fixes print(f"\nFixed {total_fixes} links across {files_fixed} files") # Show per-target counts print("\nPer-target breakdown:") for target in MAP_TARGETS: pattern = re.compile(r'\[\[maps/' + re.escape(target) + r'\]\]', re.IGNORECASE) count = 0 for dirpath, _, filenames in os.walk(CODEX_ROOT): rel = os.path.relpath(dirpath, CODEX_ROOT) if rel.startswith('.git') or rel.startswith('ops') or rel.startswith('maps'): continue for fname in filenames: if not fname.endswith('.md'): continue try: with open(os.path.join(dirpath, fname), 'r', encoding='utf-8') as f: count += len(pattern.findall(f.read())) except (UnicodeDecodeError, OSError): continue print(f" [[maps/{target}]]: {count} instances")