fix(simulation): resolve corp_presence location granularity bug (#805)
import_corp_presence() was inserting system IDs with location_type='system', violating the schema which expects body/station IDs (location_type='body'|'station'). Fix: - import_economics.py: add _resolve_hq_location() that picks the most-populated body in the HQ system (falling back to any body, then any station) - econ-sim/db.rs: load_corp_presences() now JOINs bodies/stations to recover system_id from body/station location_ids, dropping the 'system' filter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -282,12 +282,18 @@ fn load_gate_links(conn: &Connection) -> Vec<GateLink> {
|
||||
}
|
||||
|
||||
fn load_corp_presences(conn: &Connection) -> Vec<CorpPresence> {
|
||||
// Resolve body/station location_id back to system_id via LEFT JOINs.
|
||||
// corp_presence.location_type is 'body' | 'station' per schema.
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT corp_id, location_id, primary_operation
|
||||
FROM corp_presence
|
||||
WHERE location_type = 'system'
|
||||
ORDER BY location_id, corp_id",
|
||||
"SELECT cp.corp_id,
|
||||
COALESCE(b.system_id, s.system_id) AS system_id,
|
||||
cp.primary_operation
|
||||
FROM corp_presence cp
|
||||
LEFT JOIN bodies b ON cp.location_type = 'body' AND cp.location_id = b.body_id
|
||||
LEFT JOIN stations s ON cp.location_type = 'station' AND cp.location_id = s.station_id
|
||||
WHERE COALESCE(b.system_id, s.system_id) IS NOT NULL
|
||||
ORDER BY system_id, cp.corp_id",
|
||||
)
|
||||
.expect("prepare corp_presence");
|
||||
|
||||
|
||||
@@ -418,6 +418,54 @@ def sync_corporations(
|
||||
# Corp presence population
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _resolve_hq_location(
|
||||
conn: sqlite3.Connection,
|
||||
system_id: str,
|
||||
headquarters_body: str | None,
|
||||
) -> tuple[str, str] | None:
|
||||
"""Resolve a corp's HQ to a (location_id, location_type) pair.
|
||||
|
||||
Resolution order:
|
||||
1. Use headquarters_body from corporations table if set (body or station).
|
||||
2. Most-populated body in the system.
|
||||
3. Any body in the system.
|
||||
4. Any station in the system.
|
||||
Returns None if no body or station found.
|
||||
"""
|
||||
if headquarters_body:
|
||||
# Determine whether it's a body or station
|
||||
body = conn.execute(
|
||||
"SELECT body_id FROM bodies WHERE body_id = ?", (headquarters_body,)
|
||||
).fetchone()
|
||||
if body:
|
||||
return (headquarters_body, "body")
|
||||
station = conn.execute(
|
||||
"SELECT station_id FROM stations WHERE station_id = ?",
|
||||
(headquarters_body,),
|
||||
).fetchone()
|
||||
if station:
|
||||
return (headquarters_body, "station")
|
||||
|
||||
# Most-populated body
|
||||
body = conn.execute(
|
||||
"""SELECT body_id FROM bodies WHERE system_id = ?
|
||||
ORDER BY population DESC LIMIT 1""",
|
||||
(system_id,),
|
||||
).fetchone()
|
||||
if body:
|
||||
return (body[0], "body")
|
||||
|
||||
# Any station
|
||||
station = conn.execute(
|
||||
"SELECT station_id FROM stations WHERE system_id = ? LIMIT 1",
|
||||
(system_id,),
|
||||
).fetchone()
|
||||
if station:
|
||||
return (station[0], "station")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def import_corp_presence(
|
||||
conn: sqlite3.Connection,
|
||||
wiki_corps: list[dict],
|
||||
@@ -426,14 +474,22 @@ def import_corp_presence(
|
||||
) -> int:
|
||||
"""Populate corp_presence from wiki headquarters data.
|
||||
|
||||
Each corporation gets one presence row at its headquarters system.
|
||||
primary_operation is set to the first commodity tag that matches a known
|
||||
commodity ID, or None if no commodity tags are present.
|
||||
Each corporation gets one presence row at its headquarters body or station.
|
||||
location_type is 'body' or 'station' per schema (D-182).
|
||||
primary_operation is set to the first commodity tag matching a known commodity ID.
|
||||
"""
|
||||
valid_systems = {
|
||||
r[0] for r in conn.execute("SELECT system_id FROM star_systems").fetchall()
|
||||
}
|
||||
|
||||
# Load headquarters_body from corporations table (set during import)
|
||||
hq_body_map: dict[str, str | None] = {
|
||||
r[0]: r[1]
|
||||
for r in conn.execute(
|
||||
"SELECT corp_id, headquarters_body FROM corporations"
|
||||
).fetchall()
|
||||
}
|
||||
|
||||
rows = []
|
||||
skipped = []
|
||||
for corp in wiki_corps:
|
||||
@@ -444,10 +500,20 @@ def import_corp_presence(
|
||||
if system_id not in valid_systems:
|
||||
skipped.append(f"{corp['corp_id']} (system '{system_id}' not in DB)")
|
||||
continue
|
||||
|
||||
hq_body = hq_body_map.get(corp["corp_id"])
|
||||
location = _resolve_hq_location(conn, system_id, hq_body)
|
||||
if not location:
|
||||
skipped.append(
|
||||
f"{corp['corp_id']} (no body/station found in system '{system_id}')"
|
||||
)
|
||||
continue
|
||||
|
||||
location_id, location_type = location
|
||||
primary_op = next(
|
||||
(tag for tag in corp.get("tags", []) if tag in commodity_ids), None
|
||||
)
|
||||
rows.append((corp["corp_id"], system_id, "system", primary_op))
|
||||
rows.append((corp["corp_id"], location_id, location_type, primary_op))
|
||||
|
||||
if skipped:
|
||||
for s in skipped:
|
||||
|
||||
Reference in New Issue
Block a user