msq-plurality-gap / code /build_dataset.py
adeerkhan's picture
MSQ: the unstated premise
5264032 verified
Raw History Blame Contribute Delete
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()