Issue Description
This is an ergonomic feedback issue concerning how Large Language Models (LLMs) and AI code assistants interact with the workflows4s library structure. The current design, while convenient for human developers, creates an ambiguity that AI models frequently get wrong, leading to non-compiling code that requires manual correction.
The core of the issue is that WIO can be brought into scope in two common ways:
- Direct Import:
import workflows4s.wio.WIO
- Context Import: By defining an object that extends
WorkflowContext and then importing its members, e.g., import MyWorkflowContext.*
Because WorkflowContext provides access to the WIO companion object's methods (pure, runIO, etc.), a wildcard import from a context object makes the direct import of WIO redundant and ambiguous.
The Problem for AI Models
AI code generation models, like GitHub Copilot, operate on statistical patterns found in vast codebases. They learn that to use a symbol Foo, it's common practice to add import com.example.Foo.
When generating a workflows4s workflow, the AI correctly identifies the need for State and Event types from a custom WorkflowContext, and adds the import:
import MyWorkflowContext.*
However, it also recognizes the usage of WIO.pure, WIO.fork, etc., and from its general training data, it often adds a "helpful" but problematic direct import:
import workflows4s.wio.WIO
Example of AI-Generated Code Leading to Error
An AI assistant will frequently generate code like this:
import workflows4s.wio.WIO // <-- AI adds this based on general patterns
import com.example.myproject.MyWorkflowContext.* // <-- This import also brings WIO members into scope
// Compiler Error: reference to WIO is ambiguous;
// it is imported twice in the same scope by
// import workflows4s.wio.WIO
// and import com.example.myproject.MyWorkflowContext.*
class MyWorkflow {
val step1 = WIO.pure // <-- Ambiguous reference
.make[MyWorkflowContext.State]
.value { state =>
// ...
}
}
This forces the developer to manually diagnose the import conflict and remove the redundant import workflows4s.wio.WIO. While a minor issue, it adds friction to the development process and is a consistent "mistake" that AI models will likely continue to make due to the statistical nature of their training.
Discussion: Rethinking the Pattern for AI Comprehensibility
This issue isn't a bug, but rather an opportunity to consider if the library's design could be more "statistically comprehensible" to avoid these common AI pitfalls. A pattern that establishes a single, unambiguous way to access core DSL components would be more robust.
Some potential ideas for discussion:
-
Decouple WIO from WorkflowContext: Could WorkflowContext be limited to just the Event and State type members? This would force all users (human and AI) to always import workflows4s.wio.WIO separately. The pattern would be less convenient but completely unambiguous.
-
Introduce a DSL Entrypoint: Instead of having WIO members available at the top level, WorkflowContext could provide a dsl or workflow object.
- Example:
import MyWorkflowContext.*
class MyWorkflow {
val step1 = dsl.pure.make[State]... // Or `workflow.pure`
}
This would make the source of the DSL explicit (dsl) while keeping the context import for types. An AI would be less likely to add a conflicting import workflows4s.wio.WIO because the code doesn't use WIO directly.
This is a nitpick, but as AI-assisted development becomes the norm, designing APIs that are not just human-friendly but also "AI-friendly" could significantly improve developer experience. Rethinking this pattern might lead to a more robust and less error-prone interaction with modern tooling.
Issue Description
This is an ergonomic feedback issue concerning how Large Language Models (LLMs) and AI code assistants interact with the
workflows4slibrary structure. The current design, while convenient for human developers, creates an ambiguity that AI models frequently get wrong, leading to non-compiling code that requires manual correction.The core of the issue is that
WIOcan be brought into scope in two common ways:import workflows4s.wio.WIOWorkflowContextand then importing its members, e.g.,import MyWorkflowContext.*Because
WorkflowContextprovides access to theWIOcompanion object's methods (pure,runIO, etc.), a wildcard import from a context object makes the direct import ofWIOredundant and ambiguous.The Problem for AI Models
AI code generation models, like GitHub Copilot, operate on statistical patterns found in vast codebases. They learn that to use a symbol
Foo, it's common practice to addimport com.example.Foo.When generating a
workflows4sworkflow, the AI correctly identifies the need forStateandEventtypes from a customWorkflowContext, and adds the import:import MyWorkflowContext.*However, it also recognizes the usage of
WIO.pure,WIO.fork, etc., and from its general training data, it often adds a "helpful" but problematic direct import:import workflows4s.wio.WIOExample of AI-Generated Code Leading to Error
An AI assistant will frequently generate code like this:
This forces the developer to manually diagnose the import conflict and remove the redundant
import workflows4s.wio.WIO. While a minor issue, it adds friction to the development process and is a consistent "mistake" that AI models will likely continue to make due to the statistical nature of their training.Discussion: Rethinking the Pattern for AI Comprehensibility
This issue isn't a bug, but rather an opportunity to consider if the library's design could be more "statistically comprehensible" to avoid these common AI pitfalls. A pattern that establishes a single, unambiguous way to access core DSL components would be more robust.
Some potential ideas for discussion:
Decouple
WIOfromWorkflowContext: CouldWorkflowContextbe limited to just theEventandStatetype members? This would force all users (human and AI) to always importworkflows4s.wio.WIOseparately. The pattern would be less convenient but completely unambiguous.Introduce a DSL Entrypoint: Instead of having
WIOmembers available at the top level,WorkflowContextcould provide adslorworkflowobject.This would make the source of the DSL explicit (
dsl) while keeping the context import for types. An AI would be less likely to add a conflictingimport workflows4s.wio.WIObecause the code doesn't useWIOdirectly.This is a nitpick, but as AI-assisted development becomes the norm, designing APIs that are not just human-friendly but also "AI-friendly" could significantly improve developer experience. Rethinking this pattern might lead to a more robust and less error-prone interaction with modern tooling.