From 0d288165f898d9c9367cbddc7d475da278326ea9 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Tue, 1 Sep 2026 07:48:32 -0400 Subject: [PATCH] docs(fiqh): the venue boundary is closed; what is open is the premise underneath it #669 landed an open question that #667 and #668 then closed, and the merge order let all three through without a conflict. The bullet still said a SELL is never clamped, `filled_quantity` is recorded nowhere, and no sweep cancels a bracket whose position is gone -- three claims that are now false in the same file that describes the machinery making them false. It is replaced by the fact that actually remains open, and it is a better question than the one it retires. `_clamp_to_held`, rail 21 and `sweep_orphan_brackets` all fail OPEN on an unreadable balance -- deliberately, since refusing a SELL over a quiet endpoint would strand positions that wanted out -- so a venue that stops answering does not produce a refusal, it produces the old behaviour. That is survivable only while the account cannot go short, and nothing checks that: `verify_cash_account` exists on the Alpaca adapter alone. The layered defence is sound whenever the venue answers, and rests on an unverified premise whenever it does not (#666). THE PIN THAT FAILED TO FIRE, since the lesson is the durable part. #669 anchored this section to `_sell_base_size`'s docstring sentence, on the theory that #667 landing would break it and force the doc forward with the code. It did not: #667 clamped at intent construction and left that docstring standing, so the pin held while the paragraph it guarded went stale. A proxy is only a pin while the thing it stands for and the thing it matches move together, and that one stopped. Re-anchored two-sided against the coinbase adapter having no posture read and the alpaca adapter still having one -- the actual premise, not a sentence about it. When #666 lands, this fails because the fact changed. 4 mutants, 4 killed. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NzuKAe2RVrPt9acVAWjRyL --- docs/fiqh-basis.md | 29 +++++++++++++---------- tests/test_fiqh_basis.py | 50 +++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/docs/fiqh-basis.md b/docs/fiqh-basis.md index 54854ba..9122de7 100644 --- a/docs/fiqh-basis.md +++ b/docs/fiqh-basis.md @@ -306,18 +306,23 @@ Stated, not hidden — each is a place where keel's encoded behaviour could be w Whether "no underlying purpose" is disqualifying "is exactly the kind of judgement the screen defers to a human" (`docs/experiments/2026-07-20-candidate-universe.md`) — deferred, not decided. -- **Long-only is enforced where keel DECIDES, not where it SETTLES.** Everything under - "Long-only" above governs what keel chooses. It does not govern the quantity that reaches - the venue. A SELL is never clamped to the account's available base (#667): the exit sells - what the ledger believes is held, and the ledger drifts from the account through fees taken - in the base asset, partial fills (`filled_quantity` is recorded nowhere on this - deployment), and out-of-band operator transfers. A resting stop leg can outlive the - position that justified it, because no sweep cancels a SELL whose position is gone (#668). - On a cash account each of these is a rejected order — bad, but not a fiqh failure. On a - margin-enabled account the venue fills the difference as a short, and keel has no - cash-account posture check on Coinbase (#666; the check exists only on the Alpaca adapter). - So the long-only ruling above is sound at the decision layer and **not yet closed at the - venue boundary**. Named here rather than left to be discovered. +- **The venue boundary is closed by machinery that can decline to answer (#666).** This entry + was written when the boundary was open, and #667/#668 have since closed the three paths that + were named here — the SELL is clamped to the venue's holding, rail 21 refuses an order + against an empty one, and `sweep_orphan_brackets` cancels a protective order whose position + has left. What is *not* closed is the assumption every one of them rests on. All three fail + OPEN on an unreadable balance, deliberately and correctly: refusing a SELL over a balance + endpoint that went quiet would strand positions that wanted out. So a venue that stops + answering does not produce a refusal, it produces the old behaviour — an exit sized from + keel's own ledger. + + That is survivable **only while the account cannot go short**, and keel does not check that + it cannot. `verify_cash_account` exists on the Alpaca adapter alone; Coinbase has no + equivalent read, and #666 must first establish whether Advanced Trade exposes an account + posture at all — an operator attestation, on rail 17's pattern, is a legitimate answer if it + does not. Until then the layered defence is sound whenever the venue answers, and rests on an + unverified premise whenever it does not. Named here rather than left to be inferred from + three closed issues. - **ZEC and the rest of the deferrals.** The candidate-universe record lists the open questions the attestation step has to answer and "which this agent must not answer". diff --git a/tests/test_fiqh_basis.py b/tests/test_fiqh_basis.py index d0daaa0..50b7b96 100644 --- a/tests/test_fiqh_basis.py +++ b/tests/test_fiqh_basis.py @@ -388,7 +388,9 @@ def test_the_readme_links_the_document(): _HADITH_NOT_IN_KB = "That reference is not extracted in this repository's knowledge base" -_SELL_SIZE_CONTRACT = "it can only ever make an exit MORE likely to be accepted" +_CASH_POSTURE_CHECK = "verify_cash_account" + +_VENUE_BOUNDARY_PREMISE = "rests on an unverified premise whenever it does not" def test_the_long_only_ruling_is_pinned_two_sided_to_the_code_that_enforces_it(): @@ -461,24 +463,36 @@ def test_the_hadith_reference_is_marked_as_outside_the_knowledge_base(): ) -def test_the_venue_boundary_gap_is_stated_not_hidden(): - """Long-only holds where keel decides; the doc must admit it is open where keel settles. +def test_the_venue_boundary_premise_is_stated_not_hidden(): + """The boundary is closed by machinery that fails OPEN, over an account nobody checked. + + This test's first form pinned `_sell_base_size`'s docstring as a proxy for "the SELL is not + clamped", on the theory that #667 landing would break it and force the doc to be updated + with the code. It did not: #667 clamped at intent construction and left that docstring + intact, so the pin held while the paragraph it guarded became false. **A proxy is only a pin + while the thing it stands for and the thing it matches move together**, and this one stopped. - A SELL is never clamped to the account's available base, so fee dust, an unrecorded - partial fill, or an out-of-band transfer can send an order for more than is held (#667). - That is `bay' ma la yamlik` reached by arithmetic. Pinned to `_sell_base_size`'s own - contract: while that function's only job is to make an exit more likely to be accepted, it - reads no balance, and the open question must stay in the doc. When #667 lands this test - fails -- which is the point: the doc gets updated with the code, not after it. + Re-anchored to the fact that actually remains open. `_clamp_to_held`, rail 21 and + `sweep_orphan_brackets` all fail open on an unreadable balance -- correctly, since refusing + a SELL over a quiet endpoint strands positions that wanted out -- so the defence rests on + the account being unable to go short, and nothing verifies that on the venue that trades + live. When #666 gives the coinbase adapter a posture read, this test fails, and it fails + because the premise changed rather than because a sentence was reworded. """ doc = _unwrapped(_doc()) - assert "not yet closed at the venue boundary" in doc, ( - f"{_DOC} must state that long-only is unclosed at the venue boundary -- the ruling is " - "sound at the decision layer and the operational gap is not the reader's to discover" - ) - for issue in ("#666", "#667", "#668"): - assert issue in doc, f"{_DOC} must name {issue} as the open venue-boundary work" - assert _SELL_SIZE_CONTRACT in _rel("keel/execution/executor.py"), ( - "keel/execution/executor.py's `_sell_base_size` must still carry its stated contract; " - f"if the exit now clamps to a real balance, {_DOC}'s open question is stale" + assert _VENUE_BOUNDARY_PREMISE in doc, ( + f"{_DOC} must state that the long-only defence rests on an unverified premise when the " + "venue does not answer -- a layered defence described without its assumption reads as " + "settled, and the assumption is the part still open" + ) + assert "#666" in doc, f"{_DOC} must name #666 as the open venue-boundary work" + coinbase = "packages/keel-broker-coinbase/keel_broker_coinbase/adapter.py" + assert _CASH_POSTURE_CHECK not in _rel(coinbase), ( + f"{coinbase} now has a {_CASH_POSTURE_CHECK!r} read -- #666 has landed and the open " + f"question in {_DOC} is stale. Update the doc, then re-point this test." + ) + alpaca = "packages/keel-broker-alpaca/keel_broker_alpaca/adapter.py" + assert _CASH_POSTURE_CHECK in _rel(alpaca), ( + f"{_DOC} says the posture check exists on the Alpaca adapter alone; {alpaca} must still " + "carry it, or the doc is describing a check no adapter has" )