Plugin-declared coercions (RFC-FLOW-VOCABULARY O4) landed across three repos:
- labelle-core
726016f — Coercion factory
- labelle-assembler
cfd66c0 — pub const Coercions discovery + PluginCoercions registry + coercions: [...] in flow_catalog.json
- flow-codegen
c26340d — CoercionEntry, CoercionRegistry, wireFitAccepts extension, wrapEdgeWithCoercion public hook, Options.coercions field
But no flow can actually use a coercion yet. Two pieces of work remain:
1. flow_io schema + codegen — per-edge coercion annotation
Today's flow_io.Edge carries { from: { node, pin }, to: { node, pin } } with no coercion info. Pick one:
- (a) Explicit annotation on the edge: extend the edge schema to carry an optional
coercion: "<plugin>.<name>" field. The editor sets it when accepting a coercion-bridged drag; codegen consumes it via the already-public wrapEdgeWithCoercion hook. Easy to reason about; round-trips cleanly through JSONC.
- (b) Auto-detect at codegen: at edge-emit time, when source and sink types don't match exactly, query the registry for a fitting coercion and apply it if unique. No on-disk annotation; the file stays stable through type changes. Risk: ambiguity (two coercions both fit) needs a deterministic tiebreak rule.
Recommend (a) — matches how the existing wire-fit info surfaces in the editor and keeps codegen's view of the file authoritative.
2. labelle-gui editor — drag-accept + edge marking
When the user drags a wire from a source pin of type From to a sink pin of type To:
- Today (RFC §2 wire-fit rule 1 + O1's rule 2): editor accepts iff types are equal or O1-widenable.
- New rule 3: editor also accepts iff the project's catalog has a
Coercion whose from_zig_type matches From and to_zig_type matches To. On accept, the edge is annotated with the coercion's qualified name ("<plugin>.<name>").
Visual cue (suggested): coercion-bridged edges render with a small inline badge or distinct stroke color so authors see at-a-glance that an implicit conversion is happening. Mirrors Blueprint's coercion arrow visual.
Files in scope
flow-codegen:
src/flow_io.zig — Edge struct + JSON I/O for the new field.
src/codegen.zig — already has wrapEdgeWithCoercion; call it at edge consumption sites when the edge carries a coercion annotation.
labelle-gui:
src/flow_node_catalog.zig — parse coercions: [...] out of the sidecar (the data is already there, just unread).
src/modules/flow.zig (or wherever drag-fit lives) — extend the accept check.
src/modules/flow_io.zig — round-trip the new edge field.
- The flow-canvas renderer — coercion-edge visual.
Tests
- flow-codegen: round-trip parse + render preserves the
coercion field; codegen emits a wrapped expression at the consumption site.
- labelle-gui: drag-fit accepts a coercion-bridged source→sink pair; the on-disk JSONC carries the annotation.
- End-to-end: declare a synthetic coercion in a fixture plugin, build a flow that uses it, regen + build a project that depends on it.
Out of scope
- Coercion chain resolution (
A → B → C via two coercions). Reject ambiguity for v1.
- Declaring coercions in flow files (vs plugins / game-scripts only). Stays plugin-declared.
Cross-references
- RFC
RFC-FLOW-VOCABULARY.md §2 (wire-fit rule 3) — open question O4.
- Contract commits: labelle-core
726016f, labelle-assembler cfd66c0, flow-codegen c26340d.
- Parent ticket (closed): flow-codegen#15 (Phase 3).
Plugin-declared coercions (RFC-FLOW-VOCABULARY O4) landed across three repos:
726016f—Coercionfactorycfd66c0—pub const Coercionsdiscovery +PluginCoercionsregistry +coercions: [...]inflow_catalog.jsonc26340d—CoercionEntry,CoercionRegistry,wireFitAcceptsextension,wrapEdgeWithCoercionpublic hook,Options.coercionsfieldBut no flow can actually use a coercion yet. Two pieces of work remain:
1. flow_io schema + codegen — per-edge coercion annotation
Today's
flow_io.Edgecarries{ from: { node, pin }, to: { node, pin } }with no coercion info. Pick one:coercion: "<plugin>.<name>"field. The editor sets it when accepting a coercion-bridged drag; codegen consumes it via the already-publicwrapEdgeWithCoercionhook. Easy to reason about; round-trips cleanly through JSONC.Recommend (a) — matches how the existing wire-fit info surfaces in the editor and keeps codegen's view of the file authoritative.
2. labelle-gui editor — drag-accept + edge marking
When the user drags a wire from a source pin of type
Fromto a sink pin of typeTo:Coercionwhosefrom_zig_typematchesFromandto_zig_typematchesTo. On accept, the edge is annotated with the coercion's qualified name ("<plugin>.<name>").Visual cue (suggested): coercion-bridged edges render with a small inline badge or distinct stroke color so authors see at-a-glance that an implicit conversion is happening. Mirrors Blueprint's coercion arrow visual.
Files in scope
flow-codegen:
src/flow_io.zig—Edgestruct + JSON I/O for the new field.src/codegen.zig— already haswrapEdgeWithCoercion; call it at edge consumption sites when the edge carries a coercion annotation.labelle-gui:
src/flow_node_catalog.zig— parsecoercions: [...]out of the sidecar (the data is already there, just unread).src/modules/flow.zig(or wherever drag-fit lives) — extend the accept check.src/modules/flow_io.zig— round-trip the new edge field.Tests
coercionfield; codegen emits a wrapped expression at the consumption site.Out of scope
A → B → Cvia two coercions). Reject ambiguity for v1.Cross-references
RFC-FLOW-VOCABULARY.md§2 (wire-fit rule 3) — open question O4.726016f, labelle-assemblercfd66c0, flow-codegenc26340d.