GuidelinesDraftالعربية

Decision record

The contested decisions in the terminology standard, with their reasons and evidence.

The standard states the rule. This page states why the rule is what it is.

They are kept apart because a reader applying the standard wants the rule alone, while a reader who wants to change it needs what the rule rests on. A rule with no written reason gets reopened every year.

Only decisions where there was a real disagreement, or a reasonable alternative, are recorded here. Each carries a date and a status: settled, open, or superseded by a later decision. Decisions made before the record was dated are marked undated. Every entry uses the same headings: Decision, then Why, then Evidence, The boundary, Consequence and Alternative rejected where they apply, and Open for a question left standing inside a settled decision. A question that was never settled is its own entry, under Question and Status. The italic line carries the status, what the decision supersedes, and the date of any later review. Read in order, the dated entries are the changelog of the dictionary's names.

Measurements. "GitHub phrase search" is a quoted phrase query against GitHub code search, run by tools/measure_display.py, which caches every count in tools/display_measurements.json under the key a | b. Counts are point in time: they say what the index held on the day they were taken, and are not re-run. Where a count below has a cache key, the key is given.


Letter names are written as they are said

Undated · settled

Decision: noon, meem, seen — not nun, mim, sin.

Why: nun and sin are English words with a meaning far from the one intended. The measurement also shows letter names tend towards the doubled form (cache keys nun sakinah | noon sakinah, mim sakinah | meem sakinah):

noon sakinah   478  ×  nun sakinah   118
meem sakinah   308  ×  mim sakinah    57

The boundary: letter names only. A letter name carries no meaning beyond its sound, so deriving it throws away the only thing it has; every other term is a word with a meaning that the derivation keeps.

Consequence: the 28 letter names live in letter_names.tsv, and the function reads them from there.


Long vowels are written short

Undated · settled

Decision: tajwid, sukun, tafsir — not tajweed, sukoon, tafseer.

Why: usage favours the short form for terms. These counts were taken before the cache existed and are not in it; they are point in time:

sukun    289792  ×  sukoon    18432
tafsir   370688  ×  tafseer  115712
tanwin    19968  ×  tanween    4520
tartil    24736  ×  tarteel    7328

Alternative rejected: doubling everywhere. It contradicts the measurement for most terms.


tajwid goes against its own measurement

Undated · settled

Decision: code: tajwid, even though tajweed is about twice as common (45,440 × 25,280; cache key tajwid | tajweed).

Why: one steady rule is worth more than an exception that opens a door for every word.

Consequence: display: Tajweed is measured from use, and tajweed is recorded in alternative_spellings.


A word-final ayn or hamzah echoes the vowel before it

Undated · settled

Decision: rubu, jama, qata, while ruku and mamnu stay as they are.

Why: deleting them cut the word short, giving rub, jam and qat — unrelated English words. This is the same problem that made us write noon rather than nun.

Alternatives rejected: ' and ʿ do not work in identifiers, and 3 (chat-Arabic for ayn) is not a letter.

The boundary: after a long vowel the word already ends in a vowel, so nothing is added.


juz is not derived

Undated · settled

Decision: juz, where the derivation gives juzu.

Why: the derived form is effectively unused. The count predates the cache:

juz number  1384  ×  juzu number  1

The boundary: a row in established_spellings.tsv is accepted only with a measurement showing the derived form is unused. Usage merely leaning one way is not enough, or tajweed would qualify.


Five established rows rest on a rule, not a count

2026-09-06 · settled

Decision: aal (آل), taha, yasin, saad and qaaf stay in established_spellings.tsv, and the standard (§7) states the two rules they rest on: a name may not open with al, and a surah named by its opening letters is written by letter name.

Why: the file's own bar is a measurement, and these 5 have none. For aal the cache points the other way (al imran | aal imran: 18,368 × 519), so the row cannot be defended as usage; it is defended because al_imran would read as an article plus a name, which §8 forbids. The 4 letter-named surahs cannot be measured at all: the derivation gives th, ys, s and q, which nobody writes.

Alternative rejected: a second file for rule-based rows. The function reads one table, and a second one buys nothing but a second place to look.


The ordinary word in a compound name is translated

Undated · settled

Decision: small_meem, three_dots, rounded_zero — not meem_saghirah, thalath_nuqat, sifr_mustadir.

Why: saghirah adds nothing to small. §3 gives a general concept an English name; a compound is no exception.

Evidence: the source registry itself cites them in English — standard!dot, standard!two-dots, standard!three-dots.

The boundary: a technical word stays transliterated however ordinary it looks; sakinah and lazim are terms. The ordinary words are listed in general_words.tsv.


A concept no project needs does not enter the dictionary

2026-09-06 · settled

Decision: a concept enters the dictionary only when a real project needs it, and the entry names that need in purpose. For tajwid the witness is the tajweed engine: what it names in its topics and categories enters, such as letter_relation with its two values mutamathilan and mutajanisan; what it does not name, such as points of articulation, letter attributes, kinds of error and causes of stopping, does not.

Why: §1 asks for the programmatic purpose before the name, and §30 does not adopt a concept until the need for it is clear. Need is shown by a project using the concept, not by a textbook mentioning it.

Alternative rejected: entering the whole science as drafts. An entry nobody uses is an entry nobody reviews, and it sits in the dictionary at the size of a used one.


Word order in a compound follows English

Undated · settled

Decision: a translated construct head moves to the end, a translated adjective moves in front.

Why: English word order is what a reader of the identifier expects — the adjective before its noun, the possessive after it.

Evidence: with the rule applied, the derivation produced the names that had already been written by hand:

عَلَامَة الوَقْف        → waqf_mark
عَلَامَة السَّجْدَة      → sajdah_mark
نَوْع عَلَامَة الوَقْف   → waqf_mark_type

Consequence: general_words.tsv carries a role column, so a numeral stays where it stands — three_dots, not dots_three.


The article is judged one pair at a time

2026-09-06 · settled

Decision: whether a word's al is kept is decided against the word immediately before it, wherever the term opened; a translated head does not take part:

الوَقْف الجَائِز مُسْتَوِي الطَّرَفَيْن  → waqf_jaiz_mustawi_al_tarafayn
عَلَامَة الوَقْف اللَّازِم            → waqf_lazim_mark

Why: judging each pair is what Arabic grammar does — a construct nested after an adjective keeps its article. Judging the whole term by its first word dropped that al.

Consequence: translit.py implements the rule, and check_conformance.py no longer carries a list of mismatches between the tool and the entries.

Alternative rejected: keeping the first-word rule and listing the exceptions. Every 3-word name with a nested construct would be an exception.


A one-letter preposition is its own part

2026-09-06 · settled

Decision: بِ and لِ written onto a noun are parts of the name, and the noun keeps its article:

تَفْسِير بِالرَّأْي         → tafsir_bi_al_ray
المَدّ العَارِض لِلسُّكُون  → madd_arid_li_al_sukun

Why: the noun after a preposition opens a phrase of its own; it is never an adjective of what precedes, so the pairwise rule would wrongly drop its al. The kasrah on the preposition is what tells بِالرَّأْي apart from a word that happens to begin with ب.


Connectives are dropped from the code, not from the Arabic

2026-09-06 · settled · supersedes the shortened Arabic names of the waqf values

Decision: مَعَ, كَوْن, بِحَيْثُ and جَوَازًا are listed in connectives.tsv and dropped by the derivation. The waqf values keep their full Arabic names: الوَقْف الجَائِز مَعَ كَوْنِ الوَصْل أَوْلَى → waqf_jaiz_wasl_awla.

Why: §14 had stated that connectives are dropped, but nothing implemented it; the entries passed the derivation check only because their arabic.vocalized had been shortened to the words that survive. That is editing the Arabic to reach a code name, which §9 forbids. The rule is now in the function, and the names are whole again.

The boundary: a connective is a word that relates two parts and names nothing. أَوْلَى is not a connective; it is what distinguishes the value.


division_mark, not hizb_mark

Undated · settled

Decision: the division mark ۞ (U+06DE) is division_mark.

Why: the mark shows the start of a juz, a hizb, and their halves and quarters, so hizb_mark names one of 4. The Unicode name ARABIC START OF RUB EL HIZB has the same fault.

Consequence: arabic.vocalized is not edited to reach a preferred code name. The source's name is kept in dabt, and changing the concept's name is accepted only on Arabic grounds.


A mark's parent is its family

Undated · settled

Decision: harakah, tanwin, ijam, orthographic_mark and qiraah_mark are parents; mushaf_mark stays the parent of what has no family.

Why: every mark hung off mushaf_mark while mark_family carried the real grouping. The entry held two taxonomies that disagreed, and one parent over every mark in the registry says nothing.

Consequence: mark_family stays. It is the source registry's grouping, kept because it reports what the source says, while parent is the standard's taxonomy. The two differ in name where the registry's word differs from ours (imlaiyyah, alamat_qiraah).


Waqf marks are values, not marks

Undated · settled

Decision: waqf_lazim and its siblings are kind: classification_value with parent: waqf_mark_type, and they carry symbol, unicode and mark_family because they are drawn.

Why: waqf_mark_type was a classification with no values, and §27's own example gives waqf_lazim exactly this shape. The data contradicted the standard's own example.

The boundary: these 6 are the only non-marks that carry the drawing fields, and check_conformance.py refuses the fields anywhere else.


waqf_ruling and waqf_mark_type are two classifications

2026-09-06 · settled

Decision: waqf_ruling (tamm, kafi, hasan, qabih) classifies the place; waqf_mark_type (lazim, mamnu, the jaiz kinds, muanaqah) classifies what a drawn mark points to. Both are entries, and §13 and §17 name them side by side.

Why: the two had been treated as one "waqf type" in the standard's examples, with English labels that matched neither. A place with no mark still has a ruling, and a mark's type is read from the mushaf, not inferred from the grammar, so a model needs both.


The difference between parent and part_of

2026-09-06 · settled

Decision: parent says what a thing is a kind of. What a thing is inside — a rubu al-hizb in a hizb, a mushaf edition in a mushaf — is part_of, a new optional field.

Why: 3 entries had used parent for containment, so a reader of the taxonomy found a rubu al-hizb listed as a kind of hizb. One field with two meanings cannot be checked; two fields can.


Duplicated concepts are merged

Undated · settled

Decision: one entry each for sajdah_mark and division_mark.

Why: alamat_mawdi_al_sajdah and sajdah_mark defined the same thing, as did alamat_al_tahzib and division_mark.

Consequence: the former name is recorded in deprecated on the surviving entry with a note, and still resolves through aliases.json, so a project that adopted it is not stranded (§20).


A codepoint is not a mark's identity

Undated · settled

Decision: a codepoint is not used as the identifier of a mark.

Why: one character serves two marks, and one mark has more than one character:

ۜ  U+06DC   ARABIC SMALL HIGH SEEN   →  saktah_mark  or  seen_al_qiraah
sukun    ْ U+0652  and  ۡ U+06E1

The derivation is not reversible, by design

Undated · settled

Decision: ص and س are both s; ض and د are both d.

Why: the aim is a stable identifier, not an accurate pronunciation. Precise transliteration belongs in names.transliteration.


taa and haa name two letters each

Undated · open

Question: ت and ط both give taa, and ح and ه both give haa, because the derivation merges emphatic and plain letters. Neither name is used by any entry.

Status: open. It is decided when an entry needs one of them. build_aliases.py fails if two concepts ever claim one of these names, so the clash cannot arrive unnoticed.


The plural is the code plus s, whatever the code

2026-09-06 · settled

Decision: the s is added to the whole code name, a construct included:

juz              → juzs
hizb             → hizbs
sajdah           → sajdahs             not mawadi_al_sajdah
muqatta_letter   → muqatta_letters

Why: the plural is a collection name for code, not an English word for a reader. Pluralising the head of a construct would need Arabic morphology in the function, and pluralising the English gloss would need a gloss. The one rule a reader can predict is + s.

Alternative rejected: irregular plurals for the awkward cases. Every exception is a lookup, and the collection name is the one name a developer types without looking.


A ta marbutah in a construct is t

Undated · settled

Decision: hamzat_al_wasl, sajdat_al_tilawah — not hamzah_al_wasl.

Why: the ta marbutah is pronounced t when the word is bound to the next, and the code follows the sound as it does for letter names. The h form is common in English writing and is recorded in alternative_spellings.


al- is never assimilated

Undated · settled

Decision: one form of the article, whatever letter follows it:

al-Shams            not ash-Shams
sajdat_al_tilawah   not sajdat_at_tilawah

Why: assimilation to a sun letter is a rule of pronunciation, and the code spelling is an identifier, not a pronunciation. One form of the article means the article can be found and removed by a program; 14 forms cannot.


The values of origin and tier

Undated · settled

Decision: origin is quranic, borrowed or standard; tier is core or extended.

Why: origin decides whether the Arabic name is required and whether the code is derived — a borrowed term such as glyph has no Arabic to derive from, and a standard concept such as ayah_timing has no Arabic name at all. tier answers a different question, what applications actually store, and mixing it into origin would make a rarely stored Quranic term look borrowed.

Alternative rejected: a single type field. It would answer neither question cleanly.


mushaf_marks is merged into dabt

2026-09-06 · settled · supersedes the 20-domain list

Decision: the category mushaf_marks is removed; every mark is dabt.

Why: the domain glossed "the marks of the mushaf" held one entry, mushaf_mark, while the marks themselves were all in dabt. §25 says a domain is not added before there are concepts that belong to it, and this one never had them.


The dictionary is generated from the entries

Undated · settled

Decision: the dictionary page is generated from concepts/*.yml.

Why: it had been written by hand, duplicating the source of truth, which is what §29 forbids.


waqf_al_muanaqah, not taanuq_al_waqf

Undated · settled

Decision: the muanaqah mark ۛ (U+06DB) is waqf_al_muanaqah — وَقْف المُعَانَقَة.

Why: dabt_marks.tsv names the mark وَقْف المُعَانَقَة and records تَعَانُق الوَقْف only as what the mushaf introduction calls it. The registry's name is the concept's name, and it puts the value beside its siblings — waqf_lazim, waqf_mamnu and the 3 waqf_jaiz_* values — instead of leaving it the one that did not lead with waqf.

The boundary: the name taken is the one the registry already gives, not one edited to reach a form we prefer. The al stays, because the first word is indefinite, so the term is a construct and its article is part of the name — the rubu_al_hizb rule.

Alternatives rejected: waqf_muanaqah, which drops the al by treating the term as two words that each lose their own article — that patches the derivation to reach a preferred string. And paired_waqf and embracing_waqf: §3 keeps a scholarly term, and muanaqah is a term of waqf exactly as lazim is — neither is in general_words.tsv. division_mark is not a precedent for them: it went to English because the Arabic name was wrong about the concept, and this one is not.

Consequence: taanuq_al_waqf, muanaqah, muraqabah and waqf_al_muraqabah all resolve through aliases.json.


The tanwin marks are named by their harakah

Undated · settled

Decision: tanwin_al_fath, tanwin_al_kasr, tanwin_al_damm — تَنْوِين الفَتْح, تَنْوِين الكَسْر, تَنْوِين الضَّمّ.

Why: measurement. The case names are effectively unused in Latin script, and lose in Arabic too (cache keys tanwin fath | tanwin al-nasb, tanwin kasr | tanwin al-jarr, tanwin damm | tanwin al-rafa, تنوين الفتح | تنوين النصب, تنوين الكسر | تنوين الجر; the Arabic damm pair was rate-limited and is uncounted):

tanwin fath   618  ×  tanwin al-nasb    0
tanwin kasr   551  ×  tanwin al-jarr    0
tanwin damm   492  ×  tanwin al-rafa    0

تنوين الفتح   217  ×  تنوين النصب     184
تنوين الكسر   161  ×  تنوين الجر       21

Evidence: its own file ids are تنوين فتح, تنوين كسر, تنوين ضم. The case names it writes in the dabt column stay in dabtتَنْوِين الخَفْض — الكَسْرَتَان.

Alternative rejected: naming the triad by case (nasb, jarr, rafa). Usage decides, and usage went the other way.

Consequence: tanwin_al_nasb, tanwin_al_jarr, tanwin_al_khafd, tanwin_al_rafa, fathatan, kasratan, dammatan, and the registry's tanwin_fath, tanwin_kasr, tanwin_damm all resolve.


The standard names the Quran's sciences and stops there

Undated · settled

Decision: abrogation, word_meanings, mutashabihat and sajdah are entries. book, author, category, tag, language, attachment, radio, fatwa and topic are not.

Why: a survey of a working encyclopedia (surveys/quranpedia-net.md) found 77 domain tables, of which 10 resolved to an entry. The tempting reading was that the dictionary is 87% short. It is not: most of what was missing is either ordinary software furniture that needs no Quranic standard, or scholarship that is not about the Quran.

The boundary: a concept is in scope when it cannot be defined without referring to the Quran or the mushaf. sajdah cannot; radio can, and a stream of Quran audio is a stream. fatwa sits outside for the same reason a hadith does — real, Islamic, and not a concept of the Quranic text.

Alternative rejected: naming everything an application stores. It would put the standard in the business of general web modelling, where it has no authority and adds no precision.

Consequence: a project still needs names for its books and its tags. The standard does not give them, and says so, and §30 says how a project extends the dictionary locally.


Ayah numbering: the code is the school's name, the entry id carries the parent's

Undated · settled · revised 2026-09-07

Decision: the values of ayah_numbering_system are kufi, basri, dimashqi, makki, madani_first, madani_last. Their entries have the ids ayah_numbering_kufi and so on. The registry ayah_numbering.tsv is keyed by the codes.

Why: the code is short, the id is long, and neither is derived from the Arabic.

The short code: a value's name is unique within its classification, not across the dictionary. A column holds the values of one classification and never two, so makki the numbering and makki the revelation class are never candidates for the same slot — the same reason a registry is its own namespace (§13) and let hamzah the reciter and hamzah the mark keep one name. Prefixing the value with its parent's name says nothing the column does not already say. Every dataset that actually exists — quranpedia's qiraat-ayah-map, quran-text — stores kufi and madani-first, and they were right.

The long id: two entries cannot share a file, an anchor or a target for related, and makki is the revelation value's id. So the id of a value that shares its name is the parent's name plus the code, and the 6 numbering entries all take that shape rather than 5 short and one long. The alias index maps a shared name to both concepts and <parent>:<name> to each, so a caller who knows the column resolves without ambiguity, and build_aliases.py still refuses any other shared name.

Not derived: العَدّ الكُوفِيّ gives add_kufi, and add is an English verb — the same fault that made us write noon rather than nun. The code is the name of the school.

The boundary: §4 — inside a compound the technical word is transliterated and the ordinary word is translated. madani is the technical word; first and last are ordinary. madani_awwal and madani_akhir stay as recorded spellings.

Consequence: the first form was ayah_numbering_kufi as both id and code, to keep one flat namespace; the second kept that id and moved the short code into the registry alone, with a concept column pointing back. Both were the same fact written twice. This revision makes the value's own name the short one and leaves the flat namespace to the concepts that need it.


ayah_mark, with the dabt name kept in dabt

Undated · settled

Decision: code: ayah_mark, names.arabic.vocalized: عَلَامَة الآيَة, and the dabt name عَلَامَة رَأْس الآيَة recorded in dabt.

Why: the derivation of the fuller name gives ras_al_ayah_mark. ras is an ordinary word carrying no term, and it describes where the mark sits rather than what it marks. Every other mark in the dictionary is named after what it marks — waqf_mark, sajdah_mark, division_mark.

The boundary: the rule is that arabic.vocalized changes only on Arabic grounds. عَلَامَة الآيَة is the mark of the ayah's boundary; رَأْس describes the position, and the source's own name is kept in dabt, exactly as sajdah_mark keeps عَلَامَة مَوْضِع السَّجْدَة.

Consequence: it is the most common mark in the mushaf and it is not in dabt_marks.tsv, so the generation that produced the mushaf's marks from that registry produced everything except this one.


Abrogation is one entry, abrogation

Undated · settled

Decision: one entry for abrogation, abrogation, and none for the abrogating or the abrogated text.

Why: the familiar title is النَّاسِخ وَالمَنْسُوخ, but the science is النَّسْخ, and الناسخ والمنسوخ are the two sides of one relation, not two concepts. Abrogation has a plain English name, so §3 gives it that name.

Consequence: nasikh_mansukh, nasikh_wa_mansukh and nasekh_mansokh all resolve through aliases.json.


Token, morpheme and font get entries

Undated · settled

Decision: entries for token, morpheme, stem, part_of_speech and font.

Why: §18 tells the reader to keep word, token and morpheme apart, and lists font under presentation. None of the 4 had an entry, so the standard was naming a distinction it declined to define, and morphology.purpose already used the word token in its own text.

The boundary: a token is what a splitting method produces, and a word is what a reader recognises. Changing the method changes the token count and not the word count. segment, the name the Quranic corpora use, resolves to morpheme.


The parts of speech take their English names

2026-09-06 · settled

Decision: the 3 parts of speech are noun, verb and particle.

Why: a part of speech is a general concept of grammar with a plain English name that every morphology corpus uses, and its parent part_of_speech is already English. §3 gives a general concept its English name. Transliterating the Arabic would also have lengthened the particle's name, because harf alone is taken by the written letter (letter); particle has no such problem.

The boundary: the Quranic corpora tag with dozens of labels — N, PN, V, CONJ, NEG. Those are data that sit under these 3, not entries. Naming 40 tags would put the standard in the business of maintaining a tagset.

Consequence: part_of_speech had been added as a classification with no values, which is the fault §13 names, and the same fault that had left ayah_numbering_system empty. The check now refuses it.


The standard's own rules are checked, not remembered

Undated · settled

Decision: tools/check_conformance.py runs the rules the prose states — that a quranic code is the derivation of its Arabic name, that a classification has values, that a plural is the code plus s, that a related, parent or part_of link resolves, that a gloss is not a spelling, that every cited source exists, that the drawing fields sit only on marks and the 6 waqf values.

Why: validate.py checks the shape of an entry against schema.json, and the schema cannot express any of the above. Everything in this list was found the first time the check was run, on entries that had passed validation for months: a plural taken from the English gloss, two related links pointing at concepts that do not exist, and a gloss doubling as an alternative spelling.

The boundary: DOCUMENTED holds departures this record argues for, such as the ayah numbering values. A mismatch caused by the function is a defect to fix in the function, not a list to keep; the one such list the check once had is gone (see "The article is judged one pair at a time").


A closed set of members goes to a registry, not to an entry each

Undated · settled

Decision: the 10 qiraat, the 20 riwayahs, the 114 surahs and the 15 places of prostration live in tab-separated files under standards/terminology/registries/. The concept keeps its entry and names its registry; the members get rows.

Why: an entry answers "what is this?". Hafs has no answer to that question beyond pointing at him. Writing 49 entries for the qiraat would have tripled the dictionary with files whose definition and purpose fields could only restate the name, and it would have buried the 20 entries that do define something under 163 that do not.

Alternative rejected: an entry per member, with kind: instance. It puts individuals and concepts in one list and makes "is this a concept?" a judgement call at every new name.

The boundary: if a member needs a definition, a purpose and boundaries, it is a concept. If everything true of it is its name, its place in the set and where it is attested, it is a member.

Evidence: the 28 letter names went to data/letter_names.tsv on this reasoning before the word registry was used for it.

Consequence: Every row is checked by tools/check_registries.py, cites a source, and is indexed.


The rules of tajwid are a registry, not entries

2026-09-06 · settled

Decision: the rules — izhar, idgham, iqlab, ikhfa, the kinds of madd and the rest — are rows in registries/tajwid_rules.tsv; tajwid_ruling names the registry. The concepts a rule rests on (noon_sakinah, tanwin, maddah) stay entries.

Why: the standard had 5 entries in tajwid and a rules file (data/tajweed_engine_rules.json) nobody cited, while every tajwid engine ships its own rule ids. A rule has a name, a trigger and a source and nothing else to say; that is the registry test. And a rule is not the place where it applies: an occurrence is a span of text tagged with the rule's code, and belongs to the project's data, not to the dictionary.

Alternative rejected: an entry per rule. There are dozens, their definitions would restate their names, and the engines would still need a table.


rasm_imlai keeps the name every codebase uses

2026-09-06 · settled

Decision: rasm_imlai — الرَّسْم الإِمْلَائِيّ — although general_words.tsv translates إملائي for the mark family (orthographic_mark).

Why: the type of rasm is called imlai in every codebase that has one, and orthographic_rasm is a name nobody writes. The table's with_head role says when the word is translated: only beside a head word such as عَلَامَة. Beside رَسْم it is transliterated, so the derivation gives rasm_imlai and the entry is not an exception.

Consequence: imlaei, imlai, simple and text_simple resolve.


ayah_count is a standard concept named after its registry

2026-09-06 · settled

Decision: ayah_count, origin: standard, Arabic عَدَد الآيَات, registry ayah_counts.

Why: the derivation of the Arabic gives adad_al_ayat, which names the number in Arabic and nothing in code. The concept is a modelling one — a count per surah per numbering system — so it takes the English name its registry already has, and sits in the ayah_numbering_* family it belongs to.


A tariq registry at the level applications store

2026-09-06 · settled · supersedes "the same rule refused a tariq registry"

Decision: registries/tariq.tsv has 4 rows — shatibiyyah, tayyibat_al_nashr, durrah, taysir — the routes a recording or a mushaf edition actually declares.

Why: the ~980 routes of al-Nashr cannot be verified row by row from the sources in this repository, so the registry was refused. But applications store the route at the level of the transmission work, and those 4 are attested and enumerable. A registry that stops where the evidence stops is honest; one that enumerates 980 unverified rows is not.

Open: the full enumeration of the tariqs, when a source that a tool can reconcile is found.


A person's name is not derived

Undated · settled

Decision: hafs, warsh, qalun, ibn_dhakwan — written as they are commonly written, not put through §4–§8.

Why: the derivation is there because a term is a word carrying a meaning, and working from the vocalised Arabic keeps that meaning attached to the identifier. A name has no such meaning, so deriving it only produces a spelling nobody writes.

Evidence: أَبُو عَمْرو derives to abu_amrw, because the waw of عمرو is orthographic and silent; ابْن cannot be derived at all, because its initial alif is hamzat al-wasl and carries no vowel to read. "Commonly written" means the scholarly English form with its diacritics dropped, and the registry carries both; where that form disagrees with a rule the standard already states, the rule wins — shubah, not shuba, because §5 governs a ta marbutah.

Alternatives rejected: forcing names through established_spellings.tsv — the derivation was never meant for names, and patching it for them is worse than exempting them.

The boundary: people, and nothing else. A surah name is a word, so it is derived, and check_registries.py re-derives all 114 on every run.

Alternatives rejected as well: GitHub phrase counts. They decide between tajwid and tajweed because both are terms; on names they return noise (susi matched 5,185,536 unrelated tokens, and qumbul beat qunbul). The counts are not in the cache and are not evidence.


A member may share a name with a concept

Undated · settled

Decision: hamzah is the mark and also the reciter; tariq is a step in a chain of transmission and also a surah. Both keep the name. Member names are indexed by kind in registry_aliases.json, and the bare name in aliases.json goes on resolving to the concept.

Why: the two live in different domains in the sense of §25 — one hamzah is dabt, the other qiraat — so nothing can reach for both at once. A name only has to be unique where it could actually be confused.

Alternative rejected: qualifying the newcomer, the way ayah_numbering_makki was qualified when makki was already taken. That precedent holds for a value whose name is built from its parent's. It does not extend to bending a person's name, or a surah's, to dodge a collision that no caller can experience.

The boundary: a column does not hold "something from the qiraat domain", it holds a riwayah, and the caller always knows which.

Consequence: check_registries.py prints all 3 every run, so the exception stays a known fact rather than an accident.


Ayah counts are read from al-Bayan and reconciled

Undated · settled

Decision: registries/ayah_counts.tsv holds the count of every surah in all 6 numbering systems, generated by tools/extract_ayah_counts.py from al-Dani's al-Bayan. It is never edited by hand.

Why: the 6 systems disagree about 114 numbers, and a table with no source cannot be argued with. Al-Bayan states each surah's count once and then gives only the part that differs — "285 in the two Madinans, the Makkan and the Damascene, and six in the Kufan, and seven in the Basran" — so the numbers exist in the book in a form a tool can read.

Evidence: the table reconciles with its source in two ways. All 114 Kufi counts match the printed mushaf surah by surah, which tests the reading of every section rather than the arithmetic; and Kufi sums to 6,236 and Basri to 6,204, the totals al-Dani himself states.

Consequence: the reconciliation fixed the following, each now a rule in the extractor:

  • آيتان is the numeral two fused with its noun, and is counted.
  • وآية conjoined is the numeral one — "fifty and an ayah" is 51 — while a bare آية after a number is the counted noun.
  • A later part replaces the trailing part it covers: 110 and "nine" is 109; but 180 and "two" is 182, because a round ten from 20 upward takes a unit beside it while a bare 10 is replaced.
  • A two-word school name is one token.
  • An aside inside a run of school names — "with a variance reported from him" — does not break the run.

Totals alone would have hidden most of these; the surah-by-surah check found them.

The boundary: 4 columns come to one more than the total al-Dani states. Two places in the book give a count for the reading of Abu Jafar specifically, and whether "the count of Abu Jafar" is the Madani Awwal system or an authority beside it is a question about the source. A tool should not decide it, so the run prints the discrepancy every time.


verified says what was checked; no is allowed

Undated · settled

Decision: a registry row says what has actually been checked. The sajdah rows carry verified: surah, which means the surah is attested in a source and the ayah number is not.

Why: the alternative is a citation that gestures at a page which does not in fact contain the claim. That is worse than an honest blank, because it cannot be distinguished from a real one later.

Consequence: al-Itqan names all 14 sajdah surahs and gives the count as 14, which was checked against the book. 15 places in 14 surahs is not a contradiction — al-Hajj carries two. Every ayah number is checked against the verified Kufi count for its surah, so a reference outside its own surah cannot pass, and two of them land on the last ayah of the surah, which the counts confirm. What no source in this repository does is enumerate the 15 numbers, and the file says so.

Evidence: the same rule kept the tariq registry out for a time. The ayah counts could be proved because they reconcile to a total; the tariqs have no such total. A scan of al-Nashr's isnad section returns 224 distinct names at every depth of the tree with no reliable way to attach each to its parent, and an unverifiable table looks exactly like a verified one. registries/tariq.tsv now exists with verified set honestly per row, and check_registries.py reports what remains unverified on every run.


sajdah is one concept: the place and the prostration made at it

2026-09-07 · settled

Decision: one entry, sajdah, plural sajdahs, with the registry sajdah.tsv as its members. sajdah_place and sujud_al_tilawah are merged into it and stay as recorded spellings. sajdah_mark stays separate: it is the sign, and §18 still applies to it.

Why: the place and the act are one thing in every use software has for them. A dataset lists "the 15 sajdahs", counts them, locates them and attaches the rulings of prostration to them; nothing stores a prostration that is not at a place, and nothing stores a place that is not prostrated at. Two entries for one thing is the fault §18 guards against in the other direction. The same reasoning leaves ruku one entry.

Alternatives rejected: 3 entries — the mark, the place and the act — on the argument that collapsing them attaches a page number to an act of worship. And keeping sujud_al_tilawah for the rulings: rulings attach to the sajdah, and the second entry would carry no field the first does not.

The boundary: السَّجْدَة derives to sajdah, which is what the sources and the readers call it. sujud_al_tilawah, the act as the fiqh books title it, and mawdi_al_sajdah, the place as al-Itqan lists it, resolve to the entry.

Source: quran-ws/docs, at d1d6be33be9d. Anything not marked adopted is a proposal under discussion, not yet something to build on.