#!/bin/bash # Verify a proposal JSON against integrity checks # Usage: tooling/atlas-verify docs/atlas/proposals/GJ273.json cd "$(dirname "$0")/.." python3 -c " import json, sys with open('$1') as f: p = json.load(f) errors = [] bodies = p.get('bodies', []) stations = p.get('stations', []) # 1. Inhabited bodies must have names for b in bodies: if b.get('inhabited') and not b.get('proper_name'): errors.append(f\"Inhabited body {b['body_id']} has no proper_name\") # 2. Uninhabited bodies should have null names for b in bodies: if not b.get('inhabited') and b.get('proper_name'): errors.append(f\"Uninhabited body {b['body_id']} has proper_name '{b['proper_name']}' (should be null)\") # 3. All stations must have names for s in stations: if not s.get('proper_name'): errors.append(f\"Station {s['station_id']} has no proper_name\") # 4. Body count check planets = [b for b in bodies if b['body_type'] == 'planet'] star_type = p.get('spectral_class', 'M') if star_type.startswith(('G', 'F')): min_planets = 8 elif star_type.startswith('K'): min_planets = 7 else: min_planets = 6 if len(planets) < min_planets: errors.append(f\"Only {len(planets)} planets, need {min_planets}+ for {star_type} star\") # 5. Required structures oort = [b for b in bodies if b['body_type'] == 'oort_cloud'] if not oort: errors.append('No oort cloud') horizon = [s for s in stations if s['station_type'] == 'horizon'] if not horizon: errors.append('No horizon station') elif not any(s.get('has_gate_infrastructure') for s in horizon): errors.append('Horizon station missing has_gate_infrastructure: true') belts = [b for b in bodies if b['body_type'] == 'asteroid_belt'] if not belts: errors.append('No asteroid belt') # 6. Orbit consistency top_level = [b for b in bodies if not b.get('parent_body_id')] orbits = [b['orbit_index'] for b in top_level] if orbits != sorted(orbits): errors.append(f\"Top-level orbit_index not monotonic: {orbits}\") if len(orbits) != len(set(orbits)): errors.append(f\"Duplicate orbit_index in top-level: {orbits}\") # 7. Moon orbit consistency parents = {} for b in bodies: pid = b.get('parent_body_id') if pid: parents.setdefault(pid, []).append(b['orbit_index']) for pid, idxs in parents.items(): if idxs != sorted(idxs): errors.append(f\"Moon orbits under {pid} not monotonic: {idxs}\") if len(idxs) != len(set(idxs)): errors.append(f\"Duplicate moon orbit_index under {pid}: {idxs}\") # 8. Parent references valid body_ids = set(b['body_id'] for b in bodies) for b in bodies: pid = b.get('parent_body_id') if pid and pid not in body_ids: errors.append(f\"Body {b['body_id']} references missing parent {pid}\") for s in stations: oid = s.get('orbits_body_id') if oid and oid not in body_ids: errors.append(f\"Station {s['station_id']} references missing body {oid}\") if errors: print('FAIL') for e in errors: print(f' - {e}') sys.exit(1) else: print('PASS') "