# Architecture Ultimate Tool is one deterministic development core with several thin surfaces on top of it. The CLI, the loopback service (with its embedded dashboard), and the stdio MCP adapter all call the same versioned core operations; none of them implements build, run, diagnostics, or evidence logic of its own. ## Workspace layout The Cargo workspace (`Cargo.toml`) contains five crates: | Crate | Role | | --- | --- | | `ultimate-tool-core` | The development core: manifests, build/run orchestration, targets, evidence, reports. | | `ultimate-tool-cli` | The `ultimate-tool` binary. Parses commands and calls core operations. | | `ultimate-tool-server` | The loopback HTTP service and embedded dashboard assets. | | `ultimate-tool-mcp` | The stdio MCP adapter that talks to a running service. | | `ultimate-tool-c64` | The `no_std` C64 SDK statically linked into C64 programs. | The C64 fixtures (`fixtures/rust-mos-smoke`, `fixtures/rust-mos-timeline`, `fixtures/checkpoint-demo`) are excluded from the workspace because they are built by their own toolchains (Rust-MOS via the pinned Docker image, and the RISC-V fixtures via GNU RISC-V Embedded GCC). ## The core `ultimate-tool-core` (`crates/ultimate-tool-core/src/`) is organized by responsibility: - **Configuration and inputs** — `config` (manifest `c64dev.toml` parsing and schema versions), `model` (shared value types such as `TargetKind`, `TargetIdentity`, `RunOutcome`, `FailureRecord`, `HeartbeatSummary`). - **Build and artifact** — `build` executes the declared build command and captures outputs; `artifact` validates and hashes the primary PRG plus any declared supporting artifacts. - **Orchestration** — `runner` drives the build-to-evidence path for a test request and a test matrix, `lease` provides bounded exclusive target access, `progress` emits structured progress events to an observer. - **Targets** — `target` holds the `Target` trait and its adapters. - **Observation and analysis** — `diagnostic` parses the versioned mailbox events, `crash` and `crash_analysis` handle crash state and site resolution, `analysis` snapshots and normalizes declared map/ELF symbol sources, `insight` evaluates build budgets and run comparisons, `timeline` and `trace` cover the 6510 debug-stream timeline. - **Evidence and records** — `evidence` writes run records and their files, `integrity` verifies a finished run against its `SHA256SUMS`, `runs` lists and pages immutable run history. - **Read-only readers** — `doctor` inspects local prerequisites without launching commands, `report` assembles a diagnostic report from an existing run record. - **Trusted-native paths** — `ue2`, `native`, `native_runner`, `riscv`, and `riscv_runner` implement UE2 packaging, launch intents, and the RISC-V runtime. ### The `Target` trait Every execution target implements `target::Target`. The trait is the single boundary the runner uses, so the same test request can run against any adapter: ```rust pub trait Target { fn identity_key(&self) -> String; fn probe(&mut self) -> Result; fn deploy_reu_image(&mut self, artifact: &SupportingArtifact) -> Result<()>; fn deploy_and_start(&mut self, artifact: &Artifact) -> Result<()>; fn read_memory(&mut self, address: u16, length: usize) -> Result>; fn write_memory_coordinated(&mut self, address: u16, bytes: &[u8]) -> Result<()>; fn sample_screen(&mut self, screen_address: u16, color_address: u16) -> Result { self.capture_screen(screen_address, color_address) } fn capture_screen(&mut self, screen_address: u16, color_address: u16) -> Result; fn finish(&mut self) -> Result<()>; fn mutations(&self) -> Vec; fn retry_count(&self) -> u32; fn recovery_count(&self) -> u32; fn cpu_resumed(&self) -> Option; } ``` The adapters are: - `target::fake` — a deterministic target used by fast core tests. It does not execute C64 instructions; it produces reproducible observations so the orchestration, classification, and evidence path can be tested without hardware, Docker, or VICE. - `target::vice` — drives VICE `x64sc` 3.8, using coordinated binary-monitor writes for the versioned startup command. - `target::ultimate` — the C64 Ultimate over its REST/DMA interfaces, with `target::ultimate_dma` handling the DMA-service REU writes. Mutation is gated by a fresh identity probe and explicit reset/REU-write confirmations. Target selection is by `TargetKind` (`Fake`, `Vice`, `Ultimate`) rather than product-name assumptions, and target actions are gated by discovered capabilities. ## Execution planes A run records which execution plane produced it (`ExecutionPlane` in `evidence`): the ordinary C64 plane (`C64`), the volatile U64-II RISC-V updater (`UltimateRiscvUpdater`), or the 6510 debug-stream capture (`UltimateDebugStream`). This keeps emulator, physical-C64, RISC-V, and bus-capture results distinguishable in one history. ## Data flow 1. A surface loads a manifest (`config`) and builds a `TestRequest`. 2. `runner` executes the declared build command (`build`) and validates the artifacts (`artifact`). 3. `analysis` snapshots and normalizes any declared symbol sources; `insight` evaluates declared build budgets before any target mutation. 4. The selected `Target` adapter probes identity, performs any authorized mutations, and observes the program. 5. `diagnostic` / `crash` / `crash_analysis` classify the outcome. 6. `evidence` writes one immutable run directory under `.ultimate-tool/runs//` and its `SHA256SUMS`; `integrity` later verifies it. A run directory is never updated in place. Rerunning a test produces a new run ID, and readers reject unsupported future schemas explicitly. ## Surfaces ``` +-----------------------------------------------------------+ | ultimate-tool-core | | manifest (c64dev.toml) -> build -> artifact -> runner | | runs & evidence analysis/budgets reports doctor | +----------------+------------------------------+-----------+ | | Target trait adapters Surfaces - fake (deterministic, no execution) - CLI ultimate-tool - vice (x64sc 3.8) - serve loopback dashboard - ultimate (C64 Ultimate, gated) - MCP stdio adapter ``` - **CLI** (`ultimate-tool-cli`) exposes every operation directly. The outer result envelope is schema 1. - **Service** (`ultimate-tool-server`) binds only to `127.0.0.1`, owns one manifest per process, and serves the embedded dashboard. Mutating HTTP requests require a per-process token and same browser origin. Its outer envelope is schema 13. See [HTTP_API.md](HTTP_API.md). - **MCP** (`ultimate-tool-mcp`) wraps the running service over stdio. Its outer envelope is schema 12. See [MCP.md](MCP.md). The dashboard is plain embedded HTML/JavaScript/CSS with no frontend build step. It requests only GET diagnostics against the same core-backed routes the CLI uses; the report computation happens in the core, not in the browser. ## Reporting `runs report` and `runs report-items` (and their service and MCP equivalents) assemble a diagnostic report from a single existing run record. The inner report is schema 1 on every surface, while the outer envelopes differ (CLI 1, HTTP 13, MCP 12). A finalized run verifies its registered evidence before any detail is presented, and a provisional run exposes only its in-record observations. Detail rows are paged with cursors bound to the run, the section, and the source evidence hash. See [DIAGNOSTICS.md](DIAGNOSTICS.md) and [CONTRACTS.md](CONTRACTS.md). ## Contracts and versioning Manifests, run records, evidence bundles, and the service/CLI/MCP operations are versioned independently from their first implementation. See [CONTRACTS.md](CONTRACTS.md) for the current schema versions and error codes.