Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Entries for unreleased work are not written here directly. Each issue drops a
fragment in [`changelog.d/`](changelog.d/README.md); the fragments are assembled
into a version section at release. See that README for the format and for when a
change warrants an entry at all.

## [0.1.0] 2026-08-22

First release: authoring, observing, and debugging components for the
[statifier](https://hex.pm/packages/statifier) statechart engine, consuming
its effect stream through the language-neutral trace wire format (format
version 1). The Livebook inspector is the first assembled frontend; the
panes underneath it are pure folds any other frontend can render.

### Added

- `StatifierUI.Diagram.render/2` renders a compiled machine and an active
configuration as Mermaid `stateDiagram-v2` source for `Kino.Mermaid`, with
composite nesting, parallel regions, active-state highlighting, and
cross-hierarchy transitions lifted to the composite level with a
`[lifted: ...]` marker.
- `StatifierUI.EventLog.build/1` folds a trace message stream into a log
grouped by `(macrostep, round)`, ordered by the producer's stamps rather
than arrival, and `StatifierUI.EventLog.Markdown.render/2` renders it as
collapsible Markdown for `Kino.Markdown`, with wire-format indexes
resolved to state and transition names by `StatifierUI.EventLog.Labels`.
- `StatifierUI.EventInjection.build/1` turns an ADR-0003 fixture bundle
(or `nil`) into the event-injection pane model: a sorted palette of
editable event buttons via `StatifierUI.EventInjection.Palette`, a
`free_form_only?` flag for the fixture-less degraded mode, and
`send/2`/`send_draft/3` to deliver a `StatifierUI.EventInjection.Draft`
through `Statifier.Session.send_event/2` - the ordinary recordable input
path, per statifier ADR-0029.
- `StatifierUI.DatamodelExplorer.build_authoring/3` and `build_live/2` build
a read-only datamodel tree - document `<data id>` declarations, spec
5.10.1 system variables, predicator provider functions in scope, and
either a fixture scenario or a live session's datamodel with entries
marked `changed?` per macrostep - and
`StatifierUI.DatamodelExplorer.Markdown.render/2` renders it as Markdown
for `Kino.Markdown`.
- `StatifierUI.Kino.inspect/3` assembles the Livebook inspector: the
configuration diagram, datamodel explorer, event injection, and event
log panes composed over one shared subscriber, live-updating, detaching
cleanly on cell re-evaluation. Compiled only when the optional `:kino`
dependency is present.
- `StatifierUI.Trace.Subscriber.attach/3` accepts `catch_up: true`: on a
session started with `record: true` the missed prefix is replayed into
the buffer atomically with the subscription (statifier ADR-0049); an
unrecorded session falls back to live delivery with a `:not_recorded`
diagnostic the inspector surfaces as "Live-only".
- `StatifierUI.Inspector` - the pure pane-assembly fold the Kino shell
renders, usable by any other frontend.
- `notebooks/inspector.livemd` - the demo notebook, doubling as the
milestone's manual acceptance test.
- Serializes statifier's `DatamodelChange` effect as the
`effect.datamodel_change` wire type, so consumers can observe datamodel
values as they are written instead of only the variable names
`session.datamodel` carries. New types are additive under the wire
format's must-ignore rule.
- Every `effect.*` wire message carries the engine's `round` stamp in
its envelope, alongside `macrostep` and `microstep`; consumers reading
older recorded streams must still tolerate `effect.*` messages without
the key.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,22 @@ stamps them with `(macrostep, round)` counters, and retains source locations on
states, transitions, and expressions. A UI is one more interpreter of those
effects; the engine needs nothing changed to support it.

## Installation

```elixir
def deps do
[
{:statifier_ui, "~> 0.1"}
]
end
```

The `:kino` (Livebook) and `:phoenix_live_view` integrations are optional
dependencies - add whichever your host actually renders with.

## Status

Early. Nothing is published to hex yet, and the engine dependency is a git dep
until statifier publishes. The first milestone is the Livebook inspector:
Early. The first milestone is the Livebook inspector:
`StatifierUI.Kino.inspect/3` over a running `Statifier.Session` -
[`notebooks/inspector.livemd`](notebooks/inspector.livemd) walks it end to end.

Expand Down
8 changes: 0 additions & 8 deletions changelog.d/sui-67d.md

This file was deleted.

7 changes: 0 additions & 7 deletions changelog.d/sui-h92.md

This file was deleted.

7 changes: 0 additions & 7 deletions changelog.d/sui-t36.4.md

This file was deleted.

8 changes: 0 additions & 8 deletions changelog.d/sui-t36.5.md

This file was deleted.

9 changes: 0 additions & 9 deletions changelog.d/sui-t36.6.md

This file was deleted.

9 changes: 0 additions & 9 deletions changelog.d/sui-t36.7.md

This file was deleted.

16 changes: 0 additions & 16 deletions changelog.d/sui-t36.8.md

This file was deleted.

57 changes: 52 additions & 5 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule StatifierUI.MixProject do
use Mix.Project

@version "0.1.0-dev"
@version "0.1.0"
@source_url "https://github.com/riddler/statifier-ui"

def project do
Expand All @@ -15,6 +15,8 @@ defmodule StatifierUI.MixProject do
name: "StatifierUI",
description: "UI components for authoring, observing, and debugging statifier statecharts",
source_url: @source_url,
docs: docs(),
package: package(),
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
Expand All @@ -33,12 +35,47 @@ defmodule StatifierUI.MixProject do
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_env), do: ["lib"]

