data(atlas): update systems.db + add atlas tooling scripts
systems.db: 43 North Reach body catalogs (hops 4-12) tooling: atlas-verify, atlas-names, atlas-systems-done, atlas-helpers.sh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Executable
+146
@@ -0,0 +1,146 @@
|
||||
#!/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')
|
||||
"
|
||||
}
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# List all existing proper names in the atlas DB (for collision avoidance)
|
||||
cd "$(dirname "$0")/.."
|
||||
{
|
||||
tooling/atlas list-bodies 2>/dev/null | python3 -c "
|
||||
import sys,json
|
||||
for b in json.load(sys.stdin):
|
||||
if b.get('proper_name'): print(b['proper_name'])
|
||||
"
|
||||
tooling/atlas list-stations 2>/dev/null | python3 -c "
|
||||
import sys,json
|
||||
for s in json.load(sys.stdin):
|
||||
if s.get('proper_name'): print(s['proper_name'])
|
||||
"
|
||||
} | sort -u
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
# List systems that already have bodies in the atlas DB
|
||||
cd "$(dirname "$0")/.."
|
||||
tooling/atlas list-bodies 2>/dev/null | python3 -c "
|
||||
import sys,json
|
||||
for s in sorted(set(b['system_id'] for b in json.load(sys.stdin))): print(s)
|
||||
"
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/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')
|
||||
"
|
||||
Reference in New Issue
Block a user