From 5e76c8d7bd0d073aa07703f530739337e72eb5f3 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Mon, 7 Sep 2026 08:20:53 -0400 Subject: [PATCH] =?UTF-8?q?chore(release):=200.14.0=20=E2=80=94=20the=20ho?= =?UTF-8?q?nest=20cockpit,=20and=20a=20book=20that=20can=20prove=20it=20wa?= =?UTF-8?q?s=20not=20edited?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forty-eight PRs since 0.13.3. Nine console views, five engine records they were waiting on, and one thing an operator has to do before upgrading. ⚠️ THIS RELEASE CARRIES A SCHEMA MIGRATION. v20 landed after 0.13.3 was cut: `orders.quote_provenance`, `orders.client_order_id`, `attest_due_ts` on both attestation tables, plus the `cycle_balances` and `audit_events` tables. Every CLI command migrates on the way in, but `keel serve` and `keel mcp` deliberately do NOT -- a view must not take a schema write lock on a database the agent may be mid-cycle on -- so run `keel migrate` per deployment database before serving. Readers tolerate a pre-v20 database and say so rather than crashing; they simply report the new fields as unrecorded until the migration runs. THE HONEST COCKPIT (#700-#708) Positions, Balances, Activity, Orders, the Research Hub's four views, session identity on every page, and an inverted Plans page. The pattern underneath all of it: a view was built against a record the engine did not keep, and the fix was always in the engine. #703's audit export said NOT RECORDED in every hash cell until #721 chained the book. #708's Evidence Matrix could not exist until #726 stopped throwing away what `trials pbo` computed. Both surfaced as "the UI cannot show this" and neither was a UI problem. WHAT THE ENGINE NOW WRITES DOWN An append-only, hash-chained record of every write to `orders`, `transactions` and the attestation tables (#721) -- so the activity export carries real hashes and a per-row verdict on whether the chain vouches for them. The quote provenance and client order id behind each placement (#715). When an attestation's window closes (#718). The per-currency balance pair a cycle observed (#719). The full CSCV, DSR and Monte Carlo artifacts a gauntlet run produces (#726), instead of printing them and exiting. TWO NEW OPERATOR SURFACES `keel journal` -- the discretionary journal, wired at last after sitting in the schema unused since the beginning. CLI-only by constitution: there is no web form, and `add` takes no value options, so the entry cannot be scripted past the terminal gate. `keel orders cancel` -- the cancel asymmetry. Cancelling an entry refuses risk and asks once; cancelling an exit or a protective bracket removes protection and takes a typed phrase that names the order. The console classifies and hands over the command; it never cancels, because `keel serve` holds no venue credential and this release does not change that. ONE BEHAVIOUR CHANGE TO KNOW ABOUT A deployment that has never attested a cash posture now sends a webhook event, if notifications are on. `attest.cash_posture` was registered for delivery and nothing produced it (#732), so rail 22 could veto every entry while the operator heard nothing -- an agent that looks healthy and never trades again. VERSION BUMP ONLY Every workspace package and the lockfile move together (#424). The release workflow is a human action in Actions; nothing here tags anything. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6 --- packages/keel-broker-alpaca/pyproject.toml | 4 ++-- packages/keel-broker-api/pyproject.toml | 4 ++-- packages/keel-broker-coinbase/pyproject.toml | 4 ++-- packages/keel-broker-fake/pyproject.toml | 4 ++-- packages/keel-broker-kraken/pyproject.toml | 4 ++-- packages/keel-broker-robinhood/pyproject.toml | 4 ++-- packages/keel-core/pyproject.toml | 2 +- pyproject.toml | 8 ++++---- uv.lock | 16 ++++++++-------- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/keel-broker-alpaca/pyproject.toml b/packages/keel-broker-alpaca/pyproject.toml index 221227f..f98267a 100644 --- a/packages/keel-broker-alpaca/pyproject.toml +++ b/packages/keel-broker-alpaca/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keel-broker-alpaca" -version = "0.13.3" +version = "0.14.0" description = "Alpaca Trading API adapter for keel (US equities, cash account)" license = "Apache-2.0" requires-python = ">=3.14" @@ -9,7 +9,7 @@ requires-python = ">=3.14" # deliberately NO `alpaca-py` SDK: Alpaca's Trading + Market Data APIs are plain # JSON-over-HTTPS with two header credentials, so the SDK would add a version-churning # dependency for nothing the port needs. -dependencies = ["keel-core==0.13.3", "keel-broker-api==0.13.3", "requests>=2.32.0"] +dependencies = ["keel-core==0.14.0", "keel-broker-api==0.14.0", "requests>=2.32.0"] [project.entry-points."keel.brokers"] alpaca = "keel_broker_alpaca:AlpacaAdapter" diff --git a/packages/keel-broker-api/pyproject.toml b/packages/keel-broker-api/pyproject.toml index b85def2..39ca47e 100644 --- a/packages/keel-broker-api/pyproject.toml +++ b/packages/keel-broker-api/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "keel-broker-api" -version = "0.13.3" +version = "0.14.0" description = "Broker port, domain types, capability model, and conformance suite for keel" license = "Apache-2.0" requires-python = ">=3.14" # Pinned `==`: see the note in the root `pyproject.toml`. An unpinned sibling is satisfied by # whatever is already installed, which is how a deployment ends up running mixed versions. -dependencies = ["keel-core==0.13.3"] +dependencies = ["keel-core==0.14.0"] [project.optional-dependencies] conformance = ["pytest>=9.1.1"] diff --git a/packages/keel-broker-coinbase/pyproject.toml b/packages/keel-broker-coinbase/pyproject.toml index df476a9..b4bb6a8 100644 --- a/packages/keel-broker-coinbase/pyproject.toml +++ b/packages/keel-broker-coinbase/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "keel-broker-coinbase" -version = "0.13.3" +version = "0.14.0" description = "Coinbase Advanced Trade adapter for keel" license = "Apache-2.0" requires-python = ">=3.14" # Siblings pinned `==` (see the root `pyproject.toml`); the third-party SDK is not, because it # has its own release cycle and is not cut from this repo. -dependencies = ["keel-core==0.13.3", "keel-broker-api==0.13.3", "coinbase-advanced-py>=1.8.4"] +dependencies = ["keel-core==0.14.0", "keel-broker-api==0.14.0", "coinbase-advanced-py>=1.8.4"] [project.entry-points."keel.brokers"] coinbase = "keel_broker_coinbase:CoinbaseAdapter" diff --git a/packages/keel-broker-fake/pyproject.toml b/packages/keel-broker-fake/pyproject.toml index 47569a3..83529a6 100644 --- a/packages/keel-broker-fake/pyproject.toml +++ b/packages/keel-broker-fake/pyproject.toml @@ -1,11 +1,11 @@ [project] name = "keel-broker-fake" -version = "0.13.3" +version = "0.14.0" description = "A deliberately divergent second broker adapter, to keep the port honest" license = "Apache-2.0" requires-python = ">=3.14" # Pinned `==`: see the note in the root `pyproject.toml`. -dependencies = ["keel-core==0.13.3", "keel-broker-api==0.13.3"] +dependencies = ["keel-core==0.14.0", "keel-broker-api==0.14.0"] [project.entry-points."keel.brokers"] fake = "keel_broker_fake:FakeAdapter" diff --git a/packages/keel-broker-kraken/pyproject.toml b/packages/keel-broker-kraken/pyproject.toml index 3953155..9e0bd2d 100644 --- a/packages/keel-broker-kraken/pyproject.toml +++ b/packages/keel-broker-kraken/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "keel-broker-kraken" -version = "0.13.3" +version = "0.14.0" description = "Kraken adapter for keel (port-complete stub; every data/market method raises)" license = "Apache-2.0" requires-python = ">=3.14" # Siblings pinned `==` (see the root `pyproject.toml`). There is deliberately NO third-party # dependency: this package is a stub (#313) that handles no keys and makes no network calls, # so a Kraken SDK (and its credentials) arrive with the real implementation, not before it. -dependencies = ["keel-core==0.13.3", "keel-broker-api==0.13.3"] +dependencies = ["keel-core==0.14.0", "keel-broker-api==0.14.0"] [project.entry-points."keel.brokers"] kraken = "keel_broker_kraken:KrakenAdapter" diff --git a/packages/keel-broker-robinhood/pyproject.toml b/packages/keel-broker-robinhood/pyproject.toml index 1c1bb19..df33798 100644 --- a/packages/keel-broker-robinhood/pyproject.toml +++ b/packages/keel-broker-robinhood/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keel-broker-robinhood" -version = "0.13.3" +version = "0.14.0" description = "Robinhood Crypto Trading API v2 adapter for keel" license = "Apache-2.0" requires-python = ">=3.14" @@ -8,7 +8,7 @@ requires-python = ">=3.14" # Ed25519 key, which no other venue keel talks to requires. Keeping it a dependency of this # package alone means an engine that never installs this adapter never installs the crypto stack # either -- the whole point of adapters being separate distributions. -dependencies = ["keel-core==0.13.3", "keel-broker-api==0.13.3", "pynacl>=1.5.0", "requests>=2.32.0"] +dependencies = ["keel-core==0.14.0", "keel-broker-api==0.14.0", "pynacl>=1.5.0", "requests>=2.32.0"] [project.entry-points."keel.brokers"] robinhood = "keel_broker_robinhood:RobinhoodAdapter" diff --git a/packages/keel-core/pyproject.toml b/packages/keel-core/pyproject.toml index 3f12762..2a1fa96 100644 --- a/packages/keel-core/pyproject.toml +++ b/packages/keel-core/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keel-core" -version = "0.13.3" +version = "0.14.0" description = "Shared domain types, configuration, and logging for keel" license = "Apache-2.0" requires-python = ">=3.14" diff --git a/pyproject.toml b/pyproject.toml index a01bd16..5b215e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keel-trader" -version = "0.13.3" +version = "0.14.0" description = "Offline-first, broker-agnostic, rule-based spot-trading agent (halal policy by default)" license = "Apache-2.0" readme = "README.md" @@ -23,15 +23,15 @@ dependencies = [ # in one build, so `==` states a fact rather than guessing at compatibility. The cost is that # a version bump must move these numbers too -- the bump already edits every package's # `version`, and `tests/test_packaging.py` fails the build if a pin is left behind. - "keel-core==0.13.3", - "keel-broker-api==0.13.3", + "keel-core==0.14.0", + "keel-broker-api==0.14.0", # The default venue resolves through the keel.brokers entry points (#524), so the adapter # is a hard runtime dependency, not a convenience: without it installed, every config -- # including one with no `broker:` section -- fails at broker construction. The CLI also # imports the SDK directly to build the adapter's RESTClient transport # (`keel/commands/_common.py`); moving that construction into the adapter package is # Phase B's, with cb_client.py's deletion. - "keel-broker-coinbase==0.13.3", + "keel-broker-coinbase==0.14.0", ] [project.scripts] diff --git a/uv.lock b/uv.lock index dc4df10..c285293 100644 --- a/uv.lock +++ b/uv.lock @@ -454,7 +454,7 @@ wheels = [ [[package]] name = "keel-broker-alpaca" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-alpaca" } dependencies = [ { name = "keel-broker-api" }, @@ -471,7 +471,7 @@ requires-dist = [ [[package]] name = "keel-broker-api" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-api" } dependencies = [ { name = "keel-core" }, @@ -491,7 +491,7 @@ provides-extras = ["conformance"] [[package]] name = "keel-broker-coinbase" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-coinbase" } dependencies = [ { name = "coinbase-advanced-py" }, @@ -508,7 +508,7 @@ requires-dist = [ [[package]] name = "keel-broker-fake" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-fake" } dependencies = [ { name = "keel-broker-api" }, @@ -523,7 +523,7 @@ requires-dist = [ [[package]] name = "keel-broker-kraken" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-kraken" } dependencies = [ { name = "keel-broker-api" }, @@ -538,7 +538,7 @@ requires-dist = [ [[package]] name = "keel-broker-robinhood" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-broker-robinhood" } dependencies = [ { name = "keel-broker-api" }, @@ -557,7 +557,7 @@ requires-dist = [ [[package]] name = "keel-core" -version = "0.13.3" +version = "0.14.0" source = { editable = "packages/keel-core" } dependencies = [ { name = "keyring" }, @@ -574,7 +574,7 @@ requires-dist = [ [[package]] name = "keel-trader" -version = "0.13.3" +version = "0.14.0" source = { editable = "." } dependencies = [ { name = "click" },