The LLL demand-matcher has two pieces: a `default-task-supervisor`
which does the work of figuring out what to do for a given change in
an instance of demand, and a driver which computes demand instances
and calls `default-task-supervisor` for each.
An `actions` accumulator is threaded through the
`default-task-supervisor` calls. However, the driver code mistakenly
believed that the result of `default-task-supervisor` calls was a
collection of fresh actions only, and therefore consed together the
previous collection of actions with the "new" ones. Because the
`default-task-supervisor` was returning an unmodified accumulator from
time to time, any actions in the accumulator across a call to
`default-task-supervisor` would end up duplicated.
This change favours the thread-the-accumulator-through perspective,
and changes the way the driver uses `new-actions` to match.
Scenario:
- In script of facet X, (react (stop-when E (react ...)))
- This creates facet Y, child of X.
- Facet X has no endpoints, only its child facet Y.
- When the stop-when fires, without this patch, facet X
will be terminated because the *inner* react above hasn't executed yet.
- With this patch, the check for a useless X is done after the stop-when
has had a chance to run; and so X will survive for now.
- Facet IDs are now lists so arbitrary ancestors can be computed with
repeated application of cdr
- `stop-facet` is new and untested, other than that `stop-when` is
refactored to use `stop-facet`
- *all* matching stop-when instances run now; the limitation that
exactly one instance should match is lifted.
- roughly, (stop-when E X ...) === (on E (stop (current-facet-id) X ...))
Remaining to be done: fix `terminate-facet!` to do the right things in
the right order.