- generate_corp_stubs.py: add argparse with --dry-run (prints planned stub creations without writing files) and --help - calloway-distillery.md: cross_refs → [thrds, mercado-travessia] - thrds.md: cross_refs → [calloway-distillery, mercado-travessia] - vins-de-grand-vide.md: cross_refs → [nordmark-skog] - thalassa-resort-group.md: cross_refs → [the-registry, prometheus-labs] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
414 lines
16 KiB
Python
414 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate minimal wiki stub pages for corps in brands.toml that don't yet have wiki pages.
|
|
|
|
Usage:
|
|
python3 tooling/generate_corp_stubs.py [--dry-run]
|
|
|
|
In --dry-run mode, prints which stubs would be created without writing any files.
|
|
"""
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).parent.parent
|
|
BRANDS_TOML = REPO / "wiki/economics/corporations/brands.toml"
|
|
CORPS_DIR = REPO / "wiki/corporations"
|
|
|
|
# Star system ID -> (proper_name, corridor)
|
|
SYSTEMS = {
|
|
"GJ 0": ("Sol", "sol-gateway-axis"),
|
|
"GJ 1": ("Grünfeld", "west_reach"),
|
|
"GJ 1002": ("Caparica", "south_reach"),
|
|
"GJ 1005A": ("Port Desrochers", "east_reach"),
|
|
"GJ 103": ("Bestevaer", "west_reach"),
|
|
"GJ 105A": ("Nová Tržnice", "east_reach"),
|
|
"GJ 1061": ("Crux Station", "south_reach"),
|
|
"GJ 1075": ("Espinho", "south_reach"),
|
|
"GJ 1073": ("Mabuhay", "east_reach"),
|
|
"GJ 107A": ("Tình Yên", "east_reach"),
|
|
"GJ 1111": ("Zenzele", "south_reach"),
|
|
"GJ 1116A": ("Mabaso Junction", "north_reach"),
|
|
"GJ 1116B": ("Kraków Junction", "west_reach"),
|
|
"GJ 1125": ("Hwaseong", "east_reach"),
|
|
"GJ 1128": ("Devereux Point", "east_reach"),
|
|
"GJ 1156": ("Travessia", "south_reach"),
|
|
"GJ 1230A": ("Uusi Vantaa", "north_reach"),
|
|
"GJ 1232": ("Gammelstad", "west_reach"),
|
|
"GJ 1235": ("Knotenpunkt", "deep_frontier"),
|
|
"GJ 124": ("Hạ Long", "east_reach"),
|
|
"GJ 1245A": ("Okoro's Claim", "north_reach"),
|
|
"GJ 1245B": ("Koeberg", "south_reach"),
|
|
"GJ 1248": ("Haltefenn", "west_reach"),
|
|
"GJ 127A": ("Dalim", "deep_frontier"),
|
|
"GJ 127B": ("Echternach", "west_reach"),
|
|
"GJ 1286": ("Kensho", "core"),
|
|
"GJ 1289": ("Athabasca", "north_reach"),
|
|
"GJ 1292": ("Moyale", "north_reach"),
|
|
"GJ 136": ("Dài Lộ", "east_reach"),
|
|
"GJ 137": ("Novaya Zarya", "east_reach"),
|
|
"GJ 138": ("Sertão", "deep_frontier"),
|
|
"GJ 139": ("Okafor Station", "north_reach"),
|
|
"GJ 142": ("Leuchtturm", "deep_frontier"),
|
|
"GJ 144": ("Ran", "core"),
|
|
"GJ 15A": ("Lu Ban", "core"),
|
|
"GJ 166A": ("Keid", "core"),
|
|
"GJ 172": ("Kaelong", "east_reach"),
|
|
"GJ 17": ("Binh Trang", "east_reach"),
|
|
"GJ 178": ("Ashfield", "north_reach"),
|
|
"GJ 183": ("Waterkant", "north_reach"),
|
|
"GJ 19": ("Solheim", "west_reach"),
|
|
"GJ 191": ("Kapteyn's Star", "west_reach"),
|
|
"GJ 194B": ("Pemberton", "north_reach"),
|
|
"GJ 197": ("Puerto Último", "south_reach"),
|
|
"GJ 201": ("GJ 201", "deep_frontier"),
|
|
"GJ 204": ("Pedra Funda", "deep_frontier"),
|
|
"GJ 205": ("Kurashiki", "east_reach"),
|
|
"GJ 208": ("Pereira's Rest", "west_reach"),
|
|
"GJ 2097": ("Nascente", "south_reach"),
|
|
"GJ 211": ("Encruzilhada", "deep_frontier"),
|
|
"GJ 213": ("Kaapse Baai", "south_reach"),
|
|
"GJ 216A": ("Kelburn Crossing", "north_reach"),
|
|
"GJ 216B": ("Gemini Point", "north_reach"),
|
|
"GJ 222A": ("Karoo", "south_reach"),
|
|
"GJ 229": ("Port Mäkelä", "west_reach"),
|
|
"GJ 231": ("Thorvaldsen's Circuit", "west_reach"),
|
|
"GJ 234A": ("Carvalhais", "south_reach"),
|
|
"GJ 244A": ("Sirius", "core"),
|
|
"GJ 250A": ("Carrington's Post", "north_reach"),
|
|
"GJ 251": ("Renaissance", "core"),
|
|
"GJ 268": ("Yeongwol", "east_reach"),
|
|
"GJ 27": ("Okahandja", "south_reach"),
|
|
"GJ 273": ("Fremantle", "north_reach"),
|
|
"GJ 280A": ("Parallax", "core"),
|
|
"GJ 282A": ("Bout du Chemin", "west_reach"),
|
|
"GJ 285": ("Fenwick's Lantern", "north_reach"),
|
|
"GJ 286": ("Weitblick", "deep_frontier"),
|
|
"GJ 299": ("Várzea", "south_reach"),
|
|
"GJ 300": ("Dunmore Stillwater", "north_reach"),
|
|
"GJ 302": ("Lichtbrücke", "west_reach"),
|
|
"GJ 309": ("Vorposten", "deep_frontier"),
|
|
"GJ 3135": ("Whitfield Crossing", "east_reach"),
|
|
"GJ 320": ("Sonnwend", "west_reach"),
|
|
"GJ 3250": ("Rionegro", "south_reach"),
|
|
"GJ 325A": ("Purnima", "east_reach"),
|
|
"GJ 33": ("96 Piscium", "south_reach"),
|
|
"GJ 3323": ("Entroncamento", "south_reach"),
|
|
"GJ 3325": ("Calloway Reach", "north_reach"),
|
|
"GJ 3333": ("Groenland", "west_reach"),
|
|
"GJ 3379": ("Shenwei", "east_reach"),
|
|
"GJ 338B": ("Arbour", "core"),
|
|
"GJ 3454": ("Eisentor", "west_reach"),
|
|
"GJ 349": ("Randgebiet", "deep_frontier"),
|
|
"GJ 34A": ("Tanegashima", "north_reach"),
|
|
"GJ 34B": ("Yongjin", "east_reach"),
|
|
"GJ 35": ("Vuurkloof", "south_reach"),
|
|
"GJ 3522": ("Sindri", "core"),
|
|
"GJ 3533": ("Trung's Crossing", "east_reach"),
|
|
"GJ 3586": ("Eisfeld", "west_reach"),
|
|
"GJ 3612": ("Xa Vời", "east_reach"),
|
|
"GJ 3618": ("Pemberton's Loop", "north_reach"),
|
|
"GJ 3622": ("Havnfjord", "north_reach"),
|
|
"GJ 370": ("Traagwater", "west_reach"),
|
|
"GJ 3728B": ("Jeonnam", "east_reach"),
|
|
"GJ 3737": ("Nyrheim", "west_reach"),
|
|
"GJ 380": ("Groombridge", "core"),
|
|
"GJ 3820": ("Uusi Vantaa", "north_reach"),
|
|
"GJ 3877": ("Tessera", "core"),
|
|
"GJ 388": ("The Lantern", "south_reach"),
|
|
"GJ 393": ("Encrucijada", "south_reach"),
|
|
"GJ 395": ("Confluent", "west_reach"),
|
|
"GJ 3991": ("Dunbar", "north_reach"),
|
|
"GJ 402": ("Prospect Hill", "north_reach"),
|
|
"GJ 4053": ("Dzimbahwe", "south_reach"),
|
|
"GJ 406": ("Wolf 359", "north_reach"),
|
|
"GJ 408": ("Oude Kraal", "north_reach"),
|
|
"GJ 410": ("Wagtoring", "north_reach"),
|
|
"GJ 411": ("Lalande", "south_reach"),
|
|
"GJ 412A": ("Morales' End", "south_reach"),
|
|
"GJ 412B": ("Korhonen", "east_reach"),
|
|
"GJ 414A": ("Vindkast", "west_reach"),
|
|
"GJ 42": ("Langemark", "west_reach"),
|
|
"GJ 423A": ("Marunong", "east_reach"),
|
|
"GJ 423B": ("Quilombo", "south_reach"),
|
|
"GJ 4274": ("Suzhou", "east_reach"),
|
|
"GJ 4285": ("Lam's Prospect", "east_reach"),
|
|
"GJ 432A": ("Kaur's Observatory", "east_reach"),
|
|
"GJ 435": ("Mirante", "south_reach"),
|
|
"GJ 438": ("Relay 7", "east_reach"),
|
|
"GJ 442A": ("Torsby", "west_reach"),
|
|
"GJ 445": ("Jinghu", "east_reach"),
|
|
"GJ 447": ("Ross 128", "core"),
|
|
"GJ 449": ("Murakami's Lantern", "east_reach"),
|
|
"GJ 451A": ("Groombridge 1830", "south_reach"),
|
|
"GJ 453": ("Freiholt", "west_reach"),
|
|
"GJ 454": ("Steinfeld", "west_reach"),
|
|
"GJ 473A": ("Passagem", "south_reach"),
|
|
"GJ 473B": ("Nkosi's Bridge", "north_reach"),
|
|
"GJ 475": ("Braemar", "north_reach"),
|
|
"GJ 482A": ("Dagat", "east_reach"),
|
|
"GJ 49": ("Dernier Quai", "east_reach"),
|
|
"GJ 4A": ("Velha Guarda", "south_reach"),
|
|
"GJ 501B": ("Candeia", "deep_frontier"),
|
|
"GJ 502": ("Meridian", "west_reach"),
|
|
"GJ 505A": ("Bergtor", "west_reach"),
|
|
"GJ 506": ("Dokkum", "west_reach"),
|
|
"GJ 508A": ("Stilwater", "north_reach"),
|
|
"GJ 526": ("Neustadt", "west_reach"),
|
|
"GJ 529": ("Yttermark", "west_reach"),
|
|
"GJ 532": ("Kettenschmied", "deep_frontier"),
|
|
"GJ 534": ("Stillvakt", "west_reach"),
|
|
"GJ 536": ("Retiro", "south_reach"),
|
|
"GJ 53A": ("Bridgepoint", "east_reach"),
|
|
"GJ 54": ("Inhambane", "south_reach"),
|
|
"GJ 54.1": ("Ribeiro's Star", "south_reach"),
|
|
"GJ 541": ("Chandra Deep", "east_reach"),
|
|
"GJ 542": ("Kopparhytta", "west_reach"),
|
|
"GJ 546": ("Eerste Wacht", "deep_frontier"),
|
|
"GJ 551": ("Proxima", "core"),
|
|
"GJ 555": ("Tanaka Station", "east_reach"),
|
|
"GJ 556": ("Recanto", "deep_frontier"),
|
|
"GJ 559B": ("ACB", "core"),
|
|
"GJ 566A": ("Haodu", "east_reach"),
|
|
"GJ 566B": ("Confluência", "south_reach"),
|
|
"GJ 567": ("Fragua", "south_reach"),
|
|
"GJ 570A": ("Bastion", "core"),
|
|
"GJ 575A": ("Ratnagiri", "north_reach"),
|
|
"GJ 581": ("Rødvik", "west_reach"),
|
|
"GJ 588": ("Harrowfield", "north_reach"),
|
|
"GJ 598": ("Helle Wacht", "deep_frontier"),
|
|
"GJ 601A": ("Ostmark", "west_reach"),
|
|
"GJ 603": ("Mossbank", "north_reach"),
|
|
"GJ 615": ("Dunkelholz", "west_reach"),
|
|
"GJ 624": ("Halvøy", "west_reach"),
|
|
"GJ 625": ("Songjiang", "east_reach"),
|
|
"GJ 628": ("Brennan's Drift", "west_reach"),
|
|
"GJ 631": ("Bakshi Spur", "west_reach"),
|
|
"GJ 635A": ("Stilmark", "west_reach"),
|
|
"GJ 635B": ("Clearwater Station", "east_reach"),
|
|
"GJ 638": ("Greymantle", "north_reach"),
|
|
"GJ 643": ("Marktfeld", "west_reach"),
|
|
"GJ 644A": ("Mavela", "south_reach"),
|
|
"GJ 644C": ("Moçâmedes", "south_reach"),
|
|
"GJ 653": ("Dunmore", "north_reach"),
|
|
"GJ 660A": ("Seongho", "east_reach"),
|
|
"GJ 661A": ("Crown's Hollow", "north_reach"),
|
|
"GJ 661B": ("Breëvlei", "north_reach"),
|
|
"GJ 663A": ("Johannsen's Star", "north_reach"),
|
|
"GJ 664": ("Caldwell Point", "west_reach"),
|
|
"GJ 667A": ("New Ballarat", "north_reach"),
|
|
"GJ 667B": ("Kampala Gate", "north_reach"),
|
|
"GJ 667C": ("Gliese 667", "east_reach"),
|
|
"GJ 66A": ("p Eridani", "east_reach"),
|
|
"GJ 66B": ("Voss", "west_reach"),
|
|
"GJ 67": ("Roça Nova", "south_reach"),
|
|
"GJ 672": ("Nova Estrada", "deep_frontier"),
|
|
"GJ 673": ("Lindström Station", "north_reach"),
|
|
"GJ 674": ("Meridian", "core"),
|
|
"GJ 675": ("Neugrund", "deep_frontier"),
|
|
"GJ 680": ("Carnarvon", "north_reach"),
|
|
"GJ 682": ("Taishan", "east_reach"),
|
|
"GJ 684A": ("Sonnenkap", "deep_frontier"),
|
|
"GJ 684B": ("Paso Largo", "deep_frontier"),
|
|
"GJ 687": ("Matsue", "east_reach"),
|
|
"GJ 688": ("Aguas Bravas", "south_reach"),
|
|
"GJ 693": ("Mwangaza", "south_reach"),
|
|
"GJ 699": ("Barnard's Star", "core"),
|
|
"GJ 702B": ("Prometheus", "core"),
|
|
"GJ 706": ("Ngata's Star", "north_reach"),
|
|
"GJ 716": ("Murchison", "north_reach"),
|
|
"GJ 71": ("Tau Ceti", "core"),
|
|
"GJ 713A": ("Samuels Reach", "east_reach"),
|
|
"GJ 722": ("Skuilplek", "deep_frontier"),
|
|
"GJ 725B": ("Struve", "core"),
|
|
"GJ 729": ("Ross 154", "west_reach"),
|
|
"GJ 737B": ("Punta del Sol", "south_reach"),
|
|
"GJ 75": ("Enugu", "north_reach"),
|
|
"GJ 752A": ("Ribeirão", "south_reach"),
|
|
"GJ 754": ("Miryang", "east_reach"),
|
|
"GJ 764": ("Nova Roma", "core"),
|
|
"GJ 768": ("Altair", "south_reach"),
|
|
"GJ 770": ("Rekohu", "north_reach"),
|
|
"GJ 771A": ("Alshain", "west_reach"),
|
|
"GJ 775": ("Randsholm", "west_reach"),
|
|
"GJ 780": ("Puerto Rivera", "north_reach"),
|
|
"GJ 783A": ("Aurelius", "core"),
|
|
"GJ 784": ("Kovács Loop", "east_reach"),
|
|
"GJ 785": ("Porto Fechado", "south_reach"),
|
|
"GJ 79": ("Oshima", "east_reach"),
|
|
"GJ 798": ("Brückenau", "west_reach"),
|
|
"GJ 807": ("Grenzstein", "west_reach"),
|
|
"GJ 809": ("Seiðrmaðr", "west_reach"),
|
|
"GJ 820B": ("Cygni B", "core"),
|
|
"GJ 825": ("Lacaille", "north_reach"),
|
|
"GJ 827": ("Solandar", "south_reach"),
|
|
"GJ 829": ("Posto Avançado", "south_reach"),
|
|
"GJ 83.1": ("Farol", "south_reach"),
|
|
"GJ 832": ("Hansestadt", "west_reach"),
|
|
"GJ 845": ("Cairn", "north_reach"),
|
|
"GJ 848": ("Shimanami", "east_reach"),
|
|
"GJ 86": ("Kumasi", "south_reach"),
|
|
"GJ 860A": ("Kruger 60", "south_reach"),
|
|
"GJ 860B": ("Changwon", "east_reach"),
|
|
"GJ 866A": ("EZ Aqr", "east_reach"),
|
|
"GJ 873": ("Ashworth Junction", "north_reach"),
|
|
"GJ 875": ("The Narrows", "deep_frontier"),
|
|
"GJ 876": ("Koskinen's Reach", "north_reach"),
|
|
"GJ 877": ("Holmgren's Passage", "north_reach"),
|
|
"GJ 879": ("Singh's Landing", "north_reach"),
|
|
"GJ 880": ("Holgersen's Landing", "north_reach"),
|
|
"GJ 884": ("Matamba", "south_reach"),
|
|
"GJ 887": ("Lacaille", "core"),
|
|
"GJ 892": ("Cairnside", "deep_frontier"),
|
|
"GJ 896A": ("Nowa Huta", "south_reach"),
|
|
"GJ 905": ("Isibaya", "south_reach"),
|
|
"GJ 908": ("Thornfield Station", "east_reach"),
|
|
"GJ 909A": ("Tam Giang", "east_reach"),
|
|
"GJ 92": ("Pollux", "south_reach"),
|
|
"GJ 95": ("Caledonia's End", "north_reach"),
|
|
}
|
|
|
|
# Brand category -> description template suffix and tags hint
|
|
CATEGORY_META = {
|
|
"terroir": ("regional specialty producer", ["terroir", "scarcity_class_rare"]),
|
|
"heritage_craft": ("heritage craft manufacturer", ["heritage_craft", "artisan"]),
|
|
"tech_premium": ("precision technology manufacturer", ["tech_premium", "electronics"]),
|
|
"cultural": ("cultural content producer", ["cultural", "entertainment"]),
|
|
"service_premium": ("premium service provider", ["service_premium"]),
|
|
"commodity_branded": ("consumer goods manufacturer", ["commodity_branded", "consumer_goods"]),
|
|
"design_heritage": ("design and furniture manufacturer", ["design_heritage", "consumer_goods"]),
|
|
"platform_catalogue": ("media platform and catalogue service", ["platform_catalogue", "entertainment"]),
|
|
}
|
|
|
|
def slug_to_title(slug: str) -> str:
|
|
"""Convert a slug like 'my-corp-name' to 'My Corp Name'."""
|
|
return " ".join(w.capitalize() for w in slug.replace("-", " ").split())
|
|
|
|
def parse_brands_toml(path: Path) -> dict:
|
|
"""Parse brands.toml and return dict of corp_id -> {origin_system, brand_category}."""
|
|
corps = {}
|
|
current_corp = None
|
|
current_system = None
|
|
current_category = None
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line == "[[brand_products]]":
|
|
# Save previous
|
|
if current_corp and current_system:
|
|
if current_corp not in corps:
|
|
corps[current_corp] = {
|
|
"origin_system": current_system,
|
|
"brand_category": current_category,
|
|
}
|
|
current_corp = None
|
|
current_system = None
|
|
current_category = None
|
|
elif line.startswith("corp_id = "):
|
|
current_corp = line.split("=", 1)[1].strip().strip('"')
|
|
elif line.startswith("origin_system = "):
|
|
current_system = line.split("=", 1)[1].strip().strip('"')
|
|
elif line.startswith("brand_category = "):
|
|
current_category = line.split("=", 1)[1].strip().strip('"')
|
|
|
|
# Save last
|
|
if current_corp and current_system:
|
|
if current_corp not in corps:
|
|
corps[current_corp] = {
|
|
"origin_system": current_system,
|
|
"brand_category": current_category,
|
|
}
|
|
|
|
return corps
|
|
|
|
def generate_stub(slug: str, origin_system: str, brand_category: str) -> str:
|
|
title = slug_to_title(slug)
|
|
sys_info = SYSTEMS.get(origin_system, (origin_system, "unknown"))
|
|
sys_name, corridor = sys_info
|
|
|
|
cat_meta = CATEGORY_META.get(brand_category, ("commercial enterprise", []))
|
|
cat_desc, cat_tags = cat_meta
|
|
|
|
corridor_currency = "tractus"
|
|
if corridor in ("west_reach",):
|
|
corridor_currency = "mark"
|
|
elif corridor == "core":
|
|
corridor_currency = "tractus"
|
|
|
|
headquarters = f"{sys_name} ({origin_system})"
|
|
tags_list = [brand_category, corridor, corridor_currency] + cat_tags
|
|
# Deduplicate while preserving order
|
|
seen = set()
|
|
tags = []
|
|
for t in tags_list:
|
|
if t not in seen:
|
|
seen.add(t)
|
|
tags.append(t)
|
|
tags_str = "[" + ", ".join(tags) + "]"
|
|
|
|
description = f"{title} — {cat_desc} based in {sys_name}, {corridor.replace('_', ' ')}"
|
|
|
|
return f"""---
|
|
title: "{title}"
|
|
description: "{description}"
|
|
slug: {slug}
|
|
category: corporation
|
|
status: canonical
|
|
created: 2026-04-19
|
|
updated: 2026-04-19
|
|
scope: regional
|
|
faction_type: economic
|
|
headquarters: {headquarters}
|
|
tags: {tags_str}
|
|
decision_refs: [D-189]
|
|
cross_refs: []
|
|
---
|
|
|
|
# {title}
|
|
|
|
**Type:** Corporation — {cat_desc.title()}
|
|
**Status:** Canonical
|
|
**Scope:** Regional — {corridor.replace('_', ' ')} operations
|
|
**Headquarters:** {headquarters}
|
|
|
|
{title} is a {cat_desc} operating out of {sys_name} ({origin_system}). Details to be expanded.
|
|
"""
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate minimal wiki stub pages for corps in brands.toml."
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Print which stubs would be created without writing any files.",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
corps = parse_brands_toml(BRANDS_TOML)
|
|
print(f"Found {len(corps)} unique corp_ids in brands.toml")
|
|
if args.dry_run:
|
|
print("(dry-run — no files will be written)\n")
|
|
|
|
created = 0
|
|
skipped = 0
|
|
for slug, meta in sorted(corps.items()):
|
|
stub_path = CORPS_DIR / f"{slug}.md"
|
|
if stub_path.exists():
|
|
skipped += 1
|
|
continue
|
|
if args.dry_run:
|
|
print(f" (dry-run) Would create: {slug}.md")
|
|
else:
|
|
content = generate_stub(slug, meta["origin_system"], meta["brand_category"])
|
|
stub_path.write_text(content, encoding="utf-8")
|
|
print(f" created: {slug}.md")
|
|
created += 1
|
|
|
|
action = "Would create" if args.dry_run else "Created"
|
|
print(f"\nDone. {action} {created} stubs, skipped {skipped} existing.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|