Skip to content

The node world: ffrwd:av 0.19.1 - #3

Merged
imbcmdth merged 67 commits into
mainfrom
node-world
Oct 3, 2026
Merged

imbcmdth merged 67 commits into
mainfrom
node-world

Conversation

@imbcmdth

@imbcmdth imbcmdth commented Oct 3, 2026

Copy link
Copy Markdown
Owner

The node world: ffrwd:av@0.19.1, one node interface in place of every older stream interface, with every module declaring its own ports, pairing and clock.

What changes for a query: nothing that compiled before stops compiling; node modules declare DEFAULT NULL ports, rows-only returns and STRUCT returns only where a node makes several outputs (recipes 145 to 154 in docs/examples.md, rules in docs/dialect.md).

What is new underneath:

  • the sidecar binds node and runs every older world through adapters; one scheduler (lanes.rs) for every network, frame-parallel for pure nodes;
  • hold pairing with feeds by port, anchors, groups and foretold ends; interval pairing against live producers; timing-only inputs; the binding list a call's shape was planned with, carried on every node call;
  • one NUT per edge, the relay for every edge that does not chain, host-owned loopback listeners for feeds, a lateral's rows as an ndjson pipe the region writes;
  • ffrwd init --rust scaffolds a node on ffrwd-node 0.2.0;
  • four worker threads by default instead of one per core.

ffrwd/wasm 0.19.1 ships from sidecar/wasm. Every ffrwd package is migrated on its own node branch and releases after this.

Suites: sidecar workspace green (three wall-clock tests are load-flaky and pass alone); cli offline 5012; exec 499 passed with the five known environment failures.

🤖 Generated with Claude Code

imbcmdth and others added 30 commits October 1, 2026 15:57
…ts SQL

One module interface: typed input ports with a clock and a pairing each
(lockstep, hold, interval, arrival), typed outputs with a format, a time
base and a latency, describe without params and shape(params, bound),
one tick per process call with frames fetched on demand, progress from
the end of each tick's interval. types, values, encoder and decoder
carry on; every other 0.18.0 interface is frozen in worlds/0.18.0 for
the host to adapt.

Cookbook recipes 145 to 154 are the SQL surface, red until the compiler
and sidecar land: rows-only returns, structural row matching, one call
evaluated once, mixed kinds, optional inputs, many-ports, several
outputs, ffrwd.merge_spans, explain's delays, and a node with no inputs
as a source.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… read their frozen copy

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ructural rows

A LANGUAGE wasm function over a node module reads describe for its
params schema and asks the sidecar for its shape per distinct (module,
params, bound) call, cached. Arguments bind ports by position and name:
DEFAULT NULL on any stream or rows parameter, arrays on many-ports,
mixed kinds in any order, typed rows parameters as data ports with a
schema, a hold port given as a port number. A rows-only return is a
run-time data stream; a STRUCT return names the outputs the node makes;
RETURNS source on a node with no streams is a relation in FROM. A SQL
function may return a stream and its rows as one record. Row matching
is structural: a reader's fields must be in the producer's port schema
with the same type, and extra fields pass. One call with the same
module, arguments and params is one node wherever it is written.

A signature only a node can carry keeps the older world's refusal on
the declaration and raises it at lowering once describe says the module
is no node, so the seven tests that pinned that refusal now read it
there. LIVE_LEAD is declared, with its errors.md entry; timing.py holds
the delay sums and is not yet wired into compile or explain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
spot, ring, dim, hear, burn, inset, tile, matte and ticker, written with
ffrwd-node 0.1.0 (pinned by tag) and a shared stand-ins crate for the
mark finder, drawing and a bitmap font. Each exports ffrwd:av/node at
0.19.0 and is the fixture its recipe compiles against.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ith delays explained

A region holding a node is a node network: pads bind ports by name,
unlatched outputs are left off, every stream between the region and
another process rides one NUT, a region takes several inputs and
outputs, and the wire format of each edge comes from the ports it
feeds, through a split where one stream feeds two nodes. Nodes with no
inputs are sources, ended by their reader's -to; packets outputs and
inputs are wired; ffrwd.merge_spans is the host's rowmerge with
max_span; params past 4 KB go by -params-from; a hold port fed by a
port number is listed under the command.

explain's JSON gains "timing" and explain --delays prints each node's
window in streaming words and each output's delay behind the source;
compile sizes edge buffers from the same sums, warns past 512 MiB held
(HELD_STREAM) and refuses a live lead that cannot be met (LIVE_LEAD).
dialect.md carries the node world's rules. Recipes 145 to 154 are
pinned from real compile output against the nine stand-ins and a
node-aware sidecar; 151 no longer writes its rows as a track, and
153's prose names where the sound waits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mod world_0190 binds node-module, values-module and codec-module from
wit/; node_world.rs is the node binding, the tick resource with frames
fetched on demand, same resolved to the input's own buffer, and
set-params refused when the shape changes. --describe reports a node
module's world, and --shape prints the WIT's node-shape as JSON for a
module's params and bound inputs, the adapted shape for a module of an
older world (NODE-SHAPE.md). node.rs holds the shape, tick and emission
types with the host's refusals and the progress rule; tick.rs assembles
ticks: window and stride, lockstep with audio re-cut to a video clock,
interval with ahead and latency, arrival, data and packets clocks,
earlier rows.

adapters.rs gives every older world a node shape and node_loop.rs runs
them all through one loop; the five single-world run loops leave
main.rs, each world's command-line setup kept word for word in
legacy.rs. Frame modules run as nodes inside the existing lanes. The
sidecar's suite and the cli's pass as before; NODE-CLI.md is the
spelling for node calls that the compiler lowers to and the host reads
next. The six things the adapters could not say in a shape are B1 to
B6 in the plan's gap log.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	sidecar/modules/Cargo.toml
… as one NUT, and accepts is checked between nodes

The one-output rules that a module process writes one stream now apply
to old-world modules only: a node network hands several streams to one
process as one NUT with a -map per stream, and a group holding a node
may take in a split. A node input fed by another node's output is
checked against the port's accepts, through splits and through like,
and refused naming the node, the port and both formats, with the
ffmpeg filter that converts as the hint. Recipe 151 dims the picture by
the matte's rows and writes the matte beside it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…pelling, shape modules

A network binding any node module runs on the node graph: every -i is
one NUT read through PushDemuxer, one reader thread per input and one
writer per output, several -map before one output interleaved into one
multi-stream NUT (ffrwd-nut 0.1.5, patched to its branch until tagged),
data labels as NUT with heartbeats or as NDJSON, webvtt, srt or null,
and the run ending with exit 0 once every reader has closed. The parser
takes [port=pad], [port=label], [N:v|a|d[:k]], [@rows=label], source
chains with no input and -params-from name=file. rowfilter runs on data
edges and rowmerge=max_span is the span reducer. Each port's accepts is
checked against its bound stream at init.

Any pure node runs frame-parallel in lanes.rs: ticks are cut centrally
before dispatch, a state input opens every instance up front and hands
each the rows of the ticks it did not process, credit backpressure
covers lanes and output queues, and the last call goes to the instance
that said finished. A video or packets clock waits for the next frame
before it ticks, so progress is the same at every -jobs.

Nine shape test modules on raw bindings, 13 host tests asserting
identical bytes at -jobs 1, 2 and 4 and the first, a middle and the
last tick. The spike's benchmarks match a 0.27.4 build within 2.5%.
Gray on the raw wire (Y800). B7 to B12 in the plan's gap log.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The starter crate implements Node for one video input as the clock and
one output like it, hands the picture back, and names the one place
the work goes. ffrwd-node and ffrwd-frame come by git tag; there is no
build.rs and no wit copy, and the README's build line has no install
step. The scaffold tests build the crate, describe it as node-module,
compile its recipe and run it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…reach the sink, a link wins on install

NUT carries no colorimetry, so a module reading yuv420p was told
"unknown" and converted as tv BT.601 whatever the source. The compiler
now writes each raw picture's probed colour, or what leaves a filter it
placed, as the -pad of the -i that carries it, and a network of node
modules reads -pad into the bound stream's colour, row and rendition.
shape-canvas reports the colour it was handed on its first tick, and
the shape tests prove it arrives.

A node's rows under unnest(f.video) v WHERE v.index = n are one
stream's and reach a media sink as a track or a rows file. A bare
install drops a pin that a link has since answered for, so the lock
comes out as a fresh install with the link standing would write it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ne source crosses a region once

