Repository navigation
Should EdgeSpec take a list of path items, like their Path? #2
Description
Their edge is an ordered list of markers; ours is a typed edge with subclasses. Theirs composes, ours does not.
# theirs — measured against 2.35.1, runs and returns ['ADA','GRACE']
g.edge_from(g.start_node).map().transform(lambda ctx: ctx.inputs["name"]).to(shout)
# ours — not expressible. MapEdgeSpec and TransformEdgeSpec are separate types,
# and no edge is both.What it would look like
EdgeSpec(source=a, target=b, carries=papers,
path=[Map(delivers=paper), Transform(delivers=pmid, apply=take_pmid)])One EdgeSpec, no subclasses, and delivers becomes the output of the last item.
Three costs
edgesstops being flat. Today it is a tuple of arrows you scan in one pass; this nests a list inside a tuple, in the most-read part of a design.check_variablesbecomes a small interpreter. It would thread a type through each item rather than comparing two ends. Doable — that is what their type parameter does — and it would let intermediate steps be checked, but it is no longer a two-line check.- Bindable identity per item. A
Transformitem that a strategy binds needs its own identity forvaries()andcheck_bindings, so path items become a second kind of bindable thing alongside nodes and transform edges.
And an argument for what we have
Their Path is partly an artefact of the fluent builder — the field is literally called working_items, an accumulator left behind by method chaining. Our declaration is a literal, and a list is the natural shape of the former, not the latter.
More substantially: MapEdgeSpec becomes a real node at build time and TransformEdgeSpec does not.
# _flatten_paths, graph_builder.py
assert not isinstance(item, MapMarker | BroadcastMarker), 'These should be removed during Graph building'Map and broadcast are rewritten into Fork nodes before the executor ever runs; transform and label survive in the Path and are walked per completion. So the two are not the same kind of thing, and our separate types say so where a uniform list hides it until _flatten_paths.
Status
No caller. Nothing in eleven ladder rungs or in nobsmed's six arms needs map-then-transform on one wire.
Trigger to build it: the first design that wants to fan out a collection and reshape each item before it lands — e.g. carries=list[Paper], delivers=pmid — where the alternative is a step that exists only to unwrap.
parity.py now records the composition gap; the table was feature-by-feature and read as though map ✓ + transform ✓ meant both together.
Activity
docs/how-it-runs.md — their executor from the source, with a probe be…
Three runnable probes replace the prose, and the pattern section is gone
README: say there is no flagship example, and open #24 for it (#25)