pipecircuit-visualization 0.0.11

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:

```rust
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:

```text
pipecircuit 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:

```rust
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. Mount
the snapshot under the same relative module hierarchy in the host harness:

```rust
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(
    module_path!(),
    runner,
)?;
```

For example, a browser snapshot at `wiring::tests::behavior` must remain a
`behavior` child of `wiring::tests` in the host harness, not be flattened into
a differently named module. The crate-name prefix may differ; the relative
module path determines the scope. No handwritten qualified scope is needed.

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.

## Compiled program and installation views

**Experimental development scaffolding — not ready for application consumption.**
These rudimentary views support framework review. Their APIs and presentation
need further design; expansion is deferred while authoring and performance work
progress. This status applies to program/installation inspection, not the existing
state-machine architecture and behavior tooling above.

`pipe_roster!` derives `DescribeRoster` from the named pipe declarations.
Roster-bound `MioPipeSet` records derive `DescribeBindings` from the actual
installed fields. Inspection therefore needs no parallel inventory:

```rust,ignore
let program = ProgramDiagram::<program::Schema>::for_board::<NpcConversationProgram>();
let semantic = program.render(DiagramTarget::TextTree);
let physical = program.installed(&pipes).render(DiagramTarget::MermaidFlowchart);
```

The board must use the selected roster, and the bindings must name that same
roster. Text, Mermaid and Graphviz include pipe families, carrier types and
package/file/line/column locations. Rendered type names abbreviate module paths;
`pipes()` and `bindings()` preserve qualified diagnostic labels. Compiler type
names are not stable protocol identifiers or wire revisions. This renderer
currently emits plain text for both text targets.

These are declared boundary views, not inferred route or reachability graphs.
Switchboard decisions, remote placement, compatibility and transport health
cannot be deduced from Rust type names. Dashed graph edges identify the In/Out
families and installation relation only.

The underlying metadata iterators and Mio `ready_sources().statuses()` borrow
existing structures or return fixed-size values, without allocation. Source
statuses expose retained activation hints and ready/paused state, in storage
order; inspecting them neither dispatches nor resumes work. An absent source
is not evidence of a healthy pipe. The source table's capacity bounds this
observation, not the occupancy of every transport queue.

`ProgramDiagram` and its renderers allocate in this optional std tooling crate.
Use them in development tools or examples, outside measured steady-state work.
Keep `pipecircuit-visualization` a dev-dependency when semantic libraries must
remain no_std.

For a directly usable browser artifact, call `render_html()` on either view and
write the returned string to an HTML file. The standalone page works offline,
uses native disclosure controls for exact types and declaration locations, and
can hide the physical layer while preserving the logical pipes. It requires no
JavaScript, Mermaid installation or web service. Text, HTML and graph views name
message directions from each pipe's perspective: emits to the switchboard (Out),
receives from the switchboard (In).

Ordinary Rust documentation on roster roles and installed fields travels with the
compiled metadata. Write the role's purpose beside its declaration and describe
physical choices beside the installed field. These descriptions explain the
structure; they are not proofs of behavior. HTML treats them as plain escaped
text, including documentation containing markup. Optional tooling allocates to
render them; metadata iteration still uses static strings and fixed arrays.