Skip to content

calque spawn-run only binds the FIRST positional arg — a multi-arg spawned callable silently drops the rest #191

Description

@scttfrdmn

Context

Found while writing an end-to-end regression test for calque#189 (TestSpawnDictDispatchEndToEndProducesRealShards, cmd/calque/spawn_dict_dispatch_e2e_test.go) — confirming calque spawn-run's pipeline actually produces a real shard, not just that call-site/classification resolve correctly.

internal/exec/spawnshard.go's SpawnCallable{MethodArg: f.ItemArg} (from ResolveSpawnCallables) only ever carries the callable's FIRST non-self/cls parameter name — same shape ir.Function.ItemArg uses everywhere else in this codebase (the single-arg .map()-style binding protocol). spawnArgsPayload (same file) packs a call site's multiple real args into a list when there's more than one, but nothing on the callable-definition side has a binding convention for more than one name — the function's own doc comment already says this explicitly:

a .spawn()'d callable with more than one positional arg has no established binding convention yet in calque's protocol; this is the same single-arg limitation checkInvokeSupport already flags for .starmap, not a NEW gap this function introduces

This is real: AI-Almanac's forecasts_app.py's actual .spawn()-invoked functions all take 3-4 positional args (run_forecast_inference(job_id, model_id, config), run_season_forecast_bundle(job_id, model_id, config, season_params)). A real calque spawn-run against that script (once calque#189's target-resolution fix lands, which it has) would build a real shard, ship the real body, but only bind job_idmodel_id/config/season_params would be undefined inside the worker, the same class of failure calque#187 fixed for run.go's dry-run/real/fleet paths.

calque#187 does NOT cover this — its checkInvokeSupport arity guard is only called from run.go/realrun.go/fleetrun.go; spawnrun.go has its own separate driver (internal/exec/spawnshard.go) with no equivalent check at all.

Ask

Either:

  1. Extend the binding protocol so a spawned callable's warmd/runner.py invocation can bind multiple positional args by name (mirroring .starmap()'s existing MethodArgs/Starmap splat mechanism in calexec.ManifestBody/worker/warm-runner/runner.py) when spawnArgsPayload produced a list — NamedShard/SpawnCallable would need to carry the full arg-name list, not just MethodArg.
  2. At minimum, add an arity guard to spawnRunFromScript/BuildSpawnManifests refusing loudly (naming the callable and its real arg count) when a resolved SpawnCallable has 2+ non-self/cls args, instead of silently building a shard that will NameError on real hardware — the same honest-refusal pattern calque#187 established for the other three drivers.

Option 2 is the safe minimum; option 1 is the real fix and would make spawn-run actually usable against scripts like forecasts_app.py.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions