Liaisons contextuelles
Modélisez le même concept métier à travers plusieurs systèmes sources, normes et juridictions — avec provenance, transformations et niveau de confiance sur chaque valeur projetée.
Ceci est la référence d'authoring (comment le construire avec le SDK). Pour le concept — ce qu'est une ontologie contextuelle et quand vous en avez besoin — commencez par Ontologies contextuelles. Ce guide complète également le guide d'authoring des ontologies : les liaisons contextuelles sont des champs additionnels sur les mêmes helpers defineBinding, defineObjectType et defineOntology.
Pourquoi les liaisons contextuelles existent
Une ontologie canonique indique que Payment possède une propriété monetaryAmount. Mais le même concept métier se présente différemment dans chacun des systèmes sources qui l'alimentent :
| Comment vous l'appelez | Où il réside | Différence |
|---|---|---|
amount | Core banking (pacs.008, BE) | Centimes entiers, sortant, sémantique de date de valeur |
trxAmt | Hub de paiements (ISO 8583 historique) | Chaîne décimale, acquisition, sémantique de date de règlement |
gross_amount | Reporting financier (vue IFRS) | Net + frais, sémantique de date comptable |
Si vous aplatissez ces trois champs en une seule colonne monetaryAmount sans capturer ce contexte, votre IA, votre reporting et votre automatisation de conformité opèrent sur des données ambiguës. Une requête de conformité portant sur « tous les paiements transfrontaliers de plus de 10 000 € » renvoie des réponses différentes selon la liaison exécutée en dernier — et vous ne pouvez pas expliquer laquelle.
Les liaisons contextuelles résolvent ce problème en enregistrant sur chaque valeur projetée :
- Quel système source et quelle norme de message l'ont produite.
- Quelles transformations ont été appliquées (unité monétaire, fuseau horaire, division par 100, …).
- Si ces transformations étaient sans perte.
- Le niveau de confiance dans l'exactitude du mappage.
- Une fenêtre de validité (
validFrom/validTo).
Les lectures renvoient tout cela sous forme d'une enveloppe provenance à côté de { id, properties }, afin que les appelants puissent voir et expliquer les divergences entre sources au lieu de les dissimuler derrière un golden record silencieux.
bindingContext — décrire votre système source
Ajoutez un bloc bindingContext à n'importe quel appel defineBinding(...). Tous les champs sont facultatifs — ne fournissez que ceux qui ont un sens pour votre source.
import { defineBinding } from '@scrydon/sdk-authoring/ontologies'
defineBinding({
objectTypeSlug: 'Payment',
kind: 'silver_table',
source: { table: 'silver_payments_outgoing' },
identitySpec: { keys: ['msg_id'] },
columnMap: {
monetary_amount: 'amount_cents',
value_date: 'trade_ts_local',
counterparty_lei: 'customer_id',
},
bindingContext: {
sourceSystem: 'core_banking_x',
extensionVersion: '3.2',
standard: 'ISO20022',
messageType: 'pacs.008',
direction: 'outgoing',
jurisdiction: 'BE',
dataResidency: 'eu',
businessProcess: 'credit_transfer',
timestampSemantics: 'value_date',
currencySemantics: 'transaction_currency',
aggregationLevel: 'transaction_level',
confidence: 0.96,
validFrom: '2025-01-01',
validTo: null,
},
})Référence des champs
| Champ | Type | Remarques |
|---|---|---|
sourceSystem | string | Slug identifiant le système d'entreprise (par ex. "core_banking_x", "salesforce_crm"). |
extensionVersion | string | Version de l'API ou du schéma de la source (par ex. "3.2", "v2024-01"). |
standard | string | Norme de message, le cas échéant (par ex. "ISO20022", "FIX42", "HL7_FHIR"). |
messageType | string | Type de message propre à la norme (par ex. "pacs.008", "MT103", "Claim"). |
direction | string | Sens du flux — "inbound", "outgoing" ou toute valeur libre. |
jurisdiction | string | Code ISO de pays ou de région (par ex. "BE", "EU", "US-NY"). |
dataResidency | string | Zone de résidence des données (par ex. "eu", "us", "on-prem"). |
businessProcess | string | Processus métier de haut niveau (par ex. "credit_transfer", "claims_adjudication"). |
timestampSemantics | string | Signification des horodatages — "value_date", "settlement_date", "accounting_date" ou toute valeur libre. |
currencySemantics | string | Vue monétaire utilisée — "transaction_currency", "reporting_currency", etc. |
aggregationLevel | string | Granularité des données — "transaction_level", "position_level", "daily_snapshot", etc. |
confidence | number (0–1) | Niveau de confiance du mappage pour cette source. Alimente l'enveloppe provenance de chaque instance projetée. |
validFrom | string | Chaîne de date ISO 8601 indiquant à partir de quand ce mappage est valide. |
validTo | string | null | Chaîne de date ISO 8601 indiquant quand ce mappage expire, ou null pour une validité sans fin. |
transformMap — transformations par propriété
Le columnMap plat associe des slugs de propriétés à des noms de colonnes sources. transformMap ajoute par-dessus des descripteurs de transformation plus riches. Lorsqu'une propriété apparaît dans transformMap, le projecteur utilise entry.source comme colonne source et applique entry.transform ; sinon, il se rabat sur columnMap. Les deux peuvent coexister sur la même liaison.
defineBinding({
objectTypeSlug: 'Payment',
kind: 'silver_table',
source: { table: 'silver_payments_outgoing' },
identitySpec: { keys: ['msg_id'] },
columnMap: {}, // transformMap entries take precedence
bindingContext: {
sourceSystem: 'core_banking_x',
standard: 'ISO20022',
messageType: 'pacs.008',
jurisdiction: 'BE',
confidence: 0.96,
},
transformMap: {
monetary_amount: {
source: 'amount_cents',
transform: 'divide_by_100',
unit: 'EUR',
lossless: true,
},
value_date: {
source: 'trade_ts_local',
transform: 'timezone_normalize',
tz: 'Europe/Brussels',
lossless: false,
notes: 'DST ambiguity on clock-change dates',
},
counterparty_lei: {
source: 'customer_id',
transform: 'resolve_via_mdm',
lossless: false,
confidence: 0.88,
},
},
})Vocabulaire des transformations
Les transformations autorisées forment un ensemble fermé, sur liste blanche. Passer une chaîne absente de cette liste fait projeter null pour la propriété et la marque comme propriété avec perte — le projecteur ne type jamais une valeur de manière erronée en silence.
| ID de transformation | Ce qu'elle fait | Sans perte ? |
|---|---|---|
identity | Transmet la valeur sans modification. | Oui |
divide_by_100 | Divise la valeur numérique par 100 (par ex. centimes → unité monétaire). | Oui |
multiply_by_100 | Multiplie la valeur numérique par 100. | Oui |
regex_extract | Applique un groupe de capture regex à la valeur de type chaîne. Utilisez args: { pattern: "..." } pour fournir l'expression. | Selon le cas |
timezone_normalize | Normalise un horodatage local en UTC à l'aide du champ tz. | Non (ambiguïté liée à l'heure d'été) |
currency_normalize | Enregistre l'unité monétaire depuis unit. La valeur est transmise sans modification jusqu'à ce qu'un fournisseur de taux de change soit configuré. | Non |
resolve_via_mdm | Recherche la valeur dans un système de Master Data Management. Transmet la valeur telle quelle jusqu'à ce qu'un résolveur MDM soit configuré. | Non |
currency_normalize et resolve_via_mdm sont aujourd'hui des stubs portant uniquement des métadonnées — ils enregistrent que la transformation devrait avoir lieu et marquent la propriété lossless: false, mais ne réécrivent pas la valeur. Lorsqu'un fournisseur de taux de change ou un résolveur MDM est configuré sur votre déploiement, la plateforme l'utilisera automatiquement. D'ici là, considérez la valeur projetée comme la valeur source brute.
Référence des champs de TransformDescriptor
| Champ | Type | Remarques |
|---|---|---|
source | string | Expression de colonne source (remplace columnMap[propertySlug] lorsqu'elle est présente). Requis. |
transform | TransformId | L'un des ID de transformation sur liste blanche ci-dessus. Facultatif — omettez-le pour transmettre la valeur telle quelle. |
unit | string | Code de devise ou autre unité (par ex. "EUR", "USD"). Utilisé par currency_normalize et informatif pour divide_by_100. |
tz | string | Nom de fuseau horaire IANA (par ex. "Europe/Brussels"). Utilisé par timezone_normalize. |
lossless | boolean | Indique si la transformation est sans perte. Lorsqu'il vaut false, la propriété apparaît dans provenance.lossyProperties. |
confidence | number (0–1) | Niveau de confiance du mappage par propriété ; remplace le niveau de confiance de la liaison pour cette propriété. |
notes | string | Note libre à des fins de documentation et d'audit. |
args | Record<string, unknown> | Arguments supplémentaires propres à la transformation (par ex. { pattern: "^([A-Z]{2}\\d+)" } pour regex_extract). |
anchors de normes — rattachement à FIBO, ISO 20022, CDM et LEI
Les types d'objets et les propriétés peuvent porter des anchors facultatifs qui rattachent un concept canonique à une norme externe. Les ancres sont purement informatives — elles ne modifient pas la manière dont la plateforme stocke ou projette les données, mais elles sont exposées dans l'atelier d'ontologie et dans la provenance d'audit.
import {
defineObjectType,
defineProperty,
} from '@scrydon/sdk-authoring/ontologies'
defineObjectType({
slug: 'Payment',
displayName: 'Payment',
kind: 'analytical',
anchors: [
{
standard: 'FIBO',
conceptId: 'fibo-fbc-fct-fse:Payment',
uri: 'https://spec.edmcouncil.org/fibo/ontology/FBC/FunctionalEntities/FinancialServicesEntities/',
label: 'Payment',
},
{
standard: 'ISO20022',
conceptId: 'pacs.008.CreditTransfer',
label: 'Credit Transfer Initiation',
},
],
properties: [
defineProperty({
slug: 'monetary_amount',
displayName: 'Monetary amount',
scalarType: 'float',
anchors: [
{ standard: 'ISO20022', conceptId: 'Pacs.008.IntrBkSttlmAmt', label: 'Interbank Settlement Amount' },
{ standard: 'FINOS_CDM', conceptId: 'rosetta:Money', label: 'Money' },
],
}),
defineProperty({
slug: 'value_date',
displayName: 'Value date',
scalarType: 'date',
anchors: [
{ standard: 'ISO20022', conceptId: 'Pacs.008.IntrBkSttlmDt', label: 'Interbank Settlement Date' },
],
}),
],
})Normes prises en charge
| Valeur | Description |
|---|---|
FIBO | EDMC Financial Industry Business Ontology (OWL 2 DL) |
ISO20022 | Concepts du Business Model et composants de message ISO 20022 |
FINOS_CDM | FINOS Common Domain Model (Rosetta) |
LEI | Legal Entity Identifier (GLEIF) |
Ce sont des chaînes libres — la plateforme vérifie que standard, conceptId et, facultativement, uri et label sont présents, mais elle ne résout pas les URI et ne valide pas les ID de concept par rapport aux normes externes elles-mêmes. Les noms de concept en langue locale priment ; les ancres constituent une couche facultative d'interopérabilité et de traçabilité d'audit.
aliases à portée contextuelle — alias + context → concept
Différents systèmes sources et normes emploient des termes locaux différents pour le même concept canonique. Le tableau aliases au niveau supérieur de defineOntology(...) vous permet d'enregistrer ces correspondances terme → concept — limitées à un contexte, de sorte que le même terme puisse correspondre à des concepts différents selon l'endroit où il apparaît.
Les alias sont toujours limités à un contexte. Il n'existe pas de table d'alias globale. Le même terme local ("Debtor") peut correspondre à Counterparty dans une norme et à LegalEntity dans une autre — c'est voulu.
Utilisez defineAlias(...) depuis @scrydon/sdk-authoring/ontologies :
import {
defineOntology,
defineAlias,
} from '@scrydon/sdk-authoring/ontologies'
defineOntology({
id: 'acme-payments',
// ... objectTypes, bindings, etc.
aliases: [
// "Debtor" in pacs.008 outgoing payments → the canonical Counterparty object type
defineAlias({
alias: 'Debtor',
objectTypeSlug: 'Counterparty',
contextSelector: {
standard: 'ISO20022',
messageType: 'pacs.008',
direction: 'outgoing',
},
confidence: 0.97,
}),
// "Beneficiary" in pacs.008 outgoing payments → also Counterparty (different role, same type)
defineAlias({
alias: 'Beneficiary',
objectTypeSlug: 'Counterparty',
contextSelector: {
standard: 'ISO20022',
messageType: 'pacs.008',
direction: 'outgoing',
},
confidence: 0.95,
}),
// "Client" in a CRM context → Counterparty (context-free fallback, lowest rank)
defineAlias({
alias: 'Client',
objectTypeSlug: 'Counterparty',
// no contextSelector = context-free fallback
confidence: 0.75,
}),
// Property alias: "amount_cents" in outgoing pacs.008 → the monetary_amount property
defineAlias({
alias: 'amount_cents',
objectTypeSlug: 'Counterparty',
propertyTypeSlug: 'monetary_amount',
contextSelector: {
standard: 'ISO20022',
messageType: 'pacs.008',
direction: 'outgoing',
},
confidence: 0.99,
}),
],
})Référence des champs de ConceptAlias
| Champ | Type | Remarques |
|---|---|---|
alias | string | Le terme local ou source (par ex. "Debtor", "Client", "Obligor"). |
objectTypeSlug | Slug | Le type d'objet canonique vers lequel cet alias est résolu. Requis. |
propertyTypeSlug | Slug | Lorsqu'il est défini, l'alias cible une propriété spécifique du type d'objet plutôt que le type lui-même. |
contextSelector | object | Un sous-ensemble de clés de contexte qui doivent correspondre pour que cet alias s'applique. Omettez-le pour créer un repli sans contexte (priorité de résolution la plus basse). |
contextSelector.sourceSystem | string | Correspondance par slug de système source. |
contextSelector.standard | string | Correspondance par norme de message (par ex. "ISO20022"). |
contextSelector.messageType | string | Correspondance par type de message (par ex. "pacs.008"). |
contextSelector.direction | string | Correspondance par sens ("inbound" / "outgoing"). |
contextSelector.jurisdiction | string | Correspondance par code de juridiction. |
contextSelector.businessProcess | string | Correspondance par slug de processus métier. |
confidence | number (0–1) | Niveau de confiance dans l'exactitude de cet alias dans le contexte donné. Les candidats sont classés d'abord par spécificité du contexte, puis par niveau de confiance. |
Priorité de résolution : les alias dont le contextSelector correspond à davantage de clés du contexte de la requête sont classés au-dessus des correspondances plus lâches. Un alias sans contexte (sans contextSelector) est toujours le repli de plus basse priorité.
dataContract — contrat amont applicable
Un contrat de données documente le SLA et les attentes de qualité entre une liaison et sa source amont. Il est stocké sur la liaison et exposé dans les outils de gouvernance.
defineBinding({
objectTypeSlug: 'Payment',
kind: 'silver_table',
source: { table: 'silver_payments_outgoing' },
identitySpec: { keys: ['msg_id'] },
columnMap: { monetary_amount: 'amount_cents' },
dataContract: {
version: '1.0.0',
owner: 'data-platform@example.com',
requiredConcepts: ['monetary_amount', 'value_date', 'counterparty_lei'],
qualityRules: [
{ kind: 'not_null', on: 'counterparty_lei' },
{ kind: 'range', on: 'monetary_amount', min: 0 },
],
sla: { freshnessMinutes: 60 },
lineage: { upstream: 'core_banking_x.payments.outgoing' },
},
})| Champ | Type | Remarques |
|---|---|---|
version | semver | Version du contrat — incrémentez-la lorsque le SLA ou les concepts requis changent. |
owner | string | Contact ou équipe responsable de ce contrat. |
requiredConcepts | string[] | Slugs de propriétés qui doivent être projetées non nulles pour qu'une ligne satisfasse le contrat. |
qualityRules | array | Chaque règle possède un kind ("not_null", "range", "regex", etc.) et un champ on nommant le slug de propriété. Des champs supplémentaires propres à la règle sont autorisés. |
sla.freshnessMinutes | number | Âge maximal acceptable de la ligne la plus récente, en minutes. |
lineage.upstream | string | Identifiant de la table ou du flux source amont (libre, à des fins de documentation et d'audit). |
sourceRef | string | Pointeur de compatibilité future vers une définition defineDataSource(). Lorsque le travail de la plateforme sur les sources de données déclaratives aura abouti, la liaison pourra dériver automatiquement son contrat de la définition de la source de données. |
Provenance lors des lectures
Lorsque vos liaisons incluent bindingContext et transformMap, chaque instance projetée porte une enveloppe provenance à côté de ses propriétés :
{
"id": "payment-abc123",
"properties": {
"monetary_amount": 1234.56,
"value_date": "2025-04-15T00:00:00Z",
"counterparty_lei": "213800ZOHLGEF2K5DX57"
},
"provenance": {
"bindingId": "...",
"bindingVersion": 3,
"sourceRef": "silver_payments_outgoing",
"materializedAt": "2025-04-15T08:12:00Z",
"confidence": 0.96,
"bindingContext": {
"sourceSystem": "core_banking_x",
"standard": "ISO20022",
"messageType": "pacs.008",
"direction": "outgoing",
"jurisdiction": "BE"
},
"lossyProperties": ["value_date", "counterparty_lei"],
"dlpLabels": []
}
}lossyProperties liste les slugs de toutes les propriétés dont la transformation a été marquée lossless: false ou dont la transformation était inconnue (échec en mode fermé vers null). Les appelants qui doivent se fier à une valeur peuvent vérifier si elle apparaît dans lossyProperties avant d'agir.
Lorsque deux systèmes sources projettent des instances du même type canonique et divergent sur une valeur, les deux instances sont renvoyées avec leur provenance respective — la plateforme ne choisit pas silencieusement un gagnant. Si vous souhaitez une politique de survivance, configurez identityRule.survivorship: "highest_confidence" sur le type d'objet ; cette option est à activer explicitement et utilise les valeurs confidence de l'enveloppe de provenance.
Exemple complet
Une extension d'ontologie de paiement qui utilise tout ce qui précède :
import {
defineOntology,
defineObjectType,
defineProperty,
defineBinding,
defineIdentityRule,
defineAlias,
} from '@scrydon/sdk-authoring/ontologies'
export default defineOntology({
id: 'acme-iso20022-payments',
version: '1.0.0',
displayName: 'ISO 20022 Payments',
description: 'Payment ontology grounded in ISO 20022 pacs.008 — context-aware bindings from two core-banking feeds.',
maturity: 'preview',
author: { name: 'Acme Data Platform Team' },
objectTypes: [
defineObjectType({
slug: 'Counterparty',
displayName: 'Counterparty',
kind: 'analytical',
anchors: [
{ standard: 'FIBO', conceptId: 'fibo-fbc-fct-fse:Counterparty', label: 'Counterparty' },
{ standard: 'ISO20022', conceptId: 'pacs.008.Cdtr', label: 'Creditor' },
],
properties: [
defineProperty({ slug: 'name', displayName: 'Legal name', scalarType: 'string', cardinality: 'required' }),
defineProperty({ slug: 'lei', displayName: 'LEI', scalarType: 'string', anchors: [
{ standard: 'LEI', conceptId: 'gleif:LEI', label: 'Legal Entity Identifier' },
]}),
],
}),
defineObjectType({
slug: 'Payment',
displayName: 'Payment',
kind: 'analytical',
anchors: [
{ standard: 'ISO20022', conceptId: 'pacs.008.CreditTransfer', label: 'Credit Transfer Initiation' },
{ standard: 'FINOS_CDM', conceptId: 'rosetta:Transfer', label: 'Transfer' },
],
properties: [
defineProperty({ slug: 'monetary_amount', displayName: 'Monetary amount', scalarType: 'float', cardinality: 'required',
anchors: [{ standard: 'ISO20022', conceptId: 'Pacs.008.IntrBkSttlmAmt', label: 'Interbank Settlement Amount' }],
}),
defineProperty({ slug: 'value_date', displayName: 'Value date', scalarType: 'date',
anchors: [{ standard: 'ISO20022', conceptId: 'Pacs.008.IntrBkSttlmDt', label: 'Settlement Date' }],
}),
defineProperty({ slug: 'currency', displayName: 'Currency', scalarType: 'string' }),
],
}),
],
linkTypes: [],
actionTypes: [],
identityRules: [
defineIdentityRule({
objectTypeSlug: 'Payment',
deterministicKeys: ['msg_id'],
}),
defineIdentityRule({
objectTypeSlug: 'Counterparty',
deterministicKeys: ['lei'],
probabilistic: {
blockingKeys: ['name'],
signals: [{ name: 'name_levenshtein', weight: 0.8, on: 'name' }],
thresholds: { auto: 0.92, review: 0.75 },
},
}),
],
bindings: [
// Binding A — core banking X (ISO 20022 pacs.008, outgoing, Belgium)
defineBinding({
objectTypeSlug: 'Payment',
kind: 'silver_table',
source: { table: 'silver_payments_cbx_out' },
identitySpec: { keys: ['msg_id'] },
columnMap: { currency: 'ccy' },
bindingContext: {
sourceSystem: 'core_banking_x',
extensionVersion: '3.2',
standard: 'ISO20022',
messageType: 'pacs.008',
direction: 'outgoing',
jurisdiction: 'BE',
dataResidency: 'eu',
businessProcess: 'credit_transfer',
timestampSemantics: 'value_date',
currencySemantics: 'transaction_currency',
confidence: 0.96,
validFrom: '2025-01-01',
},
transformMap: {
monetary_amount: {
source: 'amount_cents',
transform: 'divide_by_100',
unit: 'EUR',
lossless: true,
},
value_date: {
source: 'trade_ts_local',
transform: 'timezone_normalize',
tz: 'Europe/Brussels',
lossless: false,
notes: 'DST ambiguity on clock-change dates',
},
},
dataContract: {
version: '1.0.0',
owner: 'data-platform@acme.example',
requiredConcepts: ['monetary_amount', 'value_date', 'currency'],
qualityRules: [
{ kind: 'not_null', on: 'currency' },
{ kind: 'range', on: 'monetary_amount', min: 0 },
],
sla: { freshnessMinutes: 60 },
lineage: { upstream: 'core_banking_x.payments.outgoing' },
},
}),
],
aliases: [
defineAlias({
alias: 'Debtor',
objectTypeSlug: 'Counterparty',
contextSelector: { standard: 'ISO20022', messageType: 'pacs.008', direction: 'outgoing' },
confidence: 0.97,
}),
defineAlias({
alias: 'Beneficiary',
objectTypeSlug: 'Counterparty',
contextSelector: { standard: 'ISO20022', messageType: 'pacs.008', direction: 'outgoing' },
confidence: 0.95,
}),
defineAlias({
alias: 'Client',
objectTypeSlug: 'Counterparty',
confidence: 0.75,
}),
],
})Essayez-le — l'extension d'exemple Contextual Payments
Tout ce qui figure dans ce guide est livré sous la forme d'une seule extension téléchargeable que vous pouvez installer et parcourir. L'exemple Contextual Payments archive exactement cette ontologie ISO 20022 ainsi que ses propres données de démonstration (deux sources de données déclaratives) ; ainsi, après l'installation — sans aucun upload de CSV — vous pouvez observer la liaison se résoudre automatiquement, inspecter les transformations et le niveau de confiance, et résoudre "Counterparty" vers un concept différent selon le sens dans l'onglet Aliases de l'atelier.
Pour aller plus loin
Téléchargez l'extension, installez-la et parcourez chaque champ sur des données réelles.
Guide de base — types d'objets, types de liens, types d'actions, règles d'identité et liaisons simples.
Sources de données déclaratives par interrogation que vous pouvez livrer avec des liaisons dans une extension.