teleo-codex/ops/fix-map-links.py
m3taversal 1fef01b163 fix: prefix 543 broken wiki-links with maps/ directory
13 map file targets were linked as bare names ([[livingip overview]])
but files live at maps/. Script walks all claim files outside maps/
and prefixes with maps/ path. 351 files modified, zero remaining
bare instances, zero double-prefixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 14:54:41 +01:00

125 lines
4.3 KiB
Python

#!/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")