feat(simulation): add corporate behavioral archetypes — Layer 3 (#809)

Implements the 6 behavioral archetypes from D-175 (Burnelli-Sheldon):

  Producer     — 1.15× production scale, neutral price signal
  Distributor  — 0.9× production, −3% price discount to move volume
  Specialist   — 1.0× production, +10% price premium for expertise
  Monopolist   — 0.8× production, withholds 25% of output, +20% premium
  Cooperative  — 1.0× production, −5% community discount
  Intermediary — 0.7× production, relies on traded goods

Archetype loading:
- Reads from corporations.behavioral_archetype (currently NULL for all corps)
- Falls back to heuristic inference from specialization text (freight → Distributor,
  extraction → Producer, luxury goods → Specialist, etc.)
- 48 corps loaded on current DB, all inferred (DB column to be populated when
  wiki corp frontmatter is extended with the behavioral_archetype field)

Applied in model.rs step():
- Per-corp effective_capacity = BASELINE_CAPACITY × production_scale
- Monopolist supply_withheld fraction reduces net output to stockpile
- Price premium: small ALPHA-scaled nudge to node price for primary commodity

All D-179 stability checks still pass with archetypes active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 22:27:00 +02:00
co-authored by Claude Sonnet 4.6
parent 26716bfc56
commit b19bfb3239
4 changed files with 224 additions and 10 deletions
+20
View File
@@ -91,6 +91,8 @@ pub struct Economy {
pub presences_by_system: HashMap<String, Vec<CorpPresence>>,
/// Bidirectional gate links (transport graph)
pub gate_links: Vec<GateLink>,
/// Raw corp data for archetype inference: (corp_id, behavioral_archetype?, specialization?)
pub corp_archetype_data: Vec<(String, Option<String>, Option<String>)>,
}
// ---------------------------------------------------------------------------
@@ -244,6 +246,22 @@ fn load_systems(conn: &Connection) -> HashMap<String, SystemInfo> {
.collect()
}
fn load_corp_archetype_data(
conn: &Connection,
) -> Vec<(String, Option<String>, Option<String>)> {
let mut stmt = conn
.prepare(
"SELECT corp_id, behavioral_archetype, specialization
FROM corporations ORDER BY corp_id",
)
.expect("prepare corp archetype data");
stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))
.expect("query corp archetype data")
.filter_map(|r| r.ok())
.collect()
}
fn load_gate_links(conn: &Connection) -> Vec<GateLink> {
let mut stmt = conn
.prepare(
@@ -315,6 +333,7 @@ pub fn load_economy(conn: &Connection) -> Economy {
}
let gate_links = load_gate_links(conn);
let corp_archetype_data = load_corp_archetype_data(conn);
Economy {
commodities,
@@ -325,5 +344,6 @@ pub fn load_economy(conn: &Connection) -> Economy {
corp_presences,
presences_by_system,
gate_links,
corp_archetype_data,
}
}