Commit Graph
8 Commits
Author SHA1 Message Date
Melvin Strobl 82c64a10b6 Make documentation standalone and generalize examples 2026-10-25 14:43:20 +01:00
stroblme e0962a4a0b Stop a quiet producer vetoing a noisy one in the same wave
Both boilers on the house had been unable to switch on since the Node-RED
transition, and the reason was here rather than in their logic: the command
reached `boiler.water_boiler` and stopped, because `dmx.switches` never ran.

A wave orders nodes by a dependency count, and two things decremented that
count only on success:

- a node that published nothing — rate limited, unchanged, or failed — never
  freed its consumers. `dmx.switches` reads both boilers through `rbe` nodes,
  so the kitchen one being unchanged, which it is nearly always, held the main
  one's command back. The encoder ran about four times an hour, and only when
  the lights happened to change in the same wave.
- a node that could not run at all never freed them either, permanently.
  `plugs.pump_run` waits on a watering pulse that only exists at 02:00, so
  every wave it appeared in took its consumers out with it.

Freeing a consumer is not the same as running it: `untouched` already refuses
to run anything whose inputs nothing refreshed, and that is the accurate test.
The dependency count is ordering, not permission.
2026-08-28 16:53:49 +02:00
stroblme cdb1bffdd4 Advisory issues read as advice rather than failure
`ADVISORY_ISSUES` moves next to `ValidationIssue` in pipeline.py, and the
model derives an `advisory` flag from its own code, so the distinction the
engine already made ships to the client instead of being re-guessed there.

The dock keeps its summary in `--destructive` only when a real fault is
among the issues and paints an advisory row `--muted-foreground`; the
canvas leaves advisories off a node's dot and border entirely, since node
status has three colours and no warning tier.

biome checks the generated `openapi.json`, which nothing formats since the
SDK script dropped its format pass — ignore it like the other generated
files.
2026-08-25 21:46:40 +02:00
stroblme f9de811d9c A batch flow's input is a run parameter, not a missing value 2026-08-25 18:51:54 +02:00
stroblme 99534a82ee Rename the import package app to fluksio
A wheel whose top-level module is `app` collides with anything else in a
user's venv, so the package that is about to be published takes the name
it is published under. Only the Python package moves; the repo, the
Docker WORKDIR and the compose project keep theirs.
2026-08-21 21:48:05 +02:00
stroblme 3d9162f50a Say what a node returned when it is not a dict of ports
Outputs are keyed by port, so a bare value cannot be one. The single mapping
point every caller routes through raised a bare AttributeError from
retval.items(); it now names the problem, and the message reaches the node the
way its other errors do.
2026-08-16 16:44:06 +02:00
Melvin Strobl 1d6f39a5de Add the flow editor: canvas, node panel and live values
The browser half of M3. Flows open on a full-bleed canvas with their chrome
floating over it: flow tabs top, dock bottom, node settings in a panel on the
right that leaves the graph visible and running behind it.

- Connections are derived, not stored. A node declares the messages it reads
  and publishes; every matching pair draws an edge, so two producers of one
  message converge on their consumer. Dragging output to input is shorthand
  for pointing that input at the producer's message, and asks before it
  replaces an existing one.
- Values land on the edges as they flow, over a websocket that feeds a store
  outside React, so a value arriving re-renders its own chip and nothing else.
  Clicking an edge shows the last payload and when it arrived.
- Node source is edited in Monaco, loaded only when a panel opens and themed
  from the design tokens.
- Edits autosave; identical documents are skipped server-side, so a quiet
  canvas writes nothing.
- Validation from the API shows on the node it belongs to and is summarised in
  the dock, where each entry pans to its node.
- Works on a phone: touch-connect, 44px dock targets, and the node panel
  becomes a full-screen sheet.

Two new tokens (--status-success, --font-mono) are mirrored in the website repo
and recorded in DESIGN-GUIDELINES.md.
2026-08-15 18:10:50 +02:00
Melvin Strobl e8895faa47 Add the flow API: typed messages, git-backed store, REST and live events
Makes the flow engine reachable from the API, which is what M3 needs before
any of it can reach the browser.

- app/flow is a package now; the prototype's watch-dir scripts and the
  matplotlib/networkx visualiser are gone with their dependencies.
- Messages carry a serializable dtype instead of a live Python type, and a
  port name, so the graph can speak qualified names while node functions keep
  local arguments. Redis state is JSON, not pickle.
- Message names are namespaced per flow ("heating.temp"); a bare name resolves
  to its own flow, a dotted one crosses flows.
- Several nodes may provide the same message: producers are a list, so fan-in
  is a real edge instead of a silently dropped one.
- Flows are stored as flow.json plus node sources in a git repository, one
  commit per save, with identical saves skipped so autosave stays quiet.
- Node failures are isolated and reported per node; validate() returns cycles
  and unconnected inputs instead of raising deep in a run.
- Credentials live in an encrypted store and are referenced as {"$secret": …}.
- Engine events reach websocket clients through a bus, so values, node status
  and execution show up live.
2026-08-15 17:23:36 +02:00