Agent skill
afferent-reactive-universe-levels
Fix universe level mismatch errors when defining Lean 4 structures containing Reactive.Event or Reactive.Dynamic types in Afferent/Canopy widgets. Use when: (1) compiler error "Type 1 of sort Type 2 but expected Type of sort Type 1", (2) WidgetM won't accept your result structure, (3) structure contains Reactive.Event Spider or Reactive.Dynamic Spider fields. The fix is to place `open Reactive Reactive.Host` BEFORE structure definitions.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/afferent-reactive-universe-levels
SKILL.md
Afferent Reactive Universe Levels
Problem
When creating Canopy widgets that return structures containing Reactive.Event Spider α or
Reactive.Dynamic Spider α fields, the compiler reports universe level mismatches like:
Application type mismatch: The argument MyResult has type Type 1 of sort Type 2
but is expected to have type Type of sort Type 1 in the application WidgetM MyResult
Context / Trigger Conditions
- Defining a new Canopy widget in
Afferent/Canopy/Widget/ - Widget returns a result structure containing
Reactive.EventorReactive.Dynamic - Error occurs at function signature like
def myWidget (...) : WidgetM MyResult - Identical pattern works in other widget files (e.g., ListBox.lean)
Solution
The open statements must appear BEFORE any structure definitions that use reactive types.
Broken pattern:
namespace Afferent.Canopy
open Afferent.Arbor hiding Event
/-- This structure ends up in Type 1 -/
structure MyResult where
onClick : Reactive.Event Spider Unit
/-! ## Reactive Section -/
open Reactive Reactive.Host -- Too late!
open Afferent.Canopy.Reactive
def myWidget : WidgetM MyResult := ... -- Error: Type 1 vs Type
Fixed pattern:
namespace Afferent.Canopy
open Afferent.Arbor hiding Event
open Reactive Reactive.Host -- Before structure!
open Afferent.Canopy.Reactive
/-- Now correctly in Type 0 -/
structure MyResult where
onClick : Reactive.Event Spider Unit
def myWidget : WidgetM MyResult := ... -- Works
Verification
After reordering, rebuild with ./build.sh. The universe error should disappear and
the widget should compile successfully.
Example
From Toolbar.lean - the working structure:
namespace Afferent.Canopy
open Afferent.Arbor hiding Event
open Reactive Reactive.Host
open Afferent.Canopy.Reactive
structure ToolbarResult where
onAction : Reactive.Event Spider String
def toolbar (actions : Array ToolbarAction) (theme : Theme)
(variant : ToolbarVariant := .filled) : WidgetM ToolbarResult := do
...
Notes
- This affects the
Spidertimeline type resolution - The
hiding EventonAfferent.Arboris necessary because Arbor has its own Event type - Compare with working files like
ListBox.leanorDropdown.leanwhich have opens at the top - Pure WidgetBuilder functions (not WidgetM) don't have this issue since they don't return reactive types
References
- Afferent/Canopy/Widget/Data/ListBox.lean - working example pattern
- Afferent/Canopy/Widget/Input/Dropdown.lean - working example pattern
Didn't find tool you were looking for?