pipecircuit-visualization 0.0.3

Code-derived architectural visualizations for Pipecircuit programs
Documentation

Pipecircuit visualization

pipecircuit-visualization derives reviewable architecture diagrams from a crate's Rust source. It walks the crate's module tree, finds every explicit StateMachine and StepInputOf implementation, follows imports, and expands each outcome enum into its variants.

No diagram-specific step list is maintained:

use pipecircuit_visualization::{CrateArchitecture, DiagramTarget};

let architecture = CrateArchitecture::read(env!("CARGO_MANIFEST_DIR"))?;
let players = architecture.state_machine("Players")?;
let snapshot = players.render(DiagramTarget::TextTree);

The uncolored text tree is intended for expect tests and redirected output. AnsiTextTree gives its role markers a terminal-safe lime treatment. The same graph can be projected to MermaidFlowchart for Markdown and browser tooling or GraphvizDot for Graphviz, SVG, and image generation.

The separately installable pipecircuit-cli package exposes the interactive surface:

pipec diagram Players

It selects ANSI text only for an interactive terminal and honors NO_COLOR.

Generation fails when a referenced local type, module, state machine, input, or outcome cannot be resolved. Procedural macros that generate StepInputOf implementations are not source-visible on stable Rust and are not currently supported; step implementations themselves must remain ordinary Rust. This keeps incomplete diagrams from masquerading as complete ones.

Behavior expectations

Keep a behavior.rs snapshot module beside a machine's tests and architecture expectation. Its inventory discovers the compiled tests automatically:

use expect_test::expect;
use pipecircuit_visualization::{BehaviorError, BehaviorInventory};

#[test]
fn behavior_remains_reviewable() -> Result<(), BehaviorError> {
    expect![[r#"
        - Equal sentences retain their distinct code locations
        - Listing order does not change the inventory
    "#]]
    .assert_eq(&BehaviorInventory::for_snapshot(module_path!())?.render());
    Ok(())
}

Register this dedicated child module with #[cfg(test)] mod behavior;. The inventory includes tests below its parent module and excludes its own module. Renaming, adding, or removing a check changes the expectation. Review the diff, then accept it with UPDATE_EXPECT=1 cargo test behavior_remains_reviewable.

Discovery asks the current test executable for its list; it neither reruns the checks nor starts Cargo. Macro-generated tests, including property tests, are included. Names become alphabetically sorted sentence bullets; duplicate sentences retain their code locations, and ignored tests carry [ignored].

This is a review aid, not evidence that a named claim passed. The ordinary verification run supplies that evidence. Discovery covers only the current libtest target and compiled features: other test targets, doctests, and Kani proof harnesses are not included. No production dependency or runtime instrumentation is needed in a consuming application's semantic core; use this library as a dev-dependency.

Browser-only checks need a host-side snapshot: the browser cannot launch a test executable or update source files. Supply a configured listing command to the same inventory instead of reimplementing discovery or rendering:

use std::process::Command;

let mut runner = Command::new(env!("CARGO"));
runner.current_dir(env!("CARGO_MANIFEST_DIR")).args([
    "test", "--target", "wasm32-unknown-unknown", "--lib", "--",
]);
let inventory = BehaviorInventory::for_snapshot_with_runner(
    "my_app::wiring::tests::behavior",
    runner,
)?;

The scope names the module in the listed target. The helper appends the standard listing flags and queries all checks and ignored checks separately. WASM discovery lists compiled exports without starting a browser; run the actual browser suite independently to verify those claims. Keep runner setup in the host test harness and the expectation in behavior.rs beside its owning browser tests. The existing UPDATE_EXPECT=1 workflow is unchanged.