Row matching reads a producer's schema through the rows nodes over it:
a row filter passes it through, a span merge adds end_t and types id,
so a reader wanting end_t accepts ffrwd.merge_spans over per-tick rows.
Ports of one region reading one source stream in one wire format bind
to one stream of the edge, split inside the network, instead of a copy
per node.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hold.rs pairs a source's frames onto a node's clock: one group per hold
input or per hold.group, the newest frame at or before the tick with
repeat and skip counted, audio re-cut to the tick and none while behind,
shared-clock held until the clock reaches the first frame, first-frame
primed on lead seconds and scheduled on the clock's grid, tagged choosing
by the source's tags, linger and timeout, a jump a new feed, ends
foretold on the grid, every feed's start and end reported as a row.
feeds.rs is the host-owned loopback listener per group: one connection
at a time, 16 MiB received only while there is room, NUT demuxed with
ffrwd-nut, headers matched to the group's members, pictures conformed
between rgba and yuv420p at any size and sound between s16 and f32.
A hold input with a port_param the call left unbound is served at init;
a bound one gets a free port written into its param. Interval inputs
are bounded by the clock's arrival and late messages reported.

shape-switch does what the switch did as one node with none of its
code, and tests/live.rs feeds it over TCP through fifteen cases: the
switch's holes, timed, late, gone, sync, layer and throughput, with the
feeder throttle its README measured gone at 720p and 1080p. ffrwd-frame
is patched to its yuv branch beside ffrwd-nut until both are tagged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…added

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t, one picture per wire format

A node called over an input's stream in FROM is read at compile time
as a packet sink was: its shape must read packets there and make no
output, the copy follows the port's wants, and its rows are the
relation (index's records and spaces). A column handed to a port
declared DEFAULT NULL may come back NULL from an outer join's gap, and
that instance leaves the port unbound. A region no longer takes in a
split whose node readers want different wire formats; the feeding
ffmpeg converts each copy and the copies that agree still merge.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… reach the node, .* reads what the shape makes

A run-time lateral's streams on a node's hold ports with a port_param
take a feeder connection, one per hold group, the picked port written
into the param and the lateral's writer placed against it, conformed to
what the ports accept. Tags a query writes on a stream a node reads go
to the region's -i as "tags" in its -pad beside the colour. (<call>).*
in a WITH body writes the fields the call's shape makes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rce, laterals on a many hold port

A RETURNS sink node is lowered as the 0.17 packet sink was: the SELECT's
rows bind its ports by kind, the WITH options shape the encoder fronting
each media cell, one -pad per input. A node whose describe has a rows
schema gets an @rows output written as the run's report. A node
network's packets keep their inputs' clock and a source's are its own.
A lateral's data argument may be a one-element array. A lateral-fed
hold port counts as bound when the shape is asked, and several laterals
feed one many port, each its own connection, their ports a list where
the param takes one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, a scalar stays its first type

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he Go modules as nodes

merge_spans keys a span by start_t and id. Rows in an ndjson file carry
pts and time. Heartbeats go only to a pipe. On the packets path: a
format-less packets output takes its clock's coded stream and delay,
order is checked on a present dts, the header keeps its frame rate, a
dts going backwards is dropped, and the first tick reports nothing
late. -pad carries tags into a stream's info, a feed group's refused
sound member is marked absent, an audio member gets its exact at, feed
ports listen before the run's inputs open, an rgba feed into an rgba
port is accepted, a rate source is not run ahead of a hold beside it,
one stream reaches two ports of one node, and a port param may be a
list, one listener per entry. The last writer keeps its output open
until exit, so a consumer's EOF arrives at exit and the cli's cascade
window stops misreading a slow exit. scheduler.rs is gone: the older
worlds run through the node lanes by older.rs. invert-go and
window3-go are nodes on both Go roads. Benchmarks at or above 0.27.4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tap is an ndjson pipe, a node's stream into a sink is encoded

A node network's data output read by several processes is written by
the network, one output per reader; the once-handed rule no longer
applies to a node's data labels, so a label read by a lateral and by a
publisher compiles. A lateral fed by a node reads its messages from an
ndjson pipe the region writes and the relay joins, not from an ffmpeg
copying NUT to tcp; an older module's tap keeps the tcp path. An edge
into a packet sink is encoded by the WITH's encoder when a node produced
it, and a node's data reaches the sink sidecar to sidecar. The demo's
head compiles as written with 9 processes where the 0.28 plan had 14.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… leaky is a host node of a network

A connection brings any subset or superset of a feed group's members;
the members it does not carry are absent from that feed, and the
offset comes from each source's own lead, the picture if it brings one,
else its first member. leaky runs inside a node network beside
rowfilter and rowmerge, so a picture from a node source keeps near the
wall.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Each packet is judged in decode order by its dts, a keyframe on its own
lateness, and a late packet drops the rest of its group up to the next
keyframe that is in time; a packet with no dts is never behind. The
0.28 leaky only ran on decoded frames; a leaf keeping a subscribed
broadcast near the wall runs it on the packets now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Nothing renamed. wants.timing for a frame input never fetched;
shape's bound list carries a binding per input with a stream hint
(the rate) per stream; interval gains an anchor and a hold group;
feed-start says when the start became known; the tick says its
ordinal and which feeds ended since the instance's previous call.
0.19.0 was never published, so this replaces it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Nothing renamed. wants.timing for a frame input never fetched;
shape's bound list carries a binding per input with a stream hint
(the rate) per stream; interval gains an anchor and a hold group;
feed-start says when the start became known; the tick says its
ordinal and which feeds ended since the instance's previous call.
0.19.0 was never published, so this replaces it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
imbcmdth and others added 29 commits October 2, 2026 11:35
…o a node's grouped data input

A run-time lateral may return a data_stream column beside its picture
and sound. Handed to a node's data input whose interval names a hold
group the lateral feeds, it takes that group's port and connection: the
instance writes picture, sound and rows into the one NUT, and the input
binds no pad. A stream of the query's own bound to such an input while
a port serves the group is refused, since its rows would never arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sked with

The host now runs the compiler's list as it stands, so the compiler
writes it: -bound <name>=<json> per node call, in chain order, the same
JSON --shape --bound took, port-served inputs and labels included. The
-pad rate goes, and so does mimicking the host's order and label rules:
the shape is asked with the compiler's own list (again only where an
audio port conforms a sound to another rate), and a node's output is
hinted at its clock's rate once more. A node read in FROM carries its
list on its reader, a node sink its second list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… timing inputs carry no bytes