# Hexdocs configuration. These paths are read off the publisher's disk at
# `mix docs` time and need no entry in package()'s files: list - the docs
# tarball hexdocs hosts is built separately from the package tarball
# `mix deps.get` fetches.
defp docs do
[
name: "StatifierUI",
source_ref: "v#{@version}",
canonical: "https://hexdocs.pm/statifier_ui",
source_url: @source_url,
main: "readme",
extras:
[
"README.md",
"CHANGELOG.md",
"docs/architecture.md",
"docs/wire-format.md",
{"docs/adr/README.md", [title: "Architecture Decision Records", filename: "adr-index"]}
] ++ Enum.sort(Path.wildcard("docs/adr/0*.md")),
groups_for_extras: [
Guides: ~r{docs/(?!adr)},
"Architecture Decision Records": ~r{docs/adr}
]
]
end

defp package do
[
name: "statifier_ui",
licenses: ["MIT"],
files: ~w(lib mix.exs README.md LICENSE CHANGELOG.md),
links: %{
"GitHub" => @source_url,
"Changelog" => "#{@source_url}/blob/main/CHANGELOG.md"
}
]
end

defp deps do
[
# Statifier is not published to hex yet, so the engine is a git dep and
# mix.lock pins the SHA. This becomes a version requirement the day
# statifier publishes; nothing else here depends on which form it takes.
{:statifier, github: "riddler/statifier-ex"},
statifier_dep(),

# Both integrations are optional: the package is a component library, and
# a Livebook host has no reason to pull LiveView, or the reverse. Anything
Expand All @@ -56,4 +93,14 @@ defmodule StatifierUI.MixProject do
{:doctor, "~> 0.23", only: :dev, runtime: false}
]
end

# Export STATIFIER_PATH to point at a local checkout while co-developing a
# change that spans both repos. It is an env var rather than a mix.exs edit
# so the override never lands in a commit by accident.
defp statifier_dep do
case System.get_env("STATIFIER_PATH") do
nil -> {:statifier, "~> 2.0"}
path -> {:statifier, path: path, override: true}
end
end
end
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"plug_crypto": {:hex, :plug_crypto, "2.2.0", "144014737daaf485407f5ed77daeaad74d651b216a28c87543f8cc7043f8efc8", [:mix], [], "hexpm", "83a95744ab1c75876542b6fab135fcc176280e0f301a111c1f757fddcec95d2c"},
"predicator": {:hex, :predicator, "9.0.0", "c15685ce74e249195df9bbaedf7593c50339ac75b8700a3b13f56cfbcc837ff7", [:mix], [], "hexpm", "8e31739e3d448f9f5d91eb716498a0dfe26f3b27c8bcf96bc6b2ce93c0087e95"},
"saxy": {:hex, :saxy, "1.6.1", "742eff28f553c066d0b54e84662dbf384a1d1f38595472ed15f6e0a33038bbe1", [:mix], [], "hexpm", "8989d504424ba29460a61950f8968380651413fa05e63b6118084db057da1a6b"},
"statifier": {:git, "https://github.com/riddler/statifier-ex.git", "1d0c6ba18e48cfb6bec3f866702cf15993bbdff7", []},
"statifier": {:hex, :statifier, "2.0.0", "826cd183113f83cb91f90f41b9e711b7df735219783d996e8ff4a48a40d96c93", [:mix], [{:predicator, "~> 9.0", [hex: :predicator, repo: "hexpm", optional: false]}, {:saxy, "~> 1.6", [hex: :saxy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8026d01db517058c01cf289f428e9a5c3c4c52ae092ddf698aefd5c4be263a50"},
"table": {:hex, :table, "0.1.2", "87ad1125f5b70c5dea0307aa633194083eb5182ec537efc94e96af08937e14a8", [:mix], [], "hexpm", "7e99bc7efef806315c7e65640724bf165c3061cdc5d854060f74468367065029"},
"telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
Expand Down
12 changes: 8 additions & 4 deletions test/statifier_ui/trace/normalizer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ defmodule StatifierUI.Trace.NormalizerTest do
macrostep: 1,
microstep: 0,
id_from_author?: false,
round: 0
round: 0,
ordinal: 1
}

assert {:ok, %Message{type: "effect.send_delayed"} = message} =
Expand All @@ -391,7 +392,8 @@ defmodule StatifierUI.Trace.NormalizerTest do
owner: {:transition, 0},
macrostep: 1,
microstep: 0,
round: 0
round: 0,
ordinal: 1
}

assert {:ok, %Message{type: "effect.cancel"} = message} =
Expand Down Expand Up @@ -1012,7 +1014,8 @@ defmodule StatifierUI.Trace.NormalizerTest do
macrostep: 1,
microstep: 0,
id_from_author?: true,
round: 0
round: 0,
ordinal: 1
}
end

Expand All @@ -1023,7 +1026,8 @@ defmodule StatifierUI.Trace.NormalizerTest do
owner: {:transition, 0},
macrostep: 1,
microstep: 0,
round: 0
round: 0,
ordinal: 1
}
end

Expand Down
Loading