Skip to content

feat: compiled-program visualizer (shared graph spec + CLI render) - #184

Merged
abrichr merged 1 commit into
mainfrom
feat/program-visualizer-20260720
Jul 20, 2026
Merged

feat: compiled-program visualizer (shared graph spec + CLI render)#184
abrichr merged 1 commit into
mainfrom
feat/program-visualizer-20260720

Conversation

@abrichr

@abrichr abrichr commented Jul 20, 2026

Copy link
Copy Markdown
Member

See what a demonstration compiled INTO

A compiled bundle is a governed program, not a video. This adds a way to see its structure — the ordered steps, how each target is re-resolved, whether an identity gate protects the click, what real system-of-record effect must hold, what the screen must look like afterward, its risk class, and where the run will halt rather than guess.

Program graph of the OpenEMR showcase bundle

One spec, three surfaces (this PR = engine + CLI)

The engine is the single source of truth. openadapt_flow.visualize.build_program_graph(workflow) projects a compiled Workflow onto a versioned, serializable ProgramGraphSpec. Every visualization surface — this CLI, the cloud view (app.openadapt.ai), the desktop app — renders that spec; none re-parse the bundle IR. Companion cloud + desktop PRs render the same spec.

Spec (v1): nodes = compiled steps/program states (each with its target-resolution ladder + top rung, identity gate armed/unarmed+reason, effect check, verification postconditions, risk class, control guards); edges = sequence with typed room for branch/loop/exception/loop_body; per-node halt points as first-class annotations; bundle header with PHI/encryption flags, provenance/certification, params, rollups. A linear bundle projects to a straight chain of action nodes ending in a success terminal; a Phase-2 program graph projects its full state machine 1:1, so richer structure renders without a spec break.

Committed JSON Schema schemas/program-graph-v1.json lets non-Python surfaces validate the same shape; a sample emitted spec is at docs/showcase-openemr/program-graph.json.

Rendering choice & tradeoffs

  • Engine emits the spec; surfaces render it (vs each surface re-parsing the bundle) — one projection of the compiled semantics, one wire contract, and cloud/desktop need no Python engine.
  • Custom lightweight layout, not a graph lib — the program is a vertical sequence with room for branches, and the value is the per-node annotations, far clearer as node cards than edges-and-boxes. A graph lib (d3/cytoscape/reactflow) is heavy overkill and would break the self-contained/CSP-safe requirement. Mermaid offered as a portable secondary format; JSON for tooling.
  • Self-contained HTML — inlines the shared CSS + a dependency-free vanilla-JS renderer and embeds the spec as JSON, so it opens offline under a strict CSP. The desktop (Tauri, CSP `'self'`) vendors those same two files; cloud reimplements the same layout in React over the same spec.

CLI

```bash
openadapt-flow visualize path/to/bundle -o program.html # self-contained HTML
openadapt-flow visualize path/to/bundle --format mermaid # Mermaid flowchart
openadapt-flow visualize path/to/bundle --format json # shared graph spec
```

What's here

  • openadapt_flow/visualize/{spec,builder,render}.py + static/program_graph.{css,js} (the shared renderer).
  • schemas/program-graph-v1.json, CLI visualize subcommand, docs/VISUALIZE.md.
  • 11 tests (tests/test_visualize.py): projection counts, resolution ladder/top-rung, identity-gate + halt-point surfacing, JSON roundtrip, self-contained-HTML assertion, Mermaid validity, schema-in-sync validation, CLI, and a regression against the real committed OpenEMR showcase bundle (18 steps, 2 irreversible, 3 identity gates, 1 halt point).

Verification

  • pytest tests/test_visualize.py → 11 passed; existing lint/report tests still green.
  • ruff check + ruff format --check clean; mypy openadapt_flow/visualize/ clean.
  • The rendered example (docs/showcase-openemr/program-graph.{html,png}) is produced by the CLI from the committed bundle.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM

See what a demonstration compiled INTO. Adds `openadapt_flow.visualize`, which
emits a shared, serializable program-graph spec from a compiled bundle and
renders it, plus an `openadapt-flow visualize` CLI subcommand.

The engine is the single source of truth: `build_program_graph(workflow)`
projects a compiled Workflow onto a versioned `ProgramGraphSpec` (nodes = steps
with their target-resolution ladder, identity gate, effect check, verification
postconditions, risk class, and control guards; edges = sequence with typed
room for branches/loops/exception paths; per-node HALT points as first-class
annotations). Every visualization surface (this CLI, cloud, desktop) renders
THIS spec; none re-parse the bundle IR. A linear bundle projects to a straight
chain of action nodes; a Phase-2 program graph projects its full state machine.

- `visualize/spec.py` — the wire contract (pydantic models).
- `visualize/builder.py` — bundle -> spec projection (honest; never fabricates
  structure the compiler did not produce).
- `visualize/render.py` — self-contained HTML (inlines the shared CSS + a
  dependency-free vanilla-JS renderer, CSP-safe, opens offline) and a Mermaid
  flowchart source.
- `visualize/static/program_graph.{css,js}` — the ONE shared renderer the CLI
  inlines and the desktop (Tauri) view vendors verbatim.
- `schemas/program-graph-v1.json` — committed JSON Schema so non-Python surfaces
  validate the same shape.
- CLI `visualize <bundle> [--format html|mermaid|json] [-o OUT]`.
- Tests (11) + a rendered example of the committed OpenEMR showcase bundle
  (docs/VISUALIZE.md, docs/showcase-openemr/program-graph.{json,html,png}).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM
@abrichr
abrichr merged commit 144dd82 into main Jul 20, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant