mmdflux 2.2.0

Render Mermaid diagrams as Unicode text, ASCII, SVG, and MMDS JSON.
Documentation
# Architecture Dependency Rules

This document defines the steady-state dependency and ownership rules for the
mmdflux Rust crate. The module tree should tell one coherent story for
contributors:

- `frontends.rs` owns source-format detection
- `mermaid/` owns Mermaid source ingestion
- `diagrams/` own compilation and instance behavior
- `payload/` owns the runtime payload contract
- `builtins/` owns default registry wiring for the supported low-level API
- `graph/` owns graph-family IR, float-space geometry, and shared policy/measurement helpers
- `engines/` own engine adapters and internal algorithm boundaries such as `algorithms::layered::kernel`
- `render/` owns output production
- `mmds/` owns the MMDS contract and output helpers

The repo-owned architecture gate should fail when the code drifts away from
these rules.

The repo-owned architecture gate is `cargo xtask architecture` or
`just architecture`.

The semantic boundaries guard reads its declarative module-dependency policy
from the repo-root
[`boundaries.toml`](/Users/kevin/src/mmdflux-semantic-architecture/boundaries.toml).
Set `SEMANTIC_BOUNDARIES_CONFIG` to point at a different file when reusing the
checker outside this repo. The semantic-only command is
`cargo xtask architecture check` or `just architecture-check`.
The normal one-shot command always works on its own. If a matching
`cargo xtask architecture host` process is already running for this worktree,
the one-shot command may reuse that warm host automatically; otherwise it
falls back to the local runner with no extra setup. Use
`cargo xtask architecture check --status` to inspect the local host state
for this worktree, or `cargo xtask architecture check --fresh` to bypass
host reuse and force a fresh local run. The watch-hosted architecture host
uses Unix sockets on macOS/Linux and a named-pipe transport shape on Windows.
The Windows client path still falls back locally today, so Windows
contributors do not need any extra socket setup.

## Public Contract Tiers

- The high-level runtime facade is `render_diagram`, `detect_diagram`,
  `validate_diagram`, plus the flat config/format/error types re-exported from
  `lib.rs`.
- The supported low-level API is `builtins`, `registry`, `payload`, `graph`,
  `timeline`, and `mmds` for adapter-oriented workflows that need explicit
  payload construction, graph IR inspection, or MMDS replay control.
- `diagrams`, `engines`, `render`, and `mermaid` are internal implementation modules.
  They are intentionally documented here for contributors, but they are not part
  of the supported low-level contract.

The repo also locks in three directory-module shell replacements for former
mega-files. These shells are part of the steady-state layout and should not be
collapsed back into singleton roots:

- `src/render/graph/svg/edges/mod.rs` is the directory-module shell replacing
  the removed `src/render/graph/svg/edges.rs`
- `src/graph/grid/routing/mod.rs` is the directory-module shell replacing the
  removed `src/graph/grid/routing.rs`
- `src/graph/routing/orthogonal/mod.rs` is the directory-module shell
  replacing the removed `src/graph/routing/orthogonal.rs`

## Core Rules

1. **frontends own input formats** — Source-format detection lives in
   `src/frontends.rs`. Runtime detects the frontend first (`mermaid`, `mmds`),
   then resolves the logical diagram type and family pipeline. Mermaid parsing
   itself lives in the separate top-level `src/mermaid/` namespace.

2. **diagrams do not parse source text directly** — Diagram modules
   (`src/diagrams/`) consume frontend-owned models and compile them into
   logical family IR or family-local runtime models.

3. **diagrams do not render**`src/diagrams/` stop at detection, parse
   delegation, compilation, and `into_payload()` orchestration. Diagram
   instances hand runtime a `payload::Diagram` instead of calling
   renderers directly. Output production lives under `src/render/`, not under
   diagram modules.

4. **render/ owns output production** — All rendering code lives under
   `src/render/`. There is no top-level `formats/` ownership boundary and no
   graph render tree under `src/graph/`. Within `render/`, the shared
   `render::text` and `render::svg` utility layers stay foundational and
   independent of each other: `render::graph` and `render::timeline` may
   depend on them, but not the other way around, and `render::text` and
   `render::svg` must not directly depend on each other either.

5. **render::graph owns geometry-based graph-family emitters** — Shared
   graph-family text and SVG emission lives under `src/render/graph/` and
   consumes `GraphGeometry`, `RoutedGraphGeometry`, or graph-owned
   `graph::grid` layouts. High-level geometry entrypoints stay at the
   `render::graph` root, low-level text drawing lives under
   `render::graph::text`, and routed SVG emission is explicit through
   `render_svg_from_routed_geometry`. Render code does not take
   `GraphSolveResult` or instantiate engines.

