Skip to content

fix(update): install keel_broker_alpaca on self-update (#425) - #504

Merged
eaitbrahim merged 3 commits into
mainfrom
fix/425-alpaca-update-wheel
Aug 22, 2026
Merged

fix(update): install keel_broker_alpaca on self-update (#425)#504
eaitbrahim merged 3 commits into
mainfrom
fix/425-alpaca-update-wheel

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

What was wrong (confirmed, not assumed)

keel update on an equities deployment (config.paper-equities.yaml, broker: name: alpaca, keel-broker-alpaca installed in the venv) fails at verification, after the wheels are in, then reverts the whole deployment — exactly the "failure AFTER a finished install" path the issue suspected, not a silent mixed install and not an overrideable warning. The trace (line numbers from main):

  1. plan_updateselect_production_wheels picks exactly the four prefixes — the constant has no keel_broker_alpaca (keel/commands/update.py:87-92), the selection at :363-397, wired at :426. The plan is offered; nothing refuses.
  2. run_update backs up the DBs, downloads those four wheels (:767-779) and installs them (:799-800, installed = True). keel_core / keel_broker_api / keel_broker_coinbase / keel_trader move to the new version; keel-broker-alpaca stays at the old one — nothing selects its wheel.
  3. Migrate runs (schema-only, succeeds).
  4. _verify_versions (:632-659) runs the NEW build's keel versions, which lists every keel distribution in the venv: the alpaca row is old (:649-651 → "keel-broker-alpaca is at X, not Y"), and keel versions itself exits 1 with PARTIAL INSTALL (keel/version.py:258, exit at keel/commands/versions.py:83) → UpdateError("verify failed: ...") at :659.
  5. installed is True, so the post-install failure branch runs (:809, :839-877): the previous wheels are re-installed from Release/ best-effort (:840-845), rolled_back=True, and the error points at the manual runbook procedure. The new wheels stay in Release/; the backups stay.

So every self-update on an equities deployment fails and reverts, from v0.10.0 — the first release publishing keel_broker_alpaca beside a config that selects it.

The fix

keel_broker_alpaca joins PRODUCTION_WHEEL_PREFIXES (now five). Selection, install, the superseded set, cleanup and the verify floor all derive from the one constant, so the adapter moves with the rest and keel versions' all-must-agree invariant holds by construction. The plan/gate/manual-recovery wording that said "four" follows.

The "awkward part", addressed

The issue weighs three shapes and leans to (2) (install venue wheels already present in the venv, keeping four as the floor). This PR takes (3) (the named five-element constant), deliberately:

  • The issue's cost argument against (3) — "a Coinbase deployment must not have Alpaca's requests dependency forced on it" — is void in fact: requests already rides every deployment transitively via the Coinbase SDK (coinbase-advanced-py depends on it; uv.lock). What (3) actually puts on a Coinbase-only box is one small unused adapter module.
  • (1) (derive from the running config's broker: name:) couples the updater to config parsing — the plan could no longer state its wheel set without first reading a deployment's config.
  • (2) is self-describing but makes the wheel set a per-deployment property: the gate wording and the runbook's named-path procedure could no longer state one list, and a deployment whose adapter was somehow missing would verify "healthy" (the remaining distributions agree) while its venue import stayed a release behind — the updater would have no way to heal it. (3) heals it.
  • The deliberate exclusions stay excluded and stay named: keel_broker_fake (registers a fake venue entry point), keel_broker_robinhood (an Ed25519 stack for an adapter nothing constructs) and keel_broker_kraken (the just-merged stub, packages/keel-broker-kraken: a stub adapter — port implemented, every method raising NotImplementedError #313 — every data/market method raises; it must never ride an update). The #: docstring on the constant re-states all of it, including why the set is stated by name rather than derived; if a third real venue ever ships, (2) is worth revisiting.
  • A test pins the set as an exact tuple, so any future venue is a deliberate edit to this list, never an accident of a glob.

Also stale (the issue's last section)

docs/RELEASING.md's "Release assets" table gains a keel_broker_alpaca-* row (a deployment installs it beside the four; keel update moves all five) and keel_broker_kraken-* joins the published-but-not-deployed row. The runbook follows: the manual procedure names the fifth wheel path (with the why), the keel versions sample shows five distributions, and the self-update section says five and names the kraken exclusion.

Tests (TDD: test commit first, then the fix)

  • New: the wheel set pinned as an exact tuple — keel_broker_alpaca IN; keel_broker_fake / keel_broker_robinhood / keel_broker_kraken OUT.
  • Extended: the selection test proves the excluded venues never ride even though the fake release carries them; verify is pinned to demand keel-broker-alpaca present at the target (the pre-fix "healthy" four-distribution output now fails verify); the run-order pin derives its download count from the constant instead of a hardcoded four; the runbook self-update pin demands the section name alpaca.
  • Nothing else in code or tests assumed a count of four (["download"] * 4 and the len(...) == 4 in the zero-byte-download test were the only sites; both now derive).

Gates

  • uv run pytest -q — 4348 passed, 3 skipped
  • uv run ruff check keel tests packages — clean
  • uv run mypy — clean (343 files)
  • uv run ruff format --check on the touched files flags only hunks that exist identically on main (CI gates ruff check, not format); this diff adds none — verified by hunk-for-hunk comparison against the origin/main blobs.

Closes #425

The equities profile (config.paper-equities.yaml, broker: name: alpaca, #386)
deploys keel_broker_alpaca beside the four base wheels, so the self-update
set must include it: an updater that moved the rest and left the adapter
behind failed its own verify step (keel versions: PARTIAL INSTALL) and rolled
the whole deployment back -- every self-update on such a box failed.

The pin is an exact-tuple assertion, stated by name: the set stays a named
list (never Release/*.whl, never config-derived), and the excluded venues are
pinned as excluded -- keel_broker_fake (registers a fake venue entry point),
keel_broker_robinhood (an Ed25519 stack for an adapter nothing constructs)
and keel_broker_kraken (a stub, #313, whose every data method raises). The
verify step is pinned to demand keel-broker-alpaca present at the target,
the run-order pin derives its download count from the constant instead of a
hardcoded four, and the runbook self-update pin demands the section name
alpaca with the other prefixes.
PRODUCTION_WHEEL_PREFIXES gains keel_broker_alpaca: the equities profile
(config.paper-equities.yaml, broker: name: alpaca, #386) deploys the
adapter beside the four base wheels, and an update that moved the rest
while leaving it behind failed the verify step (keel versions: PARTIAL
INSTALL) and rolled the WHOLE deployment back to the previous version --
every self-update on such a deployment failed, by construction, from
v0.10.0 (the first release shipping the adapter next to a config that
selects it).

The set stays stated by name (the issue's 'awkward part'), not derived
from the running config or the installed set: naming keeps the plan
knowable before anything reads a deployment's config, and the cost --
the adapter present on a Coinbase-only box -- is one unused module whose
single dependency, requests, already rides every deployment transitively
via the Coinbase SDK. The deliberate exclusions are re-stated and
extended: keel_broker_fake (registers a fake venue entry point),
keel_broker_robinhood (an Ed25519 stack for an adapter nothing
constructs) and keel_broker_kraken (a stub, #313, whose every data
method raises -- it must never ride an update either).

Every 'four wheels' wording that became false moves with it: the module
docstring, the select/verify error text, the gate and step lines, and
the operator docs (RELEASING.md's assets table gains the alpaca row the
issue called stale, plus kraken in the not-deployed row; the runbook's
manual procedure names the fifth wheel path and its self-update section
says five).
@eaitbrahim eaitbrahim self-assigned this Aug 22, 2026
@eaitbrahim
eaitbrahim merged commit 27fa074 into main Aug 22, 2026
5 checks passed
@eaitbrahim
eaitbrahim deleted the fix/425-alpaca-update-wheel branch August 22, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant