Repository navigation
Validate slot-value type compatibility at plan time #284
Description
Context
op.ValidateGraph (introduced in step 15.x of 13.0(n) extract-starlark-from-op) asserts two plan-time invariants:
- Required-parameter coverage — every required parameter of an action-bound unit's method has a slot entry.
- Bubble-up consistency — no same-named variable is declared with incompatible types across child slots (via
Subgraph.mergeBubbled).
It deliberately does not check that a slot's value is compatible with the slot's declared parameter type. This issue tracks adding that check.
Concrete example
node.SetAction(fileWriteText) // method declares: source (string)
node.SetSlot("source", op.ImmediateValue{Value: 42}) // int — incompatible with stringToday this passes ValidateGraph (the slot is present and bound) and fails only at dispatch when the executor coerces the value into the method's parameter type. The error surfaces far from the binding, with execution context noise that obscures the planning mistake.
Scope sketch
For each ExecutableUnit and each parameter on its bound method:
| Slot value form | Validation |
|---|---|
ImmediateValue{Value: v} |
reflect.TypeOf(v).AssignableTo(param.Type) — direct, plan-time |
PromiseValue{UnitRef: id, Slot: s} |
resolve the producer's declared output type via the registry; check assignability against param.Type. Requires the graph to be linked. |
VariableValue{Name: n} |
the variable's type comes from the slot's param.Type; cross-slot type consistency is already handled by mergeBubbled. No additional check needed here — same-name collisions across slots already surface. |
Edge cases
any/ interface{} params — any concrete type is assignable; check is a no-op.- Interface-typed params —
reflect.Type.AssignableTohandles this correctly (concrete satisfies interface). - Defaulted params —
ActionPlanner.Planalready wraps the default inImmediateValue, so it flows through the Immediate branch. - Variadic / Kwargs — skipped (they absorb any types).
Why it's not in step 15
Type compatibility is orthogonal to the structural strip-and-collapse work in step 15. The mergeBubbled check catches one specific kind of type mismatch (same variable, different declared types across slots) but doesn't catch concrete-value-vs-parameter-type mismatches. They're independent invariants.
Filing this so the existing TODO from ValidateGraph documentation has a tracker.
Acceptance
-
ValidateGraph(or a sibling validator) emits one violation per slot with incompatible value type, listing unit ID, slot name, expected type, actual type. - PromiseValue resolution path validated (graph must be linked at validation time — already a precondition of
ValidateGraph). - Tests cover: assignable concrete-to-concrete (OK), incompatible concrete-to-concrete (violation), concrete-to-interface (OK), nil parameter type (skipped — bound method has no signature constraint), promise output type mismatch (violation).
Related
- Plan: 13.0(n) extract-starlark-from-op, step 15.x
- File:
pkg/op/validate.go(when landed)
Activity
refactor(13.0(n) step 15.5): ValidateGraph + non-panicking Parameters()
refactor(13.0(n) step 15.5): ValidateGraph + non-panicking Parameters()