6. **runtime owns graph-family solve-result dispatch**`src/runtime/`
   resolves graph-family output formats from engine solve results and owns the
   final dispatch to MMDS serialization or geometry-based renderers. Runtime
   does not own renderer implementations.

7. **render::diagram owns family-local renderers** — Timeline/chart/table
   renderers that do not use the shared graph-family pipeline live under
   `src/render/diagram/`.

8. **graph/ owns graph-family IR, float-space geometry, and shared policy/measurement helpers**   `src/graph/` contains reusable graph-family models, solved and routed
   geometry, direction policy, and shared graph-family grid/proportional
   measurement and routing helpers. The graph-owned `graph::grid` namespace is
   the derived grid-space layer for float-to-grid conversion, grid routing, and
   replay geometry contracts. Output emission does not live under `src/graph/`,
   but graph-family routing, derived grid geometry, and shared sizing/policy do.

9. **mmds/ is a pure interchange format layer**`src/mmds/` owns the
   typed MMDS envelope, profile vocabulary, Mermaid regeneration helpers,
   hydration to graph IR, and MMDS serialization for graph-family output.
   mmds must not import from `render` or `engines`. Replay rendering
   (hydrate→render dispatch) lives in `runtime/mmds.rs`.

10. **MMDS is a frontend, not a logical diagram type** — MMDS input handling
    is detected through `src/frontends.rs`, while the MMDS parse, hydration,
    and output helpers live under `src/mmds/`. MMDS is not registered
    in the logical diagram registry.

11. **engines do not know about diagram types or output formats** — Engine
    implementations (`src/engines/`) solve generic graph layout problems and
    own layout building / measurement adapters. They may use shared
    graph-family helpers, but they never reference flowchart, class, sequence,
    or other logical diagram types, and they do not import render-owned
    modules. Engine solve requests stay in engine-owned vocabulary:
    grid/proportional measurement plus canonical/visual geometry contracts.
    Render-format mapping (`Text`, `Svg`, `Mmds`) happens above the engine
    layer in graph-family orchestration, and path simplification remains a
    downstream render/MMDS consumer concern. Within graph-family engines,
    `algorithms::layered::kernel` is the pure graph-agnostic layered engine
    boundary, while the outer `algorithms::layered` root owns the graph-family
    bridge code such as layout building / measurement adapters, float layout,
    and float routing. `layered::kernel` stays internal; it is a contributor
    boundary, not a supported public contract.

12. **flat top-level contract modules own the stable public contract**    Stable public format and error vocabulary live in `src/format.rs` and
    `src/errors.rs`. `RenderConfig` lives in `src/runtime/config.rs`
    (re-exported from `lib.rs`). Diagnostics live in `errors`, family
    classification in `registry`, and style types in `graph/style`.
    Adapter orchestration entrypoints are curated runtime facade re-exports
    from `lib.rs`. Other namespaces are either part of the supported
    low-level API or internal implementation modules.

13. **runtime/ is orchestration only** — The runtime layer detects input
    frontends, resolves logical diagram types, manages the registry, consumes
    runtime payloads, and wires the pipeline. Graph-family runtime
    dispatch lives under `src/runtime/`; runtime itself does not own Mermaid
    grammars, layout algorithms, or renderer implementations.

14. **registry is contract-only infrastructure**`src/registry.rs` defines
    reusable registry contracts (`DiagramRegistry`, `DiagramDefinition`,
    `DiagramInstance`) and does not import concrete diagram modules. Built-in
    diagram wiring lives in the separate public `builtins` namespace.

15. **timeline::sequence owns shared sequence runtime types** — Shared
    sequence-family model and layout types live under `src/timeline/sequence/`
    so the final text renderer can depend on a neutral timeline namespace
    instead of importing `diagrams::sequence`.

## Adapter Rules

16. **web main.ts is composition only** — The web playground's `main.ts` is a
    composition root that wires stores, services, and controllers. It does not
    contain application logic, state management, or rendering orchestration.

17. **wasm adapter is a thin boundary**`crates/mmdflux-wasm` deserializes JS
    requests, calls the Rust facade, and serializes responses. It does not
    duplicate config parsing, registry logic, or format selection.

18. **CLI adapter is a thin boundary**`src/main.rs` maps CLI flags to the
    Rust facade contract and formats output. It does not contain business logic
    beyond argument mapping.

## Deferred Friction

See [deferred-friction.md](./deferred-friction.md) for architecture friction items
that have been reviewed and deliberately deferred, each with a specific trigger
condition for when to revisit.