-bound <name>=<json> per node call, the k-th for the k-th chain calling a
name, is the list the shape is asked with and the hints each bound
stream gets at init, checked against the pads; an input it names that no
pad binds has to be one a port serves. -pad's rate is gone. A stream
only timing inputs read is handed its frames' times and no bytes, an
audio run its length in samples, and a port feed conforms nothing for
such a member; fetch or same on one is a fault. The run counts the bytes
it carried, which the timing test measures. A failed run stays stopped
while a port feed's listener is joined, which hung before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hain order

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd does

A name several chains call takes the k-th -params-from for its k-th
chain, and more files than chains are refused. Two refusals whose
messages ran their halves together read as one sentence again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An interval input anchored first-frame, or tagged without its tag set,
holds no tick until its first message, which stands at the tick being
made when it is first handed; that fixes the stream's offset, and every
message and progress mark after is rescaled onto the clock's time base
and moved by it. The node is told the clock's time base for the stream
at init.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nnection

An interval input naming a hold group is a data member of that group:
a port feed's connection hands it the first JSON streams in shape order,
progress marks dropped, and the group's offset places each message on
the clock, handed on the tick whose interval holds it; a connection's
messages go with its feed. Bound to a stream beside its group's, it
waits on its progress as any data input. Bound by a pad when its group
is served by a port, it is refused. shape-probe reports its feed and
cues, and a live test sends picture, sound and rows on one connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A sighting is a block of every frames of the run, named by the tick's
ordinal and starting at its first frame's time, which the bound rate
measures; any worker names a frame's sighting alike. Recipe 145 at
-jobs 1, 2 and 4 writes the same picture and the same rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both roads' bindings regenerated from the 0.19.1 world (wit-bindgen-go
for TinyGo, componentize-go for mainline Go), and the four shape exports
take the binding list. Every Go test runs and passes with both
toolchains on hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only a grouped data input's marks go to its group; a held picture's
moved its group's progress past its frames and cut one tick more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…wd-frame v0.1.1

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ound

Run by compile against the 0.19.1 sidecar and the rebuilt stand-ins:
every node call now carries the bound list its shape was asked with,
after -filter_complex, one per call in chain order; a node source
carries []. Nothing else in the pinned commands moved. 153 prints the
same delays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… at its end

The writer parsed each row into a serde_json Value to add the two fields
and wrote it again, which sorted its keys and, without float_roundtrip,
moved some numbers by one ulp (7.9005e-34 written 7.900500000000001e-34).
The row is now read only for its keys, and the fields it lacks are
appended to its own text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts with its stage

A process writing a run-time lateral's rows is held until the feeder
port of the calls its instances feed accepts. Since a node region writes
the lateral's tap itself, that region can also host one of those calls,
or feed the programme its readers need before they listen: held, it
waited for itself, and playout's lane-a-file, channel-file and the
one-reader lane B started every member but it.

A writer that reads its own connection, or whose readers read what it
writes, now starts with the rest of the stage, and its lateral's first
instance waits for the ports instead. A stage that ends without starting
a held writer, or whose port was never heard while it waited for itself,
fails with the writer named; before, both ran to exit 0 having written
nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A port read for its frames' times alone is handed the stream as it is at
that point of the plan. The format was the input's own even past
ffmpeg.format, so a yuv420p source formatted to yuv444p crossed as
yuv420p, a conversion made for a port that reads no pixels; the stream
now carries what the nearest format names, else the input's own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…faster than its turns

A rate clock with inputs cut ticks while every input was ready, and an
arrival input always is, so a node like moq's publish, whose outputs
nobody reads, was cut ticks as fast as a worker ran them: 2965 and 4841
ticks of 1/50 (59.3 s and 96.8 s) for an 8 s source in tests/live.py.
Until its inputs end, such a clock now cuts a tick when something has
arrived that no tick has taken, or one period of its rate after its last
tick, and an idle worker waits for that turn; the same run ends at 399
ticks (7.98 s). Every other clock is cut as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…me tick every run

The end of a hold input bound to a stream was told on whichever tick saw
its source close, which hangs on how far the reader had got, itself held
back by the lane's queue: blitz's presence.sql told an ad's end on 6.933 s
in some -jobs 1 runs where 6.750 s was due, and its lead-out frames
differed. Such a source is now held `lead` ahead of the clock, as its
priming already was, and its end is told only once the last frame's turn
is within `lead` of the tick, which is what that tick waited for; a
first-frame start also waits for a frame past its first. A port feed is
told as before. NODE-CLI.md says when `ends` is known for each kind of
feed.

A test runs a first-frame feed at -jobs 1, 2 and 4, three times each, and
checks the rows are identical and the end is told on its tick less the
lead (it was told 4 ticks later before).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s offset

A data input on a hold group whose hold inputs are bound to streams, not a
port, was implemented and documented but never run. The test binds an
untimed picture and a JSON stream on a millisecond time base of its own
from one file, and checks at -jobs 1, 2 and 4 that each message lands on
the tick the group's one offset puts it on, and that the feed's end is
told the lead ahead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ce they end

Once every input had ended, a rate clock with inputs ran on until its
tick count passed the newest pts any input had reached. A publisher's
arrival inputs carry whatever origin the feed has, so with a live feed
at the epoch (1.79e9 s) and a clock counting from 0, moq's publish ran
on at about 400 s of clock a wall second and never took its last call.
An arrival input's pts now never hold the clock: once every input has
ended, a tick takes what arrived untaken, if anything, and the last call
follows at once. Paired inputs (lockstep, hold, interval) still have
their last frame's time passed first, and a rate clock with no inputs
is cut as before.

shape_sink takes a `rate` for a publisher's shape. A file source stamped
at the epoch through it at 50/s ended 21 ms after its source with 45
ticks; it ran on past a 10 s deadline before. moq's live suite: packets
identical (240 in 8 groups), 244 ticks where the run-on made 399; the
same run with its source at the epoch never ended before (stopped at
30 s, its last group unsent) and now ends with the feed, 245 ticks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--jobs N still sets the count, never above the machine's cores; --jobs 1
is still the serial escape hatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It is the one object in charge of cancelling an end's blocking calls,
and the old name was one of the two words this repo keeps out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ath patches gone

Both are tagged now, so the workspace builds where the owner's checkouts
are not beside it, which is where CI builds it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A needless borrow of a Copy closure in tick.rs, and the argument count of
listen_for allowed as the file already allows it elsewhere.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Recipe 111's shown command is pinned as compile prints it, wrapped the way
the exec test wraps it. The host's timing unit test builds shape-probe for
wasm32-wasip2, so where that target is not installed (the module-free CI
job) it stands down instead of failing the build.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…en the last

Since the lanes replaced the scheduler (a71598f), what a lane hands an
output waits in the writer's queue, up to twice the worker count and two.
leaky judges a picture by the wall clock as it hands it on, so the pictures
it passed sat in that queue and grew later than it judged them: behind a
slow stage it passed runs of ten in a row and then dropped half a second
or more, and the picture's lag swung by a second where it used to hold
still. The older scheduler wrote an output from the worker itself, so a
reader that had not taken the last picture held leaky back.

A lane may now be unbuffered: it runs only once every lane it feeds has
nothing queued and every output it feeds has written all it was handed.
leaky's lane is, in a network of older modules and in a node network.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@imbcmdth
imbcmdth merged commit a4c32ab into main Oct 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant