Files
settled-reach/governance/rejected/architecture.md
T
jpmschweitzerandClaude Opus 5 bbd64307ab docs(governance): D-263 — one CLI named reach, and Q-124 answered
Q-124 asked whether the 123-file Python tooling should be retooled into a
Rust CLI. The answer is no, and it is a costing rather than a preference.
All three frictions it names — per-script permission prompts, the venv/PATH
split between interactive and non-interactive shells, and interpreter
startup paid four times per push — are packaging problems, and one bare
command on PATH with lazy subcommand loading fixes all three. Rust would
additionally owe a numerical-equivalence proof on the planet-gen path,
whose heightmaps are committed build artefacts with goldens standing on
them: a large one-time cost to avoid a small recurring one, paid in the
currency the project can least afford to spend.

D-263 fixes the shape. tooling/ becomes an installable package behind the
`reach` command: a routing-only main.py, every domain under domains/<name>/
split router/service/schemas/helpers, a core/ bounded on day one to what
has no domain, logging and error handling attached as decorators rather
than call-site discipline, and pydantic confined to domain schemas —
measured at 87 ms against a whole gate check of 20-46 ms, which is why it
must never reach the push path. Failures carry the command that fixes them
and keep their exit code; a tool that explains itself and exits 0 silently
disables its own gate.

R-014 records the Rust option as costed down, not argued down, with the
condition under which it is worth reopening. T-1247 files the work as
eight dependency-ordered epics; only the skeleton is unblocked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 02:32:21 +02:00

5.4 KiB

Rejected Alternatives — Architecture

Rejected proposals in the architecture domain, rationale preserved for the audit trail.

R-001: Stellaris mod

  • Rejected: 2026-02-08
  • Reason: Character system too shallow, multi-empire assumption conflicts with the Settled Reach's single-civilization focus, wormhole-as-infrastructure not achievable within Stellaris modding. Team Leader's experience with Star Trek: New Horizons confirmed that even well-suited IPs struggle with character connection in Stellaris.

R-002: CK3 total conversion

  • Rejected: 2026-02-08
  • Reason: Would require building a space map from scratch within CK3's framework - essentially building a game inside a game. The map system fundamentally doesn't support the complexity needed.

R-003: Other existing games (Distant Worlds 2, GalCiv IV, Sins of a Solar Empire II, Victoria 3)

  • Rejected: 2026-02-08
  • Reason: Each captures at most 40% of what's needed. Smaller modding communities, less mature tools, and none solve the core CK3+Stellaris hybrid requirement.

R-004: Pure Bevy (Rust) — no Godot

  • Rejected: 2026-02-09
  • Reason: No visual editor (level design is code-only). UI framework in flux. API breaks significantly between versions. For a solo developer who needs visual tools for hand-crafted buildings (D-014), Godot's editor is a massive productivity advantage. Bevy's ECS is used — just not its renderer.

R-005: Pure Godot (GDScript or C#)

  • Rejected: 2026-02-09
  • Reason: Scene tree paradigm fights ECS-style simulation. Perception queries (D-017) and information boundaries (D-010) map naturally to ECS component queries, not scene tree traversal. Multi-core scaling for expanded content impossible in GDScript. Kept as kill-switch fallback if Rust architecture exceeds time budget.

R-006: Godot + Rust via GDExtension

  • Rejected: 2026-02-09
  • Reason: gdext is pre-1.0 with breaking API changes. Godot version upgrades break GDExtension ABI. Thread safety at FFI boundary is CRITICAL risk (Gd<T> is !Send/!Sync). Couples Rust and Godot learning curves. Subprocess/IPC achieves the same architecture without the FFI risk surface, and maps directly to D-010 client-server. See docs/architecture/risk-godot-rust-bridge.md for full analysis.

R-007: Godot + C++ via GDExtension

  • Rejected: 2026-02-09
  • Reason: More mature bindings than gdext, but trades Rust's safety guarantees for C++ memory unsafety. No advantage over subprocess/IPC approach. Developer not experienced in C++.

R-008: Fyrox (pure Rust engine)

  • Rejected: 2026-02-09
  • Reason: Single maintainer. ~1/50th of Godot's community. Less documentation, fewer tutorials, weaker AI training data for Claude Code. Single-maintainer risk unacceptable for multi-year project.

R-009: Custom framework (Rust + raylib/macroquad)

  • Rejected: 2026-02-09
  • Reason: Maximum control but you build everything — tilemap rendering, camera, UI, audio, input, asset pipeline. Months before testing a mechanic. The game's hard problems are simulation, not rendering — don't reinvent the rendering wheel.

R-010: protobuf for client-server serialization

  • Rejected: 2026-02-09
  • Reason: Schema evolution across independent deployments is a problem we don't have (one developer, client and server ship together). Poor GDScript support. Rigid schema fights dynamic HUD composition driven by perception modes (D-017). MessagePack's schema-optional nature fits better.

R-014: Rust rewrite of the Python tooling

  • Rejected: 2026-08-20 — superseded by D-263 (one Python CLI, reach), which answers Q-124.
  • Reason: Costed down, not argued down. All three frictions that motivated it — per-script permission prompts, the venv/PATH split between interactive and non-interactive shells, and interpreter startup paid four times per push — are packaging problems, and each is fully solved by one bare command on PATH with lazy subcommand loading. None of them requires a different language. Against that, Rust would have to prove numerical equivalence for the numpy/scipy/PIL planet-gen path, whose heightmaps are committed build artefacts with goldens standing on them — a genuine porting problem, not a transliteration. It would also make one-off analysis expensive, trading a small recurring cost for a large occasional one in the place the project can least afford it. A hybrid (Rust for the four push-gate checks only, Python for the rest) was also rejected: it reintroduces the two-doors problem the whole exercise exists to remove.
  • Not rejected on principle. The quality bar this proposal was reaching for — pql-calibre, one binary, no interpreter — is the right bar, and D-263 adopts it wholesale minus the language. If the check/gate family ever becomes the dominant push cost after lazy loading is measured, this is worth reopening for that family alone, with the measurement in hand.