#!/bin/bash # Atlas helper functions for batch body catalog authoring # Usage: source tooling/atlas-helpers.sh ATLAS="tooling/atlas" # Get all existing proper names (for collision avoidance) atlas_existing_names() { { $ATLAS list-bodies 2>/dev/null | python3 -c " import sys,json d=json.load(sys.stdin) for b in d: if b.get('proper_name'): print(b['proper_name']) " $ATLAS list-stations 2>/dev/null | python3 -c " import sys,json d=json.load(sys.stdin) for s in d: if s.get('proper_name'): print(s['proper_name']) " } | sort -u } # List systems that already have bodies atlas_systems_with_bodies() { $ATLAS list-bodies 2>/dev/null | python3 -c " import sys,json d=json.load(sys.stdin) for s in sorted(set(b['system_id'] for b in d)): print(s) " } # Check if a system already has bodies atlas_system_has_bodies() { local sys_id="$1" $ATLAS list-bodies --system "$sys_id" 2>/dev/null | python3 -c " import sys,json d=json.load(sys.stdin) print('yes' if len(d) > 0 else 'no') " } # Show system info atlas_show() { $ATLAS show-system "$1" 2>/dev/null } # Author system (generate base proposal) atlas_author() { $ATLAS author "$1" 2>/dev/null } # Verify a proposal JSON against integrity checks atlas_verify_proposal() { local proposal="$1" python3 -c " import json, sys with open('$proposal') 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 only, excluding moons/belts/oort) 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 (add one unless wiki contradicts)') # 6. Orbit consistency for top-level bodies 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 — all integrity checks passed') " }