Ontologies
Créer des packs d'ontologie — types d'objets, types de liens, types d'actions, règles d'identité et liaisons
Cet artefact est distribué dans un Pack. Pour le cycle de vie partagé — installation, pack build, upload — voir Packs & SDK d'authoring.
Une Ontologie est le système de types sur lequel votre tenant fonctionne : Customer, Asset, Risk, Incident, les relations entre eux (owns, affects, mitigates), et les actions typées que vous pouvez effectuer sur eux (AssignAsset, AssessRisk). Le SDK d'authoring vous permet de distribuer cela sous forme d'un pack d'ontologie versionné et validé.
Une ontologie est le système de types. Une base de connaissances est le contenu qui l'utilise. Ce sont des choses différentes — une ontologie, de nombreuses bases de connaissances. Plusieurs ontologies peuvent coexister dans un même tenant (par défaut + par domaine + importé via pack).
Installation
bun add -d @scrydon/sdk-authoring zodnpm install --save-dev @scrydon/sdk-authoring zodimport {
defineOntology,
defineObjectType,
defineLinkType,
defineActionType,
defineIdentityRule,
defineBinding,
defineProperty,
} from '@scrydon/sdk-authoring/ontologies'Ce que contient un pack
| Élément | Rôle |
|---|---|
| Object Type | Une entité typée — Customer, Asset, RiskFinding. A des properties, un kind (analytical / transactional / binding_only). |
| Link Type | Une relation typée — affects(RiskFinding → Customer). Cardinalité + nom de traversée inverse optionnel. |
| Action Type | Une mutation côté serveur contrôlée par OPA. Porte un schéma d'entrée Zod et un descripteur d'effet secondaire (object_edit / link_edit / outbox / webhook). |
| Identity Rule | Comment les instances sont dédupliquées. Clés de correspondance déterministes, ER probabiliste optionnel (signaux + seuils). |
| Binding | Relie une source en amont (silver_table, memex_page, process_flow_task, process_flow_action, extraction, stream, manual) à des instances d'objet ou de lien typées. |
Un exemple complet
import {
defineOntology,
defineObjectType,
defineLinkType,
defineActionType,
defineIdentityRule,
defineProperty,
} from '@scrydon/sdk-authoring/ontologies'
import { z } from 'zod'
export default defineOntology({
id: 'acme-crm',
version: '1.0.0',
displayName: 'ACME CRM',
description: 'Salesforce-style CRM ontology',
maturity: 'preview',
author: { name: 'Acme Inc.' },
objectTypes: [
defineObjectType({
slug: 'Account',
displayName: 'Account',
kind: 'transactional',
properties: [
defineProperty({
slug: 'name',
displayName: 'Legal name',
scalarType: 'string',
cardinality: 'required',
}),
defineProperty({
slug: 'jurisdiction',
displayName: 'Jurisdiction',
scalarType: 'string',
classification: 'internal',
}),
defineProperty({
slug: 'riskTier',
displayName: 'Risk tier',
scalarType: 'string',
piiFlags: ['regulatory'],
}),
],
}),
defineObjectType({
slug: 'Asset',
displayName: 'Asset',
kind: 'transactional',
properties: [
defineProperty({ slug: 'name', displayName: 'Name', scalarType: 'string' }),
defineProperty({ slug: 'value', displayName: 'Value', scalarType: 'float' }),
],
}),
],
linkTypes: [
defineLinkType({
slug: 'owns',
displayName: 'Owns',
sourceTypes: ['Account'],
targetTypes: ['Asset'],
cardinality: '1-N',
reverseName: 'ownedBy',
}),
],
actionTypes: [
defineActionType({
slug: 'AssignAsset',
displayName: 'Assign asset to account',
subjectTypeSlug: 'Asset',
inputZod: z.object({ accountId: z.string().uuid() }),
sideEffectDescriptor: { kind: 'link_edit' },
}),
],
identityRules: [
defineIdentityRule({
objectTypeSlug: 'Account',
deterministicKeys: ['name', 'jurisdiction'],
}),
],
bindings: [],
})Modèle de propriété
| Champ | Notes |
|---|---|
scalarType | L'un de string, int, float, bool, uuid, timestamp, date, json, bytes |
cardinality | required, optional ou many |
classification | public, internal, confidential, restricted — alimente le DLP et le RBAC |
piiFlags | Tags libres exposés à la rédaction DLP au moment de la récupération |
Types de kinds d'Object Type
analytical— faits en masse, lecture intensive. Supporté par une liaisonsilver_table.transactional— entités modifiables (saisie manuelle, sortie de process-flow). Natif Postgres.binding_only— projection en lecture seule uniquement (ex.memex_page,extraction). Jamais directement modifié.
Liaisons — les sept kinds
| Kind | Relie |
|---|---|
silver_table | Une table analytique bronze/silver → un type d'objet |
memex_page | Un nœud de contenu KB Memex (correspondance slug/alias) → une instance d'objet |
process_flow_task | Une ligne process_instance_task → une instance d'objet typée |
process_flow_action | Un process_instance_task_action de actionType=entity_link → une instance de lien typée |
extraction | Le pipeline d'extraction analytics 5-WF → une instance d'objet |
stream | Une source de streaming (Kafka, webhook fanout) → une instance d'objet |
manual | Saisie directe dans le workbench → une instance d'objet |
defineBinding({
objectTypeSlug: 'Account',
kind: 'silver_table',
source: { table: 'silver_account' },
identitySpec: { keys: ['external_id'] },
columnMap: { name: 'legal_name', jurisdiction: 'country_code' },
})Réduction en entités — identitySpec.entityColumns
Les sources riches en observations (trajectoires de position, relevés de
capteurs, événements de journal) comptent souvent des millions de lignes pour
quelques milliers d'objets réels. Déclarer entityColumns — un sous-ensemble
strict de identityColumns désignant l'entité persistante observée — indique
au graphe d'afficher un nœud par entité avec un décompte exact
d'observations, au lieu d'un nœud par ligne :
defineBinding({
objectTypeSlug: 'AircraftPosition',
kind: 'silver_table',
source: { table: 'adsb_positions' },
identitySpec: {
identityColumns: ['icao24', 'seenAt'], // une observation (relevé de position)
entityColumns: ['icao24'], // l'objet persistant (l'aéronef)
},
columnMap: { icao24: 'icao24', seenAt: 'seenAt', latitude: 'lat', longitude: 'lon' },
})Effets sur la page graphe :
- Un nœud par aéronef, étiqueté avec un décompte exact
N observationscalculé au moment de la lecture sous vos permissions — jamais un échantillon présenté comme la donnée. - Les jointures de relations sur des colonnes de niveau entité (p. ex.
icao24) se connectent au niveau entité. - Chaque réponse du graphe rapporte
affichés / totalpar type ; tout ce que le budget de lisibilité masque est représenté par un nœud agrégé portant le reste exact. - La vue d'ensemble affiche le tissu connecté : les instances participant à au moins une relation. Les instances sans relation calculée ne sont pas éparpillées sur le canevas en points isolés — elles sont repliées dans le nœud agrégé de leur type (avec le décompte exact) et restent consultables via l'expansion de type et la recherche. Une ontologie sans aucune relation calculable retombe sur un échantillon par type afin que la page reste navigable.
- Les nœuds agrégés s'étendent au clic : chaque clic amène une page bornée des membres du type sur le canevas (rattachés autour de l'agrégat) et le décompte restant décroît exactement ; quand il ne reste rien, l'agrégat disparaît.
- Étendre les voisins montre d'abord ce qui est connecté — les voisins groupés par relation et type cible avec leurs décomptes — pour ajouter les groupes pertinents au lieu d'inonder la disposition.
- La vue Carte (bascule en bas de la page graphe) affiche les types portant des coordonnées sous forme de cellules avec des décomptes exacts en vue, selon vos permissions. Le zoom subdivise les cellules ; quand le total en vue d'un type est assez petit, les instances réelles s'affichent à la place. Les listes de cellules tronquées sont étiquetées comme bornes inférieures — jamais présentées comme des nombres définitifs.
- Les relations s'affichent aussi sur la vue Carte : les types de liens de référence avec une règle de jointure explicite tracent des arcs entre cellules, chacun portant le nombre exact de paires liées entre ces deux zones (survolez pour le voir) ; les liens de proximité tracent de fins connecteurs entre les instances actuellement affichées, et la vue précise qu'ils ne couvrent que les instances affichées — zoomez pour matérialiser le reste. Chaque type de lien rapporte son total de paires en vue aux côtés des totaux par type.
Validation : entityColumns doit être un sous-ensemble strict non vide de
identityColumns (les ensembles égaux sont rejetés — omettez entityColumns
dans ce cas). L'installation de pack rejette les manifestes qui violent cette
règle.
Visualisation du graphe
Les packs denses peuvent inclure des indications optionnelles de visualisation de graphe. Ces indications ne modifient pas le schéma d'ontologie ; elles indiquent aux surfaces de graphe comment restituer efficacement une vue d'instance.
Utilisez mode: 'compact' quand un pack a un type d'objet racine de haute valeur et de nombreuses liaisons enfant de haute cardinalité. Le point de terminaison du graphe ne projette que la liaison racine, affiche des nœuds agrégés par instance racine, et ignore la projection de lignes pour les liaisons d'objet et de lien réduites.
defineOntology({
id: 'acme-docs',
version: '1.0.0',
displayName: 'ACME Documents',
description: 'Document intelligence ontology',
maturity: 'preview',
author: { name: 'Acme Inc.' },
visualization: {
graph: {
mode: 'compact',
rootObjectType: 'DocumentCorpus',
rootLimit: 100,
rootGroup: {
slug: 'DocumentCorpusIndex',
label: 'All document corpora',
edgeLabel: 'contains corpus',
},
collapsedObjectTypes: ['Document', 'DocumentSection', 'ExtractedEntity'],
collapsedLinkTypes: ['ContainsDocument', 'MentionsEntity'],
aggregates: [
{
slug: 'Document',
label: 'Documents',
linkSlug: 'ContainsDocument',
edgeLabel: 'contains documents',
countObjectTypes: ['Document'],
},
{
slug: 'ExtractedEntity',
label: 'Extracted entities',
linkSlug: 'MentionsEntity',
edgeLabel: 'mentions entities',
countObjectTypes: ['ExtractedEntity'],
countLinkTypes: ['MentionsEntity'],
},
],
},
},
objectTypes: [],
linkTypes: [],
actionTypes: [],
identityRules: [],
bindings: [],
})Règles d'identité — déterministes + probabilistes
Les règles d'identité indiquent à la plateforme comment fusionner les instances. Le chemin déterministe est obligatoire ; le chemin probabiliste est optionnel pour les sources plus floues.
defineIdentityRule({
objectTypeSlug: 'Account',
deterministicKeys: ['external_id', 'name + jurisdiction'],
probabilistic: {
blockingKeys: ['name'],
signals: [
{ name: 'name_levenshtein', weight: 0.6, on: 'name' },
{ name: 'jurisdiction_match', weight: 0.4, on: 'jurisdiction' },
],
thresholds: { auto: 0.85, review: 0.70 },
},
})Types d'actions — mutations côté serveur contrôlées par la façade
Les types d'actions sont le seul chemin d'écriture typé. Chaque action s'exécute de la même façon :
- Validation Zod de l'entrée contre
inputZod. - Le service propriétaire de l'action résout la cible réelle et consomme une décision unique de la façade d'autorisation. OPA peut évaluer l'exigence Rego comme adaptateur privé ; le code de l'action ne l'appelle pas directement.
- Le descripteur d'effet secondaire décide de ce qui s'exécute — édition directe d'objet/lien, dispatch d'outbox, ou webhook.
- Une preuve d'autorisation durable est écrite avec la provenance des adaptateurs applicables, notamment
bundleHashetpolicy_execution_grant.grantIdlorsqu'ils sont présents.
sideEffectDescriptor.kind | Ce qui se passe |
|---|---|
object_edit | Upsert dans le store transactionnel du type d'objet |
link_edit | Upsert dans le store d'arêtes du type de lien |
outbox | Mise en file d'attente d'un événement d'outbox transactionnel |
webhook | Déclenchement d'un webhook configuré (URL dans config) |
Maturité
Choisissez-en une — affichée comme un badge dans le workbench :
verified— prêt pour la production, possédé et maintenupreview— fonctionnellement complet, peut évoluerexperimental— accès anticipé, s'attendre à des changements cassants
Validation
Le pack est validé contre OntologyManifestSchema (Zod) au moment du build et à nouveau côté serveur au moment du téléversement. Échecs courants :
| Erreur | Cause |
|---|---|
id must be lowercase kebab-case | L'id du Pack doit correspondre à /^[a-z][a-z0-9-]*$/ |
Slug must start with a letter, alnum + _ - | Le slug d'objet/lien/action/propriété a échoué le regex |
Must be a valid semver string | version n'est pas semver |
linkType source/target slug not found | sourceTypes / targetTypes référencent un slug de type d'objet inconnu |
expected array to have exactly 1 item | Chaque extrémité concrète sourceTypes / targetTypes doit contenir exactement un slug de type d'objet ; utilisez "*" uniquement pour un lien de compatibilité générique |
Empaquetés via le pipeline de bundle d'intégration (aujourd'hui)
Les packs d'ontologie sont distribués dans un bundle d'intégration via definePackOntology — la couche de registre dispatche les packs de la même façon qu'elle dispatche les vendeurs. Un CLI autonome scrydon-ontologies est prévu ; en attendant, suivez le flux de build Intégrations avec un export definePackOntology(...) de niveau supérieur.
import { definePackOntology } from '@scrydon/sdk-authoring/integrations/define'
import myCrmOntology from './crm.ontology'
export default definePackOntology({
id: 'acme-crm',
version: '1.0.0',
displayName: 'ACME CRM',
description: 'Salesforce-style CRM ontology',
maturity: 'preview',
author: { name: 'Acme Inc.' },
objectTypes: myCrmOntology.objectTypes,
linkTypes: myCrmOntology.linkTypes,
actionTypes: myCrmOntology.actionTypes,
bindings: myCrmOntology.bindings,
identityRules: myCrmOntology.identityRules,
})