Server Connector


Routes players between the servers of a split Factorio world. This server handles one planet (or the space platforms); the manager tells it what the others are.

Internal
an hour ago
2.1
15

Changelog

Version: 0.41.0
Date: 2026-11-08
  Major:
    - runtime manager traffic now uses the generic udp-net library. The connector-call console
      command and remote interface are removed.
    - connector ledger support: absolute per-item startup application and a one-item-per-second
      runtime probe.
    - freshness reset is now every 1 second (60 ticks), still connector hubs only.
    - narrow server-connector-bootstrap pause|unpause command for a save that opens tick-paused.
  Fixed:
    - the boot ready event is gated on the manager identity.
Version: 0.40.8
Date: 2026-11-08
  Fixed:
    - removed the space-server Nauvis startup clear. The server log shows it deleting 3312 entities and 113 chunks on the same tick the client was catching up, immediately before the first CRC failure.
    - reverted the 0.40.6 live-write gate and the 0.40.7 periodic-sweep removal; neither was the cause.
Version: 0.40.7
Date: 2026-11-08
  Fixed:
    - the periodic freshness sweep is disabled. It could run while a client was still connecting (before connected_players included them) and caused a CRC desync on space join. Freshness is now reset only during configuration/startup and while the fleet is empty.
Version: 0.40.6
Date: 2026-11-08
  Fixed:
    - automatic request-group writes are deferred while any player is connected, and the freshness sweep also waits for an empty fleet. Live script writes to hub groups/inventories were not client-replicated and caused space joins to desync after a landing-pad edit.
Version: 0.40.5
Date: 2026-11-08
  Fixed:
    - freshness reset no longer aborts on the first non-spoiling item. `spoil_ticks` is optional and is now read defensively, so the sweep actually reaches the eggs and other spoilables.
Version: 0.40.4
Date: 2026-11-08
  Fixed:
    - freshness reset now rewrites spoil_tick as well as spoil_percent. Resetting only the percentage left an expired absolute timer that could still convert the stack.
Version: 0.40.3
Date: 2026-11-08
  Fixed:
    - the first configuration change after loading an older save resets connector freshness immediately, before the first normal spoilage tick, instead of waiting up to 10 seconds.
  Added:
    - connector_spoilage diagnostic returns the spoil percentages from both copies of every planet connector.
Version: 0.40.2
Date: 2026-11-08
  Fixed:
    - freshness reset now covers both copies of every planet connector: the planet hub and the matching space-side hub. Real platform hubs are untouched.
Version: 0.40.1
Date: 2026-11-08
  Fixed:
    - a mod update no longer destroys and recreates every connector platform, and no longer clears connector hub inventories. That reset wiped the cargo-bay layout and every item in the hub, which looked like a random loss.
  Added:
    - connector_spoilage is a read-only diagnostic for reproducing freshness issues.
Version: 0.40.0
Date: 2026-11-07
  Added:
    - planet connector hubs reset every spoilable stack to 100% freshness every 10 seconds. The space-side copies are not touched.
    - the space server clears every entity and generated chunk from its unused Nauvis surface on startup, once no player is connected.
  Changed:
    - platform requests with no import planet (missing, empty, any or all) are no longer copied into every planet's automatic Outgoing group.
Version: 0.39.9
Date: 2026-11-06
  Fixed:
    - the in-game Checks window now reports items present in Buffer as well as Incoming/Outgoing, so a buffer/incoming duplicate no longer goes undetected.
Version: 0.39.8
Date: 2026-11-06
  Added:
    - connector hubs enforce `providing_to_other_platforms = true` every second, so every planet connector supplies the other platforms.
Version: 0.39.7
Date: 2026-11-06
  Fixed:
    - request/cargo read-back verification summed one stack per item instead of all repeated stacks, so a correct hub inventory could never verify and inventory sync retried forever.
Version: 0.39.6
Date: 2026-11-06
  Changed:
    - generated connector platforms use a leading tilde (~Space Platforms) and all generated request groups use a leading tilde, so they sort below player-created items.
    - existing connector platforms and groups are renamed in place.
  Notes:
    - no routing or request semantics changed.
Version: 0.39.5
Date: 2026-11-06
  Added:
    - solo mode: an identified server with an empty topology behaves as a Single Server. It keeps UPS/RAM/player/speed telemetry and set_speed/set_paused, but creates no planet connectors, server selector, custom surfaces or fleet research.
  Fixed:
    - the identity push and configuration change no longer run fleet surface conversion on a solo save.
    - the solo branch of the server menu no longer calls close_checks before it is defined.
Version: 0.39.4
Date: 2026-11-05
  Added:
    - platform_detail(index): read-only platform name, location, pause state, bay count, hub contents, requests and schedule when the build exposes it.
    - platform_hub_dump(index, cursor, limit): the paged hub read the manager's platform store already expects.
    - player_detail(name): read-only player server, surface, body and inventory contents.
    - the research state now carries the ordered research queue.
  Notes:
    - no new writes; every call above is a read for the manager's runtime pages.
Version: 0.39.3
Date: 2026-11-04
  Fixed:
    - the ten-event replay made push_pod a local defined after the handlers that call it, so they saw a nil global, and it stored each event with its own replay list, nesting until the stack overflowed. The helper is a global now and stores a shallow copy without the replay list.
Version: 0.39.2
Date: 2026-11-04
  Added:
    - every connector_pod push carries the last ten pod events, so one dropped datagram cannot lose a delta; the receiver dedupes by id.
  Changed:
    - the rotating cargo sweep is removed. The mirror runs on pod events only.
Version: 0.39.1
Date: 2026-11-04
  Fixed:
    - connector_set_item applied a delta computed from a probed count, so a hub that already held the item had the whole amount inserted again (every over-item read exactly 200%). It now reads the inventory that holds the item, removes that many, inserts exactly the requested count, and reports before/after.
Version: 0.39.0
Date: 2026-11-03
  Added:
    - connector_set_item: set one item's count in a connector hub exactly, inventory only, requests untouched.
    - connector_cargo_page: one sorted page of a hub's contents, for the mirror's slow sweep.
Version: 0.38.14
Date: 2026-11-03
  Fixed:
    - the debug trace added in 0.38.10 called debug.emit inside pod.lua, where that name is not the mod's debug module, so every cargo-pod event threw and pod tracking stopped. The trace is removed; pod handling is untouched otherwise.
Version: 0.38.13
Date: 2026-11-03
  Fixed:
    - the rocket trace read the silo's rocket inventory after the rocket had left, so it reported cargo=0. It reads on the launch order instead, while the cargo is still there.
Version: 0.38.12
Date: 2026-11-03
  Added:
    - debug-only trace on a rocket launch: the silo, every stack the rocket carried, and the total.
Version: 0.38.11
Date: 2026-11-03
  Added:
    - connector_clear: empties a connector hub's inventories in place, without destroying the platform, and returns how many items were removed.
Version: 0.38.10
Date: 2026-11-03
  Added:
    - debug-only trace on a cargo pod launch: every stack it carries, the destination hub's total contents at that moment, and the pod's total. Guarded by the existing debug flag.
Version: 0.38.9
Date: 2026-11-03
  Fixed:
    - a rebuilt connector never got its base grid back, because the queue is only filled from creation and ensure passes, and a load can run those before the identity is known. Any connector with no bays is queued once a minute.
Version: 0.38.8
Date: 2026-11-03
  Fixed:
    - the one-shot connector reset retried and logged every tick on an instance with no connector, because the flag only stuck when something was removed. It sticks when there is nothing to do as well.
Version: 0.38.7
Date: 2026-11-03
  Changed:
    - diagnostic build: the connector platforms are rebuilt from scratch once on the first load after this version, which starts their inventories at zero. The mod recreates them on the next ensure pass.
Version: 0.38.6
Date: 2026-11-03
  Fixed:
    - the one-shot hub clear consumed its flag before doing the work, so a pass that matched no hub cleared nothing and never retried. The flag now sticks only when a hub was actually emptied, and every pass logs what it saw.
Version: 0.38.5
Date: 2026-11-03
  Changed:
    - diagnostic build: the connector hubs are emptied once on the first load after this version, so the request cap can be observed from zero.
Version: 0.38.4
Date: 2026-11-02
  Fixed:
    - the one-shot hub clear ran before the identity was known, so no hub was ever recognised. It runs from the tick that waits for identity now.
Version: 0.38.3
Date: 2026-11-02
  Fixed:
    - the same item was written into more than one request group on one hub, so the game filled every row and a hub received a multiple of the requested amount. Incoming now wins and the duplicate is removed from Outgoing and Buffer.
  Changed:
    - connector hub contents are emptied once on the first load after this build, so the request cap can be watched from zero.
Version: 0.38.2
Date: 2026-11-01
  Fixed:
    - a cargo pod delta applied twice. The manager's de-duplication is in memory, so every restart re-applied the events the mod was still re-sending, and a lost reply re-applied one. The event id now travels with the apply and the mod ignores a repeat.
Version: 0.38.1
Date: 2026-11-01
  Fixed:
    - the Checks window missed a request with no planet set when that request was platform-sourced, and reported the game's automatic construction entries instead. It reads import_from only, in manual sections.
Version: 0.38.0
Date: 2026-11-01
  Added:
    - a Checks button beside Servers. It reports request loops (the same item in a planet hub's Incoming and Outgoing group) and planet-sourced requests with no planet set on real platforms. It only reports; nothing in the world is changed.
Version: 0.37.9
Date: 2026-11-01
  Fixed:
    - the join button was still greyed out with "Server is offline" after the join itself stopped refusing an offline server. The online flag now only decorates the row.
Version: 0.37.8
Date: 2026-11-01
  Changed:
    - joining another server no longer refuses when the manager reports it offline. The address is enough to try; a stale online flag was blocking joins.
Version: 0.37.7
Date: 2026-11-01
  Changed:
    - planet hubs are named "~[planet=x] X Hub" so the platform list sorts them to the bottom. An existing connector is renamed in place, and both names are recognised.
  Fixed:
    - the Servers button comes back as soon as the identity arrives; the identity call refreshes every player's window instead of leaving it removed.
    - a platform request made on the space server is moved to the planet it names, instead of sitting there and never launching.
Version: 0.37.6
Date: 2026-11-01
  Fixed:
    - the derived hub groups attributed a request to a planet by request_from, so once a platform was set to request from platforms every one of its requests vanished from the planet hubs' Outgoing groups. Attribution is import_from.
Version: 0.37.5
Date: 2026-11-01
  Fixed:
    - a call that answers with a plain value (set_server_status answers true) failed to encode its reply, so the manager got nothing and the mod logged a -call failure every time.
Version: 0.37.4
Date: 2026-10-31
  Added:
    - every connector hub gets a free base grid of 320 cargo bays (18x18 bays, the hub in the middle 2x2), on foundation tiles. The bays cannot be mined and are not part of the mirrored layout.
  Fixed:
    - a planet server no longer deletes pending platform requests or native platforms in ensure_all. A native platform is reported to the manager and then removed.
    - the wrong-planet request move runs (it was never scheduled), is live by default, and uses destroy(1).
    - a platform created on a planet server is carried to the space server with its starter pack, quality, a request id and an ack; a name collision gets a suffix instead of merging.
Version: 0.37.3
Date: 2026-10-31
  Fixed:
    - a space platform created on a planet server was destroyed there and never rebuilt, because the adoption path was never called. The request is carried to the space server with the same name and the same planet, and re-sent until it lands. A platform created on the space server is left exactly as it is.
Version: 0.37.2
Date: 2026-10-31
  Fixed:
    - the Servers button never came back for a player who joined before the identity arrived. The topology push refreshes every connected player now, not only the ones with the window open.
    - outbound research threw on every tick because main_force was not in scope, so no research progress was ever pushed.
Version: 0.37.1
Date: 2026-10-31
  Fixed:
    - peaceful mode is set on the space server's nauvis body only. It was applied to every surface, and the cease-fire was a force-pair setting, so the platforms' turrets stopped firing at asteroids.
  Added:
    - the body's freshly generated chunks are swept for ten seconds after a join, keeping the player's 3x3 chunk block. The body has no chunks of its own and regenerates around whoever stands on it.
Version: 0.37.0
Date: 2026-10-29
  Changed:
    - the hubs' Incoming and Outgoing groups are derived. Incoming comes from the landing pads, Outgoing from the space platforms. Both are recalculated in full whenever a request changes.
    - a platform request with no planet selected counts for every planet's hub, at its full count.
  Added:
    - a Buffer group per hub, mirrored between both hubs and never recalculated.
    - sync_* read and apply calls for the manager's startup sync; protocol number 2 in connector_ready.
  Removed:
    - the platform positions/meta/hub dump/audit streams and their calls; the landing pad is no longer written by the mod.
Version: 0.36.91
Date: 2026-10-29
  Fixed:
    - the server window no longer rebuilds itself on every status push; live values update in place and the 60-tick map poll is gone.
    - connector platforms have asteroid and asteroid-chunk entities destroyed directly; the unused on_entity_spawned handler is removed.
Version: 0.36.90
Date: 2026-10-29
  Fixed:
    - the server list lost every sidebar button after the first in a section, and the solar strip lost all but one, because several elements shared one name inside one table. Each button now sits in its own cell, and a failed element creation is logged.
Version: 0.36.89
Date: 2026-10-29
  Changed:
    - server window rebuilt on tables and fixed-size cells so every column aligns; planet strip is clickable.
    - connector platforms are swept for asteroids every 10 ticks and on every platform state change.
  Added:
    - space server turns on peaceful mode, cease-fire and disables enemy expansion.
Version: 0.36.88
Date: 2026-10-29
  Changed:
    - The server window shows only players, UPS, speed and tick; icons are sized and centred; the current server is marked 'Current Location' with a highlighted button; the window fits its content.
Version: 0.36.87
Date: 2026-10-29
  Added:
    - servers report a heartbeat and the manager pushes players, UPS and version to every server.
Version: 0.36.86
Date: 2026-10-29
  Changed:
    - The server window is a server list on the left and a detail panel on the right, with Join and Cancel at the bottom right.
Version: 0.36.85
Date: 2026-10-29
  Fixed:
    - on_load wrote the boot marker to storage, which Factorio rejects as a save/load change
      and refuses to load. The marker is now module-local and on_load touches no storage.
Version: 0.36.84
Date: 2026-10-29
  Added:
    - Every server sends connector_ready over UDP once after a save load, so the manager can
      wait for all instances before the startup pre-sync.
    - The startup pre-sync pauses the fleet, dumps every connector, and applies the planet hub's
      state to the space counterpart.
  Fixed:
    - A connector platform that lost its hub is rebuilt instead of being left as a floating cargo
      bay. connector_state reports hub=false for that platform instead of failing the read.
Version: 0.36.83
Date: 2026-10-29
  Fixed:
    - Dead mirror code removed from the platform module. Cargo-bay build and remove events now carry
      a sequence number, and the connector state reports it, so the manager can detect a lost packet
      and reconcile the pair.
  Changed:
    - A hub build now pushes the connector's full shape, cargo and requests, instead of only marking
      the platform dirty. Bay offsets are relative to the hub, so the counterpart is re-anchored at
      once rather than at the next restart.
Version: 0.36.82
Date: 2026-10-29
  Changed:
    - The server map is one Servers button that opens a list of planets, space and custom servers. It
      no longer polls or moves, so it shows instantly in map view.
Version: 0.36.81
Date: 2026-10-29
  Changed:
    - Cargo bays sync as single build/remove events: a player build sends the bay offset and the
      counterpart creates that one bay at the same offset; a mine removes that one. The full
      platform shape is only sent on boot and on the startup reconcile, so an edit no longer
      runs a whole layout comparison.
Version: 0.36.80
Date: 2026-10-29
  Fixed:
    - Building a cargo bay raced the mirror. The counterpart's ensure_bays raised a build event
      that was treated as a player edit, and the resulting state could win and remove the origin
      bay. Manager-created bay events are ignored, a player bay build or mine bumps the clock so
      the origin wins, and a placed bay is protected immediately.
Version: 0.36.79
Date: 2026-10-29
  Fixed:
    - The space server no longer prunes the real platforms. The connector is added alongside
      them; only a planet keeps just the connector. The converter keeps every platform surface
      in the base and space saves and does not add a planet connector to the base.
    - A cargo bay a player places is protected immediately, not on the next mirror apply.
Version: 0.36.78
Date: 2026-10-28
  Added:
    - Cargo accounting. Every insert and remove logs wanted versus moved when DEBUG is on; a
      shortfall is recorded in the connector event log and returned to the manager, which logs
      it as an error. A failed request-group or pad write is reported the same way. This does
      not prevent the both-writable double-use window; it makes it visible.
Version: 0.36.77
Date: 2026-10-28
  Fixed:
    - Trash-unrequested was cleared on the request point only. A hub and a pad expose several
      logistic points, so the pad still pushed its inventory into the platform and the hub
      still ejected its foundation. Every point is cleared now.
Version: 0.36.76
Date: 2026-10-28
  Fixed:
    - A real connector platform was collecting asteroids; the game repaired the damaged tiles
      from the hub's foundation, draining the starter-pack cargo. The connector now sweeps its
      asteroid chunks once a second, the same cadence as the fleet's planet sweep.
Version: 0.36.75
Date: 2026-10-28
  Fixed:
    - An empty request list from the manager was skipped as "no change", so a request cleared
      on one connector side stayed on the other. The state now says whether the lists are
      carried, and empty lists are written.
Version: 0.36.74
Date: 2026-10-28
  Fixed:
    - The connector hub and the landing pad had trash-unrequested on. The hub ejected its
      starter-pack foundation over time, and the pad pushed its whole inventory into the
      platform as soon as a request was added. Both points now keep unrequested items.
Version: 0.36.73
Date: 2026-10-28
  Added:
    - One connector platform per planet, mirrored between the planet save ("Space Platforms") and
      the space save ("[planet=<id>] <Planet> Hub"). Both sides are writable; the manager applies
      each edit to the counterpart and compares the hub weight.
    - Incoming (Space to Planet) and Outgoing (Planet to Space) request groups, with the source
      forced: platforms for incoming, planet plus the planet's location for outgoing. "all" is
      rewritten and a finite maximum is removed.
    - The landing pad keeps only the Incoming group; anything else is removed.
    - Only the hub and cargo bays may exist on a connector; other builds are mined and refunded.
    - Deleting a connector deletes the counterpart and rebuilds both hub-only.
  Notes:
    - The whole-list mirror, the cargo sweep and the platform timers are retired. The manager
      reconciles once at fleet start under a tick pause.
Version: 0.36.72
Date: 2026-10-28
  Added:
    - The save call: game.server_save(name) with a name the manager chooses. The fleet save uses
      it for every server and records the file and tick in fleet.json's worlds, so an archive
      says which file is which world instead of taking the current save's name.
Version: 0.36.71
Date: 2026-10-28
  Added:
    - The periodic platform meta now carries each hub's inventory weight. The space server is the
      source of truth; every copy reports the same scalar every few seconds, so the manager can
      see a discrepancy without reading a full hub.
Version: 0.36.70
Date: 2026-10-28
  Added:
    - platform_hub_dump reports the hub inventory's weight. The space server and every copy
      report it, so the manager can compare the scalar the fleet already uses internally
      (tick_hub) instead of only diffing item lists.
  Notes:
    - The dump's `limit` is capped at 100 stacks per page; a reader must follow `next` until
      `done`. Comparing a single page reported differences that were only unread pages.
Version: 0.36.69
Date: 2026-10-27
  Fixed:
    - debug.json logged every argument-less call as "<unserialisable: bad argument ...>". Calls
      with no args pass nil, which table_to_json rejects; it is now logged as nil. That noise was
      roughly fifteen thousand lines per server and hid real failures.
  Notes:
    - The manager no longer calls apply_requests or apply_cargo_delta on a custom instance: a
      custom world has no platform with the fleet's name, and every edit logged "no such
      platform" against blueprint-world.
Version: 0.36.68
Date: 2026-10-27
  Fixed:
    - The hub edit handler called platform_api.requests_of, but the module exports that
      function as `requests`. Every real-hub logistic edit threw ("attempt to call field
      'requests_of' (a nil value)") before it pushed anything, so no platform_requests event
      was ever sent and a station's requests were never copied to the planets.
Version: 0.36.67
Date: 2026-10-27
  Added:
    - A read-only surface_report call: entities, entity-ghosts and deconstruction orders per
      surface. It answers whether a planet that looks ghosted is unbuilt ghosts, orders, or
      simply empty.
Version: 0.36.66
Date: 2026-10-27
  Fixed:
    - apply_requests no longer requires the copy's cargo-bay count to equal the real one. A
      logistic filter list does not depend on capacity, and a copy built from an older layout
      (more bays than the real has now) made every request write fail as "copy does not have
      the ship's bays".
    - copy_is_whole now accepts a copy with at least the real platform's bays, not exactly that
      number. A copy with more bays can hold the cargo; refusing it blocked the cargo mirror
      until the bay trim caught up.
Version: 0.36.65
Date: 2026-10-27
  Changed:
    - A real hub's logistic edit now carries its full request list and bay count in the
      platform_requests event, so the manager can apply it to every copy directly. The manager
      used to answer that event with a full fleet resync, which took minutes and was throttled;
      a station's requests could sit on the space hub while every planet copy stayed empty.
Version: 0.36.64
Date: 2026-10-27
  Fixed:
    - The platform mirror destroyed a player's new platform and then threw on a require inside
      report_platform_create ("Require can't be used outside of control.lua parsing"), so the
      create was never sent and the platform vanished. The transport now lives in control/bus.lua:
      platforms and outbound both require it, and the cycle that forced the lazy require is gone.
    - Adoption is one function (adopt_native_platform), and every adopted platform is recorded
      and its create re-sent every ten seconds until a copy of the name exists here, a native
      with that name is still standing, or five minutes pass. A dropped datagram no longer loses
      a platform.
    - starter_pack.quality is a LuaQualityPrototype; it is normalised through .name in the
      request move, the debug dump and create_platform, so a moved platform keeps its quality.
  Notes:
    - The mirror still adopts a pending request as soon as it appears, so the space server
      applies the starter pack itself and the silo request is removed rather than fulfilled by a
      rocket. If the rocket should build it, the mirror has to skip pending requests; separate
      decision.
Version: 0.36.63
Date: 2026-10-27
  Fixed:
    - The once-per-build silo dump was keyed to a hand-bumped number, so a save that had run
      the previous build never dumped its silos again. It is keyed to the mod version now, so
      every build seeds once, including this one.
Version: 0.36.62
Date: 2026-10-27
  Fixed:
    - The debug boot read game.active_mods, which does not exist on the script side, so boot
      threw and skipped the rest of on_configuration_changed on every server. It now reads
      script.active_mods.
    - A debug dump can no longer stop its caller: boot is wrapped, and it now runs after the
      crash-site, surface and speed steps rather than before them.
Version: 0.36.61
Date: 2026-10-27
  Added:
    - A DEBUG switch in control/debug.lua, on while the fleet is being finalised. It logs what
      the build and save actually offer (optional events, the space-platform states, the
      logistic member indexes, the silo statuses, the controllers, mod versions), the whole
      platform list every five seconds, every silo once per build and whenever the starter-pack
      request count changes, each platform that appears or disappears with all its fields, every
      purge and resend decision, every mirror input and every removal, every create_platform
      entry and result, every join-rule decision, every event the mod handles, every RCON call
      with its arguments and result, and every UDP push.
    - Twelve kilobytes per dump, with a truncation marker, so one value cannot swallow the log.
  Notes:
    - Set DEBUG = false in control/debug.lua when the fleet is finalised for v1. Nothing else
      in the mod reads a flag.
    - Logging is local and changes no game state, so it is safe with players connected.
Version: 0.36.60
Date: 2026-10-27
  Added:
    - A pending platform request named on the wrong planet's server is moved to the server that
      owns that planet, with the same name and the same starter pack (item and quality). The
      request is destroyed on the origin, announced over UDP as platform_request_moved, recreated
      by the target through request_platform, and acknowledged through request_moved_ack. Until it
      is acknowledged it is re-sent every ten seconds, and an unacknowledged move is logged.
    - New calls: request_platform, request_moved_ack, request_purge_mode, request_probe. New
      command: server-connector-requests, which prints the probe as JSON.
  Changed:
    - The purge is dry-run by default, on new and existing saves, and only logs what it would
      move. Arm it per server with request_purge_mode {live=true}.
    - A platform creation that fails to apply its starter pack is now destroyed instead of being
      left behind as a hubless pending platform.
  Notes:
    - Anything else the delivered rocket pod carried is lost when the native platform is deleted
      and recreated on the space server.
    - This build of the game has no on_space_platform_created event, so the 60-tick purge pass is
      what catches a request; the handler is kept for builds that have it.
    - request_planet reads the platform's space_location. A pending platform that reports nil
      there is kept, never moved; the probe shows it.
Version: 0.36.59
Date: 2026-10-27
  Fixed:
    - The watch's first-pass line was gated on a flag stored in the save, so a fleet that had
      already run an older build never printed it. It now prints once per build, which is what
      makes the reader's state visible after an upgrade.
Version: 0.36.58
Date: 2026-10-26
  Fixed:
    - The silo reader probed the logistic member indices and took the first that answered, which
      is logistic_container, so a silo's starter-pack request always read as zero. It asks for
      rocket_silo_requester by name first.
    - A surface creation with no platform attached yet returned silently, which is how a new
      platform surface could be missed entirely. Every creation is logged with its platform and
      copy state before the native-platform check runs.
  Changed:
    - The platform watch runs every five seconds instead of every minute: a request can be set
      and removed inside a minute.
Version: 0.36.57
Date: 2026-10-26
  Fixed:
    - The silo reader asked for one fixed logistic member index, which this build does not
      answer, so the watch always reported unreadable. It now probes the indices and caches the
      one that answers, the way the platform hub reader already does.
  Added:
    - The watch logs one line on its first pass: how many silos it sees, the request count, and
      which member index answered. That is the line to read when a launch leaves no trace.
Version: 0.36.56
Date: 2026-10-26
  Fixed:
    - The platform watch called a helper declared below it, so it read a nil global, and it was
      scheduled at 60 ticks, so it ran every second. Both fixed: the helper is declared first
      and the pass runs once a minute.
Version: 0.36.55
Date: 2026-10-26
  Fixed:
    - A logistic edit on a platform copy is ignored. Forwarding it made the manager resync from
      the copy and write the real list back over it, which removed a request a few seconds
      after it was made.
  Added:
    - Once a minute, each planet logs its rocket silos' starter-pack request count and any
      platform name that appeared or disappeared. The logistic-slot event does not cover every
      edit the game makes, so this is the trace for a launch that goes nowhere.
Version: 0.36.54
Date: 2026-10-26
  Fixed:
    - platform_check and rebuild_platforms were named on the RCON surface but never implemented,
      so the manager's platform check and force-rebuild answered "unknown call". platform_check
      now reports each copy's bays, cargo and requests; rebuild_platforms drops the copies so
      the next mirror push rebuilds them from the fleet's own data.
  Added:
    - A rocket silo's starter-pack request count is logged whenever a logistic slot changes, so
      a launch request that disappears without a launch leaves a trace.
Version: 0.36.53
Date: 2026-10-26
  Fixed:
    - A join no longer leaves chunks on a planet this server does not own. The spawn point is
      set to the owned surface at boot, before the foreign-surface cleanup, so a joining body
      is created there instead of on nauvis.
    - Chunks on a foreign surface are swept once a minute, and a chunk holding a body is never
      deleted. Nauvis cannot be deleted (the game refuses the primary surface), so its chunks
      are the only thing that can be removed.
    - The space server is a viewer again: a join gets the remote controller, and the body the
      game created is removed on the next window with nobody connected. Destroying it in the
      join handler is the change 0.32.3 recorded as desyncing the join.
  Changed:
    - The surface check runs every second: a connected player standing on a surface this
      instance does not own is put back, and the spawn point is re-asserted when it drifted.
  Added:
    - sweep_foreign, one chunk sweep on demand; report carries foreign_last and foreign_swept.
Version: 0.36.52
Date: 2026-10-25
  Changed:
    - map.refresh writes frame.visible and frame.location only when they actually change.
    - platform_meta and platform_positions share position_of(), so their platform fields are
      read once by the same helper.
    - UDP send failures are logged at most once a minute from a local (non-storage) counter.
  Measured:
    - /server-connector-profile on the space server, 0.36.51: platform_meta full table
      0.20-0.21 ms, change-driven 0.20-0.23 ms, positions 1.78-1.88 ms, logistic
      8.6-11.1 ms, hub 70-748 ms, map 0.004 ms. The metadata saving is fewer datagrams when
      nothing changes, not a faster table build.
Version: 0.36.51
Date: 2026-10-25
  Changed:
    - platform_meta is change-driven with a five-second full heartbeat instead of sending the
      whole table ten times a second. The manager merges partial updates and prunes only on a
      full list.
    - distance moved out of platform_meta; the 2 Hz platform_positions stream now updates it.
    - platform positions remain at 2 Hz. Manager-side extrapolation was not enabled because the
      runtime does not expose a per-platform speed value to interpolate from.
  Added:
    - /server-connector-mod-profile measures the meta, positions, logistic, hub and map readers
      with helpers.create_profiler().
Version: 0.36.50
Date: 2026-10-25
  Fixed:
    - Duplicate script.on_nth_tick(60) registrations overwrote each other, so the asteroid
      sweep, map refresh and research push never ran. All intervals now go through one
      collector and one dispatcher per interval.
  Added:
    - Startup log lists every nth-tick interval and handler; the first run of each handler is
      logged once so a missing registration is visible.
Version: 0.36.49
Date: 2026-10-25
  Changed:
    - A native space platform on a planet is removed and recreated on the space server under
      the same name; the normal mirror then copies it back to every planet.
  Removed:
    - The launch-request redirect, home-world handling, ghost reporting and rocket backstop.
Version: 0.36.48
Date: 2026-10-25
  Added:
    - Manager platform check and force-rebuild calls; queue_launch_request moves a player's
      starter-pack request to the production planet's silo.
Version: 0.36.47
Date: 2026-10-25
  Changed:
    - A starter-pack launch request made on a non-production planet is removed locally and
      sent to the manager, which schedules it on nauvis where the starter hub is produced.
Version: 0.36.46
Date: 2026-10-24
  Fixed:
    - A space-platform hub ghost is reported as a new platform, so the manager can create
      the real platform on the space server instead of leaving a ghost on a planet server.
Version: 0.36.45
Date: 2026-10-24
  Added:
    - The new-space-platform starter-pack request is moved from a non-main surface's rocket
      silo to a silo on the server's main planet.
Version: 0.36.44
Date: 2026-10-24
  Fixed:
    - Extra copy bays are made destructible before removal; protected bays ignored destroy().
Version: 0.36.43
Date: 2026-10-24
  Fixed:
    - A copy of a platform with no layout now trims extra cargo bays instead of keeping
      every bay from the old layout forever.
Version: 0.36.42
Date: 2026-10-24
  Changed:
    - The server strip adapts its fixed position: top-left in the normal view, shifted right
      in map view so the map search box stays clear. It is not draggable.
Version: 0.36.41
Date: 2026-10-24
  Changed:
    - The server strip is fixed near the top-left but offset to the right of the map search
      instead of covering it. It is not draggable.
Version: 0.36.40
Date: 2026-10-24
  Changed:
    - The in-game server strip is a captioned, draggable window instead of a fixed overlay.
      It no longer sits over the map search and can be moved like RateCalculator's window.
Version: 0.36.39
Date: 2026-10-24
  Fixed:
    - The in-game server strip is no longer gated on the server's reading of the client's
      render_mode. It is visible while connected, so the map-view server buttons cannot be
      hidden by a wrong chart/game reading.
Version: 0.36.38
Date: 2026-10-24
  Fixed:
    - Boot clears game.tick_paused, so a save taken while paused cannot open frozen.
Version: 0.36.37
Date: 2026-10-24
  Fixed:
    - Empty request lists are omitted from the meta and the manager clears its cached list on
      the empty-request hash, so stale fake-platform requests no longer persist.
Version: 0.36.36
Date: 2026-10-24
  Changed:
    - No periodic layout/bay push. A real-platform build or mine still announces the full
      layout immediately; a boot is the only forced full copy.
    - Fleet start brings the space server up first and waits for its platform meta before
      starting the planets, then force-pushes layout and resyncs cargo/requests once.
Version: 0.36.35
Date: 2026-10-24
  Changed:
    - Added a 1 Hz logistic-only platform_meta stream carrying requests and request_hash,
      leaving the cheap 10 Hz identity/position stream and the 5 s full layout stream alone.
    - The manager now ingests the request list from platform_meta.
Version: 0.36.34
Date: 2026-10-24
  Changed:
    - Cheap platform_meta now runs at 10 Hz; the position stream stays at 2 Hz.
    - Handbook: the 30 s hub dump checks the hub inventory's weight first and skips the
      per-stack dump when the weight is unchanged.
Version: 0.36.33
Date: 2026-10-24
  Fixed:
    - apply_requests selects a manual logistic section using LuaLogisticSection.is_manual.
      LuaLogisticSection.group is a string, not an object, so the previous group.name check
      never matched and writes were refused.
Version: 0.36.32
Date: 2026-10-24
  Fixed:
    - apply_requests writes a manual logistic section instead of sections[1], which was
      refused with "trying to change logistic section that is not manual".
    - The manager decodes the first JSON value from the mod's page output instead of
      rejecting trailing data, so resync can read platform_meta_page and hub dumps.
Version: 0.36.31
Date: 2026-10-24
  Added:
    - platform_report, the same adoption datagram the rocket handler sends, callable over
      RCON so the outbound/manager path can be tested without /c UDP.
Version: 0.36.30
Date: 2026-10-24
  Added:
    - on_entity_logistic_slot_changed triggers platform_requests, so a hub's request change
      is synced to the copies immediately instead of waiting for the cargo audit.
Version: 0.36.29
Date: 2026-10-24
  Fixed:
    - A platform deleted on the space server now removes its copy on every planet. The mod
      records the copies it creates, so a stale copy is removed while an unknown native
      platform is still kept and adopted.
    - Platform requests are written to the copy while players are connected. The previous
      empty-server guard meant a hub's new requests never reached the clone, so its
      logistics never queued rockets.
Version: 0.36.28
Date: 2026-10-24
  Fixed:
    - events.lua used an undefined instance() in the new platform-created and rocket-launch
      handlers. The rocket launch fired and failed with "attempt to call global 'instance'".
Version: 0.36.27
Date: 2026-10-24
  Added:
    - on_space_platform_created reports a new starter-pack platform to the manager directly,
      and on_rocket_launched rescans for any platform the fleet list does not contain.
      This replaces waiting for the planet mirror to discover it.
Version: 0.36.26
Date: 2026-10-24
  Fixed:
    - Any platform the fleet list does not contain is kept and reported for adoption. The
      hub test was also wrong: a native starter-pack platform can exist before a hub object
      is visible, so the mirror destroyed it as a stale copy.
Version: 0.36.25
Date: 2026-10-24
  Fixed:
    - An unknown hub platform on a planet is kept and reported even when its protection
      flags look like a copy's. copy_is_protected() matched native starter-pack platforms,
      so the mirror destroyed them instead of asking the space server to adopt them.
Version: 0.36.24
Date: 2026-10-24
  Changed:
    - Removed the connected-player guards from the platform mirror and the space-side
      platform creation. The join desync was the per-client GUI rebuild counter, not these
      world changes. A starter-pack platform is now adopted even when its owner is standing
      on the planet or the space server.
Version: 0.36.23
Date: 2026-10-24
  Fixed:
    - Removed the require cycle introduced in 0.36.22 (platforms -> outbound -> platforms)
      by requiring outbound lazily when reporting a native platform. 0.36.22 failed to load:
      "too many C levels" in platforms.lua.
Version: 0.36.22
Date: 2026-10-24
  Fixed:
    - A starter pack launched on a planet no longer deletes the platform the game creates
      there. A native platform the fleet list does not know is kept and reported; the
      manager has the space server create the real platform, and the next mirror pass turns
      the planet's platform into its protected copy. Previously the planet mirror treated
      it as a stale copy and destroyed it.
Version: 0.36.21
Date: 2026-10-24
  Fixed:
    - The server-list GUI rebuild signature is stored in `storage` by player name instead
      of a module table. A client's Lua state is recreated on every join, so its module
      table was empty and it rebuilt the GUI on each join while the server's persisted.
      That is the +18 custom-GUI element indices in the desync report.
  Fleet:
    - The manager and node now require the exact connector version. A node rejects an
      archive whose info.json does not match the requested version, refetches the pinned
      release, and restarts a running server when the mod set changes.
Version: 0.36.20
Date: 2026-10-24
  Reverted:
    - Removed the os.clock/game.tick timing instrumentation and the slow-call logs.
    - Removed the joining check, the 10-second mirror block after join/leave, and the join
      move log. The mirror and join rule are back to their pre-guard behavior.
    - The platform streams, the os fix and the platform cadence remain.
Version: 0.36.19
Date: 2026-10-24
  Added:
    - The join rule logs when it moves a character and which surface it came from. The
      teleport was silent on success, so the rejoin desync could not be attributed.
Version: 0.36.18
Date: 2026-10-24
  Fixed:
    - Removed every os.clock() use. Factorio's Lua sandbox does not expose os, so the
      platform metadata streams were erroring on every tick. Timing is now game.tick based.
    - The copy mirror refuses while a client is joining (connected but not yet in
      connected_players), and for 10 seconds after any join or leave. The mirror was running
      during the map-load window and changing copy entity state after the client had
      downloaded the map, which desynced vulcanus.
Version: 0.36.17
Date: 2026-10-24
  Fixed:
    - Pod tests use the owning entity's create_cargo_pod{cargo_hatch=...}, which reserves the
      source hatch; the hatch's own method rejected the call and the entity method without a
      hatch left the pod awaiting_launch.
Version: 0.36.16
Date: 2026-10-24
  Fixed:
    - Pod tests create the pod through the source cargo hatch's create_cargo_pod(), not the
      owning entity's. The hatch method reserves the launch hatch and starts the pod; the
      entity method left it awaiting_launch.
Version: 0.36.15
Date: 2026-10-24
  Fixed:
    - Cleanup includes the space hub-to-hub test pod.
Version: 0.36.14
Date: 2026-10-24
  Fixed:
    - space_platform_to_platform uses the first real item in the source hub instead of
      requiring space-platform-foundation, which the source may not hold.
Version: 0.36.13
Date: 2026-10-24
  Fixed:
    - Cleanup includes the force-drop and platform-to-planet test pods.
Version: 0.36.12
Date: 2026-10-24
  Added:
    - podtest force_drop: a real copy-hub pod to the planet surface (the force-drop/remove path).
    - podtest space_platform_to_platform: a real hub-to-hub pod on the space server, the native
      platform-to-platform path the bridge intentionally ignores.
    - platform_to_planet sets the landing pad and copy hub operable/destructible/minable before
      the pod, to test the station with no protection-side effect.
Version: 0.36.11
Date: 2026-10-24
  Fixed:
    - Cleanup includes the last platform-to-planet test pod.
Version: 0.36.10
Date: 2026-10-24
  Added:
    - podtest cleanup destroys the parked test cargo pods by unit number.
Version: 0.36.9
Date: 2026-10-24
  Changed:
    - The rocket test selects a silo whose status is rocket_ready, rather than the first silo,
      which may be empty.
Version: 0.36.8
Date: 2026-10-24
  Added:
    - rocket_to_platform pod test: load the silo rocket and launch it at the copy hub with
      rocket_silo.launch_rocket, which is the real planet-to-platform path.
Version: 0.36.7
Date: 2026-10-24
  Changed:
    - Pod test clears all three protection flags on the copy hub before creating the pod, to
      tell a non-station from a protected-station rejection.
Version: 0.36.6
Date: 2026-10-24
  Changed:
    - The planet-to-platform test falls back to a landing-pad cargo pod when the silo has no
      free hatch. The destination hub is the same, so the station/bridge path is unchanged.
Version: 0.36.5
Date: 2026-10-24
  Changed:
    - Pod test makes the copy hub operable before creating a planet-to-platform pod, to
      confirm whether non-operable is what makes the game clear the station.
Version: 0.36.4
Date: 2026-10-24
  Fixed:
    - The pod test picks an input-compatible, unreserved, non-busy cargo hatch. The first
      hub hatch was reserved and the game refused it; the copy hub exposes 33.
Version: 0.36.3
Date: 2026-10-24
  Fixed:
    - planet_to_platform test uses a rocket silo, not a cargo landing pad. A landing-pad pod
      to a space platform hub is not accepted by the game; the station is cleared and the pod
      waits.
Version: 0.36.2
Date: 2026-10-24
  Added:
    - The pod test reports the created pod's state and the hub/landing-pad cargo hatch counts, so a
      pod that does not launch can be diagnosed.
Version: 0.36.1
Date: 2026-10-24
  Fixed:
    - Cargo pod destinations use defines.cargo_destination.station, not the string "station";
      the string made the game refuse the destination.
    - platform_to_planet test now removes the cargo from the copy hub first, so the copy and
      the real hub both decrease; report mode shows both sides.
Version: 0.36.0
Date: 2026-10-24
  Added:
    - Planet <-> platform cargo bridge. A pod leaving a copy hub removes the same cargo from
      the real hub; a pod arriving at a copy hub adds it. Pods between real space hubs are the
      game's native logistics and are left alone.
    - The bridge queues each move in storage and re-sends for 60 seconds; the manager
      de-duplicates by event id for an hour. There is no RCON acknowledgement because an ack
      would write script storage from outside the game while a player is connected.
    - The manager applies the delta to the real hub on the space server with the copy's name
      and ordinal.
    - server-connector-mod-podtest can create a real cargo pod from a planet landing pad to a
      copy hub, or from a copy hub to a landing pad, and can enqueue a synthetic add/remove.
Version: 0.35.21
Date: 2026-10-23
  Changed:
    - The full platform meta runs every five seconds, not every second. A build/mine event
      still carries the layout immediately.
  Added:
    - /server-connector-mod-streams on|off is a per-server diagnostic. Off stops the platform
      UDP streams so the game's own cost can be measured; everything else keeps working.
Version: 0.35.20
Date: 2026-10-23
  Changed:
    - The continuous platform position/meta stream is 2 Hz instead of 10 Hz; the board does
      not redraw fast enough to use the difference.
    - The hub dump no longer reads the first page twice.
Version: 0.35.19
Date: 2026-10-23
  Changed:
    - The 10 Hz platform meta is now the cheap shape only: identity, position, state. The
      bay count, layout, asteroid/other counts and request hash moved to a 1 Hz full meta.
      Those walks were the mod's largest constant cost on the space server.
    - The hub cargo dump runs every 30 s instead of 10 s; the aggregate audit every five
      minutes instead of one.
    - The real space platforms no longer count "other" entities in the full meta; that
      walk is only meaningful for copies.
    - The layout is taken from the build/mine event, so a new bay reaches the copies without
      waiting for the next full meta.
  Added:
    - Log lines when the cheap meta, full meta, hub dump or audit exceed their budget, so a
      mod cost is measured instead of suspected.
Version: 0.35.18
Date: 2026-10-23
  Fixed:
    - copy_is_protected was defined before bay_list, so the mirror errored with "attempt to
      call global 'bay_list' (a nil value)" on a planet and the copy was left untouched.
Version: 0.35.17
Date: 2026-10-23
  Fixed:
    - The full bay layout in the RCON platform list made the space server's reply too large
      to decode ("invalid character '{' after top-level value"), which stopped every copy
      push. The layout now rides the 10 Hz UDP platform meta; the RCON list stays small.
Version: 0.35.16
Date: 2026-10-23
  Fixed:
    - Copy entities were only destructible=false, which does not stop mining, deconstruction
      or opening the hub. The hub and bays now also set minable_flag=false and operable=false,
      and a deconstruction order on a copy is cancelled.
    - Cargo and request writes to a copy now refuse if its bay count no longer matches the
      real ship, and an inventory insert/remove counts only what actually moved. A player
      who removed bays could previously make an insert silently stop at the reduced cap.
    - Kept copies were not re-protected after a repair; they are protected on every push.
  Added:
    - A build or mine on the real platform pushes its layout to the manager immediately,
      instead of waiting for the next poll.
    - The mirror log reports how many copies are unprotected.
Version: 0.35.15
Date: 2026-10-23
  Added:
    - The mirror log now reports, after every empty-server push, how many copies differ from
      the ship layout, hold any entity other than the hub/bays, or hold an asteroid. A clean
      line is the check that the copies are the ship.
Version: 0.35.14
Date: 2026-10-23
  Fixed:
    - Copies are protected (destructible=false), and a protected platform survived
      destroy(0) even though the call reported success. Removing a copy now clears
      destructible on its hub and bays, cancels any earlier schedule and destroys on the
      next tick, which is the pattern that worked in 0.35.6.
Version: 0.35.13
Date: 2026-10-23
  Fixed:
    - A copy that differs only in bay layout or extra entities is repaired in place instead
      of being destroyed and recreated. The recreate path used destroy() without a deletion
      argument, left the old copy on the server and made the copy count grow on every push.
    - Removing a copy uses destroy(0), and a failed removal is logged with the error.
Version: 0.35.12
Date: 2026-10-23
  Changed:
    - A planet copy now reproduces the real platform's hub-and-bay layout, not a ring of the
      same number of bays. The manager sends the bay offsets from the real hub.
    - Each empty-server mirror push compares the copy with the ship. A missing hub, a
      different bay count/layout or any other entity rebuilds the copy; asteroids are
      destroyed on every push.
  Added:
    - server-connector-mod-platforms reports each platform's bay count, layout hash,
      asteroid count and other-entity count as JSON.
Version: 0.35.11
Date: 2026-10-24
  Fixed:
    - The platform metadata read a cargo_bays key the platform class does not have, so
      every bay count was nil. It is counted from the cargo-bay entities on the platform
      surface, and the platform page now shows it.
Version: 0.35.10
Date: 2026-10-24
  Fixed:
    - Cargo and request sync addressed a copy by name. A name can belong to several
      platforms, so the first match won and a duplicate could receive another platform's
      cargo. The manager now sends the ordinal within the name, and the mod selects the
      platform by that order.
    - The manager's platform store keyed entries by name and collapsed duplicates; it now
      keys by name and index, so the platform page shows every platform.
Version: 0.35.9
Date: 2026-10-24
  Fixed:
    - Copies were matched by platform name, but the fleet has several platforms with the
      same name, so a planet held 12 copies of 16 platforms. Copies are now grouped by
      name and paired by the real platform's index, so every platform gets its own copy.
Version: 0.35.8
Date: 2026-10-24
  Fixed:
    - A platform that is docked or in transit has no location or connection, and the
      manager sends that as an empty string. The copy builder treated it as a name and
      failed with "Unknown space-location name", so those platforms never got a copy.
    - The mirror log now states how many copies the server actually holds, so a missing
      copy is visible in the log rather than inferred.
Version: 0.35.7
Date: 2026-10-24
  Fixed:
    - Planet servers hold the fleet's platform copies again, as the hub plus the same
      number of cargo bays as the real platform, with no asteroids and no way to damage
      them.
    - Copies are made, kept and pruned only from the manager's RCON list. The boot,
      configuration-change and leave handlers no longer touch platforms, so a client
      never applies a platform change of its own and has nothing to diverge on.
    - The platform list now reports each platform's cargo-bay count.
Version: 0.35.6
Date: 2026-10-24
  Fixed:
    - Old planet platform copies now cancel a previously scheduled deletion and destroy one
      tick later, so the copy and its asteroid chunks are actually removed.
Version: 0.35.5
Date: 2026-10-24
  Fixed:
    - The asteroid sweep runs only on planet instances; space and custom instances such as
      blueprint-world are left alone.
    - Old fake platform copies are destroyed immediately (destroy(0)) instead of being
      scheduled for deletion, so their asteroid chunks go with them.
Version: 0.35.4
Date: 2026-10-24
  Fixed:
    - Planet servers remove old fake platform copies on init, configuration change and
      the last player leaving. The 0.35.3 cleanup only ran when the manager pushed a
      changed platform list, so copies already on a planet survived the update.
Version: 0.35.3
Date: 2026-10-24
  Changed:
    - Planet servers hold no platform copies. The copies were fake platforms at a space
      location: they spawned asteroid chunks, the sweep removed them, and their state
      diverged from the server while a player hopped planets -- desyncing on rejoin.
      The real platforms live on the space server; use the space map.
Version: 0.35.2
Date: 2026-10-23
  Fixed:
    - The fake-platform protection reads cargo bays from the platform surface. The
      LuaSpacePlatform class has no cargo_bays key, so 0.35.1 refused the platforms call
      and the hub protection threw.
Version: 0.35.1
Date: 2026-10-23
  Fixed:
    - Fake platform copies are no longer deleted by asteroid chunks. The copy's hub and
      cargo bays are made indestructible, and the existing one-second sweep keeps
      destroying the chunks. The engine has no per-platform asteroid spawn switch:
      hidden only removes it from the remote-view list, and paused only stops thrust and
      schedule.
Version: 0.35.0
Date: 2026-10-23
  Added:
    - platform_meta(): the cheap platform call (identity, position, state, bays, request hash),
      pushed at 10 Hz from every server, copies included.
    - platform_hub_dump({index, cursor, limit}): the heavy call, paged so a platform of any
      size never goes in one datagram; cargo and requests, with a hash and a done flag.
    - platform_audit(): raw item totals summed across platforms, for the manager's drift report.
    - apply_cargo_delta({platform, ops}) and apply_requests({platform, requests}): the only
      mutations; the manager computes the difference, Lua applies it.
    - Every UDP push now carries origin, origin_epoch and seq, so a save restart is visible to
      the manager.
  Changed:
    - Cargo dumps are sent only when the hub hash changed (checked every 10 s); metadata is
      the 10 Hz stream. The manager reassembles pages and does all diffing and fan-out.
Version: 0.34.0
Date: 2026-10-22
  Changed:
    - No data path uses stdout/log any more. The mod is pure RCON (calls into the game) plus
      localhost UDP (events, platform positions, research). The once-a-second report and
      platform JSON on stdout is gone.
Version: 0.33.9
Date: 2026-10-22
  Fixed:
    - UDP sends use helpers.send_udp, the API that actually exists, instead of game.send_udp.
Version: 0.33.8
Date: 2026-10-22
  Added:
    - The space server pushes every platform's serialized position (location, connection,
      distance, docked, paused) over localhost UDP every 6 ticks.
    - Research progress is pushed over UDP once a second only when it moved, with the delta
      and the queue; every research queue/selection event is pushed as well.
    - The manager keeps the last platform-position and research payloads and exposes them at
      /api/fleet/platform-positions and /api/fleet/research-udp.
Version: 0.33.7
Date: 2026-10-22
  Added:
    - A platform changing state (docking, leaving, arriving) is pushed as a server-side
      localhost UDP event to the one-container app, which exposes the last events at
      GET /api/fleet/events.
Version: 0.33.6
Date: 2026-10-22
  Changed:
    - The mod's outbound facts (telemetry, platforms, queued events) are written to stdout
      once a second as SCMOD|kind|json, so the node no longer needs an RCON round trip to
      read them. Inbound calls remain RCON; nothing is written to stdin.
Version: 0.33.5
Date: 2026-10-22
  Fixed:
    - Foreign-surface cleanup runs once per save, not on every topology push. Deleting the
      nauvis chunks after a client had loaded the map was the desync on the join tick.
Version: 0.33.4
Date: 2026-10-22
  Changed:
    - A join no longer touches the controller, the character, the editor, the remote or the
      inventory. It only teleports the player's existing body onto the surface this server
      holds. Every controller change was a world change the client did not make.
    - The non-nauvis servers remove the nauvis surface (its chunks included) as part of the
      foreign-surface check.
Version: 0.33.3
Date: 2026-10-22
  Fixed:
    - The flat surface replacement happens once, not on every topology push. Without the
      marker the unchanged branch deleted and recreated the flat Main repeatedly, wiping it.
Version: 0.33.2
Date: 2026-10-22
  Fixed:
    - The unchanged-topology branch now applies the declared surface forms too. It only ran
      the foreign-surface cleanup, so a declared flat surface that already existed was never
      replaced when the manager kept sending the same topology. This is why blueprint-world
      stayed mixed.
Version: 0.33.1
Date: 2026-10-22
  Fixed:
    - An instance declared as an editor is an editor again. The editor branch is the
      instance's declared mode, not a fallback; blueprint-world uses it. Every other server
      still gives the player its own character.
Version: 0.33.0
Date: 2026-10-22
  Changed:
    - Every server gives the player its own character on its own surface. The editor, god
      and remote fallbacks are gone from the join rule: a foreign copy is detached and a new
      character is created; if that cannot happen the player is disconnected rather than left
      in the bodyless physical controller. Each server is a separate life.
Version: 0.32.9
Date: 2026-10-22
  Fixed:
    - A declared flat custom surface that already exists in the save is now replaced with
      the flat form once. The create branch only handled a missing surface, so a old mixed
      world was carried forward every conversion and the flat form was never applied.
    - The foreign-surface cleanup no longer deletes platform surfaces on a planet. Those
      are the copies the planet needs to see the fleet's platforms, and deleting them was
      the world change behind the join-tick desync.
Version: 0.32.8
Date: 2026-10-22
  Changed:
    - The reported surface list omits nauvis on every server except the nauvis server. The
      homeworld cannot be deleted, so a stripped, empty copy is in every converted save; it
      is not a surface that server serves.
Version: 0.32.7
Date: 2026-10-22
  Changed:
    - The cross-server body tracker no longer decides a join. Each server gives the player
      its own body on the surface they joined on: attach a character already there, else
      detach a foreign copy and create one. The space server has no living body and gives
      the remote controller.
    - The server strip has no caption and is pinned to the top; it is no longer a draggable
      window.
Version: 0.32.6
Date: 2026-10-22
  Fixed:
    - A planet or custom save no longer keeps the space server's platform surfaces; they are
      foreign there. The space save now keeps its platforms and removes every non-platform
      surface, instead of skipping the cleanup entirely. Both run only with nobody connected,
      so no join is made a world change.
Version: 0.32.5
Date: 2026-10-22
  Changed:
    - A map click connects immediately again. Telling the manager first is kept, but the
      held connect read as a dead button and the target's short remote view is preferable.
Version: 0.32.4
Date: 2026-10-22
  Fixed:
    - A body whose home is the server it is stored on was indistinguishable from never having
      been told, so that server read it as nauvis and made its owner a remote viewer. The mod
      remembers that the manager has spoken.
    - A join never destroys a character and only creates one on the body's home when the save
      holds none; a copy on a foreign surface puts the player in the remote controller.
  Changed:
    - A topology that arrives while somebody is connected applies its destinations and
      refreshes the map immediately; surface creation waits for the last player to leave.
    - A map click tells the manager the destination and holds the connect for six seconds, so
      the target has the body's new home before the player arrives.
Version: 0.32.3
Date: 2026-10-22
  Fixed:
    - A remote viewer's character copy is left alone on join. Destroying it there was the
      world change the client did not see, and the join still desynced with the copy's
      inventory. The player is put in the remote controller; the copy stays on its surface.
    - The server map frame is shown in the remote controller, not only on the chart. A viewer
      could not reach the buttons that move them to another server.
Version: 0.32.2
Date: 2026-10-22
  Fixed:
    - A join no longer moves a character to another surface. That teleport is a server-side
      world change the client does not see, and it desynced the joining player. A character
      found on a surface this instance does not own is removed as a copy instead.
    - A player with no recorded body is parked on nauvis. If the join lands on nauvis and this
      world holds no character for them, one is created there, so a player with no body
      anywhere gets a nauvis body rather than the observer controller.
  Changed:
    - set_body_location only stores the body. It arrives over RCON, and applying a controller
      or character change to a connected player is a world change the client never sees; the
      stored body is applied by the join rule the next time they join.
Version: 0.32.1
Date: 2026-10-20
  Added:
    - research_all() unlocks every technology on this force. It is what a custom instance
      whose research mode is "all" is given; it never reports anything back.
    - A surface's form carries its seed, whether it generates cliffs, and its water size.
      create_custom_surfaces applies them on top of the chosen planet template.
  Changed:
    - ensure_surfaces removes surfaces this instance does not own, so the planet copies the
      old layout made disappear from existing saves. The space server is left alone: its
      platforms are what it owns, and they are not declared.
  Fixed:
    - A custom instance never contributes research to the fleet, whatever its mode says.
Version: 0.32.0
Date: 2026-10-20
  Changed:
    - No fake surfaces. A server creates only the surfaces it owns: its planet, the custom
      surfaces declared for it, or nothing at all on the space server, whose platforms are
      built. Another server's planet is no longer copied here, and the join fallback that
      cleared those copies is gone.
    - The way to another server is the server map: a list of buttons shown while the map is
      open, one per other instance, labelled with its name. A click connects. The vanilla
      space map is disabled, because it would offer a planet with no surface behind it.
    - The topology is instance-centric: name, address, kind, editor, primary and the list of
      surfaces an instance owns. No public copies and no owner id.
    - report().bodies counts a character on any surface this instance owns, not only one
      named after the instance.
    - A custom instance can give its players the editor controller on join.
    - create_surfaces takes the manager's surface forms: flat tile, planet-template
      generation, peaceful, no enemies, day length, solar, wind and cold.
  Added:
    - delete_surface(name) removes one custom surface. It refuses while anybody is
      connected, and refuses the primary.
  Fixed:
    - route_for, route_if_elsewhere and destination_for are gone with the surface-change
      trigger they existed for.
Version: 0.30.2
Date: 2026-10-19
  Changed:
    - Every event handler and both commands contain their own failure. An error from a
      handler is non-recoverable in Factorio: the server quits, and the fleet's watchdog then
      stops the other five without saving. A fault is now a log line and the handler returns.
    - The writes in the join rule (destroying a character, both set_controller calls) and the
      position lookup in enforce_surface are wrapped individually, so one refusal is a log
      line and the rest of the rule still runs.
    - A failed connect_to_server is logged and retried on the next surface change, instead of
      raising from the routing handler and leaving the player marked as handed over.
Version: 0.30.1
Date: 2026-10-19
  Fixed:
    - A player joining with their character on a different surface no longer takes the
      server down. set_controller refuses an entity from another surface and that error is
      not recoverable, so the body is put where it belongs first and the controller is only
      attached once the two surfaces agree.
    - report() only counts the bodies this server owns. A character on another planet's
      surface in this save is not this server's body; claiming it made the manager state a
      home the character was not standing on.
Version: 0.30.0
Date: 2026-10-19
  Changed:
    - A world change driven over RCON is refused while anybody is connected: set_instance,
      set_topology and create_surfaces answer skipped and write nothing. The node already
      retries an identity push until it takes, and the manager now retries a skipped topology
      push instead of reading it as applied.
    - set_instance and set_topology answer unchanged when they are told what they already
      hold. Re-pushing the same identity no longer clears the recorded body locations, and
      an identical topology with nobody connected still repairs missing surfaces.
    - set_topology drops entries with no address and compares two topologies as sets.
    - A platform surface counts as owned on every server, so a planet server's copies are no
      longer cleared by the join fallback.
    - platform_api only reads. The probes that moved a platform, unpaused it or created one
      are gone.
    - A hand-set startup setting is a working fallback again; the default, unconfigured,
      still leaves the mod inert.
  Fixed:
    - destination_for returns nil when the topology holds no entry with an address for the
      surface, and route_if_elsewhere checks the address before handing over. Looking at a
      platform on a fleet with no space server is no longer an error.
    - report() no longer depends on storage.viewing existing, so a missing table cannot cost
      the manager its whole telemetry.
    - clear_foreign_chunks collects a surface's chunks before deleting any of them; deleting
      while walking the iterator could skip entries or raise.
    - The asteroid sweep carries on past a platform it could not clear, instead of stopping
      for every other platform too.
    - game.planets and is_space_location_unlocked are read under pcall, so a build without
      Space Age cannot take ensure_surfaces down.
    - mirror_platforms collects the copies to remove before destroying them, and reports only
      the removals that took.
    - apply_research clamps the progress it is given to 0..1.
    - set_body_location reports destroyed_character when it destroyed a connected player's
      character here, and only changes a controller for a player who is connected.
    - The -call command refuses a player. Identity, research, pause and the probes are no
      longer reachable from chat.
    - The empty on_player_left_game handler is gone.
Version: 0.29.0
Date: 2026-10-19
  Added:
    - report() now includes bodies: the characters each world holds, whether their player is
      connected or not.
Version: 0.28.0
Date: 2026-10-18
  Changed:
    - Not recorded.
Version: 0.27.0
Date: 2026-10-18
  Changed:
    - Not recorded.
Version: 0.26.0
Date: 2026-10-18
  Changed:
    - Joining a server now puts a player on that server's own surface straight away, instead of
      waiting for their first surface change. Landing somewhere else and having to click their
      way across was the join being treated as a look rather than an arrival.
Version: 0.25.0
Date: 2026-10-18
  Changed:
    - Conversion is gone from this mod. Cutting a world down to the one surface a server keeps
      -- the tick-bounded strip, delete-and-recreate, and the per-surface primitives -- moved to
      the private converter mod the manager installs for the length of a conversion and removes
      afterwards. This mod routes, reports, researches and settles; it does not cut worlds down.
  Added:
    - A join fallback: a player joining can generate chunks on a surface this server does not
      own, and those are taken off at once. It is one join's worth, and it is the only clearing
      left here.
Version: 0.24.1
Date: 2026-10-17
  Fixed:
    - A surface's chunks are found by asking the world for them (get_chunks, tolerant of the
      shape it hands back) instead of walking a window around the origin. A 170MB world has
      chunks far from anywhere and every one of them is a chunk of a surface nobody wants.
    - surfaces() says which of them are platforms, because a space server keeps its platforms
      and they cannot be named in advance -- they are built.
Version: 0.24.0
Date: 2026-10-17
  Added:
    - delete_surface_chunks(name): delete one surface's chunks and everything on it. This is
      the primitive a conversion is driven with -- one surface per call, the node deciding
      which and in what order, because a sequence of steps belongs to the node and the mod is
      only the way into the game's components.
    - surfaces(): what surfaces this world has, so the node can walk them one by one.
Version: 0.23.3
Date: 2026-10-17
  Fixed:
    - The world work no longer runs on a load or on a tick. Both run on every client as well
      as the server, and a client that is joining reports no connected players while the
      server sees one -- so the client cleared surfaces the server had kept, and the game
      desynced the moment it noticed. Surfaces, the spawn point and clearing happen only on
      an order (settle), and only with nobody connected: a world change made here is not
      replicated, so it must never happen while anybody can be comparing.
Version: 0.23.2
Date: 2026-10-17
  Fixed:
    - World changes happen only with nobody connected. They are driven by orders that arrive
      over RCON, and RCON-driven world changes are NOT replicated to clients: the server cut
      a surface down and the client, never told, kept it -- "Multiplayer desynchronisation:
      crc test failed" on join, every time. Clearing, the spawn move, the strip and the
      platform mirror all run empty now, and the boot-time work is re-armed when the last
      player leaves so a busy fleet still gets it done.
Version: 0.23.1
Date: 2026-10-17
  Fixed:
    - The strip step says what it does and what fails. It was called under pcall with nothing
      logged, so a strip that made no progress for eight minutes left every counter at zero
      and no word about why. The handler logs its error, a surface the job cannot find names
      itself, an empty surface says so, and a job with nothing to strip says that too.
Version: 0.23.0
Date: 2026-10-17
  Added:
    - Stripping a world is a job now, not one call. A 170MB world cannot be stripped inside
      an RCON round trip: the work outlives the timeout, the reply comes back empty, and an
      empty reply looks exactly like a refusal -- so the manager retried, the retry started
      the work again, and the world came out untouched while the conversion reported success.
      strip_begin starts it, a permanent on_tick handler does a batch every tick,
      strip_status says where it has got to, strip_finish returns the summary, and
      strip_cancel stops it. Every step is wrapped and says what it did.
Version: 0.22.4
Date: 2026-10-17
  Fixed:
    - The space server no longer mirrors itself. It is where the platforms really are, so a
      list derived from them must not be applied back to them: a list one poll old dragged
      the real platform back to where it had been, and a pause read from it re-paused it.
      That loop is why the copies and the real platform kept reverting.
Version: 0.22.3
Date: 2026-10-17
  Added (probes):
    - Unpausing the real platform, so the copies can be watched following it both ways.
    - Which logistic member index a hub's requests live on, asked of the game rather than
      read out of the defines page.
Version: 0.22.2
Date: 2026-10-17
  Fixed:
    - 0.22.1 did not parse: the helper that reports refused position writes was put inside the
      interface table, where a local function cannot go. Every server running it refuses the
      mod. It is a top-level local again, and the parse is checked before anything is
      released -- the check caught it and the release ran on regardless, which is its own
      fault to fix.
Version: 0.22.1
Date: 2026-10-17
  Fixed:
    - The position writes on a copy say why they were refused. They were wrapped and silent,
      and a silent refusal is indistinguishable from a copy that follows: the write happens,
      nothing changes, nobody is told. Three faults today were hidden by that pattern.
Version: 0.22.0
Date: 2026-10-17
  Added:
    - A copy follows the real platform: the position fields the manager pushes (space
      location, connection, distance, paused) are applied to a copy that already exists, each
      write made only when it differs and wrapped, because these are the game's setters on
      something that is, on a planet server, only a copy.
Version: 0.21.4
Date: 2026-10-16
  Fixed:
    - A planet server's copies have no asteroids, ever. One sweep when a copy was made was
      not enough: a copy sits at a space location and spawns them regardless, so the sweep
      runs every second from a handler registered once at load. There is no switch for it --
      spawning comes from the location and a platform has to be at one to exist -- and the
      space server's platforms keep theirs, because asteroids are part of what a real
      platform is.
