From 95c94100382037043ef43c74fa70b678abd39039 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Mon, 17 Aug 2026 02:28:51 -0400 Subject: [PATCH 1/2] =?UTF-8?q?docs(review-path):=20state=20the=20scholarl?= =?UTF-8?q?y-review=20stance=20honestly=20=E2=80=94=20not=20reviewed,=20wi?= =?UTF-8?q?th=20the=20path=20defined=20(#289)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 + docs/fiqh-basis.md | 67 ++++++++ tests/test_scholarly_review.py | 270 +++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 tests/test_scholarly_review.py diff --git a/README.md b/README.md index 9f1be737..9cd6b813 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,14 @@ one who is told upfront can read it as rigour. > following different schools get different answers from the same code, by design. See > `CONTRIBUTING.md` for what that means for pull requests. +**No scholarly review of keel's fiqh basis has occurred.** The basis is one operator's +sourced reading — published as [`docs/fiqh-basis.md`](docs/fiqh-basis.md) precisely so it +can be audited and challenged — and each operator is responsible for their own +attestations. What a scholarly review would cover, and what it would and would not +signify, is defined in [that document's review-status +section](docs/fiqh-basis.md#scholarly-review-status); until someone walks that path, the +status is: not reviewed. + keel is a personal tool, not financial advice and not religious (Shariah) advice — see the disclaimers below. diff --git a/docs/fiqh-basis.md b/docs/fiqh-basis.md index aef39e5e..e4a6bd55 100644 --- a/docs/fiqh-basis.md +++ b/docs/fiqh-basis.md @@ -232,6 +232,73 @@ The route the architecture already provides — record your own ruling locally: `CONTRIBUTING.md` requires a cited source and discussion before merge — a classification with no source behind it is not mergeable, however confident the author. +## Scholarly review status + +**No scholarly review of keel's fiqh basis has occurred.** Not by a named scholar, not by a +council, not by anyone. The basis is the operator's reading of the sources this document +cites — Ayub (§65), the OIC/AAOIFI/IIFA materials (§67, §71), Mufti Faraz Adam's papers +(§85, §86) — extracted into the knowledge base at +`docs/superpowers/references/trading-knowledge-base/` and mapped into code here, published +precisely so that reading can be audited and challenged. Each operator remains responsible +for their own attestations. Until this section gains a dated review addendum (below), the +status is plain: not reviewed. + +### What review will cover when a reviewer engages + +A review, should one ever happen, is a review of the mapping from sources to code — and +its scope is this, in full: + +- **The encoded-rulings table above** — whether each screen and rail axis faithfully reflects + the section it cites: §28.4 for the sector and riba axes, §65.5/§67.2 for backing, §71.4a + for the instrument shape, §65.4 for rail 17's `qabd` test. +- **The knowledge-base extractions** — whether each source file under + `docs/superpowers/references/trading-knowledge-base/sources/` is faithful to the text it + was extracted from, including where it records "not stated" rather than papering over a + gap. +- **The per-asset attestations on the operator's own allowlist** — sector, backing, and + `pays_yield`, including the open questions named above (ATOM dilution, DOGE's *Māl* + qualification, the premise itself). + +### What a reviewer is NOT endorsing + +A reviewer would be reviewing the mapping from sources to code, nothing more. Explicitly +not endorsed: + +- **Not the trading strategy or its performance.** The honest measured result is linked from + the README's first screen and is nothing anyone is asked to endorse. +- **Not the prudential rails.** They are risk discipline carrying no religious claim (§65.6's + correction); a fiqh review has nothing to say about them either way. +- **Not a ruling that crypto is tradable property.** The §71.1 non-ruling stands: reviewing + the machinery does not settle the premise the machinery presupposes. +- **Not any particular operator's attestations.** Those carry the operator's own source and + name; they are not this repository's to have reviewed. +- **Not an endorsement of trading anything.** keel states its honest result and disclaims + advice; a review of the mapping adds no permission to trade. + +### How a review is recorded + +If a review ever happens, it is recorded as a dated addendum to this section, naming the +reviewer, the scope reviewed, the findings, and what changed as a result — versioned in git +like everything else in this repository. Until such an addendum exists, the status is "not +reviewed", and it can ratchet one way only: from not-reviewed to +reviewed-with-a-named-scope, never to an approval with no scope attached. + +### The outreach shortlist (a plan, not a claim) + +Approaching a reviewer is the operator's action, and it has not been taken as of this +writing. The shortlist, for when it is: the Islamic finance programmes at IIUM, INCEIF, and +Durham, and established Islamic fintech practitioners — approached with this note, ready to +send: + +> keel is an open-source enforcement engine for Shariah rulings an operator supplies — +> classifications are attested, never inferred, and enforced deterministically +> (https://github.com/CodeGateSoftware/keel). I am asking for a review of the mapping from +> the cited sources — Ayub, the OIC/AAOIFI/IIFA materials, Mufti Faraz Adam's papers — to +> the encoded screen and rail behaviour, as documented in docs/fiqh-basis.md. The review +> would signify only that the mapping is faithful to those sources; it would not endorse +> the trading strategy, the prudential rails, the premise that crypto is tradable property, +> or trading at all. + ## Sources index - `docs/superpowers/references/trading-knowledge-base/sources/source-65.md` — Muhammad Ayub, diff --git a/tests/test_scholarly_review.py b/tests/test_scholarly_review.py new file mode 100644 index 00000000..a37bee30 --- /dev/null +++ b/tests/test_scholarly_review.py @@ -0,0 +1,270 @@ +"""The scholarly review status, stated honestly: not reviewed, with the path defined (#289). + +A Muslim developer evaluating keel asks one question the code cannot answer by being read: +who checked the fiqh? The honest answer today is nobody -- the basis is one operator's +sourced reading, and #289's judgement is that an ambiguous claim here is worse than a modest +one, because "an overstated claim is not a marketing problem, it is a trust-destroying one." +What shipped is the modest claim said out loud -- no scholarly review has occurred, each +operator owns their own attestations -- plus the documented path a review would take when a +reviewer engages: what would be reviewed, what a reviewer would and would not be endorsing, +how a review would be recorded, and who might be asked. + +This file pins that stance so it can only harden, never soften. The no-review sentence is +pinned verbatim in the README's first screen AND in the status section of docs/fiqh-basis.md +(the house pattern from `test_governance.py`'s boundary sentence); the ratchet is pinned (the +status changes only by a dated addendum naming reviewer and scope); and the negative test +asserts that no affirmative review claim appears anywhere in the three documents a trust +decision might be made from. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +_ROOT = Path(__file__).resolve().parents[1] + +#: The document whose review-status section defines the path (#289). +_DOC = "docs/fiqh-basis.md" + +#: The sentence both documents must state the status with, quoted exactly -- pinned in the +#: README's first screen and in the status section, so neither can soften while the other +#: stays blunt. "No scholarly review" plus "has occurred", in one unsoftenable clause. +_NO_REVIEW = "No scholarly review of keel's fiqh basis has occurred" + +#: The section heading (#289), whose placement between "How to disagree" and "Sources index" +#: is part of its meaning. +_SECTION_HEADING = "## Scholarly review status" + +#: Where the README's link must land -- the heading's GitHub anchor, pinned so the README +#: cannot cite a section that has been renamed away. +_SECTION_LINK = "docs/fiqh-basis.md#scholarly-review-status" + +#: The knowledge base the basis was extracted into, named in the status section so "the +#: operator's reading" is a checkable path, not a gesture at one. +_KB_DIR = "docs/superpowers/references/trading-knowledge-base/" + +#: Affirmative review claims that must appear NOWHERE in the three files a trust decision is +#: made from. Negated forms ("not reviewed", "not endorsed") are legitimate and pinned +#: positively by the other tests here; these are the positive phrasings only, hyphen and +#: space spellings alike. +_FORBIDDEN_CLAIMS = ( + "scholar-approved", + "scholar approved", + "reviewed and approved", + "certified", + "endorsed by", +) + + +def _unwrapped(text: str) -> str: + """Join markdown wrapping: drop blockquote markers, then collapse all whitespace.""" + return " ".join(re.sub(r"(?m)^\s*>\s?", "", text).split()) + + +def _read(relative: str) -> str: + """A repo file's text; empty until it exists, so a red run FAILS rather than errors.""" + path = _ROOT / relative + return path.read_text() if path.is_file() else "" + + +def _first_screen(relative: str) -> str: + """Everything before the first `##` section: what a reader sees without scrolling.""" + return _read(relative).split("\n## ", 1)[0] + + +def _status_section() -> str: + """The review-status section alone (its `###` subsections included), wrap-joined. + + Pins must land INSIDE the section: a "not reviewed" that has drifted into some other + part of the document is a softer claim than the one #289 asks the section to make. + """ + doc = _read(_DOC) + if _SECTION_HEADING not in doc: + return "" + return _unwrapped(doc.split(_SECTION_HEADING, 1)[1].split("\n## ", 1)[0]) + + +def _claim_normalized(text: str) -> str: + """Collapse wrapping the way a reader does, including a hyphen split across lines. + + A claim wrapped as "scholar-\\napproved" reads as one word on the page; the scanner must + see it the same way, or the hyphen becomes a loophole. + """ + return re.sub(r"-\s+", "-", _unwrapped(text)).lower() + + +def test_the_readme_first_screen_states_the_no_review_fact(): + """#289's acceptance: the README says which of the three options keel actually offers. + + The modest option, said out loud, in the first screen -- where `test_governance.py` puts + the boundary sentence for the same reason: a reader deciding whether to trust keel must + not have to scroll to learn that nobody has checked the fiqh. + """ + assert _NO_REVIEW in _unwrapped(_first_screen("README.md")), ( + "the README's first screen must state, verbatim, that " + f"{_NO_REVIEW!r} -- the modest claim said out loud is the only claim available" + ) + + +def test_the_readme_no_review_statement_links_the_fiqh_basis_review_section(): + """The statement does not stand alone: it hands the reader the section that elaborates. + + Pinned two-sided -- the README must carry the link, and the link must point at a heading + the document actually has -- so a rename of the section fails here instead of leaving a + link into thin air. + """ + assert _SECTION_LINK in _first_screen("README.md"), ( + f"the README's no-review statement must link {_SECTION_LINK} -- the status claim " + "and the path that defines it travel together" + ) + assert _SECTION_HEADING in _read(_DOC), ( + f"{_DOC} must carry the heading {_SECTION_HEADING!r} that the README's link targets" + ) + + +def test_the_status_section_sits_between_how_to_disagree_and_the_sources_index(): + """The section's placement is part of its meaning: after dissent, before the sources. + + A reader who has just been told how to disagree is the reader most owed the question + "and who checked this?" -- and the sources index is the document's last word, so the + status must be stated before the citations begin. + """ + doc = _read(_DOC) + assert doc.index("## How to disagree") < doc.index(_SECTION_HEADING) < doc.index( + "## Sources index" + ), ( + f"{_DOC} must place {_SECTION_HEADING!r} after '## How to disagree' and before " + "'## Sources index'" + ) + + +def test_the_status_section_says_not_reviewed_plainly(): + """The section opens with the same unsoftenable sentence, and names the status plainly. + + Two-sided within the document: the sentence the README pins must be HERE too (one + sentence, two places, like the governance boundary), and the plain words "not reviewed" + must appear inside the section itself -- a status a reader must infer is a status they + will overread. + """ + section = _status_section() + assert _NO_REVIEW in section, ( + f"the status section must open with the same sentence the README pins: {_NO_REVIEW!r}" + ) + assert "not reviewed" in section.lower(), ( + f"{_DOC}'s status section must say the status plainly -- 'not reviewed', inside the " + "section itself" + ) + + +def test_the_status_section_names_what_the_basis_actually_is(): + """'Not reviewed' is only honest if the section also says what the basis IS. + + The operator's reading, the sources it reads (Ayub, the OIC/AAOIFI/IIFA materials, + Mufti Faraz Adam's papers), and the knowledge base it was extracted into -- named as a + path, so the auditable thing is findable from the very sentence that disclaims it. + """ + section = _status_section() + assert "operator's reading" in section, ( + "the status section must name the basis as the operator's reading of the sources" + ) + assert "Ayub" in section and "AAOIFI" in section and "Faraz Adam" in section, ( + "the status section must name the sources the reading reads: Ayub, the " + "OIC/AAOIFI/IIFA materials, and Mufti Faraz Adam's papers" + ) + assert _KB_DIR in section, ( + f"the status section must point at the knowledge base ({_KB_DIR}) the reading was " + "extracted into" + ) + + +def test_the_status_section_lists_what_a_reviewer_is_not_endorsing(): + """The not-endorsement list, pinned on its load-bearing items. + + A reviewer of the mapping must not be readable as a reviewer of the strategy, and must + not settle the premise: §71.1's non-ruling is this document's deepest caveat, and a + review of the machinery cannot be allowed to launder it into a permission. + """ + section = _status_section().lower() + assert "not the trading strategy" in section, ( + "the not-endorsement list must say a reviewer is not endorsing the trading strategy " + "or its performance" + ) + assert "not the prudential rails" in section, ( + "the not-endorsement list must say a reviewer is not endorsing the prudential rails" + ) + assert "§71.1" in section and "non-ruling" in section, ( + "the not-endorsement list must keep the §71.1 non-ruling standing: reviewing the " + "machinery does not settle the premise the machinery presupposes" + ) + assert "does not settle the premise" in section, ( + "the not-endorsement list must say so in exactly those words -- the premise is the " + "part most likely to be overread into permission" + ) + + +def test_the_status_section_defines_the_addendum_ratchet(): + """The status can change by ONE mechanism only: a dated addendum naming its scope. + + This is the ratchet: not-reviewed can become reviewed-with-a-named-scope, never a vague + approval. Pinning the mechanism's parts -- dated, naming the reviewer, the scope + reviewed, versioned in git -- means a future edit that loosens any one of them fails + here rather than shipping a softer claim. + """ + section = _status_section() + pins = ( + "dated addendum", + "naming the reviewer", + "the scope reviewed", + "versioned in git", + "reviewed-with-a-named-scope", + ) + for pin in pins: + assert pin in section, ( + f"the status section must pin {pin!r}: the only way the status leaves 'not " + "reviewed' is a dated addendum naming reviewer, scope, findings, and what " + "changed" + ) + + +def test_no_document_claims_a_review_has_occurred(): + """The one pin that cannot be allowed to go soft: nowhere is review CLAIMED. + + #289's warning is the law here: "an overstated claim is not a marketing problem, it is + a trust-destroying one" -- a reader who believed a review had happened and later learns + none existed will not believe anything else the project says. The scanner first proves + it can fail (a hyphen-wrapped synthetic claim is caught), then asserts the affirmative + phrasings appear nowhere in the three documents a trust decision is made from; the + documents' many legitimate NEGATED uses ("not reviewed", "not endorsed") are pinned + positively by the tests above. + """ + assert "scholar-approved" in _claim_normalized("scholar-\napproved"), ( + "the claim scanner must catch a claim hyphen-wrapped across lines, or the hyphen " + "is a loophole" + ) + for relative in ("README.md", "CONTRIBUTING.md", _DOC): + text = _claim_normalized(_read(relative)) + found = [claim for claim in _FORBIDDEN_CLAIMS if claim in text] + assert not found, ( + f"{relative} claims scholarly review that has not occurred ({found}): per " + "#289, an overstated claim here is not a marketing problem, it is a " + "trust-destroying one -- state 'not reviewed' plainly instead" + ) + + +def test_the_outreach_shortlist_names_programmes_and_states_the_approach_is_unmade(): + """The shortlist is a plan on paper, and must be labelled as unexecuted. + + Naming IIUM, INCEIF, and Durham without saying nobody has been approached would imply an + approach; the sentence doing the disclaiming is pinned, not just the names. + """ + section = _status_section() + for programme in ("IIUM", "INCEIF", "Durham"): + assert programme in section, ( + f"the outreach shortlist must name {programme} among the candidates (#289)" + ) + assert "has not been taken" in section and "as of this writing" in section, ( + "the shortlist must state plainly that approaching a reviewer is the operator's " + "action and has not been taken as of this writing -- a shortlist that reads as " + "outreach already made is the overstated claim in different clothes" + ) From 07ff98b375954caeeaf3ef5126bc65ff2806e8b2 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Mon, 17 Aug 2026 02:36:54 -0400 Subject: [PATCH 2/2] =?UTF-8?q?docs(review-path):=20review=20fixes=20?= =?UTF-8?q?=E2=80=94=20'would=20cover',=20not=20'when';=20attestations=20s?= =?UTF-8?q?cope=20reconciled;=20conditional=20phrasing=20throughout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/fiqh-basis.md | 18 +++++++++--------- tests/test_scholarly_review.py | 32 +++++++++++++++++++------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 9cd6b813..62189019 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ sourced reading — published as [`docs/fiqh-basis.md`](docs/fiqh-basis.md) prec can be audited and challenged — and each operator is responsible for their own attestations. What a scholarly review would cover, and what it would and would not signify, is defined in [that document's review-status -section](docs/fiqh-basis.md#scholarly-review-status); until someone walks that path, the +section](docs/fiqh-basis.md#scholarly-review-status); unless someone walks that path, the status is: not reviewed. keel is a personal tool, not financial advice and not religious (Shariah) advice — see the diff --git a/docs/fiqh-basis.md b/docs/fiqh-basis.md index e4a6bd55..8c01864d 100644 --- a/docs/fiqh-basis.md +++ b/docs/fiqh-basis.md @@ -243,7 +243,7 @@ precisely so that reading can be audited and challenged. Each operator remains r for their own attestations. Until this section gains a dated review addendum (below), the status is plain: not reviewed. -### What review will cover when a reviewer engages +### What a review would cover A review, should one ever happen, is a review of the mapping from sources to code — and its scope is this, in full: @@ -255,9 +255,9 @@ its scope is this, in full: `docs/superpowers/references/trading-knowledge-base/sources/` is faithful to the text it was extracted from, including where it records "not stated" rather than papering over a gap. -- **The per-asset attestations on the operator's own allowlist** — sector, backing, and - `pays_yield`, including the open questions named above (ATOM dilution, DOGE's *Māl* - qualification, the premise itself). +- **The open questions named above** — ATOM dilution, DOGE's *Māl* qualification, the + premise itself — as questions about the reading, not about any operator's recorded + attestations. ### What a reviewer is NOT endorsing @@ -271,7 +271,7 @@ not endorsed: - **Not a ruling that crypto is tradable property.** The §71.1 non-ruling stands: reviewing the machinery does not settle the premise the machinery presupposes. - **Not any particular operator's attestations.** Those carry the operator's own source and - name; they are not this repository's to have reviewed. + name; a review of this document does not review them — each operator owns their own. - **Not an endorsement of trading anything.** keel states its honest result and disclaims advice; a review of the mapping adds no permission to trade. @@ -286,16 +286,16 @@ reviewed-with-a-named-scope, never to an approval with no scope attached. ### The outreach shortlist (a plan, not a claim) Approaching a reviewer is the operator's action, and it has not been taken as of this -writing. The shortlist, for when it is: the Islamic finance programmes at IIUM, INCEIF, and -Durham, and established Islamic fintech practitioners — approached with this note, ready to -send: +writing. The shortlist, for that day if it comes: the Islamic finance programmes at IIUM, +INCEIF, and Durham, and established Islamic fintech practitioners — approached with this +note, ready to send: > keel is an open-source enforcement engine for Shariah rulings an operator supplies — > classifications are attested, never inferred, and enforced deterministically > (https://github.com/CodeGateSoftware/keel). I am asking for a review of the mapping from > the cited sources — Ayub, the OIC/AAOIFI/IIFA materials, Mufti Faraz Adam's papers — to > the encoded screen and rail behaviour, as documented in docs/fiqh-basis.md. The review -> would signify only that the mapping is faithful to those sources; it would not endorse +> would signify only whether the mapping is faithful to those sources; it would not endorse > the trading strategy, the prudential rails, the premise that crypto is tradable property, > or trading at all. diff --git a/tests/test_scholarly_review.py b/tests/test_scholarly_review.py index a37bee30..3d72207f 100644 --- a/tests/test_scholarly_review.py +++ b/tests/test_scholarly_review.py @@ -5,8 +5,8 @@ sourced reading, and #289's judgement is that an ambiguous claim here is worse than a modest one, because "an overstated claim is not a marketing problem, it is a trust-destroying one." What shipped is the modest claim said out loud -- no scholarly review has occurred, each -operator owns their own attestations -- plus the documented path a review would take when a -reviewer engages: what would be reviewed, what a reviewer would and would not be endorsing, +operator owns their own attestations -- plus the documented path a review would take if a +reviewer ever engages: what would be reviewed, what a reviewer would and would not be endorsing, how a review would be recorded, and who might be asked. This file pins that stance so it can only harden, never soften. The no-review sentence is @@ -33,13 +33,9 @@ _NO_REVIEW = "No scholarly review of keel's fiqh basis has occurred" #: The section heading (#289), whose placement between "How to disagree" and "Sources index" -#: is part of its meaning. +#: is part of its meaning. The README's link anchor is derived from it in the test below. _SECTION_HEADING = "## Scholarly review status" -#: Where the README's link must land -- the heading's GitHub anchor, pinned so the README -#: cannot cite a section that has been renamed away. -_SECTION_LINK = "docs/fiqh-basis.md#scholarly-review-status" - #: The knowledge base the basis was extracted into, named in the status section so "the #: operator's reading" is a checkable path, not a gesture at one. _KB_DIR = "docs/superpowers/references/trading-knowledge-base/" @@ -101,21 +97,31 @@ def test_the_readme_first_screen_states_the_no_review_fact(): the boundary sentence for the same reason: a reader deciding whether to trust keel must not have to scroll to learn that nobody has checked the fiqh. """ - assert _NO_REVIEW in _unwrapped(_first_screen("README.md")), ( + first = _unwrapped(_first_screen("README.md")) + assert _NO_REVIEW in first, ( "the README's first screen must state, verbatim, that " f"{_NO_REVIEW!r} -- the modest claim said out loud is the only claim available" ) + assert "keel is not a fatwa engine" in first and first.index( + "keel is not a fatwa engine" + ) < first.index(_NO_REVIEW), ( + "the no-review statement must come after the not-a-fatwa-engine blockquote -- the " + "boundary says whose ruling keel enforces, and 'nobody has checked this one' is the " + "very next thing a reader is owed" + ) def test_the_readme_no_review_statement_links_the_fiqh_basis_review_section(): """The statement does not stand alone: it hands the reader the section that elaborates. - Pinned two-sided -- the README must carry the link, and the link must point at a heading - the document actually has -- so a rename of the section fails here instead of leaving a - link into thin air. + Pinned two-sided -- the README must carry the link, and the link's anchor must be the + one GitHub derives from the heading the document actually has -- so a rename of the + section fails here instead of leaving a link into thin air. """ - assert _SECTION_LINK in _first_screen("README.md"), ( - f"the README's no-review statement must link {_SECTION_LINK} -- the status claim " + heading = _SECTION_HEADING.removeprefix("## ") + expected_anchor = "docs/fiqh-basis.md#" + heading.lower().replace(" ", "-") + assert expected_anchor in _first_screen("README.md"), ( + f"the README's no-review statement must link {expected_anchor} -- the status claim " "and the path that defines it travel together" ) assert _SECTION_HEADING in _read(_DOC), (