Skip to content

Port Ownership

Players and teams can acquire stations to earn passive income, secure supply priority, and shape regional economic flow. Three acquisition paths exist: direct purchase, economic takeover, and military takeover. Ownership turns a station from a neutral fixture into a configurable revenue engine — the owner sets tariffs, services, and defense, and absorbs the consequences when those choices conflict with traffic and reputation.

Status overall: 🚧 Partial. The Station.ownership JSONB field exists in the schema; the tariff lever and economic-takeover engine are implemented on the gameserver, while Information sales remain gated on Market Intelligence 📐 and the upgrade catalog is 📐 Design-only. Player Port Office UI on tip 46bce720 (after #684 / 1e181c92 — LEG-INI-35 / LEG-INI-36 / LEG-366) exposes economic takeover-defense levers, fee-distribution rebalance, and revenue levers (tax / price-lever / docking-fee / service-charge / storage-rental). Military declare/siege/occupy remains 🚧 tip-pending (LEG-368 / #688) — see Military takeover; do not treat GS ✅ or econ UI ✅ as full-stack complete.

Overview

A station, once owned, behaves as a small business with its own treasury, balance sheet, and policy levers:

  • Revenue flows in from tariffs, docking fees, services, storage rental, and information sales.
  • Expenses flow out as maintenance, wages, defense upkeep, and upgrade upkeep.
  • Owners withdraw the surplus on a configurable schedule.
  • Rivals can attempt to wrest control through three competing acquisition paths.

Most stations in core Federation space are not for sale; ownership is concentrated in border, frontier, and lawless regions. See ./trading.md for the underlying station classes and pricing model that the tariff system layers on top of.

Acquisition

Status: 🚧 Partial — schema records ownership; the purchase, economic-takeover, and military-takeover workflows are implemented on the gameserver (port_ownership_service.py declare/siege/occupy); Player Port Office UI for military declare/siege/occupy remains 🚧 tip-pending (LEG-368 / #688 — tip 46bce720); Information sales / upgrade catalog remain 📐; econ revenue + defense + fee-distribution Player UI ✅ after #684.

Purchase ✅ Shipped

Direct buy from the controlling faction. The faction lists the station at a price set by:

Factor Effect on price
Station class Class 0/4/5 not for sale; Class 1–3 cheap; Class 8–11 expensive
Region Frontier discounts, core-adjacent premium
Trailing revenue Higher recent transaction volume → higher ask
Existing upgrades Each upgrade adds its remaining capital value
Treasury balance Transfers to the buyer; included in the headline price

Range: 250,000 – 2,000,000 cr. Faction reputation gate varies by region; "Trusted" or higher with the controlling faction is the typical floor. Purchase is reputation-neutral with the seller (it is a sanctioned transaction) and reputation-positive in small amounts elsewhere (the new owner is a known entity).

A 24-hour grace window applies once the faction approves the buyer; the buyer must complete payment in that window or the listing reopens. Multiple qualified buyers within the same window trigger a sealed-bid auction resolved by the faction at the close of the window.

Listing surfaces in the station's public profile and in faction-bulletin endpoints; no off-market sales.

Economic takeover ✅ Shipped

A slow, reputation-neutral path. The challenger must:

  1. Account for >50% of the station's monthly transaction volume for 3 consecutive months, and
  2. Maintain hostile pricing pressure — undercut the station's spread or run trade contracts that bleed inventory — across the whole window.

When both conditions hold, the controlling faction triggers a forced sale at fair value:

fair_value_base = (90_day_rolling_avg_monthly_revenue) × 12   // 12× monthly = ~1-year payback

A condition multiplier penalises poorly-maintained stations:

condition_multiplier =
    1.0
  − 0.10 × max(0, 7 − days_since_last_defense_incident) / 7
  − 0.15 × (1 if security_level == 'none' else 0)

Recent defense incidents (within 7 days) reduce value by up to 10%; an undefended station incurs a flat 15% haircut. Final price is bounded:

final_value = clamp(
    fair_value_base × condition_multiplier,
    floor = acquisition_cost,           // can't force-sell below the original buy-in
    ceiling = acquisition_cost × 2.0    // no tariff-spike inflation
)

The current owner has 7 days to counter by:

  • Accepting the buyout at final_value, or
  • Matching the challenger's market share for one full month (which resets the 3-month clock to zero), or
  • Lodging a dispute within 3 days (e.g. "challenger is bot-farming volume artificially") that escalates to faction arbitration. Disputes must resolve before day 7 closes; an upheld dispute voids the takeover, a rejected dispute lets the timer run out.

On day 7 with no counter and no upheld dispute, credits equal to final_value transfer from the buyer's wallet to a faction-held escrow; the faction confirms the sale, the prior owner's wallet receives the proceeds (after deducting any outstanding station debts), and ownership flips atomically.

Volume is measured monthly on a rolling basis; any month where the challenger drops below 50% breaks the streak. Coordinated economic takeover by a team is allowed: the team's combined volume counts toward the threshold provided the team has a registered trade pact (filed publicly with the controlling faction).

Military takeover ✅ GS / 🚧 Player UI tip-pending

Status: gameserver ✅ Shipped (declare_military_takeover / siege_military_takeover / occupy_military_takeover; tip route POST /port-ownership/stations/{id}/military with action ∈ {declare,siege,occupy}). Player Port Office UI 🚧 tip-pending (LEG-368 / LEG-395 / #688 — tip portOwnershipAPI / PortOfficeVenue expose listing / tax / withdraw / economic-war-room / econ-defense / fee-distribution / revenue levers after #684; zero /military client on tip 46bce720). Planetary SiegeStatusMonitor is planet-siege only — do not conflate with station military takeover. Do not read GS ✅ as Port Office already exposing declare/siege/occupy.

Hostile and reputation-costly. The challenger:

  1. Files a declaration of intent with the controlling faction (24-hour real-time notice broadcast galaxy-wide).
  2. Conducts a siege during which the station's defenders (drones, patrol ships, garrison) must be defeated. Sector defense rules apply — see ../galaxy/sectors.md.
  3. Occupies the station once defenders are eliminated.

A successful military takeover incurs a severe reputation penalty with the prior owner's faction and a smaller penalty with allied factions. Restricted to frontier and lawless regions; core Federation space has standing garrisons that make military takeover impractical. Military Contract upgrades (see Upgrades) confer immunity for their duration.

After capture, a stabilization period applies:

  • 7-day post-takeover protection — the new owner is immune from a counter-takeover.
  • 3 days of -50% productivity — defenders' damage and operational disruption suppress traffic and service capacity.
  • Treasury seizure — the prior owner's treasury balance does not transfer to the attacker; it is forfeited to the controlling faction as a war-tax.

Multiple military takeover attempts by the same player on the same station face diminishing returns: each subsequent attempt within 90 days raises the defender garrison strength by 25%.

Ownership types

Status: 🚧 Partial — Solo / Team prose below remains product-shape; Syndicate share tracking + GS governance vote are tip-shipped; stake-transfer approval and faction arbitration stay 📐.

Solo

A single player owns 100%. Full unilateral control over pricing, tariffs, upgrades, and withdrawals. All revenue and all expenses flow to one wallet.

Team-owned

Registered to a Team (see ../gameplay/factions-and-teams.md). Role-based control:

  • LEADER + OFFICER roles configure pricing, tariffs, upgrades, and withdrawal schedule.
  • Members receive a revenue share configured at the team level.
  • Treasury is held by the team, not an individual player.

Loss of team membership ends share entitlement. Disbanding the team triggers a forced sale to the controlling faction at fair value.

Syndicate

Status: 🚧 Partial (re-verified 2026-08-21 vs Sectorwars2102 origin/feat 46bce720 / #737 / LEG-301). Share/invite tracking exists (Station.ownership.co_ownership_shares/mode/invites, port_ownership_service.py WO-SYNDICATE-CO-OWNERSHIP v1). Weighted-voting / veto / quorum / tiebreak and POST /api/v1/stations/{id}/governance/vote are ✅ tip-shipped on the gameserver (station_governance.py + station_governance_service.py; thresholds match the table below). Still 📐 Design-only: stake-transfer approval (>50% of remaining stake) and 14-day faction arbitration. Residual honesty: integer stake percents treat “>25% veto” as a 26% holder floor, while veto override needs 75% of voting stake against_veto — a sole 100% holder can both lodge and override a veto; do not invent a new override rule here. withdraw_treasury may still be solo-owner-only this pass — do not read treasury withdrawal as co-owner-complete.

Up to 10 co-owners with weighted voting. Each owner holds a stake from 1–99%, totalling 100%. Mechanics:

  • Revenue distributes proportionally to stake on each treasury sweep.
  • Policy votes resolve by stake-weighted vote per the threshold table below. ✅ GS on tip 46bce720.
  • Stake transfers require approval of stake holders representing >50% of remaining stake. 📐 Design-only.
  • Disputes that fail to reach majority for 14 days escalate to faction arbitration: the faction picks the option closest to its own policy preferences. 📐 Design-only.

Vote thresholds

Vote type Threshold Veto right Window
Tariff change 50% stake None 72 h
Major upgrade (capex > 500k cr) 50% stake Any holder >25% can veto 72 h
Sale of station 66% stake Any holder >25% can veto 96 h
Withdrawal-schedule change 50% stake None 72 h

Quorum: ≥ 50% of total stake must be represented (voting or registered absent). Inactive owners (no login ≥ 30 days) have their voting power halved (50% of stake counted).

Tiebreak: if no majority emerges within the window, the highest single stakeholder's position wins. Ties at the top break randomly.

Veto enforcement: any holder >25% can lodge a stake-weighted veto on sale or major-upgrade votes. Veto blocks the action unless overridden by a 75% supermajority of voting stake explicitly against the veto.

Vote endpoint: POST /api/v1/stations/{id}/governance/vote with {vote_type, proposed_value, voter_stake_pct, position}. ✅ Tip-shipped (46bce720 / #737). Vote weight is locked at vote-open time — no stake-buying mid-window.

Revenue streams

Status: 🚧 Partial — gameserver ✅ Shipped setters for trade tariff (POST /port-ownership/stations/{id}/tax), price-lever, docking-fee, service-charge, and storage-rental (port_ownership.py tip routes); Player Port Office UI ✅ on tip 46bce720 after #684 / 1e181c92 (LEG-366 — setTax / setPriceLever / setDockingFee / setServiceCharge / setStorageRental in portOwnershipAPI + PortOfficeVenue). Information sales remain gated on Market Intelligence 📐 (upgrade catalog Design-only). Do not read Configurable=Yes as Information sales UI complete.

Stream Range Configurable Notes
Trade tariff 5–25% per transaction Yes ✅ GS + ✅ Player tax UI (setTax). Levied on every player buy/sell at the station. Lower attracts traffic, higher extracts more per trade. Floor and ceiling match the enforced MIN_TAX_RATE/MAX_TAX_RATE bounds (port_ownership_service.py) — corrected 2026-08-04, was stale at 2-8%. See tariff impact below.
Docking fee 50–500 cr per docking Yes (toggle + amount) ✅ GS + ✅ Player UI (setDockingFee — LEG-366 / #684). Flat charge. Discourages casual traffic; useful at high-traffic transit stations.
Service charges 0.8× – 2.0× standard Yes ✅ GS + ✅ Player UI (setServiceCharge — LEG-366 / #684). Repair, refueling, drone manufacture, refining. 1.0× is baseline; 0.8× is a loss-leader for traffic; 2.0× is premium pricing for captive markets.
Storage rental 1,000–10,000 cr/day per slot Yes ✅ GS + ✅ Player UI (setStorageRental — LEG-366 / #684). Players rent station hangar slots for cargo storage. Slot count gated by Extended Storage upgrade.
Information sales 100–1,000 cr per query Yes (toggle + tier) 📐 Gated on Market Intelligence upgrade. Owner can sell market intelligence — recent trade volume, price trends, top traders — to other players.
Price adjustment lever ±10% over base Yes ✅ GS + ✅ Player UI (setPriceLever — LEG-366 / #684). Owner can nudge buy and sell prices within a ±10% band over the standard supply/demand formula. Applied after base pricing, before reputation/rank modifiers. Tightening the band attracts traders (lower sell, higher buy); widening extracts more per-trade margin (higher sell, lower buy) at the cost of traffic. Stored as Station.ownership.price_adjustment_pct.

All revenue accrues into the station treasury (see Treasury & cash flow), not directly to the owner's wallet.

Tariff impact

Tariffs are the largest revenue lever and the largest traffic risk. The elasticity model:

demand_factor = max( min(1.0 - 0.05 × tariff_pct, 1.0), 0.10 )

A 5% tariff (the enforced floor) yields demand_factor = 0.75 (75% of base traffic); 8% yields 0.60; 18%+ floors at 0.10. The demand-factor floor prevents owners from gaming the formula by spiking tariffs to artificially halt traffic during a takeover defense.

Reputation composes on top:

traffic_with_rep = base_traffic × demand_factor × (1 + 0.10 × reputation_score)

reputation_score ∈ [-1, +1] derived from the station's faction-rep drift (see Reputation impact below). A station with deeply negative reputation (-1) loses an additional 10% on top of tariff elasticity; a pristine reputation gains 10%.

Regional tax composes last (per AU3-10):

traffic_final = traffic_with_rep × (1 - region.tax_rate)

region.tax_rate ∈ [0.0, 0.25].

Per-day owner revenue projection (planning view shown in the owner dashboard):

expected_revenue_per_day =
  traffic_final
  × per_trade_revenue_avg
  × (1 - region.tax_rate)
  × (owner_pct / 100)

Worked example: 60 trades/day after elasticity, 1,000 cr average trade, 5% region tax, 30% owner cut → 60 × 1,000 × 0.95 × 0.30 = 17,100 cr/day to the owner.

Implications, holding base traffic at 100 transactions/day (range starts at the enforced 5% floor):

Tariff demand_factor Traffic Per-trade rev (avg 1,000 cr) Daily revenue (gross)
5% 0.75 75 50 cr 3,750 cr
6% 0.70 70 60 cr 4,200 cr
8% 0.60 60 80 cr 4,800 cr
10% 0.50 50 100 cr 5,000 cr
15% 0.25 25 150 cr 3,750 cr
18% 0.10 10 180 cr 1,800 cr
25% 0.10 10 250 cr 2,500 cr

The table understates the long-run effect: at high tariffs, players actively route around the station, reputation erodes, and the controlling faction begins to favour rivals — so the headline daily figure decays month over month as reputation_score slides negative.

Practical guidance:

  • 5% tariff — the enforced floor; near-baseline traffic, modest revenue.
  • 6–8% tariff — sweet spot for most owners; per-trade revenue more than compensates for the traffic drop.
  • 15%+ tariff — predatory; traffic keeps falling (18%+ hits the demand-factor floor of 0.10, capping further collapse), reputation erodes, and neighbours become more attractive.

NPC traders apply the same elasticity. The owner cannot exempt themselves from their own tariff (this prevents tariff-arbitrage between owner-controlled and competitor stations). Team and syndicate co-owners are also subject to the tariff. See ./trading.md for how tariff stacks on top of the base spread.

Fee distribution

Status: ✅ Shipped (GS + Player UI) — gameserver ✅ (set_fee_distribution, tip route POST /port-ownership/stations/{id}/fee-distribution); Player Port Office UI ✅ on tip 46bce720 after #684 / 1e181c92 (LEG-INI-36 — setFeeDistribution / po-fee-distribution in PortOfficeVenue).

Every credit of station revenue (tariff + docking fee + service charge + storage rental + information sale) flows into three buckets per the canonical split from ./station-protection.md:

Bucket Default Floor Ceiling Purpose
Defense fund 40% 30% 60% Drone replenishment, hired guards, tractor upkeep, barracks ops
Owner cut 30% 10% 50% Owner withdrawal or team treasury
Operating 30% 30% 30% Maintenance, wages, faction obligations (immutable)

Owner-tunable bounds: the owner may rebalance defense and owner buckets within their bounds; operating is fixed at 30%. Tip gameserver route POST /port-ownership/stations/{id}/fee-distribution validates (older prose path /api/v1/stations/{id}/fee-distribution/update is not the tip mount):

defense_pct ∈ [0.30, 0.60]
owner_pct ∈ [0.10, 0.50]
operating_pct = 0.30                      // immutable
defense_pct + owner_pct + operating_pct = 1.0

Defense underfunding cascade (reconciled with ./station-protection.md per ADR-0093): defense_pct < 0.35 (i.e. the defense bucket falls under 35% of revenue) defines underfunding. A per-day accounting tick monitors Station.defense_budget. 3 consecutive deficit days → the station auto-downgrades by one security tier (see ./station-protection.md for the tier model), with an owner warning notification fired on day 1 of the deficit. 7 consecutive deficit days → the station downgrades all the way to none, triggering a forced "your station is undefended" notification.

Upgrades

Status: 📐 Design-only — greenlit for build. The catalog and per-upgrade prices below are implementer-proposed and flagged provisional, pending a balance-tuning pass once live economic data exists.

Each upgrade has a one-time capital cost and a recurring monthly upkeep equal to 5–10% of capital cost. Upkeep is paid from the station treasury; if the treasury cannot cover upkeep, the upgrade goes dormant until paid.

1. Extended Storage 📐

  • Cost: 100,000 cr · Upkeep: 5%/mo
  • Effect: +50% commodity inventory cap. Smooths supply shocks, enables stockpiling for arbitrage windows, unlocks more storage-rental slots.
  • ROI: Pays back through reduced stockout frequency and rental income; ~6–12 months at moderate traffic.

2. Market Intelligence 📐

  • Cost: 200,000 cr · Upkeep: 5%/mo
  • Effect: +10% trade volume from informed players (subscribers) and unlocks the Information sales revenue stream.
  • ROI: Volume bump alone pays in ~6 months at moderate traffic; information sales accelerate.

3. Automated Trading 📐

  • Cost: 500,000 cr · Upkeep: 8%/mo
  • Effect: Reduces NPC trader friction at the station, +20% volume.
  • ROI: Strong at high-throughput border stations; weak at low-traffic frontier outposts.

4. Shipyard 📐

  • Cost: 1,000,000 cr · Upkeep: 10%/mo
  • Effect: Enables ship repair and minor construction at the station; opens a new revenue stream from repair/build contracts.
  • ROI: Gates the highest-value service tier; needs traffic to justify upkeep.

5. Refining Facility 📐

  • Cost: 750,000 cr · Upkeep: 8%/mo
  • Effect: Converts raw ore into refined equipment at premium prices. Adds a vertical stage to the station's commodity flow.
  • ROI: Strong at Class 1/3/6 stations adjacent to ore-producing regions.

6. Luxury Amenities 📐

  • Cost: 300,000 cr · Upkeep: 7%/mo
  • Effect: Attracts wealthy traders, +30% luxury_goods volume specifically. Marginal effect on other commodities.
  • ROI: Best paired with Class 10/11 stations.

7. Automated Defense Grid 📐

  • Cost: 500,000 cr · Upkeep: 6%/mo
  • Effect: +50% defense effectiveness. Stacks with sector defense rules — see ../galaxy/sectors.md.
  • ROI: Defensive; pays back by deterring takeover attempts and reducing pirate incident losses.

8. Security Patrol 📐

  • Cost: No capital cost; 200,000 cr/month upkeep
  • Effect: Deters pirates in adjacent sectors; prevents incident-related revenue loss (typically 5–15% of monthly revenue at frontier stations).
  • ROI: Net positive only at stations with non-trivial pirate exposure.

9. Military Contract 📐

  • Cost: 1,000,000 cr (one-time, binds for 3 months) · Upkeep: included in capital cost
  • Effect: Binds a Faction garrison to the station; immune to military takeover for the contract's duration. Renewable.
  • ROI: Insurance, not income. Worth it for high-value or contested stations.

Operating costs

Status: 📐 Design-only.

Cost Rate Notes
Maintenance 1% of acquisition cost / month Anchored on the original acquisition cost, not current market value, so successful upgrades and tariff swings don't retroactively raise the base bill. Pro-rated daily and deducted on the same tick that fees and tariffs accrue. Drawn from the operating bucket. On station sale (economic takeover, syndicate disbandment), the buyer's acquisition_cost resets to the new sale price for forward maintenance — no maintenance arbitrage by flipping ownership.
Wages Scales with services offered Each active service tier (repair, refuel, refining, shipyard) adds a wage line.
Defense upkeep Drone replenishment + patrol-ship retainers Scales with defense intensity; combat events spike the line. Drawn from the defense bucket of the fee distribution.
Upgrade upkeep 5–10% of upgrade capital cost / month Per-upgrade, summed.

The station treasury must cover all four lines monthly. Persistent shortfall triggers insolvency (see Treasury & cash flow).

Defense system

Status: 🚧 Partial — docking-access gating, punitive fees, defender posture, and drone allocation are shipped and combat-wired on tip 46bce720 (defense_policy JSONB lever → combat_modifiers_from_defense_policy → station defense in combat_service.py); patrol radius remains deferred (set_defense_policy rejects patrol_radius > 0).

Owners configure defense policy independently of sector defense, layered on top of it, via Station.ownership["defense_policy"] (no migration — JSONB, normalized with clamped defaults by normalize_defense_policy). Two owner-only routes: GET /port_ownership/stations/{id}/defense-policy (read, includes hostility_list) and POST /port_ownership/stations/{id}/defense-policy (set).

Related — docked-ship protection is a distinct concern covered in ./station-protection.md: the Station.security_level tier system (none/basic/standard/premium), hired STATION_SECURITY guard NPCs, the anti-theft tractor beam that locks stolen ships at undock, docking-fee economics (40/30/30 defense/owner/operating split), and the docked-ship-attack-shield rule. The defense levers in this section govern outward station defense against siege and sector-level threats; station-protection governs inward docked-ship safety. Both pull from the same revenue pool.

Policy levers:

Lever Field Range / values Status
Docking access docking_access open / faction / whitelist / hostile_deny ✅ Shipped, enforced (evaluate_defense_dock_access)
Hostility list hostility_list list of player-id strings ✅ Shipped
Punitive fees punitive_fee_mult 1.05.0× standard service rate, applies when the visitor is on hostility_list and docking is allowed ✅ Shipped
Defender posture defender_posture free-form string, e.g. passive / active / aggressive ✅ Combat-wired @ tip 46bce720combat_modifiers_from_defense_policyposture_mult applied on station defense in combat_service.py (magnitudes live in code; not restated here)
Drone allocation drone_allocation_pct 0100 ✅ Combat-wired @ tip 46bce720 — same helper → drone_scale scales defense-drone contribution in combat_service.py
Patrol radius patrol_radius must be 0set_defense_policy rejects any request with patrol_radius > 0 ("patrol is deferred") 📐 Not built (v1 explicitly defers it; canon's earlier 0–3 sector range is the target for a later WO)

Access evaluation (evaluate_defense_dock_access): the owner always docks (bypass). open always allows. whitelist requires the visitor be on hostility_list (used as an allow-list under this mode — same field, opposite meaning depending on docking_access). hostile_deny blocks anyone on hostility_list. faction gates on the station's reputation threshold via the existing docking_service.check_reputation_gate. Punitive fee applies only when access is allowed and the visitor is on the hostility list.

Sector defense rules at ../galaxy/sectors.md govern what owner-controlled drones and patrol ships can actually do in surrounding space. On tip 46bce720, posture and drone allocation already feed station-defense combat via combat_modifiers_from_defense_policy; patrol radius is still deferred (API rejects > 0 — do not invent patrol behavior). The station policy remains the station-specific overlay on sector defense. Aggressive postures in faction-patrolled space still await a separate faction-response / reputation-drift wiring pass — that residual is not the same as "combat unread."

A player visiting a hostile-owned station may be denied docking outright or charged punitive fees; both states are visible in the station's public profile so the visitor knows before approach. Denial-of-docking does not block emergency-fuel rescue per the standard galaxy rule.

Takeover defense

Status: 🚧 Partial — gameserver economic defense (tariff_cut, counter_trade, friendly trade contract) is ✅ Shipped (port_ownership_service.py + tip routes under /port-ownership/stations/{id}/takeover/defense/…); Player Port Office UI for those controls is ✅ on tip 46bce720 after #684 / 1e181c92 (LEG-INI-35 — activateTariffCut / activateCounterTrade / activateFriendlyTrade in portOwnershipAPI + PortOfficeVenue). Allied response and the military-defense sub-bullets below remain 📐 Design-only. Military declare/siege/occupy Player UI stays 🚧 tip-pending (LEG-368 / #688).

Economic defense

  • Counter-trade (✅ Shipped GS + ✅ Player UI — LEG-INI-35 / #684; activate_counter_trade/month_share_with_defense) — owner spends credits (COUNTER_TRADE_CREDITS_PER_VOLUME = 1 cr per unit of absorb volume, hard ceiling COUNTER_TRADE_MAX_ABSORB = 500,000 per activation) to place a real one-sided BUY MarketTransaction at the station (total_value = requested volume). That ledger row inflates monthly_volume so the challenger's share dilutes and can be out-traded by further real market activity. Defense-counter JSON records the market_transaction_id; legacy synthetic defense_volume rows (pre-conversion) remain honored by defense_volume_for_month until they age out. Magnitudes ratified — see DECISIONS.md port-ownership-takeover-counter-magnitudes-ratify / counter-trade-real-market-orders.
  • Friendly trade contract (✅ Shipped GS + ✅ Player UI — LEG-INI-35 / #684; activate_friendly_trade_contract) — binds a friendly faction or team's contracted volume share toward defending the tariff threshold. FRIENDLY_TRADE_MAX_VOLUME = 500,000 mirrors the ratified COUNTER_TRADE_MAX_ABSORB ceiling — see DECISIONS.md port-ownership-takeover-counter-magnitudes-ratify (Addendum, 2026-08-10).
  • Tariff cut (✅ Shipped GS + ✅ Player UI — LEG-INI-35 / #684; tariff_cut_rate) — temporarily lower the tariff (prior_rate × TARIFF_CUT_FRACTION, floored at MIN_TAX_RATE) to attract competing traffic and dilute the challenger's share. TARIFF_CUT_FRACTION = 0.5 (halves the prior rate) for TARIFF_CUT_DURATION_HOURS (= COUNTER_WINDOW_HOURS, the 7-canonical-day owner counter window).

Magnitudes (ratified): TARIFF_CUT_FRACTION=0.5, COUNTER_TRADE_CREDITS_PER_VOLUME=1, COUNTER_TRADE_MAX_ABSORB=500,000 — see DECISIONS.md port-ownership-takeover-counter-magnitudes-ratify.

Military defense

Status: 📐 Design-only across the board.

  • Drones — stocked from the station's drone manufacturing capacity.
  • Defense grid — the Automated Defense Grid upgrade.
  • Garrison — the Military Contract upgrade (full immunity for 3 months).
  • Allied response — team or syndicate co-owners can rally; faction allies may intervene if reputation is high enough.

Treasury & cash flow

Status: 🚧 Partial.

Station treasury

A per-station credit balance. All revenue flows in; all expenses flow out. Treasury balance is visible to owners only.

Owner withdrawals

Configurable schedule: daily, weekly, or monthly. On each sweep:

  • Treasury must retain at least 10% of its current balance as operating cushion.
  • Up to 90% of the balance flows to the owner (or, for teams/syndicates, distributes per share).
  • The owner can also pull manual ad-hoc withdrawals subject to the same 90% cap.

Cash-injection

Owners can inject personal credits into the treasury at any time. Injections do not count as revenue and are recoverable on a future sweep, subject to the 90% withdrawal cap. For syndicates, a stake-weighted vote can compel proportional injection during a defense or insolvency event.

Insolvency

If the treasury cannot cover monthly expenses for 3 consecutive months, the station auto-sells to the controlling faction at depreciated value (typically 40–60% of acquisition cost). Proceeds clear outstanding debts first, then distribute to owners.

Insolvency stops all upgrades, reverts service charges to baseline, and broadcasts the sale 7 days in advance — giving the owner a final window to inject cash or accept rescue offers from rivals. Rescue offers from rivals override the auto-sale path: any rival offer at or above the depreciated price (and approved by the controlling faction) takes precedence.

Worked example

A Class 2 border station, acquisition cost 800,000 cr, with Extended Storage and Market Intelligence upgrades:

Line Monthly amount
Trade tariff (4%, ~3,000 trades/mo) +120,000 cr
Docking fees +15,000 cr
Service charges +25,000 cr
Information sales +8,000 cr
Revenue total +168,000 cr
Maintenance (1% of 800k) -8,000 cr
Wages -12,000 cr
Defense upkeep -6,000 cr
Upgrade upkeep (5% of 100k + 5% of 200k) -15,000 cr
Expense total -41,000 cr
Net to treasury +127,000 cr

At a monthly sweep with the 10% reserve rule, ~114,000 cr flows to the owner each month — payback on the 800k acquisition in roughly 7 months, before factoring further upgrades or tariff changes.

Reputation impact

Status: 🚧 Partial — three one-shot personal-reputation triggers are shipped (port_ownership_service.py); the ongoing tariff-range faction-rep drift table below remains 📐 design-only (no code applies faction rep from tariff level at all today).

Shipped (all adjust Player.personal_reputation, not faction standing):

  • Fair operation (_accrue_fair_operation_bonus, FAIR_OPS_REPUTATION = 50) — a sustained low-tariff streak earns a one-time personal-reputation grant of +50, once per owner per station (not "permanent... recognised in faction-bulletin endpoints" as previously described — there's no faction-bulletin integration).
  • Insolvency ("port_insolvency", −50) — applied to the prior owner when a station goes insolvent.
  • Military takeover ("military_takeover", MILITARY_REPUTATION_PENALTY) — applied to the challenger who executed the takeover, not "the new owner inherits the controlling faction's stance" as previously described.

Still 📐 design-only (no code implements any of this): the ongoing tariff-range faction-rep drift table, predatory-pricing compounding the drift, information-sale reputation effects, and the "refusing a forced sale" note.

Tariff range (legal clamp 5–25%; fair band = MIN_TAX_RATE..FAIR_TARIFF_MAX = 5–6%) Faction rep drift (design target, unbuilt)
5–6% Neutral to slight positive (fair-operation window; tip FAIR_TARIFF_MAX=0.06)
7–10% Neutral
11–25% Slow negative

Co-ownership lifecycle

Status: 📐 Design-only.

Forming a syndicate

A solo owner can convert to a syndicate by issuing share invitations totalling up to 99% of stake. Each invitee accepts or declines within 7 days; on acceptance, the original owner's stake is reduced by the accepted amount. Conversion fees: a one-time 1% of acquisition cost paid from the treasury.

Adding members to a team

A team-owned station inherits the team's roster automatically; new joiners gain the configured member share from the next sweep. Officer promotion within the team grants configuration access to the station without a separate invitation.

Dissolving co-ownership

Three paths:

  • Buyout — one stake-holder buys out all others at fair value, reverting to solo ownership.
  • Sale — stake-weighted vote sells the whole station to a third party or back to the controlling faction.
  • Disbandment — vote dissolves the syndicate; station auto-sells to the controlling faction at depreciated value, proceeds distributed by stake.

Inactive owners (no login for 30 days) have their stake voting power reduced by 50%; after 90 days inactive, their stake is forfeit to the controlling faction and rebalanced among active owners.

Owner roster API (GET /my-stations)

Status: ✅ Shipped — gameserver + player-client hydrate on tip 46bce720 (LEG-370 / PR #694 76579208).

GET /port_ownership/my-stations returns every station the authenticated player owns. Each row includes treasury/tax/revenue fields plus the five price-modifier keys merged from _owner_price_lever_fields(station) in port_ownership_service.py (same defaults the POST setters use when a key is unset):

Field Default when unset Notes
price_adjustment_lever 0.0 Stored under Station.price_modifiers["price_adjustment_lever"] — see ../../DATA_MODELS/stations.md and ../../DATA_MODELS/jsonb-schema.md.
docking_fee 50 Credits; paired with docking_fee_enabled.
docking_fee_enabled true When false, docking fee is not charged.
service_charge_multiplier 1.0 Multiplier on service charges.
storage_rental_per_day 1000 Credits per day.

Per-station shape (abbreviated): station_id, name, tax_rate, treasury_balance, acquisition_cost, revenue (trailing summary from revenue_summary), then the five keys above. Response envelope: { "stations": [ … ] }.

Port Office and owner-roster UIs consume this hydrate — client: portOwnershipAPI.getMyStations in services/player-client/src/services/api.ts.

Player-facing affordances

  • Port Office venue mountPortOfficeVenue.tsx in the spacedock flow (services/player-client/src/components/spacedock/PortOfficeVenue.tsx; origin/feat 46bce720).
  • Listing / tax / withdraw / economic war-room — owner listing lifecycle, tax rate, treasury withdraw, and economic takeover campaign UI wired through portOwnershipAPI on tip (see Source map).
  • Revenue levers — tax, price lever, docking fee (+ enable), service charge multiplier, storage rental per day — POST routes documented above; roster hydrate via GET /my-stations.
  • Economic takeover defense + fee distribution — tariff-cut / counter-trade / friendly-trade activation and fee-distribution rebalance after #684 / 1e181c92 (Port Office UI on tip 46bce720).
  • 🚧 Military declare / siege / occupy — gameserver POST /port_ownership/stations/{id}/military is shipped; zero /military route in tip portOwnershipAPI — no player declare/siege/occupy UI on tip. Tracked: LEG-393 / #688 (tip-pending; do not read GS ✅ as PC live). Do not conflate planetary SiegeStatusMonitor (planet siege) with station military takeover.
  • 📐 Information sales / upgrade catalog — design-only per canon; Market Intelligence upgrade purchase UI not shipped.

Source map

Paths in Sectorwars2102:

Subsystem File
Port ownership model services/gameserver/src/models/port_ownership.py
Port ownership service (listing, offer, takeover-declare, siege, occupy, tax, price-lever, docking-fee, service-charge, storage-rental, fee-distribution, withdraw) services/gameserver/src/services/port_ownership_service.py (2,745 lines)
Port ownership API routes services/gameserver/src/api/routes/port_ownership.py (includes GET /my-stations @ :319)
Upgrade catalog services/gameserver/src/core/station_upgrades.py (target)
Port Office UI (owner controls) services/player-client/src/components/spacedock/PortOfficeVenue.tsx
Port ownership API client services/player-client/src/services/api.ts (portOwnershipAPI, including getMyStations)

The existing Station.ownership JSONB field on models/station.py records the current owner and stake distribution. Purchase, economic takeover, military takeover, tariff, price-lever, docking-fee, service-charge, storage-rental, fee-distribution, and syndicate governance vote (POST /stations/{id}/governance/vote on tip 46bce720 / #737) are shipped in the gameserver service above — see the ✅ GS sections throughout this page. Player Port Office UI on tip 46bce720 after #684 / 1e181c92 (LEG-INI-35 / LEG-INI-36 / LEG-366): economic takeover-defense controls (tariff-cut / counter-trade / friendly-trade), fee-distribution rebalance, and revenue levers (tax / price-lever / docking-fee / service-charge / storage-rental) are ✅. Military declare/siege/occupy remains 🚧 tip-pending (LEG-368 / LEG-393 / LEG-395 / #688 — zero /military client on tip). Information sales remain 📐 (Market Intelligence upgrade). The upgrade catalog remains 📐 Design-only — purchase prices ship implementer-proposed, flagged provisional pending a balance-tuning pass, per ADR-0093 item 33 (folded from ADR-0093, re-verified 2026-08-07).