Version: 0.21.3
Date: 2026-10-16
  Fixed:
    - Creating a platform passes both required fields. planet is a space location and
      starter_pack is space-platform-starter-pack, which the game's own prototypes name --
      asked for with plate rather than guessed.
Version: 0.21.2
Date: 2026-10-16
  Changed:
    - platform_api asks the game for the starter pack's item name, because creation requires
      one and a guessed name is the third guess today the game has had to correct.
Version: 0.21.1
Date: 2026-10-16
  Fixed:
    - mirror_platforms walked the list it was sent with ipairs, and nothing was made: the
      JSON is decoded by the game's own helper and the shape that comes back is the helper's
      business. It walks either shape now, and reports how many entries it saw and how many
      were usable, so a list that arrives unusable says so instead of looking like a fleet
      with no platforms.
Version: 0.21.0
Date: 2026-10-16
  Added:
    - mirror_platforms(entries): make, keep or remove this server's copies of the fleet's
      platforms, as ordered by the manager. A copy is a hub and its cargo -- the starter pack
      and nothing else -- with no asteroid spawning and nothing that can damage it: nothing
      here runs a platform. A platform that has left the list is removed, because a copy of
      something that no longer exists is a lie players can stand on.
Version: 0.20.0
Date: 2026-10-16
  Added:
    - platforms(): what this server's platforms are -- name, index, state, location,
      connection, distance, paused, whether it has a hub, hidden, and how long until it is
      deleted. Read-only, and every field is one the runtime docs list for LuaSpacePlatform.
      A planet server reports none, which is a real answer rather than an error.
    - platform_api(): the creation call the docs name (LuaForce::create_space_platform) tried
      with a couple of shapes under pcall, so its arguments come from the game rather than
      from a guess. Two of this fleet's outages were guessed calls.
