Pass loop variables as call arguments instead of state scopes
Loop variables (i, t, k, ...) now ride the call signature: leaf sub-blocks
of an IterativePipelineBlocks accept them after (components, state), the
loop declares their names in `loop_variables`, and `loop_step` validates
every leaf's signature against it before the first iteration. Assembled
sub-blocks (nested loops, sequential/conditional groups) are called with
the regular (components, state) interface and pass their own loop
variables to their own sub-blocks.
This removes the PipelineState scope machinery entirely — PipelineState
and get/set_block_state are unchanged from main — and loop sub-blocks keep
the familiar LoopSequentialPipelineBlocks authoring style, now with full
composability.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>