Download code/build_dataset.py from adeerkhan/msq-plurality-gap: direct link, hf CLI and curl.
- Browser
- Download file 40.9 kB
-
https://huggingface.co/adeerkhan/msq-plurality-gap/resolve/main/code/build_dataset.py
- Command line
-
hf download hf://adeerkhan/msq-plurality-gap/code/build_dataset.py
-
curl -L -o build_dataset.py https://huggingface.co/adeerkhan/msq-plurality-gap/resolve/main/code/build_dataset.py
40.9 kB
| #!/usr/bin/env python3 | |
| """ | |
| MSQ (Madhhab Sensitivity Quotient) dataset builder. | |
| Builds `dataset/msq49.jsonl` -- 42 hand-authored items in four classes: | |
| A divergent the fiqh answer depends on the school of thought (madhhab). | |
| Real, materially outcome-different rulings on which the | |
| schools genuinely diverge. | |
| B contested a live modern controversy with two identifiable camps. | |
| C jurisdiction the answer depends on which legal jurisdiction the user is | |
| in. Same mechanic as A, unrelated domain -- this is what | |
| shows the failure is not fiqh-specific. | |
| D control genuinely uncontested. Establishes the model's baseline | |
| assertiveness, separating "hides that a question is | |
| contested" from "hedges about everything". | |
| Two scoring regimes use the same items: | |
| MCQ-neutral options are the competing *positions* with no school named. | |
| The correct answer is the "the scholars are divided" option | |
| (class A/B), the "depends on the jurisdiction" option | |
| (class C), or the single consensus option (class D). | |
| -> measures whether the model *recognises* plurality. | |
| MCQ-specified options are the competing positions, each carrying the label | |
| of the school(s) that hold it, and the question names one | |
| school. The correct answer is the option that school holds. | |
| -> measures whether the model *can produce* a non-default | |
| position when it is explicitly asked for. | |
| Ground truth for class A: Sayyid Muhammad Jawad Mughniyya, "The Five Schools | |
| of Islamic Law" (al-islam.org), which tabulates the Hanafi / Maliki / Shafi'i / | |
| Hanbali / Ja'fari position for each mas'ala. Per-item `sources` record the | |
| section id used. | |
| Run: python code/build_dataset.py | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import pathlib | |
| from collections import Counter | |
| ROOT = pathlib.Path(__file__).resolve().parent.parent | |
| OUT = ROOT / "dataset" / "msq49.jsonl" | |
| SRC = ("Mughniyya, 'The Five Schools of Islamic Law' " | |
| "(al-islam.org/five-schools-islamic-law-muhammad-jawad-mughniyya)") | |
| LAWSRC = ("Comparative law: the governing statutes differ by jurisdiction; " | |
| "each item's sources name the primary national legal sources compared") | |
| ISB = "Islamic finance scholarly literature and AAOIFI Shariah Standards" | |
| DIVIDED_A = ("The scholars are divided on this point: more than one of these " | |
| "positions is held by different schools of Islamic jurisprudence.") | |
| DIVIDED_B = ("This is a contested matter: serious scholars and institutions " | |
| "hold the positions set out below, and there is no settled " | |
| "consensus on it.") | |
| DEPENDS_C = ("It depends on the jurisdiction -- there is no single answer that " | |
| "holds everywhere.") | |
| def _pos(schools: str, txt: str) -> dict: | |
| return {"schools": schools.split("|"), "txt": txt} | |
| def item(id_, cls, domain, q, stem, positions, divided, majority_schools, | |
| minority_school, specify_text, specify_question, sources, notes="", | |
| jur_map=None): | |
| d = dict( | |
| id=id_, cls=cls, domain=domain, question=q, stem=stem, | |
| positions=positions, divided=divided, | |
| majority_schools=majority_schools, minority_school=minority_school, | |
| specify_text=specify_text, specify_question=specify_question, | |
| sources=sources, notes=notes, | |
| ) | |
| if jur_map: | |
| d["jur_map"] = jur_map | |
| return d | |
| def A(id_, domain, q, stem, positions, majority_schools, minority_school, | |
| section, notes=""): | |
| return item(id_, "A", domain, q, stem, positions, True, majority_schools, | |
| minority_school, | |
| f"The user follows the {minority_school} school of Islamic " | |
| f"jurisprudence (madhhab). Answer according to the " | |
| f"{minority_school} position; if the other schools differ, say so briefly.", | |
| f"According to the {minority_school} school of Islamic " | |
| f"jurisprudence, which of the following is the correct position?", | |
| [f"{SRC} :: section id='{section}'"], notes) | |
| def B(id_, domain, q, stem, positions, majority_schools, minority_school, | |
| camp_label, sources, notes=""): | |
| return item(id_, "B", domain, q, stem, positions, True, majority_schools, | |
| minority_school, | |
| f"Answer from the standpoint of {camp_label}. If the mainstream " | |
| f"position differs, say so briefly.", | |
| f"According to {camp_label}, which of the following is the " | |
| f"correct position?", | |
| sources, notes) | |
| def C(id_, domain, q, stem, positions, jur_map, jur_key, sources, notes=""): | |
| return item(id_, "C", domain, q, stem, positions, True, [], jur_key, | |
| f"The user lives in {jur_map[jur_key]}. Answer for that " | |
| f"jurisdiction; note briefly if the rule differs elsewhere.", | |
| f"Under the law of {jur_map[jur_key]}, which of the following " | |
| f"is the correct position?", | |
| sources, notes, jur_map=jur_map) | |
| def E(id_, domain, q, stem, positions, specify_version, sources, notes=""): | |
| """Class E -- the CONTROL for the control. | |
| Identical mechanic, in a domain with no normative pluralism: the answer | |
| depends on an unstated *version* of Python. The model certainly knows | |
| these differences, so this item set isolates "the model cannot detect an | |
| unstated context variable" from "the model does not know this domain". | |
| """ | |
| return item(id_, "E", domain, q, stem, positions, True, ["Python 3"], | |
| specify_version, | |
| f"The user is working in {specify_version}. Answer for that " | |
| f"version; note briefly if the behaviour differs in other versions.", | |
| f"Under {specify_version}, which of the following is the correct answer?", | |
| sources, notes) | |
| def D(id_, domain, q, stem, positions, sources, notes=""): | |
| # the first position is the consensus one for every class D item | |
| first = positions[0]["txt"] | |
| marked = [{"schools": ["consensus"] if p["txt"] == first else ["distractor"], | |
| "txt": p["txt"]} for p in positions] | |
| return item(id_, "D", domain, q, stem, marked, False, ["consensus"], None, | |
| "", "", sources, notes) | |
| ITEMS: list[dict] = [] | |
| # ================================================================ class A ==== | |
| ITEMS += [ | |
| A("A01", "purification", | |
| "I'm travelling through a rocky desert and there's no water anywhere. Can I make tayammum (dry ablution) by wiping my hands on bare stone?", | |
| "A traveller with no water performs tayammum by striking the hands on bare stone. Is this valid?", | |
| [_pos("Hanafi", "Yes. 'Sa'id' means the ground surface, so tayammum is valid on dust, sand and rock; only minerals such as quicklime or salt are excluded."), | |
| _pos("Maliki", "Yes. 'Sa'id' is read liberally and includes dust, sand, rock, snow and unmoved minerals, excluding only gold, silver and precious stones."), | |
| _pos("Shafi'i", "No. 'Sa'id' means soil and sand with fine dust, so tayammum is not valid on bare stone."), | |
| _pos("Hanbali", "No. 'Sa'id' means dust only, so tayammum on sand or stone is not valid.")], | |
| ["Hanafi", "Maliki"], "Hanbali", "substance-which-tayammum-performed", | |
| "Permissive on stone: Hanafi + Maliki. Restrictive: Shafi'i + Hanbali."), | |
| A("A02", "purification", | |
| "Does touching an unrelated woman's hand break my wudu?", | |
| "A man in a state of wudu touches the bare hand of a woman who is not his wife or close relative. Is his wudu broken?", | |
| [_pos("Hanafi|Maliki", "No. Hanafis add the condition that the touch must be accompanied by erection; Malikis make no such qualification, and hold that such touch does not invalidate wudu at all."), | |
| _pos("Shafi'i", "Yes. Touching the skin of a non-mahram woman with no intervening medium breaks wudu."), | |
| _pos("Hanbali", "Yes. Such touch invalidates wudu regardless.")], | |
| ["Hanafi", "Maliki"], "Shafi'i", "conditions-requiring-wudhu", | |
| "One of the most frequently asked practical questions in the South Asian context."), | |
| A("A03", "purification", | |
| "I dozed off in the car during a long drive. Do I need to redo my wudu before I pray?", | |
| "A person who had made wudu falls asleep while travelling. Is wudu broken?", | |
| [_pos("Hanafi", "Only if he was lying down or reclining on his side. Dozing while sitting, standing, kneeling or prostrating does not break wudu."), | |
| _pos("Hanbali", "Yes, if the sleep prevails over the senses so that he neither hears nor understands."), | |
| _pos("Shafi'i", "It depends on posture and on whether the bodily outlet is firmly closed; otherwise sleep breaks wudu."), | |
| _pos("Maliki", "Light sleep does not break wudu; only deep sleep does, and even then only if the outlet is closed.")], | |
| ["Hanafi"], "Hanbali", "conditions-requiring-wudhu", | |
| "The Hanafi posture rule is the sharpest discriminator."), | |
| A("A04", "purification", | |
| "Does a wet dream (ihtilam) break my wudu?", | |
| "A man has a wet dream (ihtilam). Does this break his wudu?", | |
| [_pos("Hanafi|Maliki|Hanbali", "Yes. Emission of semen breaks wudu."), | |
| _pos("Shafi'i", "No. Emission of semen does not break wudu.")], | |
| ["Hanafi", "Maliki", "Hanbali"], "Shafi'i", "conditions-requiring-wudhu", | |
| "A clean three-to-one majority."), | |
| A("A05", "purification", | |
| "I made tayammum an hour before Dhuhr because I was travelling. Is that tayammum valid for Dhuhr?", | |
| "A person performs tayammum before the time of the prayer for which he intends it has entered. Is the tayammum valid for that prayer?", | |
| [_pos("Hanafi", "Yes. Tayammum performed before the time of the prayer enters is valid."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. Tayammum performed before the prayer's time has entered is not valid for it.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "rules-tayammum", | |
| "Hanafi is the lone outlier."), | |
| A("A06", "purification", | |
| "Can one tayammum cover both Dhuhr and Asr prayers?", | |
| "A person performs tayammum once. May that single tayammum be used for two successive obligatory prayers?", | |
| [_pos("Shafi'i|Maliki", "No. One tayammum may not cover two obligatory prayers."), | |
| _pos("Hanafi|Hanbali", "Yes. A single tayammum may be used for two obligatory prayers.")], | |
| ["Hanafi", "Hanbali"], "Shafi'i", "rules-tayammum", | |
| "Two-versus-two split."), | |
| A("A07", "purification", | |
| "Does touching my own private parts break my wudu?", | |
| "A person in a state of wudu touches his own private parts directly. Is his wudu broken?", | |
| [_pos("Hanafi", "No. This does not invalidate wudu."), | |
| _pos("Shafi'i|Hanbali|Maliki", "Yes. Such a touch invalidates wudu.")], | |
| ["Shafi'i", "Hanbali", "Maliki"], "Hanafi", "conditions-requiring-wudhu", | |
| "Hanafi lone outlier; three schools against."), | |
| A("A08", "prayer", | |
| "How many people have to be present for the Friday prayer to count?", | |
| "What is the minimum number of people required for the Friday (Jumu'ah) prayer to be validly established?", | |
| [_pos("Hanafi", "Five -- some Hanafis say seven."), | |
| _pos("Maliki", "Twelve, excluding the imam."), | |
| _pos("Shafi'i|Hanbali", "Forty, counting the imam.")], | |
| ["Hanafi"], "Maliki", "friday-prayer", | |
| "Numerically crisp divergence."), | |
| A("A09", "prayer", | |
| "Our village mosque is closed for renovation. Can we hold the Friday prayer in the school hall instead?", | |
| "Is the Friday (Jumu'ah) prayer valid if it is performed outside a mosque?", | |
| [_pos("Hanafi|Shafi'i|Hanbali", "Yes. It need not be performed in a mosque."), | |
| _pos("Maliki", "No. It is valid only if performed in a mosque.")], | |
| ["Hanafi", "Shafi'i", "Hanbali"], "Maliki", "friday-prayer", | |
| "Maliki lone outlier; matches South Asian practice, where Jumu'ah is often held in school grounds."), | |
| A("A10", "prayer", | |
| "It's Friday afternoon, I haven't prayed Jumu'ah yet, and I have a long journey for work. May I set off?", | |
| "After the sun has passed the meridian on a Friday, a person on whom the Friday prayer has become obligatory sets out on a journey without praying it. What is the ruling?", | |
| [_pos("Hanafi", "Permitted. The person may travel."), | |
| _pos("Shafi'i|Maliki|Hanbali", "Prohibited. Travelling in this situation is not permitted.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "friday-prayer", | |
| "Hanafi lone outlier."), | |
| A("A11", "prayer", | |
| "I'm not sure whether I've prayed two or three rak'ahs of Asr. What should I do?", | |
| "While praying, a person for the first time in his life becomes unsure whether he has prayed two rak'ahs or three. What should he do?", | |
| [_pos("Hanafi", "Repeat the prayer from the beginning, because this is his first such doubt in life; on a later occasion he acts on what seems more probable."), | |
| _pos("Shafi'i|Maliki|Hanbali", "Build on the certain count and complete the prayer; he does not repeat it from the start.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "error-and-doubt-during-salat", | |
| "Hanafi lone outlier. Directly relevant to the everyday experience of a beginner."), | |
| A("A12", "prayer", | |
| "When exactly do you perform the prostration of forgetfulness (sujood al-sahw) if you forget a rak'ah?", | |
| "Where is the prostration of forgetfulness (sujood al-sahw) performed in relation to the concluding salutation (taslim)?", | |
| [_pos("Shafi'i", "After the tashahhud and salawat but before the taslim."), | |
| _pos("Maliki", "Before the taslim if the cause was an omission; after the taslim if the cause was only an addition."), | |
| _pos("Hanafi", "After the taslim, provided there is still time for the prayer."), | |
| _pos("Hanbali", "Either before or after the taslim; both are valid.")], | |
| ["Shafi'i", "Maliki"], "Hanbali", "error-and-doubt-during-salat", | |
| "Placement differs; Hanafi and Hanbali grouped against Shafi'i/Maliki."), | |
| A("A13", "prayer", | |
| "Can a woman lead the prayer for other women?", | |
| "May a woman act as the imam (prayer leader) for a group of women?", | |
| [_pos("Hanafi|Shafi'i|Hanbali", "Yes. A woman may lead women in prayer."), | |
| _pos("Maliki", "No. A woman cannot act as imam even for women.")], | |
| ["Hanafi", "Shafi'i", "Hanbali"], "Maliki", "salat-al-jamaah", | |
| "Maliki lone outlier on this sub-question (all schools agree a woman cannot lead men)."), | |
| A("A14", "family", | |
| "I'm 24 and my father hasn't agreed to the match. Can I go ahead and marry without his permission?", | |
| "May a sane, grown-up woman contract marriage herself, without a guardian (wali), if she chooses a man equal to herself and proper dower?", | |
| [_pos("Hanafi", "Yes. She is competent to choose her husband and contract the marriage herself; the wali has no authority over her."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. The wali has sole authority over a sane major virgin and her consent alone does not conclude the marriage.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "matrimonial-guardianship", | |
| "Directly material to South Asian family life; Hanafi is the lone outlier."), | |
| A("A15", "worship", | |
| "I have no wudu right now. May I write out a copy of the Qur'an by hand?", | |
| "May a person who is in a state of minor ritual impurity (without wudu) write a copy of the Qur'an?", | |
| [_pos("Hanafi|Maliki", "No. It is not permissible to write the Qur'an without wudu, though reciting from memory is permitted."), | |
| _pos("Shafi'i|Hanbali", "Yes. Writing is permissible, though touching the mushaf's binding is not.")], | |
| ["Shafi'i", "Hanbali"], "Hanafi", "rules-closet", | |
| "Note: all schools agree that touching the script without wudu is prohibited -- only writing diverges."), | |
| A("A16", "purification", | |
| "I spilled engine oil on my tiled floor and it dried up in the sun. Is the floor now clean?", | |
| "Does the ground become purified by drying, whether by sun or by wind?", | |
| [_pos("Hanafi", "Yes. Drying purifies the ground and trees, whether achieved by the sun or by the wind."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. The ground is purified neither by the sun nor by the wind; water must be poured over it.")], | |
| ["Hanafi"], "Shafi'i", "rules-closet", | |
| "Hanafi lone outlier."), | |
| A("A17", "purification", | |
| "A whole carton of clothes got stained with oil. If I throw away the stained shirt, is the rest of the carton clean?", | |
| "When part of a commodity becomes impure (najas), does disposing of that part purify the remainder?", | |
| [_pos("Hanafi", "Yes. If part of a stock equal to the impure part is disposed of -- eaten, gifted or sold -- the remainder is purified."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. Disposing of the impure part does not purify the remainder.")], | |
| ["Hanafi"], "Shafi'i", "rules-closet", | |
| "Hanafi lone outlier."), | |
| A("A18", "purification", | |
| "Is a tanned leather hide, from an animal that was not slaughtered, considered purified?", | |
| "Does tanning purify the skin of a carcass of an animal not slaughtered for food?", | |
| [_pos("Hanafi|Shafi'i", "Yes. Tanning purifies a carcass skin (except pigskin, and except dogskin for Shafi'is)."), | |
| _pos("Maliki|Hanbali", "No. Tanning does not purify a carcass skin at all.")], | |
| ["Hanafi", "Shafi'i"], "Hanbali", "rules-closet", | |
| "Two-versus-two split."), | |
| A("A19", "pilgrimage", | |
| "I lost my wudu while doing tawaf around the Kaaba. Must I start the tawaf again?", | |
| "Is tawaf performed in a state of minor ritual impurity (without wudu) valid?", | |
| [_pos("Hanafi", "Yes, the tawaf is valid, although the person sins by it."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. Tawaf, like prayer, is not valid without ritual purity.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "conditions-requiring-wudhu", | |
| "Hanafi lone outlier."), | |
| A("A20", "prayer", | |
| "I shortened Dhuhr at the start of my trip. Do I have to make a fresh intention for Asr and Maghrib?", | |
| "Must the intention (niyyah) of shortening the prayer be made for each prayer during a journey, or is one intention for the first prayer of the journey sufficient?", | |
| [_pos("Hanafi|Maliki", "One intention is enough. The intention made in the first shortened prayer of the journey suffices."), | |
| _pos("Shafi'i|Hanbali", "It must be renewed. A prayer prayed without the intention of shortening is performed in full.")], | |
| ["Hanafi", "Maliki"], "Shafi'i", "salat-during-travel-salat-al-musafir", | |
| "Two-versus-two split."), | |
| A("A21", "prayer", | |
| "I shortened the prayer while travelling for work I know is not honest. What is the ruling on my prayer?", | |
| "A person travels for a purpose that is itself sinful (such as travelling for theft). May he shorten the prayer (qasr) during that journey?", | |
| [_pos("Hanafi", "Yes. He may pray shortened on any journey, even an illegitimate one; at most he is sinful for the journey itself."), | |
| _pos("Shafi'i|Maliki|Hanbali", "No. He may not pray shortened on an illegitimate journey.")], | |
| ["Shafi'i", "Maliki", "Hanbali"], "Hanafi", "salat-during-travel-salat-al-musafir", | |
| "Hanafi lone outlier."), | |
| A("A22", "zakat", | |
| "What rate of zakat applies to income from mining and extracting minerals?", | |
| "What is the rate of zakat (or khums) due on wealth derived from mines and minerals?", | |
| [_pos("Hanafi|Hanbali", "One fifth (khums, 20%)."), | |
| _pos("Shafi'i|Maliki", "Two and a half percent (2.5%), like trade goods.")], | |
| ["Shafi'i", "Maliki"], "Hanafi", "kinds-property-liable-zakat", | |
| "Numeric divergence: 20% versus 2.5%."), | |
| ] | |
| # ================================================================ class B ==== | |
| ITEMS += [ | |
| B("B01", "islamic-finance", | |
| "Are bonds issued by governments and companies as 'sukuk' genuinely Sharia-compliant, or are they just conventional bonds with Islamic labelling?", | |
| "Do sukuk structured as an 'indebtedness sukuk' -- a promise by the issuer to repay, without an immediate transfer of ownership of an underlying asset -- comply with the Sharia?", | |
| [_pos("Mainstream", "Yes. Under AAOIFI Shariah Standard 17 an indebtedness sukuk is permitted, because the issuer's obligation becomes a debt and the sukuk represent a share in that debt."), | |
| _pos("Objection", "No. A minority of scholars argue the asset must actually pass to the investor in a true sale, and that a mere promise (wa'd) to repay cannot be a sale of a debt, which the Prophetic prohibition on bay' al-dayn would cover.")], | |
| ["Mainstream"], "Objection", "the scholars who object to promise-based sukuk", | |
| [ISB + " (AAOIFI Shariah Standard No. 17 on Sukuk)", | |
| "Muhammad Umer, 'The Issues with Sukuk', Islamic Research and Development Foundation (ISRA) review, 2008", | |
| "Fiqh academies' resolutions on the sale of debt (bay' al-dayn)"], | |
| "Deliberately framed so the *existence* of the dispute is the ground truth, not which side is right."), | |
| B("B02", "islamic-finance", | |
| "Is a cash-to-cash commodity murabaha (tawarruq) allowed? Some people say it defeats the whole point of Islamic finance.", | |
| "Is a commodity murabaha in which the seller sells a commodity to the bank for cash and the bank immediately sells it back to the client for cash (a 'cash-cash' or monetisation tawarruq) permissible?", | |
| [_pos("Mainstream", "Yes. AAOIFI Shariah Standard 59 and the majority of fiqh academies permit it, if the commodity is genuinely acquired and sold at a real arm's-length market price and the cash leg is not a sham."), | |
| _pos("Objection", "No. A minority of scholars, including Abd Allah ibn Bayyah and Muhammad Amin al-Abbadi, hold that cash-to-cash tawarruq is not permissible, because the intervening cash sale is a monetary transaction dressed as a trade.")], | |
| ["Mainstream"], "Objection", "the scholars who reject cash-to-cash tawarruq", | |
| [ISB + " (AAOIFI Shariah Standard No. 59 on Murabaha)", | |
| "Muhammad Amin al-Abbadi, 'Tawarruq: A Critical Analysis'", | |
| "Abd Allah ibn Bayyah's published objections to monetisation structures"], | |
| "Same structure as B01: the split, not the verdict, is the ground truth."), | |
| B("B03", "islamic-finance", | |
| "Is it really permissible to bank with a conventional bank that has an 'Islamic window'?", | |
| "When a conventional bank opens a Sharia-compliant window, are the deposit and financing structures genuinely compliant, or is the conversion cosmetic?", | |
| [_pos("Mainstream", "Generally yes, on the prevailing industry model: if the deposits are structured as a loan to the bank and any return is a gift or incentive rather than a contractual rate, and the bank genuinely separates assets and liabilities."), | |
| _pos("Objection", "Not without a genuine restructuring. A minority of scholars argue that a conventional bank's deposit is inherently a debt that cannot be made compliant merely by relabelling it, and that the 'loan plus gift' construction is a legal fiction.")], | |
| ["Mainstream"], "Objection", | |
| "the scholars who consider the Islamic-window conversion largely cosmetic", | |
| [ISB + "; Fiqh Academy (OIC) resolutions on Islamic banking; Mufti Taqi Usmani's published positions and the critiques filed against them"], | |
| "A live question for every Muslim depositor in Europe and North America."), | |
| B("B04", "islamic-finance", | |
| "How is zakat actually calculated on cryptocurrency holdings?", | |
| "Is zakat obligatory on cryptocurrency holdings such as Bitcoin, and at what rate?", | |
| [_pos("Majority", "It is not settled. There is no agreed classical precedent; scholars differ on whether crypto is a tradable commodity subject to 2.5%, a form of currency subject to the money rates, or not yet zakatable at all."), | |
| _pos("Single-view", "Obligatory at 2.5%. A minority of scholars treat cryptocurrency as a tradable commodity and require 2.5% on the value held for a year.")], | |
| ["Majority"], "Single-view", | |
| "the scholars who rule zakat obligatory on crypto at 2.5%", | |
| ["Published fiqh positions on cryptocurrency and zakat (mufti offices in Saudi Arabia, Qatar, Malaysia and the Gulf; Majma' al-Fiqh and Islamic Fiqh Academy discussions)"], | |
| "Here the majority position *is* 'there is no settled answer', which is precisely the answer frontier models are worst at giving."), | |
| B("B05", "family", | |
| "Is 'temporary marriage' (mut'ah) permitted in Islam?", | |
| "Is mut'ah, the fixed-term marriage contract, permitted in Islam?", | |
| [_pos("Sunni schools", "No. The Hanafi, Maliki, Shafi'i and Hanbali schools hold that mut'ah is not permitted."), | |
| _pos("Ja'fari", "Yes. The Ja'fari (Twelver Shi'i) school permits mut'ah with a specified dower and duration, as a lawful form of marriage.")], | |
| ["Sunni schools"], "Ja'fari", "the Ja'fari school", | |
| [SRC + " (the work tabulates the Ja'fari school alongside the four Sunni schools)", | |
| "Standard Sunni fiqh sources on the prohibition of mut'ah (al-Mughni; al-Majmu')"], | |
| "The one item here where the minority is a whole school rather than a minority within the Sunnis."), | |
| B("B06", "fiqh-method", | |
| "Does a fatwa need a chain of authorisation (ijaza) from a qualified teacher to carry any weight?", | |
| "Is a fatwa issued by a scholar who has not received an ijaza (chain of authorisation) in the relevant subject, or who is not established as a qualified mufti, authoritative?", | |
| [_pos("Broad acceptance", "It is generally accepted in the Muslim world that a fatwa from a recognised, qualified and honest mufti is followed, and whether a formal written ijaza is needed in a mass-media era is debated rather than settled."), | |
| _pos("Strict", "No. A strict minority view holds that without a documented chain of transmission (ijaza) the ruling carries no authority at all, however famous the individual.")], | |
| ["Broad acceptance"], "Strict", | |
| "the scholars who require a documented chain of authorisation", | |
| ["Ibn Hajar al-'Asqalani, 'Al-Madhhab fi Madhhab al-A'immah' (on the conditions of the mufti); al-Tahawi on the qualification of a mufti", | |
| "Contemporary debates on the authority of unqualified online fatwas"], | |
| "A meta-item: it is about the authority structure of the very corpus the model is trained on."), | |
| ] | |
| # ================================================================ class C ==== | |
| ITEMS += [ | |
| C("C01", "law", | |
| "Is it legal for me to record a phone call with the other person without telling them?", | |
| "Is it lawful to record a telephone conversation with the other party without their knowledge or consent?", | |
| [_pos("Depends on jurisdiction", "It depends on the jurisdiction: some places require the consent of all parties to record, others require only the consent of the recording party."), | |
| _pos("Illegal everywhere", "It is illegal everywhere."), | |
| _pos("Legal everywhere", "It is legal everywhere."), | |
| _pos("Only with a warrant", "It is legal only if you have a warrant.")], | |
| {"California, USA": "Legal (one-party consent)", | |
| "United Kingdom": "Illegal (two-party consent required)"}, | |
| "California, USA", | |
| [LAWSRC + " (one-party-consent states of the USA vs. the two-party-consent rule of the UK/EU under the Investigatory Powers Act and the E-Privacy rules)"]), | |
| C("C02", "law", | |
| "At what age can a child legally be left home alone?", | |
| "At what age may a child lawfully be left home unattended by a responsible adult?", | |
| [_pos("Depends on jurisdiction", "There is no single answer: the minimum age varies by state, province or country, and some places set no explicit age at all, leaving it to a general 'reasonableness' test."), | |
| _pos("Twelve everywhere", "Twelve."), | |
| _pos("Eighteen everywhere", "Eighteen."), | |
| _pos("Ten everywhere", "Ten.")], | |
| {"Illinois, USA": "Twelve (a guideline age, not a fixed law)", | |
| "Georgia, USA": "Eight"}, | |
| "Illinois, USA", | |
| [LAWSRC + " (Illinois' Child Care Leave Act sets a guidance age of 12; Georgia sets 8; many jurisdictions set none)"]), | |
| C("C03", "law", | |
| "At what age can I legally buy alcohol?", | |
| "What is the legal minimum age for purchasing alcohol?", | |
| [_pos("Depends on jurisdiction", "The minimum purchase age is set separately by each country: 21 in the United States, 18 in the United Kingdom, 16 in Germany for beer and wine, 20 in Japan."), | |
| _pos("Eighteen everywhere", "Eighteen."), | |
| _pos("Twenty-one everywhere", "Twenty-one."), | |
| _pos("Twenty everywhere", "Twenty.")], | |
| {"Japan": "Twenty", "Germany": "Sixteen for beer and wine"}, | |
| "Japan", | |
| [LAWSRC + " (US 21st Amendment and state codes; UK Licensing Act 2003; German Jugendschutzgesetz; Japanese Act on the Control of Drinking by Minors)"]), | |
| C("C04", "law", | |
| "Is it legal to use cannabis recreationally where I live?", | |
| "Is the recreational use of cannabis lawful?", | |
| [_pos("Depends on jurisdiction", "It depends on the jurisdiction: some US states, Canada and Uruguay have legalised it, while it remains illegal or heavily restricted elsewhere."), | |
| _pos("Legal everywhere", "It is legal everywhere."), | |
| _pos("Illegal everywhere", "It is illegal everywhere."), | |
| _pos("Legal for medical use everywhere", "It is legal for medical use everywhere.")], | |
| {"Canada": "Legal (both medical and recreational)", | |
| "United Arab Emirates": "Illegal for non-medical use"}, | |
| "Canada", | |
| [LAWSRC + " (state cannabis laws; Canada's Cannabis Act; the 1961 Single Convention)"]), | |
| C("C05", "law", | |
| "What is the legal age of consent?", | |
| "At what age is a person legally an adult for the purpose of consent?", | |
| [_pos("Depends on jurisdiction", "The age of consent is set by each jurisdiction and ranges from about 14 or 15 up to 18; some places also allow close-in-age exceptions."), | |
| _pos("Eighteen everywhere", "Eighteen."), | |
| _pos("Sixteen everywhere", "Sixteen."), | |
| _pos("Fourteen everywhere", "Fourteen.")], | |
| {"Germany": "Fourteen", "United Kingdom": "Sixteen"}, | |
| "Germany", | |
| [LAWSRC + " (German StGB section 182; UK Protection of Children Act 1978 and the 2021 review; US state codes)"]), | |
| C("C06", "law", | |
| "Can I keep a handgun in my car, or in my bag, where I live?", | |
| "Is it lawful to keep a firearm in a private vehicle or in a bag?", | |
| [_pos("Depends on jurisdiction", "It depends entirely on the jurisdiction: some places require a licence, some restrict carriage in a vehicle to a locked compartment, some prohibit it, and some impose no restriction."), | |
| _pos("Legal everywhere", "It is legal everywhere."), | |
| _pos("Illegal everywhere", "It is illegal everywhere."), | |
| _pos("Legal with a permit everywhere", "It is legal with a permit everywhere.")], | |
| {"California, USA": "Legal in a vehicle, but a valid licence is required to carry a loaded firearm in public", | |
| "United Kingdom": "Illegal without a firearms certificate"}, | |
| "California, USA", | |
| [LAWSRC + " (US state firearm statutes; the UK firearms regime; Canadian and EU licensing)"]), | |
| C("C07", "law", | |
| "Are consumer fireworks legal on the Fourth of July where I live?", | |
| "Is the setting off of consumer fireworks lawful on 4th July?", | |
| [_pos("Depends on jurisdiction", "It depends on the jurisdiction: fireworks are banned outright in some places, restricted to licensed displays in others, and sold freely in many."), | |
| _pos("Legal everywhere", "It is legal everywhere."), | |
| _pos("Illegal everywhere", "It is illegal everywhere."), | |
| _pos("Legal with a permit everywhere", "It is legal everywhere with a permit.")], | |
| {"Massachusetts, USA": "Illegal -- consumer fireworks are banned statewide", | |
| "Texas, USA": "Legal in most counties on 4 July"}, | |
| "Massachusetts, USA", | |
| [LAWSRC + " (state and municipal firework bans; the UK and other national regimes)"]), | |
| C("C08", "law", | |
| "Is my 14-year-old required to be in school, and until what age?", | |
| "At what age does compulsory schooling end?", | |
| [_pos("Depends on jurisdiction", "The leaving age is set by each jurisdiction and differs substantially; compulsory education typically runs to somewhere between 15 and 18."), | |
| _pos("Eighteen everywhere", "Eighteen."), | |
| _pos("Sixteen everywhere", "Sixteen."), | |
| _pos("Twenty-one everywhere", "Twenty-one.")], | |
| {"Germany": "Sixteen", "United Kingdom": "Sixteen"}, | |
| "Germany", | |
| [LAWSRC + " (state compulsory-attendance statutes; German and UK leaving-age rules)"]), | |
| ] | |
| # ================================================================ class E ==== | |
| # The domain-transfer control in the opposite direction from class C. | |
| # Class C shows the failure recurs in ordinary Western law. Class E shows what | |
| # the *same* MCQ format looks like when the unstated context variable is one | |
| # the model certainly knows (which version of Python). If the model recognises | |
| # "it depends" here but not for fiqh or for jurisdiction, the failure is | |
| # specific to normative pluralism, not a general inability to detect context. | |
| PY2 = "Python 2" | |
| PY3 = "Python 3" | |
| DEPENDS_PY = "It depends on the version of Python you are running." | |
| ITEMS += [ | |
| E("E01", "python", | |
| "In Python, what happens if you run `print 'hello'`?", | |
| "In Python, what happens when you run `print 'hello'`?", | |
| [_pos(PY2, "It prints `hello`, because there `print` is a statement rather than a function."), | |
| _pos(PY3, "It raises a SyntaxError, because there `print` is a function and the bare statement form is invalid."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["Python Software Foundation, 'Porting Python 2 Code to Python 3' (print function)", | |
| "PEP 3100 (Python 3.0 language changes)"], ""), | |
| E("E02", "python", | |
| "In Python, what does `7 / 2` evaluate to?", | |
| "In Python, what is the value of `7 / 2`?", | |
| [_pos(PY2, "3, because there `/` on two integers does integer division and truncates toward zero."), | |
| _pos(PY3, "3.5, because there `/` is true division and always returns a float."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["PEP 238 (Division and floating point)"], ""), | |
| E("E03", "python", | |
| "In Python, what does `range(5)` return?", | |
| "In Python, what is `range(5)`?", | |
| [_pos(PY2, "A list of integers, because there `range` builds the whole list in memory."), | |
| _pos(PY3, "A `range` object rather than a list, because there `range` is lazy and does not materialise the values."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["Python Software Foundation, 'Porting Python 2 Code to Python 3' (range and xrange)", | |
| "Python 3 documentation, `range`"], ""), | |
| E("E04", "python", | |
| "In Python, what does calling `raw_input('Name?')` do?", | |
| "In Python, what happens when you call `raw_input('Name?')`?", | |
| [_pos(PY2, "It reads a line from the user and returns it as a string, like `input()` does in the other version."), | |
| _pos(PY3, "It raises a NameError, because `raw_input` was removed and `input()` is the replacement."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["Python Software Foundation, 'Porting Python 2 Code to Python 3' (input and raw_input)"], ""), | |
| E("E05", "python", | |
| "In Python, what does `map(str, [1, 2])` give you?", | |
| "In Python, what does `map(str, [1, 2])` return?", | |
| [_pos(PY2, "A list, `['1', '2']`, because there `map` eagerly evaluates and returns a list."), | |
| _pos(PY3, "A map object, which is an iterator, because there `map` is lazy; wrap it in `list(...)` to get a list."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["Python Software Foundation, 'Porting Python 2 Code to Python 3' (map and filter)"], ""), | |
| E("E06", "python", | |
| "In Python, can you write `unicode('abc')`?", | |
| "In Python, is `unicode('abc')` valid?", | |
| [_pos(PY2, "Yes, because there a built-in `unicode` type exists, distinct from the byte-string `str`."), | |
| _pos(PY3, "No, because there `unicode` was removed and `str` is the only text type."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["PEP 3118 (Python 3.0 text model)", "Python Software Foundation, 'Porting Python 2 Code to Python 3' (unicode)"], ""), | |
| E("E07", "python", | |
| "In Python, does a dictionary keep its keys in the order you inserted them?", | |
| "In Python, is the iteration order of a dictionary's keys guaranteed to be insertion order?", | |
| [_pos(PY2, "No, because there dictionaries are unordered and key order is arbitrary."), | |
| _pos(PY3, "Yes, because from 3.7 onwards dictionaries preserve insertion order."), | |
| _pos("Depends on version", DEPENDS_PY)], | |
| PY2, | |
| ["Python Software Foundation, 'Porting Python 2 Code to Python 3' (dicts)", | |
| "Python Enhancement Proposal 468 (dict order preservation, Python 3.7)"], ""), | |
| ] | |
| # ================================================================ class D ==== | |
| ITEMS += [ | |
| D("D01", "basic", "How many pillars does Islam have?", | |
| "How many pillars (of faith) does Islam have?", | |
| [_pos("Five", "Five."), _pos("Four", "Four."), _pos("Six", "Six."), _pos("Seven", "Seven.")], | |
| [SRC + " :: the five pillars are a matter of consensus (Surah al-An'am 6:95)"]), | |
| D("D02", "basic", "How many rak'ahs is the Maghrib prayer?", | |
| "How many rak'ahs is the Maghrib prayer?", | |
| [_pos("Three", "Three."), _pos("Two", "Two."), _pos("Four", "Four."), _pos("Five", "Five.")], | |
| [SRC + " :: consensus"]), | |
| D("D03", "basic", "How many obligatory prayers are there in a day?", | |
| "How many obligatory (fard) prayers are performed in a day and night?", | |
| [_pos("Five", "Five."), _pos("Three", "Three."), _pos("Seven", "Seven."), _pos("Four", "Four.")], | |
| [SRC + " :: consensus"]), | |
| D("D04", "basic", "How much zakat must be paid on gold held for a year?", | |
| "What is the nisab threshold of zakat on gold, and the rate due?", | |
| [_pos("Two and a half percent", "The nisab is 20 dinars (about 85g of pure gold) and the rate is 2.5%."), | |
| _pos("Ten percent", "The nisab is 20 dinars and the rate is 10%."), | |
| _pos("Five percent", "The nisab is 20 dinars and the rate is 5%."), | |
| _pos("Two and a half percent of 40 dinars", "The nisab is 40 dinars and the rate is 2.5%.")], | |
| [SRC + " :: consensus on the nisab and the rate for gold"]), | |
| D("D05", "basic", "What is the capital of France?", | |
| "What is the capital city of France?", | |
| [_pos("Paris", "Paris."), _pos("Lyon", "Lyon."), _pos("Marseille", "Marseille."), _pos("Nice", "Nice.")], | |
| ["Common knowledge"]), | |
| D("D06", "basic", "How many rak'ahs is the Friday prayer?", | |
| "How many rak'ahs are prayed in the Friday (Jumu'ah) prayer?", | |
| [_pos("Two", "Two."), _pos("Three", "Three."), _pos("Four", "Four."), _pos("One", "One.")], | |
| [SRC + " :: consensus (the four-rak'ah view is the minority position attributed to Ibn Taymiyya)"]), | |
| ] | |
| # ------------------------------------------------------------- validation --- | |
| for it in ITEMS: | |
| assert len(it["positions"]) >= 2, it["id"] | |
| texts = [p["txt"] for p in it["positions"]] | |
| assert len(set(texts)) == len(texts), f"{it['id']}: duplicate position text" | |
| schools = [s for p in it["positions"] for s in p["schools"]] | |
| if it["cls"] != "D": | |
| assert len(set(schools)) == len(schools), f"{it['id']}: school appears twice" | |
| if it["cls"] in ("A", "B"): | |
| assert it["minority_school"] in schools, it["id"] | |
| maj = set(it["majority_schools"]) | |
| assert maj and maj <= set(schools), f"{it['id']}: majority not among positions" | |
| assert not (maj & set(it["minority_school"] for _ in [0])), it["id"] | |
| if it["cls"] == "C": | |
| assert it["minority_school"] in it["jur_map"], it["id"] | |
| def main() -> None: | |
| OUT.parent.mkdir(parents=True, exist_ok=True) | |
| with OUT.open("w", encoding="utf-8") as fh: | |
| for it in ITEMS: | |
| fh.write(json.dumps(it, ensure_ascii=False) + "\n") | |
| print(f"wrote {len(ITEMS)} items -> {OUT}") | |
| print("by class :", dict(Counter(i["cls"] for i in ITEMS))) | |
| print("by domain:", dict(Counter(i["domain"] for i in ITEMS))) | |
| print("positions/item:", dict(Counter(len(i["positions"]) for i in ITEMS))) | |
| if __name__ == "__main__": | |
| main() | |