# Spec: crate workspace — core, terminal, Bevy, assets ``` Type: spec Status: IMPLEMENTED Status note: landed 2026-07-10. This page is the **standing** package architecture: shape, contracts, and the reasons they exist — not a one-shot migration checklist. Knowledge page architecture.md mirrors as-built paths; amend this page when package boundaries change. Stage: Process Design: - wiki/vision/simulation-laws.md#justification-and-legibility - wiki/process/living-spec.md#the-corpus-rule - wiki/process/living-spec.md#no-dead-code Depends on: - wiki/process/agent-scale.md#spec-agent-scale-architecture-many-agents-one-main - wiki/engineering/architecture.md#architecture - wiki/process/workflows.md#workflows ``` ## Dependency notes - [agent-scale.md](../process/agent-scale.md) — multi-agent gates and claims map onto these packages (`--lib` ≈ core/terminal; `--frontend` ≈ bevy/assets). - [architecture.md](architecture.md) — knowledge mirror of as-built layout and the sim/frontend contract (non-authoritative where this page conflicts). - [workflows.md](../process/workflows.md) — how to run cargo and check.sh against packages. ## Why the workspace exists The game law was already clear: **rules in the lib; frontends are thin views.** A single Cargo package with optional Bevy features did not enforce that law. It only *suggested* it: 1. **Compile graph** — Any `src/` touch shared one feature matrix with Bevy. Agents paying for a sim-only fix still rebuilt (or risked rebuilding) the heavy frontend graph. Tiered `check.sh` path heuristics papered over a boundary the crate graph did not draw. 2. **Mental model** — One package trained agents to treat “the crate” as the unit of work. Contending on one `Cargo.toml` and one local-package personality made parallel worktrees thrash. 3. **False coupling** — Feature flags (`terminal`, `bevy_ui`) are switches, not walls. They do not stop a frontend from re-implementing a rule “just this once,” and they do not prove that core is free of Bevy. The workspace makes the law **structural**: - A core agent can `cargo test -p misaligned-core` without Bevy in the graph. - A Bevy agent does not rebuild terminal chrome. - Package edges are the same cut as the sim/frontend contract. This is a **spread-out codebase on purpose** — less monolith, more packages with narrow jobs — so many agents can work without contending on one product crate. ## As-built shape (binding) ``` Cargo.toml — virtual workspace only (members, shared deps, profiles) crates/ misaligned-core/ — sim library (package name); lib name `misaligned` misaligned-terminal/ — binary `misaligned` (crossterm + agent protocol) misaligned-bevy/ — binary `misaligned-bevy` (Bevy 0.18 frontend) misaligned-assets/ — shared art lib + `misaligned-assets` / `misaligned-effects` ``` There is **no** root `src/` product tree and **no** feature-flag substitute for these packages. Optional features must not re-merge package jobs. ### Why four packages (not two, not twenty) | Package | Job | Why it is separate | |---|---|---| | **core** | All game rules, save format, sim tests | Must stay free of render/input toolchains so sim work stays cheap and deterministic. | | **terminal** | Player/agent text surface + wall clock | First-class frontend; must not pull Bevy; must not own rules. | | **bevy** | Material/digital 3D/2.5D view + shot harness | Heavy compile graph; isolated so frontend thrash does not block sim agents. | | **assets** | Shared meshes/effects plus focused art harnesses | Reusable render code without loading the full game loop; no sim progression. | **Not** one umbrella `misaligned-frontends` package: that would keep terminal and Bevy compile-coupled and erase the frontend-tier win. **Not** one crate per mechanics module: coordination cost exceeds compile win until a real module boundary demands it (see out of scope). ### Naming choices (and why) | Choice | Why | |---|---| | Package `misaligned-core`, **lib name `misaligned`** | Frontends keep `use misaligned::…` so imports and mental model stay “the sim,” not a rename churn. Package name states the *job* (core); lib name states the *product*. | | Binary names `misaligned`, `misaligned-bevy`, `misaligned-assets`, `misaligned-effects` | Product names and each focused art harness stay explicit. | | Directory prefix `crates/misaligned-*` | Workspace-local, greppable, matches package names. | ### Dependency edges (and why) ``` misaligned-terminal ──► misaligned-core misaligned-bevy ──► misaligned-core ──► misaligned-assets (shared rack / mesh spawn) misaligned-assets ──► bevy only (no core, no sim progression) misaligned-core ──► serde, serde_json, dirs ✗ bevy, crossterm ``` - **Bevy → assets** exists so rack chassis meshes are not copy-pasted into the game binary. Assets remain free of `Sim` so the tester does not boot a run. - **`dirs` in core** is allowed only for **save-path infrastructure** on the save format (where the JSON file lives), not for wall-clock or network I/O as game rules. Sim progression still does not read the environment for behavior switches (see env registry: game rules are not env-toggled). - **No shared `CARGO_TARGET_DIR` across worktrees** for local packages — already caused a false green. Dependency caches (e.g. sccache) may be shared; local package artifacts stay private (agent-scale / seed script). ### Package contracts (standing) | Package | May contain | Must not contain | |---|---|---| | `misaligned-core` | `Sim`, map, systems, save format, rule tests | Bevy, crossterm, wall-clock-driven rules, `Instant::now` as game time, env reads that change rules | | `misaligned-terminal` | UI, input, agent line protocol, wall-clock → tick | Game-rule `if`s that belong on `Sim` | | `misaligned-bevy` | View, shot harness, wall-clock → tick | Game-rule forks of `Sim` behavior | | `misaligned-assets` | Mesh/effect render code, asset tester, effects lab | Full-run save/load; sim progression | Frontends talk to core through **command/query methods** and read state for render — same contract as [architecture.md](architecture.md) “The sim/frontend contract,” enforced by package edges. ### Gates map onto packages (why tiers work) | Change class | Default gate | Why | |---|---|---| | docs | `./tools/check.sh --docs` | No product graph. | | lib / sim | `./tools/check.sh --lib` | Core (+ terminal clippy) + cheap `cargo check -p misaligned-bevy` so API breaks still surface without full Bevy clippy. | | frontend | `./tools/check.sh --frontend` | Bevy + assets only. | | full / CI | `./tools/check.sh --full` / Tangled | Whole workspace; conservative. | Path classification keys off `crates/misaligned-*`, not a single `src/`. ## What this is *not* - A claim that four packages are forever enough — only that further splits need a new reason as strong as the ones above. - Permission to put game rules in a frontend “temporarily.” - Permission to reintroduce feature flags as the real boundary between jobs. - A mandate to micro-crate every mechanic. ## Rejected alternatives (keep these rejected) - **Stay one package, smarter features only** — features are not walls; agents still share one product crate and one mental model. - **core + one `misaligned-frontends` umbrella** — terminal and Bevy stay compile-coupled; loses proportional frontend gates. - **Shared `CARGO_TARGET_DIR` across worktrees for speed** — produced a false green; forbidden for local package artifacts. - **Rename the lib to `misaligned_core` in Rust code** — huge import churn for no boundary gain; package name already states the job. ## Standing acceptance criteria These remain true for the life of the layout (not a one-time land checklist): 1. The repo is a Cargo **workspace** with at least `misaligned-core`, `misaligned-terminal`, `misaligned-bevy`, and `misaligned-assets`. 2. `misaligned-core` has **no** dependency on `bevy` or `crossterm`. `cargo test -p misaligned-core` does not build Bevy. 3. Game rules live only in core; frontends do not re-implement sim rules. 4. Binary names remain `misaligned`, `misaligned-bevy`, `misaligned-assets`, `misaligned-effects` unless a deliberate product rename is specced. 5. `./tools/check.sh` auto-classification and documented tiers key off packages; CI enforces a conservative full workspace gate. 6. [architecture.md](architecture.md) stays an accurate as-built mirror; ROADMAP conflict language names packages/hot modules under core. 7. Save format ownership stays in core; migrations do not move into frontends. 8. **Why sections above stay true** — if a future change weakens a reason (e.g. Bevy back in core “just for types”), amend this page in the same commit or reject the change. ## History (non-authoritative) Implemented 2026-07-10 from a READY deferred work order. Pre-split form was a single package with optional `terminal` / `bevy_ui` features under root `src/`. Migration detail lives in `wiki/log/2026-07-10-crate-workspace.md`.