A machine that arrives as a value can still be commanded, so a name may name its state (#58)
game-maker / suite (push) Successful in 6m12s

Set state and State branch derived their ports from the graph, so a machine
that came out of a variable or a list had no ports at all: nothing to set,
nowhere to branch. It could be passed around but not operated.

stateByName() resolves id first, then name; a name two states carry answers
with nothing, the same rule transitionTo already follows for two transitions
of one name — without something in the graph that decides between them, any
pick would be a guess.

Set state by name takes the machine and a text, and has a second exec output
not found, so a typo is not swallowed in silence. State branch gains a
derived else that fires whenever no state output matches — no state set, a
state of another machine, or a machine that arrives as a value and therefore
has no state outputs at all. A flow that enters State branch now always
leaves it somewhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-16 09:08:57 +02:00
1 parent 7e5003b590
commit 1135205d69
7 files changed
+218 -14

No files matched your search

+55 -3
View File
@@ -122,7 +122,12 @@ const CASES: Record<string, Case[]> = {
},
],
StateBranch: [
{ name: 'in no state yet, the flow ends', inputs: { machine: 'm' }, derivedOutputs: ['s1'], next: null },
{
name: 'in no state yet, the flow leaves along else',
inputs: { machine: 'm' },
derivedOutputs: ['s1'],
next: 'else',
},
{
name: 'follows the output of the current state',
inputs: { machine: 'm' },
@@ -131,11 +136,58 @@ const CASES: Record<string, Case[]> = {
next: 's1',
},
{
name: 'a state that is not among its outputs (another machine, a deleted state) ends the flow',
name: 'a state that is not among its outputs (another machine, a deleted state) takes else',
inputs: { machine: 'm' },
context: { states: { m: 'gone' } },
derivedOutputs: ['s1'],
next: null,
next: 'else',
},
{
// The point of #58: a machine arriving as a value has no state outputs at all.
name: 'a machine the graph cannot name has no state outputs, so else is the whole node',
inputs: { machine: 'm' },
context: { states: { m: 's1' } },
next: 'else',
},
],
SetStateByName: [
{
name: 'moves the machine to the state of that name',
inputs: { machine: 'm', state: 'Open' },
lookup: machineWithStates([{ id: 's1', name: 'Open' }]),
next: 'exec',
after: (ctx) => expect(ctx.states).toEqual({ m: 's1' }),
},
{
name: 'a state id names the same state, so a rename cannot break a graph that used the id',
inputs: { machine: 'm', state: 's1' },
lookup: machineWithStates([{ id: 's1', name: 'Open' }]),
next: 'exec',
after: (ctx) => expect(ctx.states).toEqual({ m: 's1' }),
},
{
name: 'a name no state answers to moves nothing and takes "not found"',
inputs: { machine: 'm', state: 'Ajar' },
lookup: machineWithStates([{ id: 's1', name: 'Open' }]),
next: 'notFound',
after: (ctx) => expect(ctx.states).toEqual({}),
},
{
name: 'a name two states share is no answer: the graph never picked between them',
inputs: { machine: 'm', state: 'Open' },
lookup: machineWithStates([
{ id: 's1', name: 'Open' },
{ id: 's2', name: 'Open' },
]),
next: 'notFound',
after: (ctx) => expect(ctx.states).toEqual({}),
},
{
name: 'without a machine there is nothing to set',
inputs: { machine: '', state: 'Open' },
lookup: machineWithStates([{ id: 's1', name: 'Open' }]),
next: 'notFound',
after: (ctx) => expect(ctx.states).toEqual({}),
},
],
SetState: [