diff --git a/Behaviors.md b/Behaviors.md index cd55336..6635446 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -118,8 +118,16 @@ shown on the node and editable in the inspector. bottom edge shrinks it again (keys `a`, `b`, `c`, … up to 26). `Run behavior` takes its ports from the behavior it names, and a behavior's `Start`/`End` node declares them. Pointing a call at a different behavior **takes the edges of the ports that go away** and gives them back on - undo: an edge on a port that no longer exists draws as nothing but survives every save, and - would come back to life once the port returns. + undo. +- **An edge can outlive its port**, because a derived list loses a key without anything touching + the edges: a state deleted in its machine, the `machine` edge cut, a `Start` node or a whole + asset removed. Only a setting of the node itself is cleaned up (above) — the other four reach + across graphs, where no single command can see them. So the canvas puts the key back as a + **ghost port**: a hollow red pin, the key as its label, the edge drawn dashed in the warning + colour and the node marked *"1 edge on a port that is gone"*. It is a handle, not a port — + `resolveDef` never has it, so nothing runs through it and nothing new can be connected to it; + right-clicking it offers the usual link menu, and *Disconnect* is how it goes away. Leaving it + alone is just as valid: put the state back and the edge works again. - **Structs**: several named values travelling as one, so a bundle needs one edge instead of one per part. `Pack` declares its fields as inputs, `Expand` reads them back out as outputs, a behavior port may be declared `struct` — which is how a bundle crosses a call — and a diff --git a/Development.md b/Development.md index 3c05641..3f9c1a3 100644 --- a/Development.md +++ b/Development.md @@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs # code is lost (tail's is reported), so a red run reads as green npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output -node tools/seed-e2e.mjs && node tools/e2e.mjs # 837 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 844 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result @@ -165,4 +165,4 @@ widths to find click points. The **render device is not in this repo** — `/dev and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`, -WebGL 2.0, and the same 837 checks as here. +WebGL 2.0, and the same 844 checks as here. diff --git a/State-machines.md b/State-machines.md index 0813b24..8587e4f 100644 --- a/State-machines.md +++ b/State-machines.md @@ -14,14 +14,18 @@ unconnected (or takes a `State machine` node, the literal every kind has): - **`State branch`** grows **one exec output per state**, named after the state, and continues along the one the machine is in. Before `Set state` has run the machine is in **no state**, and the flow ends there — there is no start state. A state the machine no longer has (deleted, or of - another machine) ends it too. + another machine) ends it too — the run ignores a ghost port, whatever the canvas draws. - **`Set state`** is the mirror image: **one exec input per state**, one exec output. The input the flow *arrives through* names the new state — so `OnStart → Set state (Open)` and `On key down → Set state (Closed)` are two edges into one node. The interpreter hands every node the exec input a pulse entered through (`run(…, entry)`); this is the first node to read it. The ports are keyed by the **state's node id** and labelled by its name: renaming a state keeps -every edge, deleting one leaves its edges dangling like any port that is gone. Which machine the +every edge. Deleting one is the awkward case, because the port lives in a *behavior* while the +state lives in the *machine* — so nothing cleans up there, and the edge stays behind. It is not +lost, though: the behavior's node shows the key as a **ghost port** with the edge dashed in the +warning colour, and *Disconnect* on its right-click menu removes it. Put the state back and the +edge works again. Which machine the ports belong to is read off the graph, not off a running value — the inline pick, or a `State machine` literal wired in; a variable or an `Item at` feeding the input yields no state ports, exactly as `Run behavior` knows its behavior only as a setting. Picking another machine