Skip to content

Plugin-declared coercions: end-to-end wire-fit (editor + schema) #19

@apotema

Description

@apotema

Plugin-declared coercions (RFC-FLOW-VOCABULARY O4) landed across three repos:

  • labelle-core 726016fCoercion factory
  • labelle-assembler cfd66c0pub const Coercions discovery + PluginCoercions registry + coercions: [...] in flow_catalog.json
  • flow-codegen c26340dCoercionEntry, 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:

  1. Today (RFC §2 wire-fit rule 1 + O1's rule 2): editor accepts iff types are equal or O1-widenable.
  2. 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.zigEdge 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions