Architecture
ISNAD Scientific Platform — Audit de l’ingestion et architecture cible
Sur cette page
Date des observations : 3 novembre 2026
Référentiel inspecté : oboutj7/isnad-app-fr, branche master, commit 8a2503a
Périmètre : audit et conception uniquement ; aucune migration, aucun import, aucune écriture de production.
Statut des énoncés#
- OBSERVÉ : constat issu du code, du schéma ou d’une requête en lecture seule sur la base rattachée.
- TESTÉ : comportement démontré par une commande exécutée pendant l’audit, généralement sur fixture ou base jetable.
- PROPOSÉ : architecture, estimation ou critère à valider ; ce n’est pas une capacité existante.
- NON VÉRIFIÉ : information inaccessible ou preuve insuffisante.
Le fichier audit-artifacts/live-db-2026-11-03.json est la trace brute des mesures de base. Il est produit par scripts/audit/audit-ingestion-live.mjs, dans une transaction PostgreSQL READ ONLY. Les comptes constituent une photographie, pas un résultat scientifique de qualité.
ISNAD ne part pas de zéro. Le dépôt contient déjà un corpus public, un référentiel transversal de narrateurs, des assertions et preuves, des projections de commentaires, des traductions versionnées et une publication humaine. Le problème central n’est donc pas l’absence de modèle scientifique, mais l’absence d’un orchestrateur unique et durable reliant les capacités existantes.
Les constats les plus importants sont :
- L’import OpenITI actuel est synchrone et monolithique. Une route HTTP acquit, segmente, écrit le staging et canonise dans une transaction, puis lance une extraction de domaine « best-effort » dont l’échec est absorbé.
src/app/api/admin/openiti/import/route.ts:14-42;src/server/openiti/import-runner.ts:51-54,112-138,273-310. - La classification et l’extraction OpenITI sont spécialisées. Le classifieur reconnaît surtout des titres et URI de rijāl ; les autres ouvrages restent
UNCLASSIFIED.src/server/openiti/prepare.ts:152-162. - Le moteur canonique générique existe mais n’est pas exposé en production.
DefaultKnowledgeAcquisitionEngine,ObservedAcquisitionRunneretHadithCorpusProjectorsont couverts par des tests, sans route applicative de production trouvée. Les bindings nécessaires sont vides dans la base observée. - Le corpus OpenITI n’alimente pas le corpus public générique. Les 15 126 hadiths publics ont
corpus_id = NULL, et chaque hadith possède exactement une chaîne dans l’état actuel. Cela ne démontre pas que les sources ne contiennent qu’une chaîne ; cela décrit uniquement la projection stockée. - La résolution des identités reste incomplète. Sur 47 206 crosswalks, 6 665 sont
matched, 3 195ambiguouset 37 346unresolved. Les 777 maillons publics sansnarrator_idsont un autre périmètre, à ne pas additionner aux crosswalks. - Les traductions et commentaires sont réels, mais leurs statuts doivent rester explicites. Les 2 772 traductions de notices comprennent 1 139
REVIEWEDet 1 633COMPLETE_UNREVIEWED. Les 18 274 versions de traduction de commentaires se répartissent également entre états machine et publiés ; une ligne publiée n’est pas une preuve de revue humaine. - Le contrôle qualité incrémental n’a pas démarré sur la base liée.
quality_engine_stateetquality_decisionssont vides. Les 32data_quality_snapshotsne prouvent pas l’exécution de ce moteur particulier. - L’atelier OCR/traduction possède une conception robuste mais non déployée ici. Le code gère leases, retries, budgets et fencing, mais aucun schéma
book_workshopn’existe dans la base inspectée.src/infrastructure/book-workshop/postgres/worker.ts:36-83,132-183,187-214.
Décision recommandée : conserver les modèles scientifiques et construire une couche d’orchestration par runs, étapes, artefacts et tâches persistantes. Ne pas créer un second corpus public, une table générique de personnes ni un nouveau silo de traduction.
A1. Méthode, accès et limites#
Éléments effectivement inspectés#
- dépôt local, historique Git, branches locales et liste distante ;
- routes, services, domaines, adaptateurs et scripts d’import ;
- migrations présentes dans
supabase/migrations; - schéma PostgreSQL réel dans
publicetopeniti; - comptes, statuts, couverture des chaînes, traductions, alignements et volumes ;
- suites de tests ciblées et vérification TypeScript.
Limites explicites#
- NON VÉRIFIÉ : l’historique distant
supabase_migrations.schema_migrationsest refusé par les privilèges disponibles. Il est donc impossible de certifier l’ordre d’application des migrations. - OBSERVÉ : aucun dossier
supabase/functionsni configuration de cron n’a été trouvé dans le dépôt. Cela ne prouve pas l’absence de planificateurs configurés hors du dépôt. - NON VÉRIFIÉ : aucun test de bout en bout n’a été réalisé contre l’application publique ou les routes d’administration déployées.
- NON VÉRIFIÉ : l’audit n’établit ni la licence effective des témoins OpenITI ni la justesse scientifique des contenus extraits.
- OBSERVÉ : GitHub expose 100 branches. Les branches locales
feat/openiti-commentary-importetchore/retire-idrap-fr-legacyn’ont pas de commit ou diff propre par rapport àmaster. Le contenu exclusif des 98 autres branches distantes n’a pas été audité exhaustivement. - Le dépôt contient des modifications utilisateur préexistantes. Elles ont été lues mais ni modifiées ni annulées.
A2. Architecture actuelle#
Interface admin OpenITI
└─ POST /api/admin/openiti/import (synchrone, maxDuration 300 s)
└─ runImport
├─ GitHub : URI → métadonnées → version → texte
├─ analyse mARkdown : entrées, pages, offsets, SHA-256
├─ staging openiti.stg_*
├─ fonction SQL openiti.canonicalize_import
└─ extraction de domaine hors transaction, best-effort
└─ pont narrateur exact-normalisé → external_narrators/crosswalk/assertions
Pipeline canonique générique, actuellement surtout testé
CorpusAdapter/SourceReader
→ DefaultKnowledgeAcquisitionEngine
→ HadithCorpusProjector / adaptateurs spécialisés
→ corpus public, rijāl ou commentaires
ObservedAcquisitionRunner → import_batches + dataset_acquisition_bindings
Services séparés
traductions de notices / commentaires / atelier OCR
publication éditoriale humaine / journaux / contrôles qualité
Références principales : src/server/openiti/import-runner.ts:1-10,273-320, supabase/migrations/20260905130000_openiti_auto_ingestion_support.sql:39, src/infrastructure/knowledge-acquisition/ObservedAcquisitionRunner.ts:1-32,99-193.
A3. Inventaire des quinze domaines demandés#
| Domaine | Constat observable | Tables, dépendances et limites | Réutilisation |
|---|---|---|---|
| 1. Dépôt et branches | master à 8a2503a, synchronisé avec origin/master ; 100 branches distantes | Pas d’inventaire fonctionnel exhaustif des branches distantes autres | Base de travail conservée ; modifications utilisateur protégées |
| 2. Application | Next.js, routes Node et consoles admin séparées | Import synchrone via src/app/api/admin/openiti/import/route.ts:5-42 | Authentification admin et pages réutilisables |
| 3. Migrations | Nombreuses migrations couvrant corpus, identités, traductions, commentaires et OpenITI | Historique d’application distant inaccessible | Conserver les contraintes et journaux ; aucune réécriture historique |
| 4. Schéma réel | Schémas public et openiti ; pas de book_workshop | Vues comprises dans l’inventaire des colonnes ; certaines anciennes tables supposées sont absentes | Le schéma réel prime sur les noms historiques du code |
| 5. Async et planification | Files et leases dans le code de l’atelier ; aucune Edge Function ou cron trouvée | Atelier non déployé ; processing_runs ne constitue pas une file générale | Reprendre les principes de lease, fencing et budgets |
| 6. OpenITI | Acquisition GitHub, version choisie, texte brut, empreintes, offsets, staging et canonisation | src/server/openiti/prepare.ts, metadata-resolver.ts, github.ts, analyze.ts, import-runner.ts | Excellent socle d’acquisition et de localisation |
| 7. Catalogue éditorial | 10 œuvres, toutes PUBLISHED / UNVERIFIED ; publication humaine avec verrou optimiste | openiti.work_publication, work_publication_events ; src/server/openiti/publication.ts:84-193 | Réutiliser sans automatiser la publication |
| 8. Hadiths et isnād | 15 126 hadiths, 15 126 chaînes, 87 060 maillons ; aucun hadith sans chaîne, aucun avec plusieurs chaînes | hadiths, hadith_chains, hadith_chain_nodes ; toutes les lignes ont corpus_id = NULL | Projecteur canonique réutilisable, mais projection actuelle limitée |
| 9. Normalisation arabe | Normalisation légère OpenITI et normalisations distinctes pour recherche, identité et matn | src/server/openiti/markdown.ts:239-251, src/domain/tradition-variant/MatnMatching.ts:43-75, src/domain/narrator-identity/NameRepresentation.ts:16-57 | Préserver le verbatim et versionner chaque fonction ; ne pas unifier aveuglément |
| 10. Identités de narrateurs | Génération de candidats, preuves, variantes et décisions ; pont OpenITI conservateur | Pont exact sur normalized_name_ar, aucune création canonique : src/server/openiti/narrator-bridge.ts:1-25,212-279 | Réutiliser le référentiel et enrichir la résolution multisource |
| 11. Rijāl et correspondances | 43 935 notices, quatre sources ; crosswalks et relations présents | knowledge_entries, narrator_assertions, narrator_relation_assertions, narrator_crosswalk* | Réutiliser les notices sans fusionner les personnes |
| 12. Traduction française | Orchestrateur idempotent, versionné par hash arabe ; revue humaine distincte | src/server/rijal-translation/translationOrchestrator.ts:71-140 ; tables knowledge_entry_translations, commentary_translations | Réutiliser les contrats ; les raccorder aux tâches durables |
| 13. Commentaires | Deux sources, 2 974 documents, 14 018 passages, 11 395 alignements | commentary_* ; adaptateur canonique Fatḥ limité à une tranche : CommentaryCorpusAdapter.ts:74-120,123-197 | Conserver passages, preuves, cibles et alignements révisables |
| 14. Qualité et provenance | Sources, datasets, batches, hashes, locators, journaux ; quality engine vide | 52 batches, 352 runs ; aucune liaison dataset_acquisition_bindings | Consolider la télémétrie, ne pas remplacer les preuves scientifiques |
| 15. OCR et imports externes | Atelier OCR/traduction et scripts spécialisés Fatḥ, Nawawi, Ibn Hajar | Atelier absent de la base ; scripts/ibnhajar/load-from-openiti.cjs:121-132 supprime puis réinsère sous --apply | Réutiliser les patterns, isoler les traitements destructifs historiques |
A4. Mesures réelles de la base rattachée#
Toutes les valeurs de cette section sont OBSERVÉES dans audit-artifacts/live-db-2026-11-03.json, clés queries.* et tableCounts.
Corpus public#
| Mesure | Valeur |
|---|---|
| Collections | 29 |
| Livres | 155 |
| Chapitres | 5 240 |
| Hadiths documentaires | 15 126 |
| Chaînes | 15 126 |
| Maillons | 87 060 |
| Hadiths avec zéro chaîne | 0 |
| Hadiths avec plusieurs chaînes | 0 |
Maillons avec narrator_id | 86 283 |
Maillons sans narrator_id | 777 |
Hadiths avec corpus_id = NULL | 15 126 |
Le ratio 86 283 / 87 060, soit environ 99,11 %, mesure uniquement le remplissage de la clé étrangère dans les maillons existants. Il ne mesure ni l’exactitude des identifications ni le rappel d’extraction des chaînes.
Narrateurs et connaissances#
| Mesure | Valeur |
|---|---|
| Narrateurs canoniques | 14 709 |
| Narrateurs externes | 47 206 |
| Assertions sur narrateurs | 132 923 |
| Assertions de relations | 23 186 |
| Transmissions | 218 172 |
| Notices de connaissance | 43 935 |
| Mentions de notices | 59 |
| Résolutions de mentions | 59 |
| Source | Liées | Ambiguës | Non liées |
|---|---|---|---|
| Al-Kāshif | 7 140 | 0 | 1 228 |
| Tahdhīb al-Kamāl | 8 471 | 0 | 3 093 |
| Tahdhīb al-Tahdhīb | 1 003 | 0 | 10 955 |
| Taqrīb al-Tahdhīb | 10 226 | 154 | 1 665 |
Ces statuts sont ceux stockés ; ils ne constituent pas une validation humaine globale.
OpenITI#
| Mesure | Valeur |
|---|---|
| Imports | 10 |
Imports COMPLETED | 8 |
Anciens imports encore RUNNING | 2 |
| Œuvres / versions / documents canoniques | 10 / 10 / 10 |
| Entrées | 57 362 |
| Faits | 102 376 |
| Relations | 23 186 |
| Anomalies de staging | 3 |
openiti.knowledge_entry_bindings | 0 |
openiti.document_lifecycle_events | 0 |
Les deux imports RUNNING datent du 3 septembre, n’ont ni URI d’œuvre ni dates de début/fin. Leur statut stocké ne prouve pas qu’un processus soit encore actif.
| Type d’entrée | Nombre |
|---|---|
| Notice biographique | 47 693 |
| Renvoi | 4 706 |
| En-tête de section | 4 329 |
| Inconnu | 634 |
Les méthodes extractor:* historiques coexistent avec TAHDHIB_HEADER_BEFORE_RAWA_AN_V1, taqrib-grade-span-v1, taqrib-name-boundary-v1 et taqrib-tabaqa-v1. Les 76 602 faits produits par extractor:* sont NEEDS_REVIEW. Le code actuel du pont filtre explicitement sur extractor:* et documente les autres lignes comme héritées : src/server/openiti/narrator-bridge.ts:149-154.
Les cinq œuvres classées sont Taqrīb, Tahdhīb, Lisān al-Mīzān, Taʿjīl al-Manfaʿa et Taʿrīf Ahl al-Taqdīs. Bulūgh al-Marām, al-Iṣāba, al-Majmaʿ al-Muʾassis, Nukat ʿalā Ibn al-Ṣalāḥ et Nukhbat al-Fikar restent UNCLASSIFIED.
Commentaires et traductions#
| Mesure | Valeur |
|---|---|
| Sources de commentaires | 2 |
| Éditions | 5 |
| Documents | 2 974 |
| Passages | 14 018 |
| Alignements | 11 395 |
| Cibles | 9 112 |
| Assertions de passages | 0 |
| Versions de traduction de commentaires | 18 274 |
| Décisions de revue de traduction de notices | 1 139 |
Fatḥ al-Bārī : 2 973 documents et 11 343 passages. Nawawi : 1 document et 2 675 passages.
| Alignements | Nombre |
|---|---|
EXACT | 7 964 |
PROBABLE | 3 264 |
CONFLICT | 146 |
AMBIGUOUS | 17 |
MISSING | 4 |
Tous les alignements sont MACHINE_REVIEW_NEEDED, y compris les EXACT. Les 2 974 documents de commentaires sont REVIEW_NEEDED pour les droits et MACHINE_REVIEW_NEEDED pour la vérification.
Les traductions de commentaires comprennent 9 137 lignes MACHINE_REVIEW_NEEDED et 9 137 lignes PUBLISHED pour les mêmes couples de modèles et volumes ; cela correspond vraisemblablement à des versions ou projections distinctes, mais la table de comptage seule ne suffit pas à établir leur cycle de vie. Ne pas conclure à 18 274 textes distincts publiés.
Orchestration et qualité#
import_batches: 45completed, 5failed, 2running.processing_runs: 2PARSER / COMPLETED; 346RESOLVER / COMPLETED, 1RUNNING, 1FAILED, 2CANCELLED.dataset_acquisition_bindings: 0.quality_engine_state: 0 ;quality_decisions: 0.data_quality_snapshots: 32.
Les journaux actuels ne sont ni interchangeables ni suffisants pour relancer une étape arbitraire avec ses entrées, versions et artefacts.
A5. Composants réutilisables#
| Priorité | Composant | Pourquoi le conserver |
|---|---|---|
| Critique | Référentiel narrators et tables de représentations, assertions, relations | C’est l’identité historique transversale ; le pont ne crée volontairement pas de doublon |
| Critique | Corpus collections/books/chapters/hadiths/hadith_chains/hadith_chain_nodes | Modèle public existant, à alimenter par projection plutôt que par corpus concurrent |
| Critique | Provenance data_sources/datasets/import_batches, hashes et locators | Base de la reproductibilité et de la révision |
| Élevée | prepareImport, parseur mARkdown et canonisation SQL | Acquisition, offsets, texte original et transaction déjà présents |
| Élevée | Contrat CorpusAdapter, moteur et projecteur | Séparation déjà conçue entre lecture neutre et persistance |
| Élevée | Publication humaine et journal append-only | Verrouillage optimiste et séparation du statut de vérification |
| Élevée | Orchestrateur de traduction de notices | Idempotence, hash source, contrôles de complétude et concurrence |
| Élevée | Alignements de commentaires et preuves | Distinction exact/probable/conflit et revue |
| Moyenne | Atelier OCR/traduction | Leases, fencing, budgets, retries et protection des validations humaines |
| Moyenne | MatnMatching | Signaux explicables de similarité, sans conclusion d’identité : MatnMatching.ts:118-158 |
A6. Doublons, fonctions manquantes et risques#
Doublons fonctionnels#
- Deux voies OpenITI coexistent : import
openiti.*et adaptateurs du pipeline canonique, sans composition de production. - Plusieurs pipelines d’écriture spécialisés coexistent pour hadiths, rijāl, Fatḥ, Nawawi et Ibn Hajar.
- Plusieurs orchestrations techniques coexistent :
openiti.imports,import_batches,processing_runs, jobs de l’atelier. - Plusieurs surfaces de traduction existent. Elles répondent à des objets différents, mais n’ont pas d’orchestrateur commun de planification et de coût.
Ces doublons ne doivent pas être supprimés avant cartographie des écritures, dépendances et décisions humaines.
Fonctions manquantes ou non câblées#
- orchestration générale asynchrone, reprise par étape et annulation contrôlée ;
- registre des versions de classifieurs, extracteurs, resolveurs et configurations ;
- classification scientifique générique avec revue et règles de capacité ;
- extraction générique de collections structurées dans l’import OpenITI principal ;
- projection OpenITI vers
corpus_idet chaînes multiples en production ; - gestion explicite des renvois incomplets et graphes de bifurcation/convergence dans le pipeline principal ;
- gestion des droits dans l’acquisition OpenITI générique ;
- tableau de bord unique de runs, étapes, coûts, couverture et erreurs ;
- déploiement du quality engine et de l’atelier dans la base liée.
Risques de régression#
| Risque | Gravité | Mesure obligatoire |
|---|---|---|
| Casser les lectures publiques en changeant le corpus | Critique | Projections additives, tests de contrat, rollback applicatif |
| Fusionner des homonymes ou écraser une décision humaine | Critique | Identités externes conservées, candidats et preuves, décisions versionnées |
| Perdre les enrichissements lors d’une réimportation | Critique | Idempotence par contenu et protection des versions revues |
| Confondre statut technique et qualité scientifique | Critique | Axes séparés, publication humaine |
| Réécrire des données par traitement spécialisé | Élevée | Interdire les suppressions larges dans les nouveaux runners ; dry-run et impact préalable |
| Timeout HTTP ou double exécution | Élevée | File durable, leases, idempotency keys, worker séparé |
| Coûts IA non maîtrisés | Élevée | Budgets, réservation, quotas, cache par hash et journal d’usage |
| Croissance du staging et des versions | Moyenne | Rétention des artefacts dérivés sans supprimer le texte source ; métriques de volume |
| Dérive entre code et migrations | Élevée | Inventaire réconcilié dans un environnement avec droits de lecture suffisants |
Le DELETE FROM ibnhajar.shuyukh du script spécialisé est un risque réel si --apply est utilisé ; il n’a pas été exécuté pendant cet audit. scripts/ibnhajar/load-from-openiti.cjs:121-132.
A7. Tests effectivement exécutés#
| Commande | Résultat observé | Portée et limite |
|---|---|---|
npm run test:openiti | 54 tests : 47 réussites, 7 tests DB ignorés, 0 échec | Ne prouve pas l’intégration à la base distante |
npm run test:independent-source-proof | Réussite sur PGlite | Fixture Muslim : chaînes, idempotence, enrichissements |
npm run test:independent-source-resilience-proof | Réussite sur PGlite | Reprise et préservation sur environnement jetable |
npm run test:e13 | Réussite | Segmentation, versioning, orchestration et repository de traduction |
npm run test:translation-review | Réussite, y compris PGlite | Revue, concurrence, RLS et journaux sur périmètre testé |
npm run test:commentary-vertical-slice | Réussite sur 17 passages réels en base jetable | Idempotence et rollback d’une tranche, pas du corpus complet |
npm run test:commentary-corpus-adapter | Réussite | Contrat de l’adaptateur Fatḥ |
npm run typecheck | Réussite | Typage statique uniquement |
La preuve indépendante couvre 50 hadiths, 136 chaînes et 577 nœuds sur fixture. Ces chiffres ne sont pas des comptes de production et ne doivent pas être comparés aux 15 126 hadiths publics.
| Capacité cible | Existant | Écart | Décision cible |
|---|---|---|---|
| Acquisition multisource | OpenITI/GitHub abouti ; autres readers spécialisés | Pas d’enregistrement générique des fournisseurs et droits | Adaptateurs SourceProvider et manifeste d’acquisition |
| Conservation originale | Texte en staging, hashes, offsets | Cycle de vie et retraitement non unifiés | Document immutable, artefacts et versions de traitement |
| Classification | Règles titres/URI de rijāl | Cinq œuvres non classées ; autres genres non couverts | Classifieur de capacités, règles + preuves + revue |
| Extraction hadiths | Parseurs canoniques et spécialisés | Non connectés à l’import principal | Plugin HADITH_COLLECTION vers projecteur existant |
| Chaînes multiples | Reader Muslim sur tranche ; production à une chaîne/hadith | Couverture générale non démontrée | Graphe de chemins et références explicites, sans inférence cachée |
| Variantes | Modèles traditions, tradition_variants, signaux matn | Pas de preuve d’intégration OpenITI générique | Assertions de relation avec méthode et preuves |
| Identités | Candidats, crosswalks, décisions | Pont limité au nom exact normalisé | Résolution progressive multisource et files de revue |
| Rijāl | 43 935 notices et nombreuses assertions | Lien OpenITI canonique vide | Binding explicite, sans duplication des notices |
| Commentaires | Modèle riche et imports réels | Adaptateur générique limité à une tranche Fatḥ | Plugin commentaire avec mêmes tables et preuves |
| Traduction | Versioning et revue robustes | Planification et budgets non unifiés | Étape séparée réutilisant les orchestrateurs |
| Qualité | Snapshots et anomalies ; quality engine vide | Pas de contrôle obligatoire par étape | Gates numériques, métriques et rapports signés par version |
| Publication | Humaine, optimiste, journalisée | Non reliée à un tableau de préparation global | Préconditions calculées, décision admin inchangée |
| Orchestration | Logs et files spécialisés | Import HTTP synchrone ; pas de reprise par étape | Runs + étapes + tâches persistantes + workers |
| Coûts | Budget dans l’atelier | Pas de budget général pour toutes traductions/IA | Réservations, usage, quotas et estimation avant lancement |
| Administration | Pages import/œuvres/imports/anomalies | Pas de reprise sélective ni vision pipeline | Console unique alimentée par le modèle de runs |
C1. Principes non négociables#
- Un seul référentiel de narrateurs :
public.narratorsreste canonique ; les mentions externes restent distinctes. - Un seul corpus public : les nouvelles acquisitions projettent dans le modèle existant ; pas de corpus OpenITI concurrent.
- Le texte source est immutable ; toute normalisation est un artefact dérivé et versionné.
- Une étape produit des artefacts, pas une vérité scientifique implicite.
- Une extraction, une déduction et une décision humaine ont des provenances distinctes.
- Aucune publication automatique. La publication et la vérification numérique restent des axes éditoriaux distincts.
- Toute étape est idempotente et rejouable à périmètre constant.
- Aucune suppression historique pendant la migration vers le nouvel orchestrateur.
C2. Flux logique proposé#
Demande admin
→ Acquisition planifiée
→ Document source + métadonnées + droits + empreinte
→ Classification des capacités
→ Segmentation structurelle
→ Extraction spécifique au type
→ Résolution progressive des identités
→ Enrichissement et relations scientifiques
→ Projection dans les modèles canoniques existants
→ Contrôles numériques
→ Traductions optionnelles et budgétées
→ Rapport de préparation
→ Décision humaine de publication
Chaque flèche = dépendance explicite entre étapes persistantes.
Chaque sortie = artefact versionné + provenance + métriques + anomalies.
Un échec de traduction ne remet pas en cause les étapes amont. Une correction d’identité déclenche seulement la résolution, les enrichissements dépendants et les projections affectées.
C3. Composants applicatifs proposés#
| Composant | Responsabilité | Réutilisation |
|---|---|---|
IngestionCatalog | Œuvres, versions, capacités, état courant | openiti.works, versions, publication |
SourceProvider | Découverte et acquisition d’une source autorisée | GitHub/OpenITI prepare.ts, github.ts |
DocumentStore | Texte original, métadonnées, droits, hash, localisation | stg_documents, documents canoniques |
CapabilityClassifier | Type documentaire et extracteurs applicables | Règles actuelles comme premier fournisseur de signaux |
StructureParser | Segments, pages, offsets, structure hiérarchique | markdown.ts, analyze.ts |
DomainExtractor | Hadiths, chaînes, rijāl, commentaires | Extracteurs et readers existants |
IdentityResolver | Candidats, preuves, ambiguïtés, décisions | Domaines narrator-identity, crosswalks |
EnrichmentLinker | Relations, notices, matn, commentaires | Assertions, preuves, MatnMatching, alignements |
CanonicalProjector | Écriture idempotente dans corpus/rijāl/commentaires | HadithCorpusProjector, repositories actuels |
TranslationService | Versions, statuts, revue, budget | Orchestrateurs de notices/commentaires/atelier |
DigitalQualityService | Complétude, intégrité, couverture, anomalies | Snapshots, issues, quality model |
PublicationService | Décision humaine et journal | publication.ts inchangé fonctionnellement |
RunCoordinator | DAG d’étapes, dépendances, reprise, annulation | Nouveau, alimenté par les journaux existants |
Worker | Exécution par lot avec lease et fencing | Patterns de book-workshop |
AdminConsole | Suivi, preuves, anomalies, coûts, actions | Pages OpenITI et consoles existantes |
C4. Modèle de contrôle proposé#
Les noms ci-dessous sont logiques ; leur implémentation doit être revue avant toute migration.
ingestion_run: demande, œuvre/version, périmètre, configuration, état global, demandeur.ingestion_stage: type, dépendances, version de code, entrée hash, état, compteurs, début/fin.ingestion_task: lot, lease, tentative, prochaine exécution, erreur, priorité.ingestion_artifact: sortie adressable, hash, schéma, producteur, métriques, rétention.ingestion_event: transitions append-only et actions humaines.ingestion_budget: plafond, réservation, consommation et coût monétaire observé.ingestion_binding: correspondance explicite entre run etimport_batch,processing_runou import historique.
Clé d’idempotence recommandée : (type_étape, document_sha256, périmètre, version_extracteur, configuration_hash). Les décisions humaines ne font jamais partie des artefacts supprimés lors d’un rejeu.
États techniques#
PENDING → READY → RUNNING → SUCCEEDED, avec FAILED_RETRYABLE, FAILED_FINAL, CANCEL_REQUESTED, CANCELLED, BLOCKED.
Un run techniquement réussi peut produire un rapport scientifique partiel. Cette distinction suit déjà ObservedAcquisitionRunner : src/infrastructure/knowledge-acquisition/ObservedAcquisitionRunner.ts:23-29,178-193.
C5. Contrats scientifiques par famille#
Collections de hadiths#
- conserver document, livre, chapitre, numéro source, ordre, offsets et verbatim ;
- modéliser chaque ṭarīq séparément et chaque maillon dans son ordre ;
- stocker
ح,بهذا الإسناد,نحوه,مثلهcomme objets structurels typés ; - représenter une référence non résolue comme telle, sans recopier silencieusement une chaîne précédente ;
- permettre bifurcations et convergences par chemins, sans déduire une convergence à partir du seul nom ;
- ne jamais confondre hadith documentaire, tradition, variante et chaîne.
Rijāl#
- chaque notice reste rattachée à son ouvrage et son édition ;
- génération de candidats à partir des noms, kunya, nisba, générations, dates et relations ;
- preuves contradictoires conservées ;
- correspondance plausible = candidat, jamais identité certaine automatique ;
- correction d’identité = nouvelle décision et reprojection ciblée.
Commentaires#
- passages et lemmes liés à leur document source ;
- cibles déclarées séparées des cibles calculées ;
- alignements exact/probable/ambigu/conflit conservés ;
- assertions attribuées à leur autorité avec citation et locator.
Traduction#
- source arabe et hash obligatoires ;
- modèle, prompt/profil, version, date, statut et revue obligatoires ;
- reprise par lots et invalidation par changement de hash ;
- aucune traduction ne remplace l’arabe ou une version humaine protégée.
C6. Interface administrative cible#
Une page « Ingestions » doit offrir :
- catalogue et sélection de version, droits et métadonnées ;
- estimation préalable du périmètre et du coût IA ;
- graphe d’étapes, progression, durée, retry et annulation ;
- compteurs distincts documents/hadiths/traditions/variantes/chaînes/maillons ;
- narrateurs non résolus, candidats, preuves et décisions ;
- anomalies bloquantes et non bloquantes ;
- aperçu côte à côte arabe/source/extraction/traduction ;
- retraitement sélectif avec affichage des dépendances ;
- rapport qualité et couverture de revue ;
- action de publication via les règles actuelles.
Ce plan est PROPOSÉ et subordonné à validation. Chaque étape est livrable indépendamment, sans migration destructive.
| Priorité | Étape | Contenu | Critères d’acceptation | Dépendances et risques |
|---|---|---|---|---|
| P0 | D0. Réconciliation | Inventaire migrations/déploiement, propriétaires des tables, routes et écritures | Matrice approuvée ; aucun écart non expliqué sur les tables touchées | Accès lecture historique migrations ; modifications utilisateur |
| P0 | D1. Contrats et témoins | Geler les modèles d’entrée/sortie, jeux de référence et métriques | Fixtures versionnées ; dénominateurs documentés ; baseline reproductible | Expertise scientifique humaine |
| P0 | D2. Orchestrateur en shadow | Runs, étapes, tâches, artefacts, worker, auth admin | Reprise après crash, lease expiré, retry, annulation et double clic sans doublon | Nouvelle couche seulement ; aucun changement de production |
| P1 | D3. Adaptateur acquisition | Envelopper prepareImport sans réécriture ; manifeste droits/version/hash | Même document produit même manifeste ; staging existant conservé | API GitHub et licences |
| P1 | D4. Classification | Registre de capacités et règles génériques, sortie explicable | Ouvrage non reconnu bloqué pour revue ; aucun extracteur inapproprié | Validation des types et vocabulaire |
| P1 | D5. Pilote rijāl | Raccorder extraction, bindings et résolution progressive | Rejeu idempotent ; décisions humaines intactes ; mesures précision/rappel | Risque d’homonymies ; gros volumes |
| P1 | D6. Pilote collection structurée | Projection additive dans corpus existant avec corpus_id renseigné | Comptes réconciliés ; rollback logique ; aucune duplication publique | Lectures publiques et index |
| P1 | D7. Pilote Muslim | Ṭuruq, ح, renvois, chemins et offsets | Jeu de référence complet sur périmètre ; ambiguïtés visibles | Ne pas généraliser les règles d’une tranche |
| P2 | D8. Commentaires | Généraliser l’adaptateur et réutiliser alignements/preuves | Cibles déclarées/calculées distinctes ; 17 passages témoins non régressés | Variation des éditions |
| P2 | D9. Traductions | Tâches séparées, budgets et orchestrateurs existants | Échec traduction sans rejeu amont ; cache hash ; coût observable | Tarifs et quotas fournisseurs |
| P2 | D10. Qualité et console | Gates, dashboards, reprise sélective et rapport | Métriques avec dénominateurs ; publication toujours humaine | Ne pas transformer score en verdict |
| P3 | D11. Extension progressive | Nouvelles œuvres par capacité, ramp-up mesuré | Seuils E atteints sur trois témoins puis échantillons nouveaux | Dette des extracteurs spécialisés |
Règles de livraison#
- chaque étape inclut tests unitaires, tests PostgreSQL jetables, test de rejeu et test de rollback logique ;
- le chemin historique reste disponible jusqu’à preuve de parité sur le périmètre pilote ;
- les scripts destructifs ne sont pas intégrés au moteur ;
- aucune généralisation à partir du seul succès d’un test vert ;
- les changements de schéma sont additifs et accompagnés d’une analyse des lectures/écritures.
E1. Trois témoins#
| Témoin | Rôle | Périmètre initial proposé |
|---|---|---|
| Collection structurée déjà supportée, p. ex. Bukhārī | Segmentation, livres/chapitres, hadiths, projection canonique | Un livre complet choisi et figé, pas un échantillon de commodité |
| Ṣaḥīḥ Muslim, témoin OpenITI existant | Chaînes multiples, ح, renvois, variantes et convergences | La tranche actuelle complète, puis un livre complet avant extension |
| Taqrīb al-Tahdhīb, puis Tahdhīb en second témoin rijāl | Notices, grades, renvois, homonymies, résolution | Ensemble complet de notices sélectionnées par strates documentées |
Les textes et éditions doivent être épinglés par URI, commit et SHA-256. Les jeux de référence sont relus par des personnes compétentes, avec procédure de désaccord et version.
E2. Jeux de référence#
Chaque cas contient : identifiant source, verbatim, offsets, structure attendue, chaînes/chemins attendus, mentions, rattachements acceptés, ambiguïtés acceptées, variantes et traduction de référence lorsque pertinente.
Prévoir des strates : cas ordinaires, renvois, homonymes, notices courtes/longues, pagination absente, marqueurs inconnus, contradictions et erreurs volontairement injectées.
Aucun chiffre de qualité n’est calculé sur les seules lignes faciles ou déjà résolues.
E3. Indicateurs et dénominateurs#
| Mesure | Formule | Dénominateur obligatoire |
|---|---|---|
| Précision de segmentation | segments corrects / segments produits | Tous les segments produits sur le périmètre |
| Rappel de segmentation | segments attendus retrouvés / segments attendus | Référence humaine exhaustive du périmètre |
| Exactitude des limites | limites exactes / limites attendues | Début et fin séparés si nécessaire |
| Rappel des chaînes | ṭuruq attendus retrouvés / ṭuruq attendus | Toutes les voies du témoin, y compris renvois |
| Fidélité des chaînes | chemins entièrement exacts / chemins attendus | Ordre, narrateurs, formules et références |
| Précision d’identification | liens automatiques corrects / liens automatiques produits | Inclut les faux liens ; exclut seulement les abstentions déclarées |
| Couverture d’identification | mentions liées / mentions du périmètre | Toutes les mentions, y compris non résolues |
| Taux d’ambiguïté | mentions ambiguës / mentions du périmètre | Ne pas assimiler ambiguïté à erreur |
| Conservation des variantes | variantes attendues conservées / variantes attendues | Variantes et renvois distingués |
| Exactitude des rattachements | liens source corrects / liens évalués | Cibles déclarées et calculées rapportées séparément |
| Stabilité de rejeu | sorties identiques / sorties attendues | Hash des artefacts et comptes, hors timestamps |
| Couverture de revue | objets revus / objets publiés du périmètre | Type d’objet et niveau de revue précisés |
Pour la traduction, rapporter séparément complétude mécanique, erreurs de sens, omissions, ajouts, terminologie et taux d’acceptation humaine. Un contrôle automatique n’est pas une validation linguistique ou scientifique.
E4. Tests techniques obligatoires#
- même entrée exécutée deux fois : aucun doublon, mêmes artefacts logiques ;
- interruption avant/après commit : reprise sans perte ni double appel non tracé ;
- lease expiré et deux workers : un seul commit valide ;
- correction d’extracteur : nouvelle version, ancienne preuve consultable ;
- correction d’identité : seules les projections dépendantes sont rejouées ;
- source arabe modifiée : traduction précédente devient obsolète, jamais écrasée ;
- traduction en échec : extraction et publication antérieure intactes ;
- publication concurrente : conflit optimiste visible ;
- source indisponible ou quota IA atteint : état explicite, reprise contrôlée ;
- aucune décision humaine supprimée par rejeu.
E5. Critères de passage à l’échelle#
Les seuils chiffrés doivent être approuvés après la baseline ; en fixer maintenant serait arbitraire. Conditions minimales :
- référence humaine complète et versionnée sur chaque témoin ;
- aucun défaut critique ouvert : faux lien silencieux, perte de verbatim, écrasement humain, doublon public ;
- précision et rappel publiés avec intervalles, strates et dénominateurs ;
- rejeu, interruption, concurrence et retraitement sélectif démontrés ;
- coût et durée mesurés par unité documentaire ;
- revue des droits et provenance complète ;
- publication humaine et rollback logique démontrés.
L’extension se fait par cohorte limitée, avec comparaison à la baseline et arrêt en cas de régression.
F1. Mesures observées#
- Base PostgreSQL : 2 080 566 419 octets, environ 2,08 GB décimaux ou 1,94 GiB.
- Texte OpenITI canonique : 21 199 630 caractères ; même total en staging. La duplication logique du texte est donc réelle, sans déduire son coût physique exact du seul nombre de caractères.
- Documents de commentaires : somme déclarée de 41 091 313 octets.
- 352
processing_runset 52import_batchesdonnent un historique utile, mais pas une mesure actuelle de débit. - Aucun tarif fournisseur, nombre de tokens ou coût réel consolidé n’a été mesuré par cet audit.
F2. Charge de développement — hypothèses#
Ordre de grandeur pour un développeur senior connaissant Next.js/PostgreSQL, avec revue scientifique séparée :
| Lot | Hypothèse de charge |
|---|---|
| D0–D2 : réconciliation, contrats, orchestrateur | 20–30 jours-personne |
| D3–D4 : acquisition et classification | 10–18 jours-personne |
| D5 : rijāl et résolution | 18–30 jours-personne |
| D6–D7 : collections et Muslim | 25–40 jours-personne |
| D8 : commentaires | 10–18 jours-personne |
| D9–D10 : traduction, qualité, console | 20–32 jours-personne |
| D11 : durcissement et extension initiale | 10–20 jours-personne |
| Total indicatif | 113–188 jours-personne |
Cette estimation n’est ni un devis ni un engagement. Elle suppose la réutilisation effective des composants ; une refonte du corpus ou des identités la rendrait caduque. La constitution des références humaines peut représenter plusieurs semaines de travail expert et n’est pas comprise dans les jours de développement.
F3. Infrastructure#
PROPOSÉ :
- PostgreSQL/Supabase pour contrôle, files et données canoniques ;
- worker Node séparé, à concurrence bornée, sans transaction ouverte pendant un appel IA ;
- stockage objet pour artefacts volumineux et exports, avec hashes dans PostgreSQL ;
- secrets uniquement côté serveur, rôles minimaux et audit admin ;
- métriques de files, latence, erreurs, retries, coûts, saturation et stockage ;
- environnements jetables pour migrations et tests de rejeu.
Le choix d’hébergement du worker reste ouvert. L’import HTTP actuel ne doit pas devenir le worker long.
F4. Coût IA — modèle paramétré, sans prix inventé#
Pour chaque famille :
coût = Σ (tokens_entrée × prix_entrée + tokens_sortie × prix_sortie)
+ coût OCR éventuel + coût embeddings éventuel
coût_unitaire = coût_total_observé / unités réellement traitées
coût_projeté(N) = N × coût_unitaire / (1 − taux_de_rejeu_ou_échec)
À mesurer sur les trois témoins : caractères et tokens par entrée, contexte ajouté, sortie, taux de retry, taux de cache, modèle et prix à la date d’exécution.
Optimisations : traduction uniquement à hash modifié, lots adaptés, contexte borné, quotas par run, plafond avant lancement, cache et réutilisation des validations humaines. Les traductions existantes ne doivent pas être régénérées pour alimenter une nouvelle orchestration.
F5. Stockage et montée en charge#
Le coût futur dépend de W œuvres, C caractères par œuvre, V versions conservées, A artefacts dérivés et I index/embeddings :
volume_brut ≈ W × C × V + A + I + journaux + sauvegardes
Aucune projection monétaire fiable n’est possible sans tarifs et volumétrie cible. Les risques principaux sont les copies staging/canonique, les embeddings, les index de recherche, les traductions multiversion et les journaux.
Mesures recommandées : artefacts dérivés régénérables, rétention différenciée, partitionnement si mesuré nécessaire, traitement par lots, index surveillés et sauvegardes testées. Le texte original et les preuves ne sont pas des artefacts à purge automatique.
| Existant | Cible | Action |
|---|---|---|
openiti.imports, stg_* | Acquisition + documents + artefacts | Envelopper et lier aux runs |
openiti.canonicalize_import | StructureParser + canonisation OpenITI | Conserver initialement |
prepare.ts, github.ts, metadata-resolver.ts | OpenitiSourceProvider | Extraire derrière un port, sans duplication |
inferWorkType | CapabilityClassifier | Étendre avec preuves et revue |
Extracteurs extractor:* | Plugins rijāl versionnés | Conserver comme baseline, mesurer |
narrator-bridge.ts | IdentityResolver initial | Étendre progressivement ; conserver les abstentions |
DefaultKnowledgeAcquisitionEngine | Composition des adaptateurs | Câbler au coordinator |
ObservedAcquisitionRunner | Binding run/batch et provenance | Réutiliser les principes, pas comme DAG complet |
HadithCorpusProjector | Projection du corpus public | Réutiliser et renforcer chaînes multiples |
knowledge_entries et assertions | Référentiel documentaire rijāl | Aucun remplacement |
commentary_* | Commentaires canoniques | Réutiliser passages, preuves, alignements |
translationOrchestrator et revue | Étape traduction | Orchestrer sans réécrire le modèle |
book_workshop worker | Worker pattern | Réutiliser lease/fencing/budget après déploiement validé |
quality_engine_state, quality_decisions | Suivi incrémental qualité | Activer seulement après contrats et tests |
openiti.work_publication* | Publication humaine | Conserver la décision et le journal |
Approuver ou ajuster, dans l’ordre :
- la conservation stricte du corpus et du référentiel existants ;
- le modèle d’orchestration par runs/étapes/tâches/artefacts ;
- les trois témoins et leurs périmètres exhaustifs ;
- les responsables scientifiques des jeux de référence ;
- les lots D0 à D2 comme premier incrément, en environnement non productif.
Aucun développement du moteur, migration ou import massif n’est justifié avant cette validation.