Version: 0.19.0
Date: 2026-10-16
  Changed:
    - The mod does nothing at all until a node tells it what it is. It is a driver: it
      reaches into the game's components and the node decides what is done with them, the
      order coming in over stdin and the event going out over stdout. A server that never
      hears from a node -- somebody's own save, a server with nothing to do with this fleet
      -- never gets an identity, and now every action in the file does nothing: no surfaces
      created, no players moved, no chunks cleared, no scenario touched. Loading it changes
      nothing.
Version: 0.18.4
Date: 2026-10-16
  Fixed:
    - The sweep had two copies of itself and the older one was the live one -- in Lua the
      last definition wins -- so it still called get_chunk, the method this build does not
      have, and cleared nothing on any server while reporting an error per surface. One
      copy, and it asks the surface API rather than assuming it.
Version: 0.18.2
Date: 2026-10-16
  Fixed:
    - The sweep no longer asks for a chunk with a method this build of the game does not
      have (get_chunk), which threw from a boot-time handler and took clearing down with it
      -- including the report of what had already been taken off. The entities go first and
      now always report; chunks are deleted only if delete_chunk is there at all.
  Added:
    - surface_api, which reports which of these calls the game actually has, so the next
      question about it is answered by the game rather than guessed at.
Version: 0.18.1
Date: 2026-10-16
  Fixed:
    - 0.18.0 did not start. The spawn-position check called get_spawn_position with no
      argument where the API wants one, and the error came out of a boot-time tick handler,
      which is non-recoverable: every server running it quit as it loaded. The spawn
      position is set on the surface this server is for instead of being compared with
      anything, and every step of the boot work is wrapped, so a fault in one of them is a
      log line rather than a fleet that will not start.
Version: 0.18.0
Date: 2026-10-16
  Added:
    - A player standing somewhere they do not belong is put back on the surface this server
      owns. It happens only when they are not on that surface, and only after
      route_if_elsewhere has had its turn: looking at another server's planet is a journey
      and connect_to_server takes them there, and a redirect already in flight counts as
      handled, so nothing fights the connection being made.
    - A surface this server does not own is cleared on boot: every creature on it is
      destroyed and the chunks around the origin are deleted. A fleet server's save is a
      nauvis world whatever planet the server is for, so nauvis is generated -- spawn area
      and biters -- before anybody arrives, and on five of the six servers nobody ever goes
      there. Those biters are a UPS cost paid every tick by a server playing elsewhere.
    - The spawn point moves to the surface this server is for, so a player arriving without
      a body does not generate a fresh spawn area -- biters and all -- on a surface that was
      just cleared.
    - clear_surfaces, so the manager can ask for the same thing after loading a save.
  Changed:
    - The report says which surface the spawn point is on and what the last clear took.