Code / tools/publish.py
tools/publish.py
90 lines
#!/usr/bin/env python3
# =============================================================================
# Project : modelmap
# File : tools/publish.py
# Purpose : Export validated atlas entries to site/data — refuses incomplete
# Author : Simon-Pierre Boucher
# Contact : contact@spboucher.ai
# Website : https://modelmap.io
# Created : 2026-08-12
# Modified : 2026-08-12
# Platform : macOS / Apple Silicon (arm64)
# License : All rights reserved (research code)
# =============================================================================
"""Publish gate for the atlas (charter §14 hard constraints).
Walks atlas/<model>/<type>/<version>/, validates each entry's mapcard.json
(schema v0) plus the presence of provenance.json and confidence.md, and exports
valid entries to site/data/atlas-index.json. Any violation blocks that entry
and is reported; nothing incomplete ever reaches modelmap.io.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from modelmap.atlas.mapcard import MapCard
def entries():
atlas = ROOT / "atlas"
for model in sorted(p for p in atlas.iterdir() if p.is_dir()):
for map_type in sorted(p for p in model.iterdir() if p.is_dir()):
yield from sorted(p for p in map_type.iterdir() if p.is_dir())
def main() -> int:
exported, blocked = [], []
for entry in entries():
rel = entry.relative_to(ROOT)
problems = []
for required in ("provenance.json", "confidence.md", "mapcard.json"):
if not (entry / required).exists():
problems.append(f"missing {required}")
card = None
if not problems:
try:
card = MapCard.load(entry / "mapcard.json")
problems += card.validate()
except (json.JSONDecodeError, TypeError) as e:
problems.append(f"mapcard.json unreadable: {e}")
if problems:
blocked.append((str(rel), problems))
else:
exported.append({
"path": str(rel),
"map_id": card.map_id,
"map_type": card.map_type,
"model_id": card.model_id,
"quantization": card.quantization,
"confidence_level": card.confidence_level,
"replication_rate": card.replication_rate,
"negative_result": card.negative_result,
"created": card.created,
})
out = ROOT / "site" / "data"
out.mkdir(parents=True, exist_ok=True)
(out / "atlas-index.json").write_text(json.dumps({
"author": "Simon-Pierre Boucher",
"contact": "contact@spboucher.ai",
"website": "https://modelmap.io",
"entries": exported,
}, indent=2) + "\n")
print(f"publish: {len(exported)} entry(ies) exported to site/data/atlas-index.json")
for rel, problems in blocked:
print(f"BLOCKED {rel}:")
for p in problems:
print(f" - {p}")
return 1 if blocked else 0
if __name__ == "__main__":
sys.exit(main())