From b01a4105de1cb6c0b8d086ed5a272c47e982c360 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Sun, 9 Aug 2026 09:26:22 -0400 Subject: [PATCH] docs(experiments): assess US equities and refuse on screening capability Asks whether keel can add US stocks, from Coinbase or any other broker. The answer is no, and the binding gate is keel's own screening capability rather than any venue -- which makes stocks "not yet" where cTrader's CFDs were "never". Two refusals, each sufficient alone: 1. KB 71.6 rejects equity-representing instruments BY CAPABILITY: they require share-style business and financial screening keel performs none of. Broker-independent; no probe can move it. asset_attestations cannot even express the answer -- there is no vocabulary for debt over market cap in (asset, sector, backing, pays_yield, source). 2. Coinbase's equity surface has no market data at any price. A live re-run of the committed probe on 2026-08-09 found ONE_DAY candles n=0 across 21 trading days, empty open/close on regular sessions, and empty price fields on all 1000 products sampled. Corrects the 2026-08-05 study on two counts: "order path refused by design" rested solely on a preview 403 and was never established, and the non-deterministic universe finding no longer reproduces (stable cursor walk to 19,188 ids). Coinbase does expose an equities order path -- equity_order_metadata on create-order -- so the venue premise collapsed in Coinbase's favour and the verdict did not move. Records AAOIFI Shari'ah Standard No. 21 as the decided methodology with its criteria quoted from the standard, and leaves two tensions open: SS 21 reads as exemption-from-prohibition rather than permissive tolerance, and clause 3/4/6/1 would exempt keel's ~24-day holds from purification by timing. Also corrects KB 65.10, whose DJIM description no longer describes DJIM after its 2023 screen retirements. Robinhood shipped official agentic equities trading on 2026-05-27, but it is an MCP server needing interactive OAuth PKCE consent with no client_credentials grant -- unusable from keel's headless launchd runner. Status: feasibility only. No code changed, no adapter added, no dependency introduced. Co-Authored-By: Claude Opus 5 (1M context) --- .../2026-08-09-equities-feasibility.md | 1483 +++++++++++++++++ 1 file changed, 1483 insertions(+) create mode 100644 docs/experiments/2026-08-09-equities-feasibility.md diff --git a/docs/experiments/2026-08-09-equities-feasibility.md b/docs/experiments/2026-08-09-equities-feasibility.md new file mode 100644 index 00000000..3e7e9555 --- /dev/null +++ b/docs/experiments/2026-08-09-equities-feasibility.md @@ -0,0 +1,1483 @@ +# US equities — can keel trade stocks, from Coinbase or from anyone else? + +**Date:** 2026-08-09 +**KB basis:** **§71.6** is the centre of this document. Its screening axis is *what an instrument +legally REPRESENTS*, not only what it does: utility = `Haqq`, tradable if the project is compliant; +**equity/revenue-bearing instruments require share-style business AND FINANCIAL screening "we do +not perform" ⇒ REJECT BY CAPABILITY**; buy-back-dependent = hard reject +(`docs/superpowers/references/trading-knowledge-base/sources/source-71.md:385`ff, and the §71.6 +rows in `.../README.md:126`). §65.10 supplies the other half and cuts the opposite way: it +reproduces the Dow Jones Islamic Market Index screen *in full* — halal core business, debt ÷ +12-month avg market cap < 33%, (cash + interest-bearing securities) ÷ market cap < 33%, +receivables ÷ market cap < 33%, non-permissible income ≤ ~5% with the excess purified — and records +that keel's crypto screen is **stricter** than that standard, "a deliberate over-compliance". That +sentence is the seed of §3.1, the open question this document hands forward unresolved. ⚠️ §65.10's +DJIM description is faithful to Ayub but **no longer describes DJIM**, which retired two of those +three ratios in 2023 and now uses a 24-month window — one of two corrections §3 records against the +KB's only screening entry. +§29.1–29.2 name **AAOIFI** as the authoritative screening-standards reference and license a +conservative divergence from it; §71.4b/§71.5 already cite **AAOIFI Shari'ah Standard No. 18** §3/5 +directly — which is why **Shari'ah Standard No. 21 (*Financial Paper — Shares and Bonds*) is +recorded in §3 as the decided methodology**, a sibling standard rather than a new authority. +§65.9 (income purification, report-only, `keel/compliance/purification.py`) is the machinery a +dividend-bearing instrument would need, and SS 21 makes purification an obligation rather than an +option. §65.6 (speculation per se is permissible) and §65.1 (riba strict-liability with **no de +minimis**, gharar a materiality threshold) keep this from collapsing into a reflexive rejection — +and §65.1 is also what makes §3.1 a genuine tension rather than a formality. +**Status:** feasibility only. **No code changed, no adapter added, no dependency introduced.** +This assessment is the entire deliverable — it is a settled decision record, not a plan handed to a +build. Nothing in §6 is proposed or scheduled; §7 states what would have to be true for the +question to be worth asking again. +**Evidence:** three kinds, deliberately not conflated — and §1 is a worked example of why that +separation earns its keep, because the three disagree there. (1) **Measured by probe**, and this +category now carries **two dates that must not be merged.** The 2026-08-05 measurements are +inherited from the committed, re-runnable +`docs/experiments/2026-08-05-coinbase-asset-class-probe.py` and the study it produced +(`docs/experiments/2026-08-05-coinbase-asset-class-feasibility.md`). **That same committed script +was then re-run against the production CDP key on 2026-08-09** — read-only and POST-guarded, +`create_order` never called — as part of an adversarial fact-check of this document. Every +2026-08-09 measurement below carries that date explicitly; where the two runs disagree, **both are +printed and the disagreement is itself the finding** (§1a). (2) **Verified against the working +tree** — every keel-side line/file citation below was executed or read on 2026-08-09; where +this document says a thing does not exist, that is a `grep` over the tree, stated as such. Four +citations inherited from the 2026-08-05 study had drifted and were corrected against the current +tree rather than copied forward. (3) **Read in vendor docs on 2026-08-09** — the external Coinbase +and broker claims, each carrying a URL and that read-date. + +⚠️ **A note on how category (3) was disciplined, because it changed what this document is willing to +print.** The externally-sourced claims went through **three** passes: delegated research, then +direct verification of the load-bearing ones, then an adversarial fact-check that re-opened the +sources a fourth time and re-ran the probe. **No pass simply confirmed the one before it.** The +second refuted two claims the brief supplied and reduced several the first had asserted with +confident specificity — occurrence counts, an enum's value list, a regulator's file number, a press +quotation. The third then went the other way on two of those withdrawals: the Coinbase-for-Agents +roadmap wording and the equity trading-session enum both **turned out to be readable at source**, +and are restored below with their verbatim text and their URLs (§1d, §5/E3). Everything still +unconfirmed is **withdrawn and printed nowhere**, even where it is probably true, and the +withdrawals are itemised in the caveats. Where a source is silent this document says "docs silent"; +where a claim could not be confirmed it says **"unverified"** or withdraws it outright; and where an +earlier pass asserted something that did not survive checking, the correction is made **in place and +attributed and dated**, never quietly dropped. + +## The question + +keel trades halal-screened spot crypto on Coinbase. The question asked of it is short: **can we add +US stocks — from Coinbase, and if not, from another broker?** + +That decomposes into three, and they fail for entirely different reasons at entirely different +costs: + +1. Does the venue keel already holds a key for sell stocks through an API? (**Yes — and the brief + for this document said no.** The correction is in §1b. keel's own account measurably could not + use it, and three documented equity rules conflict with keel's execution model, but "no + securities endpoint" was simply wrong.) +2. Would keel's *charter* permit a stock even if a venue did? (**Not today** — and this is the + finding that matters, because it is broker-independent and no probe can move it.) +3. If the charter gate were cleared, what would the engineering cost? (**Large but tractable** — + and Coinbase would still probably not be the venue, for reasons that are now about fit rather + than about existence.) + +## Verdict + +**No, keel cannot add US equities today — but the reason is not the one the Coinbase study +implies, and it is not the reason cTrader was refused. The binding gate is keel's own screening +CAPABILITY, not the instrument. Stocks are "not yet", where a CFD is "never".** + +| Gate | What it asks | Result | Kind of blocker | +|---|---|---|---| +| **Coinbase venue** | is there an equities order path on Advanced Trade? | ⚠️ **YES — the brief said no and was wrong.** Equity orders route through the ordinary create-order endpoint, addressed by `product_id`, with `equity_order_metadata` carrying the session and time in force | corrected in §1b. **Not the blocker.** | +| **Coinbase, as measured** | could keel's own account actually use it? | **NO, and the 2026-08-09 re-probe made it worse, not better.** Preview refused 403 with a **product-class** message, and **zero market data on every surface tried** — no candles over a 30-day window, no closes on regular trading days, empty price strings on all 1000 products | **re-measured, no longer "stale". Independently decisive** | +| **Coinbase market data** | can an algo price an equity at any granularity? | **NO — the vacuum is total.** `get_candles` ONE_DAY over 30 days returns **n=0** across 21 trading days on both quote legs; `recent_trading_days` returns empty open/close for regular sessions; book and trades 500; **zero equities mentions in any WebSocket channel doc** (2026-08-09) | **not a rollout artifact and not a weekend artifact.** A second, self-standing refusal | +| **Coinbase, for keel specifically** | do the documented equity rules fit keel's execution model? | **NO — three conflicts.** No preview (fatal to `executor.py:445`), no attached orders (breaks `place_bracket`), no `quote_size` outside the normal session (breaks `MarketIOCByQuote`) | real, and survives however the row above resolves | +| **Charter — §71.6** | may keel hold an instrument representing equity in an issuer? | **NO — reject BY CAPABILITY.** Share-style *business and financial* screening is mandatory and keel performs none | **capability gap, not a prohibition.** The true blocker. Buildable. | +| **Screen schema** | can `asset_attestations` even express the answer? | **NO** — the row is `(asset, sector, backing ∈ {ayn,dayn,native}, pays_yield, source)`; there is no vocabulary for debt ÷ market cap | schema change; part of the capability gap | +| **Rail 19 (`spot_instrument`)** | is the id a spot `BASE-QUOTE` shape? | **NO for any equity id** — and there is deliberately **no config field to widen it** | keel's own charter code. Mandatory, safety-critical change. | +| **Rail 18 (`settlement_currency`)** | does the settlement leg parse to a configured currency? | depends on the adapter's id spelling — `AAPL-USD` would pass | not a defence here; rail 19 is | +| **Broker port on the live path** | can any adapter actually trade? | **NO** — `executor.py` types `broker: Any` and calls raw `CoinbaseClient` signatures; `_common.py` constructs `CoinbaseClient` directly and never calls `load_broker()`; no `broker:` key in any config | temporary, scheduled (Phase B). Two migrations, not one. | +| **Session calendar** | does keel know a market can be closed? | **NO** — no `is_market_open`, no exchange calendar anywhere in the tree. A closed market currently reads as a **stale feed** | new subsystem. Observability defect, not a safety hole | +| **Existing Robinhood adapter** | does keel's second adapter reach stocks? | **NO** — it is built against the Robinhood **Crypto** Trading API v2, and there is still no official Robinhood **REST** equities API. ⚠️ Robinhood *did* ship official MCP-based equities agentic trading on 2026-05-27 — a separate funded account and a tool surface, not a `Broker` (§4) | a common and expensive misconception, and the brief's version of it was also out of date | +| **Rail 13 (`usdc_funding`)** | settled quote balance ≥ notional, no ACH/margin | **PASSES, and is a point in keel's favour** — it already encodes a cash-account, no-margin posture | the one gate T+1 equities *fit* | + +**One-line answer: the venue question turned out to be the easy one — Coinbase's API does support +equities, keel's account measurably could not use them, and a better venue exists anyway (Alpaca). +The thing actually standing between keel and a stock is a shariah financial-ratio screen nobody has +built, which no choice of broker fixes and no probe can measure.** + +**Two independent refusals, and each is sufficient on its own. They should be read separately, not +stacked.** + +1. **The charter gate (§2).** keel performs no share-style *financial* screening, §71.6 requires it, + and that is a **capability keel does not have**. It is broker-independent, it is unaffected by + anything a probe can return, and it is the reason the answer is no. +2. **The Coinbase surface is unusable for an algo, on market data alone (§1a, 2026-08-09).** There + are no bars, no closes, no quotes and no stream — on any endpoint tried, for any of 1000 + products, over a 30-day window covering 21 trading days. Every rule in `keel/strategy/rules/` + takes `candles_by_tf`. **A venue that cannot be priced is not a venue at any price**, regardless + of what its order endpoint documents. This one is Coinbase-specific and would be answered by + choosing Alpaca; it does not touch reason 1. + +**The strongest evidence for that framing is that this document's own venue premise collapsed and +the verdict did not move.** The brief held that Coinbase exposes no securities endpoint; §1b +corrects that outright. Had the charter gate been a formality, that correction would have flipped +the answer. It changes nothing, because the binding constraint was never the venue — which is +exactly what makes §2, not §1, the finding worth keeping. + +**Two things this document decides, and two it deliberately does not.** It decides that the answer +is *no* and that the answer is settled rather than pending (§7). It decides that **AAOIFI Shari'ah +Standard No. 21 is the methodology** if the screen is ever built, and quotes its criteria from the +standard's own text (§3). It does **not** decide whether keel would adopt that standard's ratio +tolerances as written, nor whether it would accept clause 3/4/6/1's sell-before-period-end +purification exemption — both would be places where keel's compliance posture became *less* +conservative than its own precedent, and both are stated in full and left open at **§3.1**. + +## 1. Coinbase equities — what is actually there, and a correction to the brief + +### (a) keel's own committed probe — measured 2026-08-05, **re-measured 2026-08-09** + +Same script both times: +`docs/experiments/2026-08-05-coinbase-asset-class-probe.py` — read-only, POST-guarded, +`create_order` never called — run against the production account's own CDP key. The 2026-08-05 run +and the study it produced (`docs/experiments/2026-08-05-coinbase-asset-class-feasibility.md`) are +**inherited**; the 2026-08-09 run is **new to this document** and was performed by an adversarial +fact-check of an earlier draft. Both dates are printed. Where they disagree, the disagreement is the +finding. + +**Inherited, 2026-08-05:** + +- `product_type=EQUITY` returns products — **1000 of them, and that number is a cap, not a count.** + The listing was measured as **not deterministically enumerable**: four identical calls differed + from the first in 400/400/401 ids and unioned to **1868** distinct ids; `offset`+`limit` was + unstable (261 of 500 differ); a cursor walk reached 13 089 distinct ids over 20 pages and repeat + walks did not converge. ⚠️ **This no longer reproduces — see the 2026-08-09 correction below.** +- **Zero market data at any granularity.** `get_candles` returns `n=0` at ONE_HOUR *and* ONE_DAY, + on both the USDC-quoted id and its `alias` USD-quoted twin. `get_best_bid_ask` returns + `{"pricebooks": []}`. `price`, `best_bid_price`, `best_ask_price`, `mid_market_price` and + `volume_24h` are **empty strings on all 1000 products**. Book and trades return HTTP 500 — + corroborating only, since a fault can be fixed. +- **Not a market-hours artifact.** The identical calls were re-run five minutes into the `NORMAL` + session across `SPY`/`QQQ`/`AAPL`/`NVDA`/`TSLA`, on both quote legs, ten products: identical + results, `trading_halted: false` throughout. +- **Preview is refused.** `preview_order` returns 403 + `"API order preview is not available for equities products"`. keel's + executor calls `broker.preview_order` unconditionally and **re-raises on failure** + (`keel/execution/executor.py:445`), and the Coinbase adapter declares + `supports_native_preview=True, synthesizes_preview=False`, so there is no fallback. +- The equity `product_id` is an **opaque 64-char hex hash** with the ticker buried in + `equity_product_details.ticker`. + +#### ⚠️ Re-measured 2026-08-09 — three corrections and one decisive new finding + +**1. The market-data vacuum is worse than 2026-08-05 recorded, and it is the decisive measurement in +this document.** The re-run was performed on a Sunday, so it was deliberately designed to be +**weekend-independent** — every probe below asks about *past trading days*, not about a live +session: + +- `get_candles` at **ONE_DAY over a 30-day window** returns **n=0**. That window spans **21 regular + trading days**. Zero bars. Run on both quote legs — the USDC-quoted id and its `alias`. +- `recent_trading_days` for **2026-08-05, 2026-08-06 and 2026-08-07**, each returned by Coinbase + itself as `TRADE_DATE_TYPE_REGULAR`, carries `market_open_price: ''` and `market_close_price: ''`. + **Coinbase's own product payload says those were regular US trading days and then declines to say + what the stock opened or closed at.** +- `last_market_day_close_price`, `open_price`, `volume_today`, `price`, `best_bid_price`, + `mid_market_price` and `volume_24h` are **empty strings on all 1000 products**. +- `get_product_book` and `get_market_trades` return **HTTP 500**; `get_best_bid_ask` returns + `{"pricebooks": []}`. +- **Zero mentions of equities in any WebSocket channel documentation** — there is no streaming path + either. + +**There is no granularity, no historical depth, no snapshot and no stream. This is not a rollout +artifact, a weekend artifact or a fault: it is the absence of a market-data product.** Every rule in +`keel/strategy/rules/` takes `candles_by_tf`; with no bars there is no setup, no ATR, no stop, no +size and no mark. **This alone makes the Coinbase equity surface unbuildable for an algo, and it +stands entirely independently of the charter argument in §2.** + +**2. ⚠️ Correction against the 2026-08-05 study: the "non-deterministically enumerable universe" +finding is GONE.** Re-measured 2026-08-09, the listing is **stable**: four identical calls produced +**zero drift**, and a clean cursor walk advanced **+1000 ids per page** to a terminating total of +**19 188 distinct ids**. Whatever produced the 2026-08-05 instability — a paginator bug, a rollout +in progress — has been fixed. **The 2026-08-05 study's enumeration finding should not be carried +forward by anyone, and the id-instability line in this document's own §1c is retired with it.** The +64-char-hash identity problem is unaffected and still stands. + +**3. ⚠️ Correction against the 2026-08-05 study: "the order path is refused by design" was never +established.** That claim rested **solely on a preview 403**. `create_order` was never called — then +or now, deliberately. A refused *preview* is evidence about the preview endpoint; generalising it to +"the order path is refused" was an over-reach, and this document made the same over-reach in its own +first draft. **What is established is: preview is refused. What is unknown is whether `create_order` +would be.** + +**4. The 403's wording is a product-class statement, not an entitlement one — and the contrast is +sharp.** The message is *"API order preview is not available for equities products"*. Compare how +the same API says "you are not onboarded" for futures: *"FCM preview orders are only enabled for +onboarded users."* Coinbase has a house phrasing for an entitlement gap, and **this is not it.** The +equities message names the *product class*, not the caller. That materially weakens the +"entitlement or rollout" hypothesis this document previously left open, and it points the same way +as finding 1: the surface is listed, not launched. + +**5. ⚠️ And a finding that cuts the other way, recorded because suppressing it would be exactly the +failure this document is trying to avoid.** `equity_trading_flags`, read across all 1000 equity +products on 2026-08-09, returns **`tradable: true, buy_enabled: true, sell_enabled: true` on +998 of 1000**, with `view_only: false`, `trading_disabled: false`, `liquidate_only: false` and +`trading_halted: false`. **The products declare themselves tradable.** Taken with §1b's documented +order path, the honest reading is that the *order* half of this surface may well work and nobody has +called it; what is missing is not permission to trade but anything to trade *on*. That is a +different — and for keel, equally fatal — problem. + +That study's verdict row read **"not buildable at any price today. The venue gate is absolute."** +⚠️ **The first half stands, and the 2026-08-09 re-probe strengthens it; the second half is too +strong, and §1b below is why.** "Absolute" was an inference about the venue drawn from an account's +behaviour, and the documented API contradicts it. **"Not buildable at any price" survives — but on +market data, not on the order path.** That correction is made here rather than left for a reader to +trip over. + +What the study established that **is** unaffected, and that this document depends on: these are +**real US shares** — venue `CCM`, CIK numbers, `venue_id: "apex"` clearing — and not the +tokenized-stock product. Any reasoning imported from tokenized equities is wrong here (§1e). + +⚠️ **On the brokerage launch itself — the substance behind venue `CCM` — this document deliberately +asserts very little, and the reason is methodological rather than incidental.** An earlier draft +carried a precise account: two-stage rollout with specific dates, a FINRA BrokerCheck firm number, +an SEC Form X-17A-5, an Apex press-release quote, and commission/settlement terms from Coinbase's +help pages. **None of it could be re-confirmed at write-up time** — `coinbase.com` and +`help.coinbase.com` return HTTP 403 to automated fetching (re-tested 2026-08-09), and the +non-Coinbase sources were not independently re-read. It is therefore **withdrawn rather than +printed**, since a decision record that cites a regulator's file number should have opened it. + +What survives is what keel's own probe measured and what the KB already holds, which is enough for +every argument this document makes: the equity products carry **venue `CCM`**, **CIK numbers**, and +`venue_id: "apex"` on the trading-day block — an introducing-broker/clearing arrangement, i.e. +genuine US brokerage rails, not tokenized wrappers. **That these are real US shares cleared through +Apex is repo-sourced and solid.** The brokerage's launch chronology, its exact regulatory filings, +and whether the retail product is app-only or also web are **unverified here and not relied on +anywhere below** — the brief's specific "2026-01-22, app-only" framing should be treated as +unconfirmed rather than as corrected-to-something-else. + +### (b) ⚠️ A correction to this document's own premise — read 2026-08-09 + +**This document was commissioned on the assumption that the Advanced Trade API exposes no +securities order path and that `product_type` routing covers SPOT and FUTURE only. That assumption +is wrong, and it is corrected here rather than quietly dropped.** + +Verified against the authoritative OpenAPI specification +(https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/advanced-trade-spec.yaml) +and against the rendered create-order reference +(https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/orders/create-order), both +read 2026-08-09 — `docs.cdp.coinbase.com` is ungated, unlike `coinbase.com` itself, which returns +HTTP 403 to automated fetching. **Every finding below was opened directly at least twice, on +separate passes and by separate fetches.** + +- **`EQUITY` is a member of the `ProductType` enum.** The full enum is + `UNKNOWN_PRODUCT_TYPE, SPOT, FUTURE, EQUITY, OPTION_GROUP, FUTURE_GROUP`. +- ⚠️ **PRECISION, because an earlier draft of this document got it backwards and the error is + load-bearing: `product_type` is a LISTING and FILTERING dimension, not an order-routing one.** + `create_order` has **no `product_type` field at all** — an order is addressed by `product_id`. + `product_type` is what you pass to *list products* to enumerate equities, what you set on *list + orders* to filter to `EQUITY`, and what *get order* echoes back on the response. Saying "`EQUITY` + is a valid `product_type` for order placement" is a category error and should not be repeated. + What makes an order an equity order is the `product_id` you address and the + `equity_order_metadata` you attach. +- **Equity orders go through the ordinary `POST /api/v3/brokerage/orders` endpoint** — there is no + separate securities endpoint, and none is needed. The create-order reference carries its own + equities paragraph, verbatim: + + > **Equities:** Use the canonical `product_id` returned by the Products API, not the display + > ticker. Include `equity_order_metadata` to select the trading session and time in force. Use + > `market_market_ioc` with `MARKET_GFD` for market orders, which are supported only during the + > normal session. Use `limit_limit_gtc` with `LIMIT_GFD` or `LIMIT_GTC` for limit orders. In + > pre-market, after-hours, overnight, or multi-session trading, specify a positive whole-share + > `base_size`; `quote_size` and fractional sizing are not supported. Attached orders are not + > supported for equities. + +- **`equity_order_metadata` is a real request field on BOTH `create-order` and `preview-orders`**, + carrying `equity_trading_session` and `displayed_order_config`. It is documented as *not* to be + sent on cancel. The 2026-08-05 probe independently found `equity_product_details` on the product + payload, with subtypes and a four-session `trading_day_info` block — so the equity surface is + threaded through products, orders and fills rather than bolted to one endpoint. + +⚠️ **One item withdrawn by an earlier pass is now RESTORED, and one stays withdrawn.** Restored: the +trading-session enum, which is directly readable on the create-order reference and is quoted with +its real spelling in §5/E3 below — the earlier draft's version of it was wrong in both its type name +and its value spellings, which is why it was pulled. Still withdrawn and printed nowhere: an +**occurrence count** for "equity" in the spec, and **named equity-specific error codes**. Neither +could be confirmed on any pass, and neither is load-bearing. + +**What produced the wrong premise is worth recording, because it will mislead the next reader too — +and the honest reading of it has changed.** The API's own introduction page describes it as +*"Coinbase's programmatic interface for **spot crypto and derivatives**"* +(https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/introduction, read +2026-08-09), and its navigation offers exactly three families: **Spot & US Derivatives**, **US +Derivatives**, and **International Derivatives (INTX, deprecated)**. No equities section anywhere. + +⚠️ **An earlier draft concluded from this that "the prose is out of date and the schema is not." +That is not established, and the documentation pattern points the other way.** Equity support +appears **only** inside auto-generated per-endpoint OpenAPI schema blocks — the ones carrying +internal protobuf names like `coinbase.public_api.authed.retail_brokerage_api.*`. The hand-written +surfaces are silent: the REST introduction, the API overview, the orders guide, the FAQ, and the +changelog, which contains **zero occurrences of the string "equit"**. So the split is not +prose-lagging-schema; it is **generated-artifacts-lagging-editorial-intent**, which is the opposite +inference. Taken with the live 403 and the market-data vacuum in §1a, **the introduction page +describes what is *usable* more accurately than the schema describes what is *shipped*.** Read both, +and treat the schema as evidence of what exists rather than of what works. + +### (c) Reconciling (a) and (b) — documented is not shipped, and shipped is not priceable + +Two true things that look contradictory: the API *documents* equity trading, and keel's own probe +*measured* that it could not do any of it. Both stand, on two dates now. The reconciliation matters +more than either. + +| What | Status | +|---|---| +| Equity order path exists in the documented API | **yes** — spec + create-order reference, read 2026-08-09 | +| Equity products declare themselves tradable | **yes** — `equity_trading_flags` `tradable/buy_enabled/sell_enabled: true` on **998 of 1000**, measured 2026-08-09 | +| keel's account could preview an equity order | **no** — 403 `"API order preview is not available for equities products"`, measured 2026-08-05 **and again 2026-08-09** | +| Equity market data on this account | **none** — no daily bars over 21 trading days, no open/close on regular trading days, empty price strings on all 1000 products, no WebSocket channel. Measured 2026-08-05 and, more thoroughly, 2026-08-09 | +| **`create_order` on an equity** | **never called.** Deliberately, then and now | + +So the accurate statement is **not** "Coinbase has no equities API," and it is no longer "we do not +know why it fails." It is: **the documented surface exists, the products advertise themselves as +tradable, preview is refused with a product-class message rather than an entitlement one, and there +is no market data of any kind on any endpoint. The order half is plausibly live and untested; the +data half is definitively absent.** For keel that ordering is irrelevant — the data half alone is +disqualifying — but it is the difference between "we are not entitled" and "it is not finished," +and the 2026-08-09 evidence favours the second. + +**Three documented constraints conflict directly with keel's execution model, and they survive +however that resolves:** + +1. **No preview for equities.** keel's executor calls `broker.preview_order` **unconditionally and + re-raises on failure** (`executor.py:445`), and the Coinbase adapter declares + `supports_native_preview=True, synthesizes_preview=False` — there is no fallback. A 403 on + preview is fatal to keel's order path *even if `create_order` would succeed*. +2. **Attached orders are not supported for equities.** keel places protective legs via + `place_bracket` (`executor.py:731`). A venue that refuses attached orders forces keel to manage + stops as independent resting orders — a real change to the execution model, not a flag. +3. **`quote_size` and fractional sizing are rejected outside the normal session.** keel's entries + are `MarketIOCByQuote` — "spend $N". Under this API keel's own entry model would work **only + during the normal session**, and whole-share `base_size` would be mandatory otherwise, which is + C6 (no lot rounding) becoming a blocking defect rather than a latent one. + +Plus the identity problem the probe already found and the docs now confirm in their own words — +*"Use the canonical `product_id` returned by the Products API, not the display ticker"* — which is +the 64-char hash. ⚠️ **Earlier drafts added "on a listing that is not deterministically enumerable"; +that half is retired.** The 2026-08-09 re-probe found the listing stable and cleanly walkable to +19 188 ids (§1a). The hash-not-ticker problem is real; the enumeration problem is not, any more. + +**Zero market data remains the decisive keel-side fact, and the 2026-08-09 re-probe made it +stronger rather than weaker.** Every rule in `keel/strategy/rules/` takes `candles_by_tf`; with no +bars there is no setup, no ATR, no stop, no size and no mark. A documented order endpoint keel +cannot price into is not a capability — and this is the one Coinbase-specific conclusion that would +survive even if the charter question in §2 were answered tomorrow. + +### (d) Coinbase's own agent product — ⚠️ **withdrawn by an earlier pass, and now RESTORED** + +The brief for this document supplied what it called a decisive citation: that **"Coinbase for +Agents"** shipped with equities listed as *planned for the future*, which would have been Coinbase +confirming, in its own words, that no equities API existed. + +**An earlier pass withdrew that citation on the grounds that `coinbase.com` returns HTTP 403 to +automated fetching. That withdrawal was wrong — it looked at the wrong host.** The Coinbase for +Agents documentation lives on the ungated `docs.cdp.coinbase.com`, and it says the thing verbatim +(https://docs.cdp.coinbase.com/coinbase-for-agents, read 2026-08-09): + +> **Coming soon:** x402 payments for agent-consumed services (paywalled research, data APIs, +> compute), **equities**, prediction markets, and additional asset classes. If it's on Coinbase, +> your agent will be able to trade it. + +**Coinbase uses the word "equities" under an explicit "Coming soon" header, in its own developer +documentation.** ⚠️ **This also refutes a claim made in the brief and repeated in an earlier draft: +that the "planned for the future" line was a journalist's paraphrase rather than Coinbase's own +wording.** Only the exact *sentence* that appeared in the CoinDesk coverage was the journalist's +construction; **the substance is Coinbase's published roadmap**, and it is quotable at source. No +press citation is needed or printed for it. + +**What it does and does not establish, because the two are easy to run together.** It is a statement +about the *agent product's* roadmap, not about the REST surface — §1b shows the REST surface already +carries equities in its schema. Read alongside §1a's measured vacuum, the two agree with each other: +Coinbase's own editorial voice places equities in the future tense, its agent product does not have +them, its REST introduction does not list them, and its market-data endpoints return nothing for +them. **The schema is the outlier, not the roadmap.** That is a materially different picture from +"the docs are stale," which is what an earlier draft of §1b concluded. + +### (e) Tokenized equities — a different product, and not for a US person + +⚠️ **Provenance, stated plainly: the specifics below are inherited from the 2026-08-05 study and +from general knowledge, not from sources re-read for this document.** The press citations an earlier +draft carried — announcement date, a CoinDesk URL, a "no-action relief" characterisation — were not +re-confirmed and are not printed. + +What is solid, because it is repo-sourced, is the 2026-08-05 study's own finding, restated here +unchanged: **the widely-reported Coinbase "tokenized equities" launch is a non-US product issued on +Base, and it is NOT what this account's API returns.** What the Advanced Trade API returns is +`product_type: EQUITY` on venue **`CCM`** with CIK numbers and Apex clearing — real US shares. + +**Keep the two straight, because confusing them produces both the wrong technical answer and the +wrong halal one.** "Coinbase equities" means either **CCM/Apex brokerage shares** — real shares, on +the Advanced Trade API — or **Base tokenized equities** — on-chain, and *not* on that API. Whether +tokenized equities remain unavailable to a US person, and on what regulatory basis, is +**unverified here** and nothing below depends on it. + +### What this means together + +The brief's framing — "Coinbase equities: NO, confirmed twice, independently" — **was right for the +wrong reasons, and the reasons matter more than the answer.** Its API leg was **refuted**: the +documented order path exists (§1b). Its Coinbase-for-Agents leg was **withdrawn as unverifiable by +one pass and then restored verbatim by the next** (§1d), which is its own lesson about how a +withdrawal can be as unfounded as an assertion. What survives is narrower, better sourced, and still +sufficient: + +- **The documented API supports equities**, and the products advertise themselves as tradable + (998/1000, 2026-08-09). The brief's premise to the contrary was wrong, and is corrected in place. +- **There is no market data at any granularity, on any endpoint, over any window** — re-measured and + widened on 2026-08-09, deliberately weekend-independent. This is the Coinbase-side finding that + actually decides anything. +- **Preview is refused with a product-class message**, not an entitlement one, on both probe dates. +- **Three documented equity constraints conflict with keel's execution model** — no preview, no + attached orders, no quote-sized entries outside the normal session — and the first is + independently fatal to `executor.py`'s unconditional preview call. +- **None of that is the reason the answer is no.** §2 is. The market-data vacuum is why Coinbase in + particular would not be the venue *even if* §2 were cleared; §2 is why no venue would be. + +**Consequence for the 2026-08-05 study's R6 ("re-probe equities in ~6 months"): it has now been +done, on 2026-08-09, and it answered all three of the questions an earlier draft of this section +listed as live.** Has market data appeared? No — and the vacuum is deeper than 2026-08-05 recorded. +Does the preview refusal still stand? Yes, in the same words. Is it an entitlement gap? The wording +says product class, and `equity_trading_flags` says the products are tradable, so probably not. +**R6 should be closed rather than rescheduled.** The remaining unanswered question is whether +`create_order` works, and that one is not answerable by a read-only probe and will not be attempted: +it would place a real order, in a real brokerage account, for an instrument keel's charter forbids +it to hold. **Every one of these was, and remains, downstream of a charter gate no probe can move.** + +## 2. The real gate is the charter, not the venue — and it is broker-independent + +This is the most important finding in this document, and it is the one that does not change if a +better venue is chosen tomorrow. §1 is the demonstration, twice over: the venue premise this +document started from was wrong in keel's favour — the order path exists — and then the 2026-08-09 +re-probe moved the venue evidence hard in the other direction — there is no market data at all — +**and the answer did not move by a single step in either case.** That is the test of a +broker-independent gate, and this one passes it. Everything below is what a probe cannot measure and +a broker cannot supply. + +**Keep this separate from the market-data finding in §1a.** They are both refusals, they are both +firm, and they are not the same refusal. The data vacuum is a fact about Coinbase that Alpaca would +answer tomorrow. §71.6's screening requirement is a fact about keel that no venue answers ever. +**Fixing the first would leave the verdict exactly where it is.** + +### What §71.6 actually says + +The Shariyah Review Bureau material behind §71.6 classifies instruments by **what they legally +represent**, and rules per type +(`docs/superpowers/references/trading-knowledge-base/sources/source-71.md:385`ff): + +| Type | What it represents | Ruling | +|---|---|---| +| Utility tokens | rights to services | `Huquq` — *"permissible to trade such tokens on a secondary market **provided that the project is Shariah compliant and has passed the Shariah screening for ICOs**."* | +| Revenue instruments | participation in future revenues | possible if genuine equity + risk-sharing; **"requires screening of core business activity AND financials, 'like the screening methodology of shares'"** | +| **Equity instruments** | **equity in the issuer — votes, dividends, beneficial interest** | ***"similar to purchasing shares"*; requires the same share-screening methodology** | +| Buy-back-dependent | appreciation backed by issuer repurchase-and-destroy | ⚠️ contract combination — hard reject | + +And the rule the KB extracted from it, in its own words: + +> **⭐ Function screening is not sufficient for *any* token carrying a claim on an issuer.** SRB +> requires equity and revenue tokens to pass **share-style screening of the issuer's core business +> activity AND its financials** — a two-part test our binary sector screen does not perform. This +> is the same standard §65.10 noted we already exceed on the *sector* half (binary rejection vs +> AAOIFI/DJIM's ~5% tolerance) — but **we perform no financial-ratio screen at all**, because our +> allowlist contains no issuer-claim tokens. **The rule to record: admitting any equity/revenue/ +> claim-bearing token would require a screening capability we do not have.** + +The README states the same conclusion in four words: **"equity/revenue ⇒ REJECT BY CAPABILITY"**. + +### One inference, named as such + +§71.6 is a **token**-screening section. Applying it to a real US common share is an **inference**, +not a direct citation — the 2026-08-05 study flagged this in the same terms and it has not been +closed since. It is, however, an unusually strong inference: the section's ruling for equity tokens +is *"similar to purchasing shares… requires the same share-screening methodology."* It reaches +shares by analogy **to shares**. Applying it to the thing the analogy points at is the one +direction the inference cannot be wrong in. + +### The distinction that this whole document turns on + +**"Reject by capability" is not "reject".** It is the KB saying: *the test exists, it is +well-specified, and we do not run it.* + +Compare the two refusals this repo has now recorded: + +| | cTrader (2026-08-09) | US equities (this document) | +|---|---|---| +| What is wrong | leverage, short-symmetry, financing and cash-only P&L are **load-bearing in every core message type**; no message anywhere expresses an unleveraged spot holding | **nothing about a share is structurally defective.** A common share is an ownership stake, risk-sharing by construction, deliverable, and holdable | +| How it could change | Spotware or a licensee inventing an account type and a set of messages that do not exist | **keel building a screen that Islamic finance already specifies in full** | +| Who can act | not keel | **keel** | +| Verdict word | **never** | **not yet** | + +§65.10 is the proof of the second column. It reproduces the DJIM screen in full — the halal-core- +business test, the three sub-33% balance-sheet ratios, the ~5% non-permissible income tolerance +with purification of the excess — from Ayub, verbatim, as *"what §29's 'AAOIFI is the authoritative +reference' pointer actually resolves to in practice."* Equities are not an unscreened frontier in +Islamic finance; they are the **original** subject of the screening literature, and crypto is the +part that had to be reasoned to by analogy. The canonical treatment is **AAOIFI Shari'ah Standard +No. 21, *Financial Paper (Shares and Bonds)*, and it is the methodology this document records as +decided** should the screen ever be built — see §3, where its criteria are quoted from the standard +text, and §3.1, which names the two places that choice would cut against keel's existing posture. +⚠️ **Distinguish two senses of "read": this document has read the standard (§3 quotes it from +AAOIFI's own published text), but SS 21 has *not* been read into the knowledge base as a source +file, and §71.4b/§71.5's SS 18 remains the only AAOIFI standard in it.** That authoring step +follows the §3.1 decisions rather than preceding them (§7 item 2). + +§65.10 also records the direction of keel's existing divergence, which matters for the design: + +> Our posture is **binary rejection** on any riba-yield function (§41.1). **That is stricter than +> the standard.** … it should be documented as a deliberate over-compliance, not presented as *the* +> standard. + +keel is already *more* conservative than DJIM on the sector half. A keel equity screen inheriting +that posture would be tighter than an off-the-shelf Islamic index, not looser. **The capability gap +is real; the compliance instinct behind it is already calibrated.** + +### The schema cannot express the answer — verified + +`asset_attestations` (`keel/data/db.py:231-240`) is: + +```sql +CREATE TABLE IF NOT EXISTS asset_attestations ( + asset TEXT PRIMARY KEY, + sector TEXT NOT NULL, + backing TEXT NOT NULL, + pays_yield INTEGER NOT NULL, + source TEXT NOT NULL, + attested_by TEXT NOT NULL, + attested_at INTEGER NOT NULL +) +``` + +mirrored by `AssetAttestation` (`keel/compliance/screen.py:76-86`). `sector` is free text matched +against `HARAM_SECTORS` (`screen.py:33-44`: gambling, casino, adult, alcohol, pork, tobacco, +firearms, riba_yield). `backing` is one of `{'ayn, 'dayn, native}`. `pays_yield` is a boolean. + +**None of those is a vocabulary for a company's debt-to-market-cap ratio, its interest income as a +fraction of revenue, or its receivables.** There is no numeric field on the row at all. A DJIM +screen is four ratios and a threshold; this schema can record neither a ratio nor a threshold. The +gap is not "fill in a column" — it is a second attestation kind that does not exist. Note also that +`backing` would be genuinely awkward: a share is not `'ayn` (it is not a specific identified +object), not `'dayn` (it is not a debt claim), and not `native`. **Which value a share takes is +itself an open question this document does not answer — unverified, and it needs a ruling, not a +probe.** + +### The screening work is genuinely recurring, unlike a crypto attestation + +This is the cost that is easiest to underestimate. A crypto attestation is a **one-time** judgement +about what a token is: BTC's `backing=native, sector=crypto, pays_yield=False` does not change +because a quarter closed. A financial-ratio screen is a **per-reporting-period** judgement about +numbers that move every period — debt is refinanced, cash balances swing, and a company can cross a +threshold without doing anything a headline would report. + +**And under the standard keel has chosen it is worse than per-period, for a reason specific to that +standard: SS 21's denominator is market capitalisation** (§3), so the *denominator moves every time +the price does. A company's compliance can change on a price move alone, with an unchanged balance +sheet.** That is not true of MSCI's total-assets basis, and it is the sharpest recurring-cost +consequence of the §3 decision. (SS 21 mitigates it slightly by specifying no averaging window at +all — clause 3/4/5's *"last budget or verified financial position"* — so the ratio is struck +point-in-time rather than tracked continuously; but *when* it is struck then becomes a policy +choice keel must make and defend.) + +Consequences, stated plainly because they are design constraints and not caveats: + +- An admitted stock can become **inadmissible while held** — through a filing, or (per the above) + through a price move alone. The screen needs an *exit* semantics the crypto screen has never + needed. **SS 21 clause 3/4/8 supplies the requirement** — *"it is obligatory to give up such + investment"* — so this is no longer an open question of policy, only of mechanism (§3 item 4). +- `attested_at` is currently a timestamp nothing expires on. A ratio screen needs a **staleness + policy**, and "fails closed on a stale attestation" is the only safe default — which means the + screen must know each issuer's fiscal calendar. +- Somebody has to read filings. keel has no ingestion path for XBRL, 10-Qs, or any fundamentals + vendor, and `screen.py:251`'s standard is that *"an unsourced claim is not evidence"*. + +**This recurring cost is the single most under-priced item in this document**, and it is an +operating cost, not a build cost — it does not end when the code ships. + +## 3. What an equity shariah screen would actually require + +### The standard is decided: AAOIFI Shari'ah Standard No. 21 + +**Should the equity screen ever be built, the methodology is AAOIFI Shari'ah Standard No. 21, +*Financial Paper (Shares and Bonds)*.** This is recorded here as a decision, not offered as an +option, so that the question does not have to be re-argued if the subject is ever re-opened. + +The grounding is that SS 21 is not a new authority being imported — it is **the consistent sibling +of a standard this KB already cites directly**: + +- §29.1–29.2 name **AAOIFI as the authoritative screening-standards reference**, and license + documenting a conservative divergence from it. +- §71.4b/§71.5 cite **AAOIFI Shari'ah Standard No. 18 §3/5** directly, for the two-condition + `'ayn`-vs-`dayn` possession test, and it is the KB's first AAOIFI standard applied to a digital + asset. §71.5's *"Three sources now converge"* on `qabd` rests on it. +- SS 21 is the same body's standard governing dealing in shares — the instrument class §71.6 sends + an equity to be screened *like*. Choosing anything else would mean screening keel's possession + test by AAOIFI and its admission test by somebody else. + +**DJIM, MSCI Islamic and S&P Shariah are the comparison set SS 21 was chosen over, not alternatives +left open.** They matter to this document for exactly one reason: §65.10's record of keel's current +posture is stated *against DJIM's* numbers, so the comparison is how the tension in §3.1 below +becomes visible at all. The three commercial index families differ from AAOIFI and from each other +on the ratio denominators and thresholds — a difference that is a compliance decision rather than an +implementation detail, and one this document deliberately does not resolve. + +#### What SS 21 actually says — read from the standard text, 2026-08-09 + +**AAOIFI publishes the full English text of SS 21 on its own site**, so the following is quoted from +the standard rather than from a secondary summary: +https://aaoifi.com/wp-content/uploads/2020/08/SS-21-Financial-Paper-Shares-and-Bonds.pdf (a 28-page +extract of the compiled *Shari'ah Standards* volume, book pagination 557–583, AAOIFI-hosted since +August 2020; catalogue page https://aaoifi.com/ss-21-financial-paper-shares-and-bonds/?lang=en). +Issued **20 May 2004** (30 Rabi' I 1425 A.H.), adopted at Shari'ah Board meeting No. 12, +Al-Madinah Al-Munawwarah. Scope covers shares and interest-bearing bonds, and **excludes** +investment Sukuk (SS 17). + +**⚠️ The framing is the most important thing in the standard, and it is not what a reader expecting +an index methodology would predict.** Clause **3/4** introduces the ratios like this: + +> "Participation or trading (for investment and trading) in the shares of corporations whose primary +> activity is permissible, but they make deposits or borrow on the basis of interest — **The +> fundamental rule is that of prohibition** of acquiring shares of and transactions (investment and +> trading) in the shares of corporations that sometimes undertake transactions in Riba and other +> prohibited things **even when their primary activity is permissible**, but from this rule +> subscription and transactions (investment or trading) are **exempted** with the following +> conditions:" + +**The ratios are a narrow exemption from a baseline prohibition, not a permission with limits.** +The Appendix grounds the exemption in *"removal of hardship and acknowledging of general need, +widespread practice."* This materially changes §3.1 and is picked up there. + +**The tests, verbatim, with their exact denominators:** + +| Clause | Test | Threshold | Denominator — exact wording | +|---|---|---|---| +| **3/4/2** | interest-bearing debt, long- or short-term | **30%** | *"of the **market capitalization** of the corporation"* | +| **3/4/3** | **interest-taking deposits** | **30%** | *"of the **market capitalization of total equity**"* | +| **3/4/4** | income from a prohibited component | **5%** | *"of the **total income** of the corporation"* | +| **3/19** | tangible assets, benefits and rights | **≥ 30%** | *"of the **total assets** value of the corporation"* | +| — | accounts receivable | **no such test exists in SS 21** | — | + +The only percentages anywhere in the standard are 30% (three times) and 5% (once). **There is no +33% and no receivables screen.** + +**Four details that a DJIM-shaped implementation would get wrong:** + +1. **The deposits numerator is *deposits*, not cash.** 3/4/3 counts *"interest-taking deposits"* — + AAOIFI does **not** put a company's ordinary cash in the numerator, where DJIM/MSCI/S&P use + `cash + interest-bearing securities`. A keel implementation reusing the commercial-index + numerator would be screening something AAOIFI did not ask for. +2. **The income denominator is *total income*, not revenue.** AAOIFI says *income*; DJIM and S&P + both say *Total Revenue*. Not interchangeable. +3. **There is no averaging window at all.** Clause **3/4/5**: *"For the determination of these + percentages, recourse is to be had to the **last budget or verified financial position**."* + Point-in-time, off the latest verified financials. Every commercial index uses a trailing average + (DJIM 24-month, MSCI M-Series and S&P 36-month); **AAOIFI uses none**, and anyone citing "AAOIFI's + 12-month average" is importing it from elsewhere. ⚠️ **This corrects a claim made earlier in this + document's own §2**, where the recurring-cost argument leaned on a continuously-moving average + denominator — see the correction there. +4. **⚠️ SS 21 contradicts itself on the 3/19 floor.** Clause 3/19 says **30%**, but footnote (1) to + 3/1 says *"should not be less than **one-third**"* and the Appendix says *"less than a third."* + The footnote even carries AAOIFI's own hedge: *"(This explanatory note is intended to complete + the text of the Standard for implementing subsequent amending procedures, God willing)."* + **Do not present that floor as unambiguous.** + +**Ongoing obligation — and it answers a question this document raised as open.** Clause **3/4/8**: + +> "It is necessary to observe these rules **throughout the period** of participation or trading. If +> the rules cannot be applied, **it is obligatory to give up such investment**." + +That is the admitted-then-failed disposal semantics named as undecided earlier in §3. **SS 21 +decides it: forced disposal.** It is not left to the implementer. + +**Purification — clause 3/4/6, and it has a sharp edge for a trading agent.** The obligation is +*"to eliminate prohibited income specific to the share that is mixed up with the earnings of the +corporations"*, and: + +- **3/4/6/1** — the obligation falls on whoever holds the share **at the end of the financial + period**. *"Accordingly, elimination is not obligatory for one who sells the shares before the end + of the financial period."* +- **3/4/6/2** — it applies *"whether or not the profits have been distributed and whether or not the + corporation has declared a profit or suffered a loss."* **Purification is therefore not a + dividend-only concern** — a non-dividend-paying holding can still carry the obligation. +- **3/4/6/4** — the formula: total prohibited income ÷ number of shares, × shares held. +- **3/4/6/5** — *"It is **not permissible to utilise the prohibited component in any way whatsoever** + nor is any legal fiction to be created to do so **even if this is through the payment of taxes**."* + +⚠️ **The 3/4/6/1 carve-out is a live hazard, not a convenience.** keel's mean hold is ~24 days, so +keel would frequently sell before a period end and owe nothing under the letter of the rule. **An +agent that satisfies a purification obligation by holding briefly is gaming a timing rule**, and +§65.9's posture — segregate what accrued, report it, never adjust — is the more conservative +reading. This document does not resolve it, but it is a second place (alongside §3.1) where SS 21 +as written is *looser* than keel's existing instincts, and it should not be discovered during +implementation. + +**Other SS 21 prohibitions keel already satisfies by construction**, worth recording because they +confirm the fit: **3/5** no margin or interest-financed purchase and no pledging shares for such a +loan (this is rail 13's posture, and §65.10 quotes the same rule from Ayub); **3/6** no short +selling; **3/9** no share lending; **3/11** no Salam; **3/12** no futures; **3/13** no options; +**3/14** no swaps; **3/15** no renting of shares. keel is long-only spot with settled cash — it +clears all eight without a line of code. + +**How SS 21 compares to the index families it was chosen over** (all methodologies read 2026-08-09): + +| | Debt | Cash / deposits | Receivables | Impermissible income | Denominator | Window | +|---|---|---|---|---|---|---| +| **AAOIFI SS 21** | **30%** | **30%** (deposits) | **none** | **5% of total income** | **market cap** | **none** | +| DJIM (May 2025) | 33% | **screen retired 09/2023** | **screen retired 03/2023** | 5% of total revenue | 24-mo avg market cap | 24-mo | +| MSCI Islamic | 33.33% | 33.33% | 33.33% | 5% of revenue | **total assets** | latest report | +| S&P Shariah | 33% | 33% | 49% | 5% of revenue | market value of equity | 36-mo | + +⚠️ **Two corrections this table forces on §65.10's material, which is the KB's only screening +reference today.** First, **§65.10's three-ratio DJIM description is out of date**: S&P DJI retired +the receivables screen effective 2023-03-17 and the cash/interest-bearing-securities screen +effective 2023-09-15, leaving DJIM with a **single** accounting screen. A keel screen built against +§65.10's DJIM form would be implementing a methodology its own author retired three years ago. +Second, **§65.10 records the DJIM denominator as a 12-month average; current DJIM uses 24 months** — +Ayub's book predates the change. Neither correction affects the *verdict*, and neither is a defect +in §65.10, which faithfully records what its source said; both are reasons the KB entry needs a +refresh whenever SS 21 is read in. + +**MSCI is the real outlier and the comparison worth keeping:** a **total-assets** denominator is +price-insensitive, where AAOIFI's **market-cap** denominator means a company can fail the debt +screen on a price drawdown alone, with an unchanged balance sheet. **For a trading agent that is a +genuinely awkward interaction** — the moment a holding's price falls hardest is the moment it is +most likely to breach a market-cap-denominated leverage screen, which is also the moment keel's +stop is closest. A forced-disposal obligation (3/4/8) and a stop-loss exit would fire together, for +unrelated reasons, and the audit trail would need to say which one caused the sale. + +### 3.1 ⚠️ The open question the owner will face: adopting SS 21 would make keel *less* conservative + +This is named, not resolved. It is the first place in keel's history where following a standard +would loosen the project's posture rather than tighten it, and whoever builds the screen will meet +it on day one. + +**⚠️ Read the standard's own framing first, because it narrows this tension substantially — and +this subsection was drafted before the text was available, on the assumption that it would not.** +SS 21 does not present its ratios as neutral thresholds the way an index methodology does. Clause +3/4 states that **"the fundamental rule is that of prohibition"**, that this holds **"even when +their primary activity is permissible"**, and that the ratios are an **exemption** from that rule, +grounded in the Appendix on *"removal of hardship and acknowledging of general need, widespread +practice."* Each ratio clause then repeats the point against itself: 3/4/2 adds *"knowingly that +raising loans on interest is prohibited whatsoever the amount is"*, and 3/4/3 *"knowingly that +interest-taking deposits are prohibited whatsoever the collective amount is."* + +**That is much closer to keel's instinct than DJIM's numbers are, and it changes the shape of the +question.** AAOIFI is not saying a 4% riba income is fine; it is saying it remains prohibited and is +tolerated under necessity, with mandatory purification attached. keel's binary rejection and +AAOIFI's exemption-from-prohibition are the *same posture* at different points on a hardship +argument — where DJIM's threshold, read cold, genuinely is a de minimis test. + +**The tension is therefore real but narrower than it first appears, and it reduces to one question: +does the hardship rationale that justifies AAOIFI's exemption apply to keel at all?** The exemption +exists because a Muslim investor who refused every company with incidental interest exposure could +barely participate in modern equity markets. **keel is not in that position.** It is a discretionary +agent with a five-asset allowlist and no mandate to hold equities whatsoever, so "removal of +hardship" is a weak argument in its case — which is an argument *for* keel keeping its stricter +line, and it is an argument the standard's own reasoning supplies rather than one keel would be +inventing. + +With that framing established, the original tension still stands on the numbers: + +> ⚠️ **Criterion 5 is the interesting one, and it cuts against our instincts.** The mainstream +> standard is **not** zero-tolerance: a company with ≤5% incidental interest income is *investable*, +> with the tainted fraction purified. Our posture is **binary rejection** on any riba-yield function +> (§41.1). **That is stricter than the standard.** +> … **it should be documented as a deliberate over-compliance, not presented as *the* standard.** + +Every precedent in this repo runs the same way. keel's screen rejects a `riba_yield` sector +outright where AAOIFI/DJIM tolerate an incidental fraction. `backing == "dayn"` is an **unwaivable** +rejection and `WAIVABLE_CRITERIA` is exactly `{"history"}` (`screen.py:60`). §65.14 refuses staking +on §29.2 conservatism rather than on a ruling keel holds. Rail 19 carries no config field because +*"spot-only is this agent's CHARTER"*. **The pattern is: where the standard permits a tolerance, +keel has declined to use it.** + +Adopting SS 21 as written would invert that, and in the most conspicuous possible place — an +impermissible-income tolerance is, by construction, a rule that admits an instrument keel *knows* +carries some riba, on the grounds that the amount is small and the remainder can be purified. That +is a coherent and mainstream position, held by every major Islamic index. It is also the exact +shape of reasoning §65.1 warns about: **riba is strict-liability with no de minimis**, where gharar +is a materiality threshold. A percentage tolerance is a de minimis test. + +The two defensible resolutions pull in opposite directions, and both have KB support: + +- **Adopt SS 21 as written.** The tolerance is not keel's invention to reject — it is the standard's + considered position, paired with a mandatory purification obligation that keel already has + machinery for (§65.9, `keel/compliance/purification.py`). §65.10's own reasoning for keeping the + stricter crypto line was that *"a 5% test is unmeasurable for tokens"* — a company's financial + statements make it perfectly measurable, so the stated reason for the divergence **does not + transfer to equities**. This is the strongest argument, and it is worth noticing that it is an + argument §65.10 supplies against itself. +- **Adopt SS 21's structure with keel's stricter thresholds**, recorded as deliberate + over-compliance under §29.2 exactly as §65.10 asks. Consistent with every precedent above, at the + cost of a smaller investable universe and of keel holding a position no standard body holds. + **The standard's own hardship rationale is the strongest support for this option** — see the + framing above: an exemption granted to relieve hardship is weakest where there is no hardship, and + a five-asset discretionary agent has none. + +**And a second, smaller instance of the same tension, which the standard text surfaced and nobody +would have predicted: the purification timing rule.** Clause 3/4/6/1 places the obligation on +whoever holds the share **at the end of the financial period** and states outright that +*"elimination is not obligatory for one who sells the shares before the end of the financial +period."* keel's ~24-day mean hold means it would routinely fall on the exempt side. **A system that +discharges a purification obligation by not being there on the measurement date has satisfied the +letter and hollowed out the intent** — and §65.9's posture (segregate what accrued, report it, +adjust nothing) is the stricter and more coherent reading. Same shape as the ratio question, same +answer available, and worth deciding at the same time rather than separately. + +**This document does not choose, on either.** Both readings are defensible; the choice is a +compliance decision for the repo owner, it should be made explicitly and written into the KB rather +than falling out of an implementation, and it should be made **before** any screen is built rather +than discovered while calibrating one. Naming it is the deliverable here. + +### The rest of what a screen would need + +Sketched, not designed. Enumerated so the cost estimate below has something to point at. + +1. **SS 21 read into the KB as a source**, in the KB's normal form, with the §3.1 decisions recorded + and keel's deviations stated. The criteria are quoted above and the standard is freely available + from AAOIFI, so this is a KB-authoring task rather than a research one — **and it should carry + the two §65.10 corrections this document surfaced** (DJIM's retired screens, the 12- vs 24-month + window), since §65.10 is the KB's only screening entry today. +2. **A second attestation kind** — **issuer-keyed, not asset-keyed**, which is itself a schema + departure — carrying: core business line; **interest-bearing debt ÷ market cap (3/4/2, 30%)**; + **interest-taking deposits ÷ market cap (3/4/3, 30%)** — note the numerator is *deposits*, not + cash; **prohibited income ÷ total income (3/4/4, 5%)**; **tangible assets ÷ total assets (3/19, + ≥30%, ⚠️ stated inconsistently in the standard)**; plus the verified financial position each was + taken from (3/4/5 — point-in-time, no averaging) and the filing it came from. **No receivables + field: SS 21 has no such test.** +3. **A thresholds policy object**, versioned, with keel's divergences from SS 21 recorded the way + §65.10 asks — because after §3.1 the interesting question is not "does keel implement AAOIFI" + but "where does keel deviate, in which direction, and why". +4. **Per-period re-screening with fail-closed staleness** — mandated, not optional: clause **3/4/8** + requires the rules be observed *"throughout the period"*. **The action on a later failure is no + longer an open design question**: 3/4/8 specifies *"it is obligatory to give up such + investment"* — forced disposal. What is still keel's to decide is the *mechanism*, and it is + awkward: a compliance-driven forced sale is an exit no rule generated, and `guards.py`'s + rail 16 comment warns that a breaker blocking exits "would trap capital" — so this exit must be + able to fire even when other machinery is halting. **A compliance exit is a new order class**, + not a reuse of the stop path. +5. **A purification path — and it is broader than dividends.** Clause 3/4/6/2 is explicit that the + obligation applies *"whether or not the profits have been distributed and whether or not the + corporation has declared a profit or suffered a loss"*, so a non-dividend-paying holding still + carries it; the 3/4/6/4 formula needs the issuer's total prohibited income and share count, not + keel's own cash ledger. §65.9 already has the machinery and the right posture — report-only + segregation, `keel/compliance/purification.py`, ⛔ **"REPORT-ONLY. The agent never disposes of + funds."** — but note it currently computes from **keel's transaction ledger**, and this + obligation is computed from **the issuer's financials**. That is a new input, not a new report. + The §3.1 timing hazard (3/4/6/1's sell-before-period-end exemption) is a policy decision that + belongs here. +6. **A fundamentals data source**, with cost and licensing. Unverified — no vendor was priced for + this document. + +**Item 6 and the recurring cost in §2 are why this is not day-estimable with confidence.** The +estimate below gives a range and says so. + +## 4. If not Coinbase, who? — broker survey + +**Every row here is documentation and pricing-page reading on 2026-08-09. No account was opened, no +key issued, no sandbox exercised** — the single exception is an unauthenticated 401 handshake +against Robinhood's MCP endpoint, which needed no account and is flagged where it is used. Sandbox +fidelity, fill behaviour, rate limits and corporate-action reporting are therefore all +**unmeasured**, and the recommendation below is a paper judgement. Some vendor doc hosts +(`docs.alpaca.markets`, `docs.tradier.com`) block automated fetching; where a finding rests on +search-indexed official documentation rather than a directly loaded page, it is flagged in the +prose. ⚠️ **Correction: an earlier draft listed `developer.schwab.com` among the blocked hosts. It +is not** — its terms-and-conditions page loads fine and was read directly (see the Schwab note +below); what is gated is the Individual Developer Agreement behind login. + +| Venue | Official equities API | Auth | Free paper sandbox | Fractional | Market data | Official Python SDK | Fit for keel | +|---|---|---|---|---|---|---|---| +| **Alpaca** | yes — REST + WebSocket | key + secret | **yes, self-serve** | **yes**, $1 notional | free IEX real-time / **$99·mo⁻¹** full SIP | **`alpaca-py`** ✓ | **best fit** | +| **Interactive Brokers** | yes | local gateway login | paper needs a funded live account first | broker yes, **API rounds down** | free non-consolidated; ~$4.50·mo⁻¹ NBBO | `ibapi` (in the TWS zip) | most capable, highest cost | +| **Tradier** | yes — REST | bearer token | yes, free, 15-min delayed | **RIA-only** | included, $0 | **none** | **disqualified — see below** | +| **Tastytrade** | yes | **OAuth2 only** | yes, resets q24h | yes, notional | included | none (unofficial `tastytrade`) | viable second choice | +| **Schwab** | yes | OAuth2, **7-day refresh** | **no** | unverified | included | none | **unsuited to unattended use** | +| **Robinhood** | **no REST** — MCP only | **OAuth PKCE, browser consent, no `client_credentials`** | no | n/a | n/a | none | **disqualified — cannot run unattended.** See the correction below | +| **Coinbase** | **yes** (§1b) — but no preview, no attached orders | existing CDP key | no | normal session only | **none — measured absent 2026-08-05 and again 2026-08-09** | `keel-broker-coinbase` (crypto) | **unusable for keel today** (§1a/§1c) | + +### Why Alpaca, on keel's specific constraints rather than on vendor marketing + +Three of keel's own defects decide this, and they point the same way. + +- **C6 (no lot rounding) makes fractional support load-bearing, not a nicety.** + `keel/execution/sizing.py` emits fractional `Decimal`s and rounds to nothing. A venue that + requires whole shares turns C6 from a latent gap into a blocking one. **This is what disqualifies + Tradier and damages IBKR**: Tradier's own disclosure restricts fractional shares to *"a Registered + Investment Advisor"* — a self-directed retail developer cannot place notional equity orders at all + — and IBKR documents that *"Stock orders submitted using Cash Quantity field through the API will + round down to the nearest whole share."* +- **keel's entry model is quote-sized.** Entries are `MarketIOCByQuote` — "spend $N" — which is + exactly Alpaca's notional-order shape ($1 minimum, market orders only, long only). keel is + long-only by type (`Setup.direction: Literal["long"]`), so every one of those restrictions is + already keel's own posture. **The one adapter constraint that broke Robinhood-for-crypto — no + quote-sized market orders, so it "cannot open positions under keel's current entry model" + (`packages/keel-broker-robinhood/README.md`) — does not recur here.** +- **Unattended operation is non-negotiable.** keel runs from launchd with no human in the loop. + That is what rules out Schwab, and for a more mundane reason than any policy: **its refresh token + hard-expires at 7 days with no renewal mechanism**, so unattended operation would require a human + redoing a browser OAuth flow every week. Combined with the absence of any paper-trading simulator + — Schwab's "sandbox" is an API-call harness returning engineered datasets, not a fill simulator — + it is the worst fit in the table for this workload. + +Alpaca is also the closest **DX shape** to Advanced Trade — REST + WebSocket, key/secret, a +self-serve paper account that needs no funded live account first — which matters because it is the +shape `packages/keel-broker-coinbase` is already written against. `alpaca-py` is unambiguously the +current official SDK (v0.43.5, 2026-07-02); its predecessor `alpaca-trade-api-python` is +**archived and formally deprecated**, and Alpaca's own marketing page still shows sample code +importing the dead one — a trap worth recording before anyone copies it. + +The honest cost note: the **free data tier is IEX-only for real-time**, which is a fraction of +consolidated volume and a poor basis for a daily-candle strategy's marks. Full SIP is **$99·mo⁻¹** +(https://alpaca.markets/data, read 2026-08-09), which would be keel's first recurring market-data +bill — Coinbase candles are free today. The free tier does serve 15-minute-delayed SIP and full +historical SIP older than 15 minutes, so a **daily-bar** strategy might survive on it; whether it +does is **unverified — needs a probe**, and it is a real input to any cost decision. + +### ⚠️ Correction to a premise this survey was started with: Robinhood + +The brief for this document held that Robinhood offers no sanctioned programmatic equities access. +**That is now out of date, and the correction matters enough to state plainly rather than bury.** + +What remains true: **there is still no official public REST equities API.** `docs.robinhood.com` +ships one product — the **Crypto** Trading API — and that is what +`packages/keel-broker-robinhood` is written against (its own README: *"implemented against the +Robinhood Crypto Trading API v2"*). **keel's existing Robinhood adapter does not extend to stocks, +and no amount of work on it would make it.** The unofficial libraries (`robin_stocks` still active, +`pyrh` in maintenance mode) still hit undocumented private endpoints with real ToS and +account-suspension risk, and should not be used. + +What is new: on **2026-05-27** Robinhood launched **Agentic Trading** +(https://robinhood.com/us/en/newsroom/robinhood-is-now-open-to-agents/, read 2026-08-09), which is +official, first-party, OAuth-authenticated programmatic equities access — *"Agentic Trading is +launching in beta with support for equities only out of the gate."* It is delivered as a **hosted +MCP server**, with read access across accounts but **write access only within a dedicated, +separately-funded Agentic account.** + +**The endpoint is real and live**, confirmed 2026-08-09 without an account: +`POST https://agent.robinhood.com/mcp/trading` returns **HTTP 401** with +`www-authenticate: Bearer resource_metadata=…/mcp/trading` — a correctly-formed MCP authorization +challenge, not a 404 and not a marketing page. + +**Four reasons this does not change the verdict, and one reason it is still worth recording:** + +1. **It does not touch the charter gate.** §2 is broker-independent. An easier venue does not + screen a company's balance sheet. +2. **⚠️ Its auth model is disqualifying for keel specifically, and this is the concrete blocker + rather than a stylistic objection.** Authorization is **OAuth PKCE requiring a one-time desktop + browser consent**, and the advertised grant set carries **no `client_credentials`** — there is no + machine-to-machine path. **keel runs headless, from launchd, with no human in the loop** + (`com.keel.live.plist`, 24 invocations a day). An auth flow whose first step is "open a browser + and click approve" cannot be automated by keel and must not be worked around. This is the same + defect that rules out Schwab, arriving by a different route. +3. **An MCP server is not a `Broker`.** keel's port is a typed Python `Protocol` whose + implementations make direct HTTP calls; an MCP endpoint is a tool surface designed to be driven + by an LLM agent. Wiring it in would make keel an MCP *client* and put a model in the order path — + architecturally alien to a deterministic rule engine whose entire audit story is that + `guards.check` ran over a typed `OrderIntent`. That is not an adapter; it is a different agent. +4. **It is a separate funded account**, and its scope model is coarse in a way that forecloses the + obvious fallback. `scopes_supported` is the single value `["internal"]` — **there is no read-only + variant**, so keel could not take Robinhood's equity market data without simultaneously granting + order-placement authority over the Agentic account. "Use it for data only" is not available here + the way it was for cTrader. +5. **But it is a clear signal that programmatic equities access is arriving from several directions + at once** — Robinhood shipped an agentic equities path in May 2026, and Coinbase's REST surface + already carries equities in its schema (§1b). The venue question is getting easier on its own. + **The screening question is not**, and that asymmetry is the whole finding. + +### One claim from the brief that did not survive checking — and the rule it produced + +The brief asserted that Schwab's commercial-approval review *"explicitly scrutinizes automated or +AI-driven functionality"* — a real risk for an unattended bot, if true. **It is not Schwab's +wording, and it is not printed here as a finding.** Schwab's publicly-readable developer terms +(https://developer.schwab.com/terms-and-conditions, read 2026-08-09 — 16.6 KB of real contract text, +not a login wall) contain **zero matches** for `AI`, `artificial intelligence`, `machine learning`, +or `advisory`. The app registration form collects four fields and an order limit, with no automation +or AI attestation anywhere. + +**The wording traces to five interlinked articles on a single domain, `mylinedchart.com`, whose +registration record dates to 2026-04-20** and whose own disclaimer states it is *"not affiliated +with or endorsed by Charles Schwab."* The articles paraphrase rather than quote, cite no Schwab +document, and describe the *Commercial* track rather than the Individual one — and they now rank +highly enough that AI search summaries restate them as policy. **A five-page cross-linked cluster on +one four-month-old domain reads as corroboration and is a single source.** + +⚠️ **Caveat on that refutation, preserved deliberately:** Schwab's **Individual Developer Agreement** +is gated and could not be read. So this is refuted **across every publicly-readable Schwab page**, +not disproven absolutely. The documented gate is mundane: *"Most requests are reviewed within two +business days"*, individuals are limited to one app, and the dashboard shows `Approved - Pending` +before an app is actually usable (`Ready For Use` is the state to wait for). **Schwab is ruled out +below on its 7-day refresh token, which is a documented mechanism, not on any AI-policy claim.** + +This is recorded at length for one reason: it is a live example of the failure mode this repo's +documents are written to avoid. **A plausible, specific, useful-sounding claim, repeated by search +summaries, with no primary source under it.** It was in the brief for this document and would have +been printed as fact. + +## 5. The engineering gap, if the charter gate were cleared + +The 2026-08-05 study numbered keel's instrument-model defects C1–C13. Those findings are cited, not +restated. What follows is which of them equities hit, plus the ones that are new to equities and do +not appear in that list at all. + +### Inherited from C1–C13 (see the 2026-08-05 study for the evidence) + +| # | Area | How equities hit it | +|---|---|---| +| **C1/C2** | instrument identity and construction | `quote_currency_of` does `rpartition("-")`, `guards._asset` does `split("-")[0]`, and `keel/commands/_products.py` can only construct `f"{asset}-{quote}"`. An `AAPL-USD` id from a sane adapter survives all three — **equities are much kinder here than futures were.** Coinbase's 64-char hash does not, and its docs now confirm the hash is mandatory (*"not the display ticker"*, §1b) — one more reason §4 lands on a different venue. | +| **C3** | position model | positions are reconstructed from keel's own SQLite audit log and never fetched from the venue; the port still has **no `get_positions`** (`packages/keel-broker-api/keel_broker_api/port.py:23-47` — verified 2026-08-09: the Protocol is exactly eight methods, `capabilities`/`get_candles`/`get_balances`/`preview_order`/`place_order`/`get_fee_summary`/`get_order`/`cancel_order`, and none of them is one). Corporate actions make this worse: see below. | +| **C4** | balance model | `Balance(currency, available, total)` has no notion of **settled vs unsettled** cash. T+1 makes that distinction real. | +| **C6** | lot sizing | `keel/execution/sizing.py` emits fractional `Decimal`s and never rounds to a venue lot (`size`, `dca_size`, `spend` — the whole module, verified 2026-08-09). Fractional-share brokers make this survivable; a whole-share venue does not. | +| **C11** | 24/7 assumption | the live one. Expanded below. | +| **C13** | capability gate is dead | `BrokerCapabilities.asset_classes` already contains `"equity"` in its vocabulary (`packages/keel-broker-api/keel_broker_api/capabilities.py:21`, `ASSET_CLASSES = frozenset({"spot", "futures", "equity"})`) and **is read by nothing** — the field's own docstring says so: *"`asset_classes` is **not** what keeps keel spot-only today, and no engine code reads it."* All three shipped adapters declare `frozenset({"spot"})`. **Declared, not wired.** | + +### New to equities, and not in C1–C13 + +**E1. The broker port is not on the live path — so equities sit behind TWO migrations.** +Verified 2026-08-09: + +- `keel/execution/executor.py` types the broker as bare `Any` at every site (`:110`, `:312`, + `:416`, `:731`, `:801`, `:841`, `:946`, `:965`), and calls the **pre-port raw `CoinbaseClient` + signatures**, not the port's: `broker.preview_order(intent.product_id, intent.side, + order_configuration)` (`executor.py:445`) and `broker.place_order(...)` (`:486`) against + `keel/data/cb_client.py:223,247` — where the port's shape is `preview_order(spec: OrderSpec)` + (`port.py:32`). `broker.get_accounts()` (`executor.py:282`) is not on the port at all; the port + has `get_balances()` (`port.py:30`). +- `keel/commands/_common.py:137-156` (`_build_broker`) constructs `CoinbaseClient` directly, from + `coinbase.rest.RESTClient` and `keel.config.load_secrets`. It **never calls `load_broker()`** — + `packages/keel-broker-api/keel_broker_api/registry.py:23` is reachable only from + `discover_brokers`, and nothing on the order path calls either. +- There is **no `broker:` key in any config** — `grep broker config.yaml config.live-sandbox.yaml + config.paperforward.yaml` returns nothing. +- Three adapters register under the `keel.brokers` entry-point group (coinbase, robinhood, fake — + `packages/*/pyproject.toml`) and all pass the conformance suite + (`packages/keel-broker-api/keel_broker_api/conformance/suite.py`). Installing one makes it + **discoverable and conformance-checkable, not tradeable.** + +That migration is Phase B, already scoped: +*"Phase B (spec steps 6–9) migrates the engine onto the validated port: retiring `executor.py`'s +three `_*_order_configuration` builders and `_initial_status`, typing `agent.py`'s broker parameter +as `Broker`, deleting `keel/data/cb_client.py` … It carries all of this work's behavioural risk and +warrants its own plan."* (`docs/superpowers/plans/2026-07-19-keel-broker-port-phase-a.md:1159`). +**An equities adapter written before Phase B lands is dead code by construction** — exactly the +state `packages/keel-broker-robinhood/README.md` documents for the adapter already in the tree. + +**E2. Rails 18 and 19 veto every equity id, and rail 19 has no widening knob.** +`keel/execution/guards.py:668-757`, read 2026-08-09. Rail 19's check is: + +```python +if parse_spot_product_id(intent.product_id) is None: + violations.append( + f"spot_instrument: {intent.product_id!r} is not a well-formed spot product id " + f"(BASE-QUOTE, uppercase, exactly one hyphen). keel is spot-only: futures " + f"(BASE-DDMMMYY-CDE), equities (an opaque 64-char hash) and any other instrument " + f"shape are refused here regardless of what they settle in." + ) +``` + +Two things to be precise about, because the naive reading is wrong in both directions: + +- The error message **names equities explicitly**, but what it actually rejects is the *Coinbase* + equity id shape (a hash with no hyphen). A well-behaved adapter emitting `AAPL-USD` **passes both + rails** — the grammar checks shape, not what backs the instrument, which is the same residual + `guards.py:726-731` records for `BTC-PERP` (Coinbase International's actual perpetual format, + which passes this grammar and is stopped only by rail 18). So rail 19 is not a semantic equity + gate and must not be described as one. +- What *is* load-bearing is the comment, and it is un-negotiable by design: + + > Spot-only is this agent's CHARTER, not an operator preference, so there is no config field here + > to widen (unlike rail 18's `settlement_currencies`). + + Rails 18 and 19 both run on **both sides, in every mode, DCA included** — deliberately not in + `LIVE_STATE_RAILS` (`guards.py:167`), so paper cannot skip them. + +**Widening rail 19 is mandatory for equities, and it is the single most safety-critical change in +this document.** Whatever replaces "is this a spot pair" has to keep refusing everything the +current grammar refuses — the `CDE` futures family, the `BASE-PERP-QUOTE` residual, the hash — while +admitting exactly one new shape. It is also the change where a mistake is silent: rail 19 is the +thing standing between keel and a derivative, and there is no second rail behind it for a +three-segment id. Any equities work must ship this with its own tests before an adapter, not after. + +**E3. No market-hours or session model exists anywhere. Verified by grep, 2026-08-09.** +`grep -rn "is_market_open|market_hours|exchange_calendar|trading_session" --include="*.py"` over the +tree returns exactly one hit, and it is in the 2026-08-05 probe script +(`docs/experiments/2026-08-05-coinbase-asset-class-probe.py:268`, printing Coinbase's +`session_type` list). **Nothing in `keel/` knows a market can be closed.** + +What happens instead is C11: a closed market fails +`keel/data/market_feed.py:160-176`'s `is_fresh`, which compares the newest stored candle to +`now_ts` against `config.auto_trade.interval_sec * FEED_STALENESS_CYCLES` (`keel/agent.py:856`). +The product is skipped for the cycle and logged as `feed_stale`. **That behaviour is safe — keel +refuses to act on a stale series, which is what the check is for — but it is indistinguishable in +the logs from an outage.** Every weekend, every holiday, and every overnight would emit the same +event a broken feed emits. Over a 252-day calendar that is the majority of wall-clock hours. + +The deployment cadence says the same thing from the other side: `com.keel.live.plist` fires +`StartCalendarInterval` **24 times a day**, hourly at :20, on a UTC daily-candle cadence. That is a +crypto calendar. It is not wrong for equities so much as meaningless — 14 of those 24 cycles would +have nothing to do. + +**And a session model is not optional at the venue either, which §1b makes concrete.** +⚠️ **This paragraph previously named a type `EquityTradingSession` with five bare values; that +spelling was invented and is corrected here against the source.** The real field is +`equity_order_metadata.equity_trading_session`, and its enum, read directly from the create-order +reference on 2026-08-09 +(https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/orders/create-order), is +**six** prefixed values: + +``` +UNKNOWN_EQUITY_TRADING_SESSION (the documented default value) +EQUITY_TRADING_SESSION_NORMAL +EQUITY_TRADING_SESSION_PRE_MARKET +EQUITY_TRADING_SESSION_AFTER_HOURS +EQUITY_TRADING_SESSION_OVERNIGHT +EQUITY_TRADING_SESSION_MULTI_SESSION +``` + +**A second correction in the same paragraph: the field is optional, not required.** Coinbase's own +description reads *"Defaults to `EQUITY_TRADING_SESSION_NORMAL` when omitted. Market orders are +supported only in the normal session. Any non-normal session requires a limit order with a positive +whole-share `base_size`; `quote_size` and fractional sizing are not supported."* + +So the accurate statement is weaker than the earlier one and still sufficient: **the session is not +a required field, but it is a field whose default silently confines keel to one session, and whose +non-default values change both the permitted order type and the sizing basis.** A crypto-shaped +`OrderIntent` carries no concept that could populate it, and an agent that never sets it is an agent +that can only trade 09:30–16:00 ET and does not know that about itself. That keeps E3 a hard +prerequisite for this venue, on a smaller claim, correctly spelled. + +**E4. No table records asset class.** `keel/data/db.py`, `SCHEMA_VERSION = 9` (`db.py:22`). +`orders`, `positions`, `candles` and `transactions` all key on an opaque `product_id`/`asset` +string; `asset_attestations` keys on `asset`. **Nothing anywhere in the schema records what kind of +thing a row is about.** A mixed crypto/equity ledger would be indistinguishable per-row, which +matters for P&L attribution, for the exposure walk in `_open_exposure_by_asset`, and for +`UNCORRELATED_ASSETS` (`guards.py:120` — the 2026-08-05 study's C10 cites `:98`; the line has moved +since, the fact has not) — a hardcoded single-member set `frozenset({"PAXG"})` that says nothing +about whether AAPL is correlated with BTC. + +**E5. T+1 settlement and settled-vs-unsettled cash — and the one place keel is already right.** +This is a genuinely new accounting concern: `Balance(currency, available, total)` cannot express +"sold yesterday, cash not yet settled", and a good-faith-violation / free-riding rule has no +representation anywhere. + +**But rail 13 is well-aligned, and this deserves to be said plainly rather than buried.** +`guards.py:512-541`: + +> **13. USDC-funding** — a BUY may only spend an **already-settled** quote-currency balance, never +> a linked bank/ACH source. Fails closed: an unknown balance (`None`) vetoes the BUY. + +That is, almost word for word, the posture a **cash account with no margin** requires — which is +also the only equities posture §65.10 permits (*"it is not permissible to purchase a share with an +interest-bearing loan offered to the purchaser by a broker"*). keel did not build rail 13 for +equities and it lands on the right side anyway. The honest caveats: rail 13 is **BUY-only** (SELL is +exempt — it produces quote currency) and **skipped when `offline=True`** (`LIVE_STATE_RAILS`, +`guards.py:167`), so it is not a defence a paper rehearsal exercises. + +**E6. The Pattern Day Trader rule — eliminated, and it barely mattered to keel anyway.** +The $25,000 pattern-day-trader minimum-equity requirement is the constraint most people expect to +bind an automated equities strategy. **It no longer exists.** FINRA **Regulatory Notice 26-10**, +*"FINRA Adopts New Intraday Margin Standards to Replace the Day Trading Margin Requirements"* +(https://www.finra.org/rules-guidance/notices/26-10, read 2026-08-09), states that the amendments +replace *"the day trade count requirements for designating a customer as a 'pattern day trader' and +the $25,000 pattern day trader minimum equity requirement."* FINRA's investor page puts it plainly: +*"no 'pattern day trader' designation based on counting trades"* and *"no $25,000 minimum equity +requirement for day trading"* (https://www.finra.org/investors/insights/intraday-margin-requirements). + +Effective **2026-06-04**, replaced by a risk-based intraday margin framework, with an **18-month +phase-in ending 2027-10-20**: *"Members that need more time to implement the rule change will be +permitted to phase in their implementation over a period of 18 months, until October 20, 2027."* +The SEC approved the proposal on **2026-04-14** (Exchange Act Release No. 105226, 91 FR 20731, +file SR-FINRA-2025-017 — citation chain per FINRA's own notice; sec.gov and federalregister.gov +both refuse automated fetching, so the release number was not read at source). Independently +corroborated by WilmerHale, 2026-04-23. + +**Two caveats and one reason this is a footnote rather than a finding.** The new regime applies +*regardless of whether the customer day trades* — firms must monitor intraday margin deficits in +all margin accounts — so it is not simply a deregulation. And during the phase-in window an +individual broker may still be running the old rules, so "the PDT rule is gone" is not yet true of +every venue. **But keel holds positions for ~24 days on average +(`.../sources/source-71.md:758`, §71.8's substantive-defence line: *"real asset, real ownership, +real delivery, ~24-day holds, rule-driven exits"*) and is long-only with no margin: it was never a +pattern day trader, and rail 13's settled-cash requirement means it could not use margin buying +power even if offered.** The rule change removes an obstacle keel did +not have. It is recorded because its *absence* would otherwise be the first thing a reader checks, +and because a cash-account posture is now the only relevant one. + +**E7. Corporate actions — a class of position mutation keel has never modelled.** +A split changes the quantity of a held position without any order; a dividend credits cash without +any order; a spin-off creates a position that was never bought. keel's positions are reconstructed +**from keel's own audit log of its own orders** (C3, `db.py:74-89`), so every one of those is a +silent divergence between keel's books and the broker's. Worse, `_warn_on_unexplained_jump` +(`keel/execution/equity.py:133`) exists precisely to detect equity that moved for reasons keel +cannot explain, and is deliberately **detection-only** — its docstring: *"it NEVER adjusts +anything… flows are declared by the operator (`keel record-flow`) and this is only here to make a +forgotten one loud."* A dividend season would fire it routinely with nothing for the operator to +record, **training them to ignore the one alarm that guards rail 11's high-water mark.** That is a +worse outcome than the missing feature itself. + +The dividend half has a compliance dimension that is, unusually, already solved in outline: +§65.9's purification report (`keel/compliance/purification.py`) segregates non-compliant credits +from the transaction ledger and is **report-only by design** — *"The agent never disposes of funds. +This computes an amount owed and says so; moving it is the operator's act."* Extending it to the +non-permissible fraction of a dividend is an extension, not an invention. + +## 6. What it would cost + +**This is a magnitude, not a plan.** Nothing here is proposed, scheduled, or recommended — the +decision this document records is *no*, and the numbers exist so that the *no* is an informed one +rather than a shrug. A reader should be able to tell from this section whether equities are a +quarter of work or a year of it, and nothing more should be inferred from it. + +**These are estimates, not measurements.** They are engineer-days for a single engineer, covering +design + implementation + tests to this repo's standard, and they assume no scope growth. They +exclude the standards and ruling work in §7 items 1–2, which is not engineer-days at all. The +2026-08-05 study's own caveat applies unchanged: *"Day estimates are judgement, not measurement."* + +Ordered by dependency, and by which is the true blocker. + +| Phase | Work | Days | Unlocks | +|---|---|---:|---| +| **P0 — Broker-port migration to the live path (Phase B)** | type `executor.py`/`agent.py` on `Broker`, retire the raw `CoinbaseClient` call shapes, delete `cb_client.py`, add a `broker:` config key routed through `load_broker()`, load-time capability reconciliation | **15–30** | **everything.** Not equity-specific — it is owed anyway, and both existing non-Coinbase adapters are inert until it lands | +| **P1 — The equity shariah screen** | second attestation kind, ratio fields, thresholds policy, per-period re-screen with fail-closed staleness, admitted-then-failed disposal semantics, dividend purification extension, fundamentals ingestion | **20–40**, plus an **unbounded** standards/ruling item and a **recurring** per-period operating cost | **the actual gate.** Nothing else matters until this exists | +| **P2 — Instrument model + rail 19** | an id→class notion `OrderIntent` does not carry today (the A1 slice the 2026-08-05 study priced), widening rail 19 without loosening what it refuses, wiring `asset_classes` from a declaration into a gate | **8–15** | makes spot-vs-equity a thing the rails can *say*, rather than a shape they infer. **Safety-critical** | +| **P3 — Session calendar** | exchange calendar, session state, a market-closed signal distinct from a stale feed, holiday handling, a non-24×7 scheduler to replace the 24×/day plist | **6–12** | correctness of the feed-freshness signal and of any time-based rule. Without it every close reads as an outage | +| **P4 — Equities adapter** | `packages/keel-broker-alpaca/`, conformance suite, paper-account integration tests | **8–15** | the venue. Cheap *only because* P0–P3 did the hard parts | +| **P5 — T+1, settled cash, corporate actions** | settled-vs-unsettled on `Balance`, a corporate-actions ingestion path, position reconciliation against the broker rather than the audit log, dividend purification wiring | **10–20** | correctness of the books. Deferrable at first, not indefinitely | + +**Total: roughly 65–130 engineer-days**, plus the unbounded standards item and the recurring +screening cost. Call it **four to seven months of one engineer**, and treat the low end as +optimistic — the range is wide because P1's true size depends on a fundamentals data decision +nobody has made and a standards read nobody has done. + +**Three properties of that ordering matter more than the totals, and they are the part of this +section worth remembering:** + +- **P0 unlocks the most and is the one item on the list that is owed whether or not equities are + ever built.** It is what makes the Robinhood adapter already in the tree do anything, and it is + what makes any future venue a package rather than a rewrite. It is on this list only because + equities would need it too — it is not equity work, and it should not be counted as the cost of + a decision this document is answering *no*. +- **P1 is the true blocker, and it is the phase nobody would build first.** That asymmetry is the + risk this document exists to record. P0/P2/P3/P4 are legible engineering with visible progress; + P1 is reading a standard and designing an attestation schema, and it gates all of them. Anyone + approaching equities from the engineering side would produce a working adapter that the charter + forbids using — the exact "dead code that reads as a capability" failure the cTrader study + declined to commit. +- **P2 could not follow P4.** Rail 19 is the charter expressed in code. Widening it under schedule + pressure from a finished-but-unusable adapter is precisely how a spot-only agent would stop being + one, and the ordering above exists to make that sequence visible before anyone is standing in it. + +## 7. What would have to be true to re-open this + +**The answer recorded here is no, and it is a settled answer, not a deferral pending someone's +time.** This section exists so that a future reader can tell, quickly, whether the thing that +changed is one of the things that matters. Most changes are not. In particular, **a new venue +appearing is not a reason to re-open this** — the gate is not the venue and never was. + +The preconditions are ordered, and the ordering is the point: **the first two are not engineering, +and until both hold, nothing below them is worth costing.** + +**The gate — before the question is worth asking again:** + +1. **A ruling, or a documented interpretive position under §29.2, that a common share is admissible + in principle for this agent.** §71.6's application to real US shares is an *inference* (§2), and + this document has been explicit that it is one. It is a strong inference, but the KB's own + standard is that an unsourced claim is not evidence (`screen.py:251`), and the whole verdict + rests on this single step. Confirming or replacing it costs a reading and a write-up, not a + build — **which makes it both the cheapest item on this list and the only one that is strictly + required before any other has meaning.** +2. **The two §3.1 decisions taken and written down** — whether keel adopts SS 21's ratio tolerances + as written or keeps its stricter line under §29.2, and whether it accepts clause 3/4/6/1's + sell-before-period-end purification exemption. **This is now the live item, and it is cheaper + than it was:** the standard has been read (§3), its criteria are quoted, and AAOIFI's own + hardship rationale is on the record — so what remains is a judgement, not research. Formally + reading SS 21 into the KB follows the decision rather than preceding it, and should carry the two + §65.10 corrections this document surfaced. +3. **A fundamentals data source, priced and licensed.** Unverified — none was evaluated here, and + it is the largest single unknown in the estimate. Note SS 21 makes this harder than an index + methodology would: a **market-cap** denominator (3/4/2, 3/4/3) needs price data alongside + filings, and clause 3/4/6/4's purification formula needs the **issuer's** total prohibited income + and share count — a datum most fundamentals feeds do not carry. Without a source, item 4 has no + inputs and the recurring cost in §2 has no upper bound. +4. **The equity screen actually built** — the per-period re-screen (3/4/8's *"throughout the + period"*), the fail-closed staleness policy, the **forced-disposal exit 3/4/8 mandates** as its + own order class, and the issuer-sourced purification path. **This is the gate.** Everything after + it is ordinary engineering; this is the part that decides whether keel may hold a share at all, + and it is the part no choice of broker, and no amount of adapter work, moves by a single day. + +**Only then, and only in this order, the engineering preconditions:** the broker-port migration on +the live path (P0, owed independently of all of this); an instrument class the rails can name, with +rail 19 widened to admit exactly one new shape and its tests shipped alongside rather than after +(P2); a session calendar, so that "market closed" and "feed broken" stop being the same log line +(P3); an adapter against a venue whose equity rules fit keel's execution model — **Alpaca on +current evidence, and not Coinbase**, which has the documented API but refuses preview, refuses +attached orders, refuses quote-sized entries outside the normal session, and — measured twice — +**publishes no market data of any kind for its equities** (P4); and T+1 +settlement, settled-vs-unsettled cash and corporate actions, +before a position is ever held across a dividend or a split rather than after the first one +silently breaks the books (P5). + +**Two changes would materially move this document, and one that looks like it would does not:** + +- ✅ **A ruling on item 1, or a decision to read SS 21 in.** This is the only cheap change that + reaches the actual gate. It is also the only one keel can make unilaterally, today, without + writing code. +- ✅ **keel deciding it is a crypto-only agent as a matter of charter rather than of capability.** + This is a legitimate answer and, stated plainly, it is *cheaper and more honest than the current + state* — which is a charter that permits shares in principle and a codebase that cannot screen + one. If that is the answer, it should be written down the way spot-only is written down at + `guards.py:741` ("this agent's CHARTER, not an operator preference"), and this document becomes + the record of why. **That would close the question rather than defer it, and closing it is worth + more than leaving it ambiguous.** +- ❌ **Coinbase's equities surface becoming usable on keel's account.** This is the change most + likely to be mistaken for a reason to re-open, and it is not one — **and it has already partly + happened without moving anything.** The order path exists today (§1b); the brief for this + document assumed it did not; correcting that changed no part of the verdict. The probe was then + re-run on 2026-08-09 and found the surface *less* usable than recorded, not more — no market data + on any endpoint — and that changed no part of the verdict either. **Two measurements in opposite + directions, neither of which moved anything, is the cleanest available demonstration that this + gate is not the venue.** If data appears and the preview refusal lifts tomorrow, items 1–4 are + untouched, because they are not about venues. **The 2026-08-05 study's R6 is answered and should + be closed rather than rescheduled** (§1's closing note). + +## What was deliberately NOT done + +No Alpaca, Tradier, Tastytrade, Schwab, Robinhood or IBKR account was opened, no key was issued, +and no paper-trading sandbox was exercised — **every broker claim in §4 is documentation and +pricing-page reading, not measurement** (the one exception is the unauthenticated 401 handshake +against Robinhood's MCP endpoint, which required no account), and the DX judgements are inferences +from those pages. No `packages/keel-broker-alpaca/` package. No dependency added to the workspace. +No entry point registered under `keel.brokers`. No change to `capabilities.py`, `guards.py`, +`screen.py`, or `db.py`. + +**⚠️ One line in this section has been retracted.** An earlier draft recorded that the committed +Coinbase probe was *deliberately not re-run*, and defended that choice on scope. **It has since been +re-run, on 2026-08-09, read-only and POST-guarded**, and the results are in §1a — including a +market-data finding that is now one of the two legs the verdict stands on, and two corrections +against the 2026-08-05 study that nobody would have found by argument. The earlier defence of the +omission was coherent and wrong: re-running it did produce an identical verdict, but it also +produced two retractions and one decisive new fact. **A one-minute measurement that is cheap enough +to decline is cheap enough to run.** + +**`create_order` was still never called**, on any date, by any pass. That is the one measurement +this document declines on purpose and will keep declining: it would place a real order in a real +brokerage account for an instrument keel's charter forbids it to hold, and no amount of curiosity +about whether the endpoint works justifies it. + +The unbuilt guard rail is deliberate in the specific way this repo has twice recorded. `"equity"` is +already in `ASSET_CLASSES` (`capabilities.py:21`) and is read by nothing; the temptation on writing +a document like this is to make it *mean* something. It must not be made to mean something yet, for +the reason `capabilities.py`'s own docstring gives — a gate on a field no live path reads *"would +be dead code on every real path while reading as a defence"*, and that exact pattern was built and +deleted once already (R1). The same argument forbids the adapter: an equities adapter in this tree +would imply stocks are a live option pending only wiring, when the actual state is that the screen +which would clear one has not been designed. + +## The research-integrity lesson + +Three research passes went into §1 and §4. **Each one reduced the pass before it, and the second one +over-corrected.** The first produced confident, well-formed, specific claims — an occurrence count, +an enum with named values, a regulator's file number, a press quotation — that direct verification +could not support, and they were withdrawn. The second withdrew two things it should have kept: the +Coinbase-for-Agents roadmap wording, which was sitting readable on `docs.cdp.coinbase.com` while the +pass was checking `coinbase.com` and getting a 403, and the trading-session enum, which is printed +in full on the create-order reference. **It also left a fabricated version of that enum standing in +§5/E3 while announcing its withdrawal in §1b** — a retraction that did not survive a `grep` of the +document making it. The third pass re-opened every source and re-ran the probe, and turned up the +single most decisive fact in the document, which no amount of reasoning would have produced: there +is no equity market data. + +Three rules fall out of that, and they are cheap: + +1. **A claim is only as good as the source someone actually opened.** Not searched, not summarised, + not inferred from a schema — opened. This is the same rule §4 arrives at independently from the + Schwab case, where five cross-linked pages on one four-month-old domain read as corroboration and + were a single source. +2. **A withdrawal is a claim too, and needs the same standard.** "Could not be confirmed" often means + "was looked for in the wrong place." Two of this document's withdrawals were wrong. +3. **A retraction is not done until the retracted text is gone.** Announce it in the caveats *and* + `grep` for it in the body. The confidence of a claim is uncorrelated with its truth, and a + document that says so about its sources owes the same scepticism to itself. + +## Caveats and what is UNVERIFIED + +- **The probe was re-run on 2026-08-09** (read-only, POST-guarded, `create_order` never called), so + the Coinbase measurements are current rather than four days stale. **This removes what an earlier + draft called the document's weakest point** and replaces it with a narrower one: the re-run + measured the *product surface*, not the order endpoint, which remains untested by design. +- ⚠️ **Two claims from this document's brief were REFUTED and are corrected in place, not silently:** + that Advanced Trade exposes no securities endpoint (§1b), and that Schwab's approval review + scrutinizes AI-driven functionality (§4 — traced to five interlinked pages on one non-affiliated + domain registered 2026-04-20). A third, that Robinhood offers no sanctioned programmatic equities + access, is materially out of date (§4). +- ⚠️ **Two corrections run against the 2026-08-05 study itself, and are attributed and dated rather + than quietly fixed** (§1a, both from the 2026-08-09 re-run): its **"non-deterministically + enumerable universe"** finding no longer reproduces — the listing is now stable, zero drift across + four calls, a clean cursor walk to 19 188 ids — and its **"the order path is refused by design"** + conclusion was never established, because it rested solely on a preview 403 and `create_order` was + never called. Neither is a defect in that study's method; the first is a venue that changed, the + second is an over-generalisation this document repeated before catching it. +- ⚠️ **Two claims withdrawn by an earlier pass have been RESTORED, and the withdrawals were the + error:** the **"Coinbase for Agents" roadmap wording**, which is quotable verbatim from + `docs.cdp.coinbase.com` and uses the word "equities" under an explicit "Coming soon" header (§1d — + the earlier pass checked the 403-gated `coinbase.com` instead), and the **equity trading-session + enum**, which is printed in full on the create-order reference and is quoted with its real + six-value spelling in §5/E3. ⚠️ **The related brief claim that the "planned for the future" line + was CoinDesk's paraphrase rather than Coinbase's own wording is REFUTED**: only the exact CoinDesk + sentence was the journalist's construction. +- ⚠️ **Still withdrawn and printed nowhere, because no pass could confirm them:** the brokerage + launch chronology and its FINRA/SEC/Apex filing citations (§1a — `coinbase.com` and + `help.coinbase.com` return HTTP 403 to automated fetching), the tokenized-equity press citations + (§1e), an **occurrence count** for "equity" in the spec, and **named equity-specific error codes**. + **An earlier draft printed several of these as verified.** None is load-bearing: §1b settles the + venue question from a directly-readable source, and the "real US shares on venue CCM with Apex + clearing" finding those citations were decorating is independently established by keel's own + committed probe. +- ⚠️ **A finding that cuts against this document's conclusion, recorded rather than buried:** + `equity_trading_flags` returns `tradable/buy_enabled/sell_enabled: true` on **998 of 1000** equity + products, with no halt, view-only or liquidate-only state (2026-08-09). The products declare + themselves tradable. It does not change the verdict — §2 is broker-independent and the market-data + vacuum is separately fatal — but anyone arguing the surface is dead should know it is the products + themselves saying otherwise. +- **`create_order` has still never been called on a Coinbase equity**, on any date, by any pass, and + it will not be. The order path is documented as existing, measured as un-previewable, and has + never been verified *working*. +- ⚠️ **"The introduction page is merely stale" is NOT established, and an earlier draft asserted it.** + Equity support appears only inside auto-generated per-endpoint OpenAPI schema blocks carrying + internal protobuf names (`coinbase.public_api.authed.retail_brokerage_api.*`). The hand-written + surfaces — REST introduction, overview, orders guide, FAQ, changelog (**zero occurrences of + "equit"**) — are silent. Given the live 403 and the data vacuum, **the introduction describes what + is usable more accurately than the schema describes what is shipped** (§1b). +- **§71.6 applied to real US shares is an INFERENCE**, not a direct citation. Stated above; restated + here because the whole verdict rests on it. +- **Which `backing` value a common share takes (`'ayn` / `'dayn` / neither) is UNVERIFIED** and is + a ruling question, not a probe question. +- **No fundamentals data vendor was priced or licence-checked.** It is a direct input to P1's range + and is the largest single source of uncertainty in the estimate. +- **Every broker in §4 is documentation-read, never exercised.** Sandbox quality, fill behaviour, + rate limits, corporate-action reporting and data-feed reliability are all unmeasured. The + recommendation of Alpaca is a paper judgement. +- **AAOIFI SS 21's criteria are VERIFIED from the standard's own text**, which AAOIFI publishes + openly (§3). All four thresholds (30% / 30% / 5% / ≥30%), their exact denominators, the absence of + any receivables test, and the absence of any averaging window are read from that document, not + from a secondary summary. Two items remain open: **the edition is UNVERIFIED** (the AAOIFI-hosted + extract carries no edition year; issuance is confirmed as 2004-05-20), and **whether any post-2004 + revision exists is UNVERIFIED** — none was found, none was ruled out, since AAOIFI's e-standards + portal is paywalled. Neither affects the verdict; both should be checked before the standard is + written into the KB. +- ⚠️ **SS 21 contradicts itself on the clause 3/19 tangible-assets floor** — 30% in the clause, + one-third in footnote (1) to 3/1 and in the Appendix, with AAOIFI's own note that the footnote + anticipates *"subsequent amending procedures"*. Recorded, not resolved. +- ⚠️ **Two claims in §65.10 are now out of date, through no fault of the entry**, which faithfully + records its source: DJIM retired its receivables screen (2023-03-17) and its cash screen + (2023-09-15) and now has a **single** accounting ratio, and its window is **24 months**, not the + 12 §65.10 records. A screen built against §65.10's DJIM description would implement a retired + methodology. This matters only because §65.10 is the KB's sole screening entry today. +- **The current S&P Shariah (2026) and DJIM (2026) methodologies were not read directly** — + spglobal.com refuses automated fetching. The verified editions are DJIM May 2025 and S&P Shariah + January 2015; DJIM's own change log shows no accounting-screen change after 2023-09-15, so the + comparison table is high-confidence but not certified current. +- **Day estimates are judgement, not measurement**, and the range is deliberately wide. P1 in + particular could be much larger — or could be correctly refused. +- **The recurring per-period screening cost is an operating cost that is not in the day estimate + at all**, because it does not end.