Skip to content

keel update cannot update an Alpaca deployment — the equities profile is outside PRODUCTION_WHEEL_PREFIXES #425

Description

@eaitbrahim

Noticed while deploying v0.10.0.

The gap

keel/commands/update.py downloads and installs exactly four wheels:

PRODUCTION_WHEEL_PREFIXES: tuple[str, ...] = (
    "keel_core",
    "keel_broker_api",
    "keel_broker_coinbase",
    "keel_trader",
)

That list predates keel-broker-alpaca (#382), and it is stated by name rather than derived — deliberately, and rightly: Release/*.whl would drag in keel_broker_fake (registers a fake venue entry point) and keel_broker_robinhood (pulls an Ed25519 stack for an adapter nothing constructs). Naming the set is the correct shape. The set is just now incomplete.

Since #386 there is a tracked config, config.paper-equities.yaml, whose broker: name: alpaca selects an adapter that self-update will never install.

What actually happens on such a deployment

keel update succeeds. keel_core, keel_broker_api, keel_broker_coinbase and keel_trader move to the new version — and keel_broker_alpaca stays where it was.

Then keel versions runs, and it checks every keel distribution in the venv:

A partial upgrade fails it, with the numbers: error: PARTIAL INSTALL: 4 keel distributions at 2 different versions

So the verify step should catch it. Which means the likely failure mode is not a silent mixed install but a self-update that always fails at verification on an equities deployment, after the wheels are already in — the "failure AFTER a finished install" path, where the updater re-installs the previous wheels best-effort and points at the manual procedure. Worth confirming that is what happens rather than assuming; it is also possible the mixed set is reported as an error the operator reads as spurious and overrides.

Either way an equities deployment cannot use the shipped update path today, and v0.10.0 is the first release where that is reachable, since it is the first to publish keel_broker_alpaca alongside a config that selects it.

The awkward part

"Production wheels" is no longer one set. A Coinbase deployment must not have Alpaca's requests dependency forced on it, and an Alpaca deployment must not be missing it — but the wheel list is a module constant, while which venue a deployment runs is a property of its config.

Options, none obviously right:

  1. Derive the venue wheel from the running config's broker: name:. Most correct, most coupling — the updater would have to read config to decide what to download.
  2. Install every venue wheel that is ALREADY present in the venv, keeping the four as the floor. Self-describing, needs no config, and matches what an upgrade means: move what is installed. A deployment that has keel_broker_alpaca gets it upgraded; one that does not, does not.
  3. Add keel_broker_alpaca to the constant unconditionally. Simplest, and puts an unused adapter plus requests on every Coinbase box — the thing the named-set rule exists to prevent.

(2) looks strongest: it needs no new input, cannot install a venue a deployment did not already choose, and keeps keel versions' all-must-agree invariant true by construction.

Also stale

docs/RELEASING.md's "Release assets" table has no row for keel_broker_alpaca — it describes six distributions and the workspace now has seven. Nothing functional depends on it (uv build --all-packages builds it, the workflow publishes it, and keel versions reads installed metadata rather than a fixed list), but the table is what a reader consults to know which wheels a deployment takes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttoolingDev/release tooling (Docs, CI & tooling)

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions