ISNAD Scientific Platform

Documentation Center
V1 · Référence officielle

SPEC

RUWAT-FR-TRANSLIT-V1

6 min de lectureMis à jour le 29 أكتوبر 2026
Sur cette page

Norme éditoriale et technique canonique pour les noms français/latins des narrateurs RUWAT. Publiée dans public.transliteration_standards (code RUWAT-FR-TRANSLIT-V1, version 1.0.0) par la migration supabase/migrations/20260824180000_add_transliteration_standard.sql.

0. Finalité#

texte français approximatif (Abdallah ibn Omar, Abdullah ibn Umar...)
   -> retrouver عبد الله بن عمر
   -> toujours AFFICHER une seule forme canonique : ʿAbd Allāh ibn ʿUmar

AFFICHAGE CANONIQUE STRICT ≠ RECHERCHE TOLÉRANTE. Les variantes populaires (transliteration_aliases) servent uniquement au retrieval ; elles ne déterminent jamais la forme éditoriale publiée (transliteration_lexicon.canonical_latin).

Translittération ≠ identité. Une translittération est du texte, jamais une preuve d'identité de personne. Rien dans ce référentiel ne crée, ne fusionne ni ne valide de narrator_crosswalk/décision de réconciliation. external_narrator ≠ narrator RUWAT.

1. Alphabet et caractères spéciaux#

ArabeLatinNote
عʿayn — ne jamais confondre avec l'apostrophe ASCII '
ءʾhamza, seulement quand représenté (voir § Hamza)
حḥ
صṣ
ضḍ
طṭ
ظẓ
ا/ی longuesā / ī / ūvoyelles longues
خkh
غgh
شsh
ثth
ذdh
قq
جj

Les caractères ʿ ʾ ḥ ṣ ḍ ṭ ẓ ā ī ū appartiennent à la forme canonique d'affichage. Ils ne sont jamais requis pour retrouver un narrateur en recherche (voir § Normalisation de recherche).

2. Hamza#

Ne pas ajouter mécaniquement ʾ devant chaque alif portant hamza :

  • أحمد → Aḥmad (pas de ʾ)
  • إبراهيم → Ibrāhīm (pas de ʾ)
  • أنس → Anas (pas de ʾ)
  • mais عائشة → ʿĀʾisha (hamza médiane conservée)

Règle : ʾ n'est représenté que lorsqu'il est médian ou final et phonétiquement audible dans la forme savante attendue ; jamais en position initiale d'un ism/kunya courant.

3. Article al-#

Convention unique, sans assimilation solaire dans la forme canonique :

  • الزهري → al-Zuhrī (jamais az-Zuhrī)
  • الشيباني → al-Shaybānī (jamais ash-Shaybānī)

L'assimilation solaire peut exister comme alias de recherche (transliteration_aliases), jamais comme forme publiée.

4. Ibn / Bint#

  • بن / ابن → ibn
  • بنت → bint
  • عبد الله بن عمر → ʿAbd Allāh ibn ʿUmar
  • En tête de nom (appellation indépendante) : ابن شهاب → Ibn Shihāb (capitale, casse éditoriale — voir § Composition).

5. Kunya#

  • أبو → Abū
  • أم → Umm
  • Les formes grammaticales أبو/أبي/أبا sont normalisées vers Abū en forme canonique française, mais la forme arabe SOURCE (arabic_form) est toujours conservée telle qu'attestée — jamais réécrite.

6. Noms composés — longest match first#

Le lexique comprend des expressions, pas seulement des mots isolés :

  • عبد الله → ʿAbd Allāh (pas عبد + الله séparément)
  • عبد الرحمن → ʿAbd al-Raḥmān
  • أبو هريرة → Abū Hurayra

La composition (composeCanonicalLatin) tente d'abord les fenêtres de mots les plus longues (jusqu'à 4 tokens) avant de retomber sur un mot seul. Exemple entièrement travaillé (golden test) :

عبد الله بن عمر بن الخطاب العدوي القرشي
-> [عبد الله] + [بن] + [عمر] + [بن] + [الخطاب] + [العدوي] + [القرشي]
-> ʿAbd Allāh ibn ʿUmar ibn al-Khaṭṭāb al-ʿAdawī al-Qurashī

Simplification assumée et documentée : la casse position-dépendante (ibn/al- minuscule en milieu de nom, Ibn/Al- capitale en tête) n'est modélisée que par une capitalisation de la première lettre du résultat composé. Un futur raffinement pourrait modéliser la casse par position dans transliteration_lexicon (dette documentée, non bloquante — aucun cas du dry-run initial n'a produit de résultat structurellement invalide de ce fait : proposed_structural_valid = false pour 0/8862 narrateurs).

7. Types du lexique (transliteration_lexicon.entry_type)#

PERSONAL_NAME, COMPOUND_NAME, KUNYA, NASAB_PARTICLE, NISBA, LAQAB, TRIBAL_NAME, TOPONYM, PARTICLE, FULL_NAME_OVERRIDE, OTHER. Abū, ibn, al-Baṣrī, Muḥammad ne sont jamais traités comme des objets linguistiques équivalents — chacun a son propre type.

8. Statuts de revue (review_status)#

AUTO_PROPOSED → UNDER_REVIEW → APPROVED / OVERRIDDEN / REJECTED. Seuls APPROVED et OVERRIDDEN font autorité canonique publiée (vue public.public_transliteration_lexicon). Transition exclusivement via set_transliteration_lexicon_review_status() (SECURITY DEFINER, admin uniquement).

9. Normalisation nominale (parité SQL / TS / Node)#

Deux implémentations indépendantes doivent produire le même résultat pour un même texte d'entrée :

  • SQL : public.normalize_ar_query() (supabase/entity_resolution_v2.sql)
  • TypeScript/Node : normalizeNominalArabic() (src/domain/narrator-identity/nominalTransliteration.ts), importée telle quelle par les scripts Node (scripts/lib/contextual-resolver-core.mjs, scripts/audit/contextual-resolver-readonly.mjs) — une seule source TS/Node, pas une troisième réimplémentation.

Parité vérifiée par 21 fixtures partagées (scripts/lib/transliteration-golden-fixtures.mjs), testées des deux côtés : npm run test:transliteration-golden (TS/Node) et npm run test:transliteration-golden:sql (SQL). 21/21 identiques.

Dette découverte et documentée pendant cette parité (non corrigée dans cette étape — porte sur normalize_ar_query() en production, hors périmètre "harmoniser uniquement la normalisation nominale") :

  1. Le motif honorifique رضي الله عنه(ما|م)? ne couvre pas le suffixe féminin عنها ("elle") : normalize("عائشة رضي الله عنها") laisse un "ا" résiduel ("عايشه ا" au lieu de "عايشه").
  2. La virgule arabe ، (U+060C) n'est pas dans la classe de ponctuation remplacée par espace (seule la ponctuation latine + guillemets l'est).

Ces deux gaps existent identiquement côté SQL et TS (vérifié en direct sur la base liée) — ce n'est donc pas une divergence de parité, mais une limite connue de la règle elle-même, à traiter dans un futur correctif SQL dédié (avec ses propres tests de non-régression, car normalize_ar_query est utilisée en production par le retrieval narrateurs).

Portée volontairement limitée : cette étape harmonise la normalisation nominale (noms propres). La normalisation générale du texte de hadith (matn) reste un chantier séparé, futur (§ 12).

10. Validation structurelle#

validateNameStructure() (TS, src/domain/narrator-identity/nominalTransliteration.ts) et public.validate_name_structure() (SQL, même migration) — parité vérifiée sur 18 fixtures PASS/FAIL (18/18 identiques).

Codes d'erreur détectés : UNBALANCED_PARENTHESES/BRACKETS/BRACES, UNBALANCED_QUOTES, EMPTY_PARENTHESES, CONTROL_CHARACTER, UNICODE_REPLACEMENT_CHAR, HTML_FRAGMENT, MARKDOWN_FRAGMENT, LITERAL_UNDEFINED, LITERAL_NULL, LITERAL_OBJECT_OBJECT, REPEATED_PUNCTUATION, MULTIPLE_SPACES, TRAILING_DASH/SLASH/APOSTROPHE, INCOMPLETE_TRAILING_COMPONENT, INCOMPLETE_LEADING_COMPONENT.

CRITICAL INVARIANT : aucun nom canonique généré ne peut atteindre le statut FULLY_LEXICON_RESOLVED (candidat publiable) s'il échoue la validation structurelle — il est automatiquement rétrogradé à STRUCTURAL_ERROR (voir scripts/validation/transliteration-dry-run.mjs::auditNarrator). Sur le dry-run initial (8862 narrateurs), 0 proposition générée n'a échoué la validation structurelle.

11. Architecture retenue#

texte arabe (narrators.full_name_ar)
   -> normalizeNominalArabic()          [TS, src/domain/narrator-identity/nominalTransliteration.ts]
   -> composeCanonicalLatin()           [TS, longest-match-first sur le lexique]
   -> validateNameStructure()           [TS, sur la proposition ET sur la forme actuelle]
   -> scripts/validation/transliteration-dry-run.mjs
   -> start_transliteration_dry_run() + append_transliteration_dry_run_proposals()
      [SQL, SECURITY DEFINER — seule porte d'écriture]
   -> transliteration_dry_run_runs / transliteration_narrator_proposals

Choix assumé : la génération du dry-run (composition + validation) tourne côté Node, réutilisant directement les mêmes fonctions TS que celles testées par les golden tests — pas une réimplémentation PL/pgSQL parallèle. Le lexique et son exposition publique restent en SQL (RLS, vue public_transliteration_lexicon), cohérent avec le reste de l'architecture RUWAT où le retrieval vit en SQL. validate_name_structure() existe aussi en SQL (parité vérifiée) pour une future validation live côté UI sans aller-retour Node — mais la génération de masse reste Node pour éviter une troisième implémentation de composeCanonicalLatin à maintenir en PL/pgSQL.

Écriture par lots de 500 narrateurs par appel RPC (append_transliteration_dry_run_proposals) : un appel unique avec les 8862 lignes dépasse la limite de taille de requête du canal supabase db query --linked (HTTP 413, constaté en conditions réelles) — voir 20260824181000_batch_transliteration_dry_run_write.sql.

12. Hors périmètre de cette étape#

  • Construction du moteur de recherche (search_hadiths(), tsvector sur hadiths.text_ar/fr, embeddings, retrieval sémantique français→arabe générique).
  • Bascule globale des noms français publiés (narrators.full_name_fr) vers les propositions du dry-run — reste un dry-run tant qu'une validation humaine explicite n'a pas eu lieu.
  • Fusion des trois modèles de décomposition d'identité qui se chevauchent (narrators colonnes brutes / narrator_name_forms / narrator_identities
    • tables satellites) — dette documentée dans le rapport d'audit précédent, non retouchée ici : transliteration_lexicon est un concept différent (lexique linguistique réutilisable, pas une représentation de personne).

13. Versioning#

Toute génération de canon connaît son standard d'origine (transliteration_lexicon.standard_id → transliteration_standards.code). Une future révision éditoriale majeure devient RUWAT-FR-TRANSLIT-V2, une nouvelle ligne dans transliteration_standards, sans effacer l'historique de V1 (aucune suppression, status passe à DEPRECATED).