Skip to content

SPIKE (Opus/local): typed-command keyword-arg support via TYPE_CHECKING stub #403

Description

@coretl

Not for the autonomous nightly job — interactive, Opus-driven local spike (fast pyright feedback loop). Deliberately NOT labelled api-convergence.

Context

Follow-up to #393 (typed commands). Core typed commands (ADR 0015 / #388 decision 5), in scope for #393 autonomously, cover:

  • Args: [] | [DT1, DT2, …] (positional, known types)
  • Returns: None | DT (0015 L97)

There is no Command[Any, Any] — a statically-declared command has fully-known P/T; a driver that knows nothing statically builds the whole controller (commands included) at runtime. So this spike is not about a partially-typed command; it is purely about the keyword-arg spelling on an otherwise fully-known signature.

The spike

Keyword-argument commands are the hard part. coretl's sketch (0015 L91):

def fn_spec(named_arg: float) -> int: ...

if TYPE_CHECKING:
    def command_spec(spec: Callable[P, T]) -> Command[P, T]: ...
    # runtime equivalent TBD

kw_known = command_spec(fn_spec)

Prototype a spelling giving pyright-checked keyword args on a typed command, with a runtime that builds the Command. Ref: bluesky/ophyd-async#1138 (discussion r2965959411).

Resolved: no Command[Any, Any] needed

@Tom-Willemsen confirmed on #402 that SECoP devices are discovered entirely from an over-the-wire describe — you never statically know something is a command without also knowing its signature. There is no "known command, unknown args" middle case, so runtime Command[Any, Any] introspection is not a requirement. Fully-dynamic drivers build their commands programmatically at runtime (each with a concrete signature from the wire datainfo); statically-declared controllers get fully-known Command[P, T]. This spike therefore stands on its own merits — pyright-checked keyword args for statically-declared typed commands — rather than as an alternative to Any.

When / How

Non-blocking; best after #393 core lands so you prototype against the real Command[P, T]. Fresh Claude Code Opus session pointed at this issue, scratch branch, tight pyright loop. Fold back as a follow-up PR to refactor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    spikeInteractive/Opus-driven prototype, not for the autonomous nightly job

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions