Règles de surveillance
Déclarez des détections de motifs comportementaux dans votre extension d'ontologie — évaluez les regroupements de rôles par rapport aux poids de signature, supprimez les re-déclenchements et déclenchez optionnellement un flux de processus de réponse lors d'une détection.
Les règles de surveillance sont créées dans une extension d'ontologie aux côtés de vos Types d'objets, Types de liens et Liaisons. Pour le cycle de vie de l'extension — extension build, téléchargement, installation — consultez Extensions et SDK d'authoring. Pour le moteur de détection et la propagation des détections déclenchées, consultez la documentation Ontologie.
Une règle de surveillance surveille en continu les observations de l’ontologie et émet des détections gouvernées. Les règles à signature évaluent la composition des rôles ; les règles report_gap détectent les entités qui ont cessé de transmettre ; les règles zone détectent les épisodes en zone réglementée. Vous déclarez la règle en code, versionnée avec le reste de votre extension.
Déclarer une règle de surveillance
Ajoutez un tableau watchRules à votre appel defineOntology :
import { defineOntology } from '@scrydon/sdk-authoring/ontologies'
export default defineOntology({
id: 'c2-threat-awareness',
version: '1.0.0',
displayName: 'C2 Threat Awareness',
// ... object types, link types, bindings ...
watchRules: [
{
slug: 'kaliningrad-air-buildup',
displayName: 'Kaliningrad — allied air build-up',
description: 'Detects a concentration of ELECTRONIC_WARFARE, AEW, and FIGHTER airframes near the Kaliningrad approaches.',
target: {
objectTypeSlug: 'Aircraft',
entityProperty: 'icao24', // collapse positional fixes → airframes
timeProperty: 'seenAt',
latProperty: 'latitude',
lngProperty: 'longitude',
roleVia: { linkTypeSlug: 'AircraftOfType', property: 'missionRole' },
},
area: { objectTypeSlug: 'AreaOfInterest', areaId: 'kaliningrad-approaches' },
windowSeconds: 900, // 15-minute rolling window
signature: {
weights: { ELECTRONIC_WARFARE: 5, AEW: 4, FIGHTER: 1 },
roleSaturation: 2, // cap each role's contribution at 2 entities
},
threshold: {
minDistinctRoles: 2,
minScore: 10,
},
suppression: {
cooldownSeconds: 3600, // suppress re-fires for 1 hour
refireOnNewRole: true, // unless a new role appears
refireOnScoreDelta: 4, // or the score changes by more than 4
},
emit: {
objectTypeSlug: 'BuildUpDetection',
clearanceCeiling: { schemeId: 'default', rank: 2 },
},
},
],
})Référence des champs
Champs de niveau supérieur
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
slug | string | Oui | Identifiant stable de cette règle. Doit être un slug valide (lettres minuscules, chiffres et tirets ; pas d'espaces). Utilisé comme nom de la déclaration SCHEMA_WATCH émise. |
displayName | string (1–100 car.) | Oui | Nom lisible affiché dans l'interface de la plateforme. |
description | string (≤500 car.) | Non | Description optionnelle plus longue de ce que cette surveillance détecte. |
enabled | boolean | Non | Indique si la surveillance est active. Par défaut true si omis. Passez à false pour distribuer une surveillance désactivée qui pourra être activée sans republication de l'extension. |
target | objet | Oui | Définit quel Type d'objet observer et comment résoudre l'identité des entités et leurs rôles. Voir target ci-dessous. |
area | objet | Oui | Identifie l'instance AreaOfInterest qui définit la limite spatiale. |
windowSeconds | integer (1–3600) | Oui | Fenêtre temporelle glissante en secondes (max 3600 — 1 heure). |
signature | objet | Oui | Poids des rôles et plafond de saturation. Voir signature ci-dessous. |
threshold | objet | Oui | Conditions devant être réunies simultanément pour déclencher une détection. Voir threshold ci-dessous. |
suppression | objet | Oui | Contrôle du re-déclenchement. Voir suppression ci-dessous. |
emit | objet | Oui | Type d'objet de sortie et plafond de classification pour la détection. Voir emit ci-dessous. |
dispatch | objet | Non | Flux de processus optionnel à démarrer lors d'une détection. Voir dispatch ci-dessous. |
target
| Champ | Type | Description |
|---|---|---|
objectTypeSlug | string | Le Type d'objet dont les observations sont notées. |
entityProperty | string | Propriété identifiant l'entité persistante (ex. icao24). Les observations partageant cette valeur sont regroupées en un seul comptage d'entité. |
timeProperty | string | Propriété d'horodatage utilisée pour appliquer la fenêtre glissante. |
latProperty | string | Propriété de latitude (degrés décimaux WGS-84). |
lngProperty | string | Propriété de longitude (degrés décimaux WGS-84). |
roleVia | { linkTypeSlug, property } | Traverser ce type de lien et lire cette propriété pour déterminer le rôle de l'entité à des fins de notation. |
roleOverrideObjectTypeSlug | string? | Si défini, restreint la résolution des rôles aux entités de ce Type d'objet à l'extrémité distante du lien. |
area
Une instance AreaOfInterest chargée depuis le graphe ontologique, définissant la limite spatiale pour la surveillance. Les observations hors de la zone sont exclues de la notation.
windowSeconds
Fenêtre temporelle glissante en secondes. Le maximum est 3600 (1 heure). Les observations plus anciennes que windowSeconds sortent du score.
signature
| Champ | Type | Description |
|---|---|---|
weights | Record<string, number> | Contribution au score par rôle. Les clés doivent être des valeurs de rôles présentes dans le Type d'objet lié. Les valeurs doivent être ≥ 0 et finies. |
roleSaturation | number | Nombre maximal d'entités par rôle contribuant au score. Empêche une vague d'un seul rôle de masquer une composition multi-rôles. |
threshold
| Champ | Type | Description |
|---|---|---|
minDistinctRoles | number | Nombre minimum de rôles distincts devant être présents avant le déclenchement de la détection. |
minScore | number | Score pondéré minimum devant être atteint. |
Les deux conditions doivent être satisfaites simultanément pour déclencher la détection. Une détection exige aussi au moins un contact dans la zone et la fenêtre : avec les deux seuils à 0, une zone vide ne déclenche rien, car une détection doit enregistrer les contacts dont elle est dérivée.
suppression
| Champ | Type | Description |
|---|---|---|
cooldownSeconds | number | Après qu'une détection se déclenche, supprime les re-déclenchements pendant ce nombre de secondes (max 86 400 — 24 h). |
refireOnNewRole | boolean | Lorsque true (par défaut), un nouveau rôle entrant dans la fenêtre contourne le délai et déclenche une nouvelle détection. |
refireOnScoreDelta | number | Lorsque le score change d'au moins cette valeur, une nouvelle détection se déclenche même dans la fenêtre de délai. Doit être positif. |
emit
Une surveillance dont le clearanceCeiling dépasse le rang 0 ne s'exécute qu'une fois qu'un administrateur a sélectionné un compte d'exécution des surveillances.
| Champ | Type | Description |
|---|---|---|
objectTypeSlug | string | Le Type d'objet à matérialiser pour chaque détection déclenchée. |
severity | low, medium, high ou critical | Gravité facultative affichée aux opérateurs, déclarée par la règle et inscrite dans chaque détection. Les anciennes règles l'omettent ; aucune gravité n'est déduite des preuves ou du carnet. |
clearanceCeiling | { schemeId, rank } | Obligatoire. Plafonne la classification de l'objet de détection émis. L'évaluateur lit également à ce plafond : les observations classifiées au-dessus ne sont jamais lues et ne peuvent pas contribuer, et la classification de chaque détection est la borne supérieure des preuves qu'elle cite — définir ce plafond explicitement est donc une exigence stricte (sécurité par défaut). schemeId: 'default' désigne le schéma de classification actif de l'organisation qui installe l'extension ; une même extension fonctionne ainsi dans toutes les organisations. |
dispatch (optionnel)
dispatch: {
extensionId: 'c2-drone-response',
processFlowSlug: 'buildup-response',
}Lorsque présent, une détection déclenchée démarre le flux de processus nommé en plus d'émettre l'objet de détection. Le flux reçoit uniquement un pointeur detectionId — aucun contenu de détection n'est transmis directement.
Note de classification. Le flux distribué résout la détection sous la classification de ses propres principals via le chemin de lecture gouverné normal. Il ne peut pas accéder à plus de la détection que ce que les principals qui l'exécutent sont autorisés à voir. Le flux n'est démarré que si l'identité sous laquelle la surveillance s'exécute (le compte d'exécution choisi pour les surveillances, ou l'acteur système) est habilitée pour le marquage de la détection ; sinon la réponse est refusée et enregistrée comme échouée. Une fois démarrée, l'instance porte le nom du slug de la surveillance, et quiconque peut la voir apprend que la surveillance s'est déclenchée — voir Notifications.
| Champ | Type | Contraintes |
|---|---|---|
extensionId | string | 1–256 caractères. Doit identifier l'extension qui publie le flux de processus cible. |
processFlowSlug | string | 1–256 caractères. Slug du flux de processus à démarrer lors d'une détection. |
Les deux champs sont des identifiants exacts — pas de wildcards ni de motifs.
Compte d'exécution des surveillances
Les surveillances planifiées lisent les données de l'ontologie sous une identité, et une surveillance ne lit que ce que cette identité est habilitée à voir. Par défaut, cette identité est celle de la plateforme, habilitée aux seules données publiques (rang 0). Une surveillance dont le clearanceCeiling dépasse le rang 0, comme l'exemple de rang 2 ci-dessus, ne s'exécute donc pas tant qu'un administrateur de l'organisation n'a pas sélectionné un compte d'exécution des surveillances pour son environnement d'espace de travail : un compte de service doté d'une habilitation d'exécution, sous lequel la surveillance lit alors.
Sur Paramètres → Organisation → Membres, ouvrez l'onglet Comptes de service. Compte d’exécution des surveillances se trouve en haut de l'onglet ; seuls les propriétaires et administrateurs de l'organisation le voient.
Choisissez l'Environnement de l’espace de travail dont les surveillances doivent s'exécuter sous ce compte.
Choisissez le Compte de service et enregistrez. La liste n'affiche que les comptes capables de s'y exécuter : actifs, disposant de tables:read (ou tables:write), dotés d'une habilitation d'exécution, et dont l'accès aux espaces de travail et à l'environnement couvre cet environnement. Une fois un compte choisi, le sélecteur indique le rang au-dessus duquel les surveillances sont ignorées.
La sélection vaut par environnement d'espace de travail et s'applique à chaque exécution planifiée :
| Sélection | Ce qui s'exécute |
|---|---|
| Aucune | Les surveillances dont le plafond est le rang 0 s'exécutent sous l'identité de la plateforme. Toutes les autres sont ignorées. |
| Un compte | Toutes les surveillances de l'environnement s'exécutent sous ce compte. Une surveillance dont le plafond dépasse le rang d'habilitation du compte est ignorée ; elle n'est jamais évaluée en dessous de son plafond. |
| Un compte qui ne remplit plus les conditions (désactivé, supprimé, ou dont l'accès ou les portées ont changé) | Aucune surveillance de l'environnement ne s'exécute, et aucune ne se replie sur l'identité de la plateforme. Le sélecteur affiche le choix enregistré comme Compte indisponible ; sélectionnez un autre compte ou retirez la sélection. |
Une surveillance ignorée n'est pas silencieuse : la plateforme consigne un avertissement, ontology watches skipped because sweep clearance is too low, qui désigne l'organisation, l'environnement et les surveillances ignorées. Elle le consigne la première fois qu'elle voit l'ensemble ignoré et chaque fois que cet ensemble change, puis le répète au plus une fois par heure tant que les mêmes surveillances restent ignorées. Lorsque les surveillances ne sont plus ignorées, parce qu'un compte a été sélectionné ou que la surveillance a été supprimée, elle consigne une seule ligne d'information, ontology watches are no longer skipped for sweep clearance.
La sélection comme son usage sont consignés dans le journal d'audit de l'organisation :
- L'enregistrement d'une sélection consigne
ontology.watch.execution_accounts.updated, avec l'administrateur qui l'a enregistrée et les sélections avant et après. - Chaque jeton qu'une exécution planifiée émet pour le compte consigne
service_account.token.issued, ouservice_account.token.refusedlorsque le compte ne remplit plus les conditions. L'entrée désigne comme initiateur l'administrateur qui a enregistré les sélections en dernier ; si cet enregistrement portait sur un autre environnement, les entréesontology.watch.execution_accounts.updatedmontrent qui a choisi celui-ci. Le jeton lui-même n'est jamais consigné. - Si le journal d'audit ne peut pas consigner une émission, aucun jeton n'est émis, et les surveillances de cet environnement ne s'exécutent pas avant qu'une exécution planifiée ultérieure réussisse.
Notifications
Lorsqu'une surveillance se déclenche, la plateforme notifie les propriétaires et administrateurs de l'organisation dont la classification domine à la fois le marquage de la surveillance et celui de la détection — la classification que la lecture gouvernée exige pour voir la surveillance et pour ouvrir la détection qu'elle a produite. Le marquage d'une détection est dérivé de tout ce qui a servi à la construire, il peut donc dépasser celui de la surveillance ; un membre en dessous n'est pas notifié du déclenchement de la surveillance, car ce fait est dérivé des mêmes données. Le rôle administratif détermine qui peut agir sur une détection ; il ne détermine pas qui peut apprendre qu'elle existe. Un membre dont la classification ne peut pas être établie n'est pas notifié.
La notification ne nomme pas la surveillance, car son slug identifie souvent ce qui est surveillé. Elle indique A watch fired et ne contient qu'un pointeur vers la détection ; Ouvrir la détection y conduit le destinataire dans son organisation, son espace de travail et son environnement, où la détection elle-même est lue sous sa classification.
Ce contrôle de classification ne s'applique qu'aux notifications. Lorsque la surveillance déclare dispatch, chaque détection peut aussi démarrer une instance de flux de processus portant le nom du slug de la surveillance. Elle n'est démarrée que si l'identité sous laquelle la surveillance s'exécute est habilitée pour le marquage de la détection. La visibilité d'une instance démarrée suit les accès propres au flux de processus, si bien qu'un membre non notifié peut quand même apprendre par elle que la surveillance s'est déclenchée.
Exemple complet avec dispatch
watchRules: [
{
slug: 'kaliningrad-air-buildup',
displayName: 'Kaliningrad — allied air build-up',
target: {
objectTypeSlug: 'Aircraft',
entityProperty: 'icao24',
timeProperty: 'seenAt',
latProperty: 'latitude',
lngProperty: 'longitude',
roleVia: { linkTypeSlug: 'AircraftOfType', property: 'missionRole' },
},
area: { objectTypeSlug: 'AreaOfInterest', areaId: 'kaliningrad-approaches' },
windowSeconds: 900,
signature: {
weights: { ELECTRONIC_WARFARE: 5, AEW: 4, FIGHTER: 1 },
roleSaturation: 2,
},
threshold: { minDistinctRoles: 2, minScore: 10 },
suppression: {
cooldownSeconds: 3600,
refireOnNewRole: true,
refireOnScoreDelta: 4,
},
emit: {
objectTypeSlug: 'BuildUpDetection',
clearanceCeiling: { schemeId: 'default', rank: 2 },
},
// When the detection fires, start the response flow in the c2-drone-response extension.
// The flow receives a detectionId pointer and resolves content under its own clearance.
dispatch: {
extensionId: 'c2-drone-response',
processFlowSlug: 'buildup-response',
},
},
],Garantie de stabilité
watchRules est un champ optionnel. Les extensions qui ne déclarent aucune règle de surveillance continuent de compiler et de se hacher sans modification — l'ajout de ce champ à votre version d'extension n'invalide pas les manifestes précédemment publiés.
Dans une règle de surveillance, dispatch est également optionnel. Les extensions qui déclaraient une règle de surveillance avant l'existence de dispatch continuent d'être analysées et compilées sans modification.
Rapports manquants et état du flux
Pour une règle d’absence utilisée dans une vue opérationnelle, définissez
absence.requireSourceHealth: true avec baselineSeconds et
minMissingEntities. Ce paramètre reste facultatif pour préserver les révisions
publiées existantes ; indiquez-le explicitement dans les nouvelles règles maritimes.
L’évaluateur exige alors une lecture gouvernée complète et cohérente, ainsi que
des preuves récentes du service d’ingestion. Une collecte réussie doit avoir
commencé après l’échéance de signalement du navire absent. Un flux inconnu, en
erreur, suspendu, périmé ou traité partiellement ne peut pas déclencher cette règle.
Le résultat indique source-health-unavailable si cette exigence ne peut pas être
établie. Un rapport plus récent hors de la zone signifie un départ, pas un silence.
Ces preuves sont actuellement disponibles pour les sources de collecte installées, liées à leur table gérée et à leur environnement exacts. Elles expirent deux périodes de collecte après le début de la collecte réussie. Une modification de la configuration nécessite une nouvelle collecte réussie avant de qualifier le flux. Les autres types de sources restent inconnus tant qu’ils ne fournissent pas des preuves équivalentes. Cela mesure l’activité d’ingestion, sans garantir que le fournisseur transmet toutes les observations réelles. Adaptez la cadence et les fenêtres d’absence en conséquence.
Les composants des applications publiées affichent cet état gouverné indépendamment des horodatages des pistes et de la connexion. L’animation ne rend pas une ancienne observation récente. La surveillance fonctionne indépendamment des applications ouvertes.
Absence de rapports sans rôle de mission
Utilisez kind: 'report_gap' pour un flux de navires sans répertoire de rôles de mission :
{
slug: 'north-sea-vessel-report-gap',
displayName: 'Vessel stopped reporting',
kind: 'report_gap',
target: {
objectTypeSlug: 'Track',
entityProperty: 'trackId',
timeProperty: 'observedAt',
latProperty: 'latitude',
lngProperty: 'longitude',
},
area: { objectTypeSlug: 'Zone', areaId: 'north-sea' },
windowSeconds: 900,
absence: { baselineSeconds: 3600, minMissingEntities: 1, requireSourceHealth: true },
suppression: {
cooldownSeconds: 3600,
refireOnNewRole: false,
refireOnScoreDelta: 1,
},
emit: {
objectTypeSlug: 'Detection',
clearanceCeiling: { schemeId: 'default', rank: 2 },
},
}La période de référence précède la fenêtre de rapport manquant ; baselineSeconds
doit être supérieur à windowSeconds. Un rapport plus récent, n’importe où,
signifie que l’entité transmet encore, même si elle a quitté la zone surveillée.
La détection porte la dernière position connue, le marquage de la source et
l’identifiant de l’entité, sans rôle ni poids inventés. refireOnScoreDelta
compare le nombre d’entités manquantes. Définissez refireOnNewRole sur
false, car cette règle n’a pas de rôles. L’évaluateur exige une lecture
complète de la source ; une règle MIK opérationnelle doit également exiger des
preuves récentes de l’état de la source. Un flux de pistes corrélées signale
actuellement son état comme inconnu tant que ses preuves d’achèvement du
runtime de source ne sont pas raccordées ; cette règle n’affirmera donc pas
encore qu’un navire manque dans ce flux.
Épisodes dans une zone réglementée
Utilisez kind: 'zone' pour surveiller les positions courantes sans poids de rôles de mission :
{
slug: 'restricted-north-sea',
displayName: 'Restricted North Sea area',
kind: 'zone',
target: {
objectTypeSlug: 'Track',
entityProperty: 'vesselId',
observationProperty: 'observationId',
timeProperty: 'observedAt',
latProperty: 'latitude',
lngProperty: 'longitude',
},
area: { objectTypeSlug: 'Zone', areaId: 'restricted-north-sea' },
windowSeconds: 120,
zone: { maxTransitionGapSeconds: 60, requireSourceHealth: true },
emit: {
objectTypeSlug: 'Detection',
clearanceCeiling: { schemeId: 'default', rank: 2 },
},
}Déclarez dans votre ontologie les types d’objets référencés et les liaisons de
sources gouvernées. L’objet de zone doit exposer areaId, minLatitude,
maxLatitude, minLongitude et maxLongitude. Par défaut, la règle évalue ce
rectangle. Pour évaluer exactement une zone dessinée, définissez
area.boundaryProperty sur une propriété de la zone contenant un Polygon ou un
MultiPolygon GeoJSON sous forme de texte (1 024 positions et 16 Kio au plus ;
les trous sont pris en charge) :
area: { objectTypeSlug: 'Zone', areaId: 'restricted-north-sea', boundaryProperty: 'boundary' },Une position est alors intérieure si elle se trouve dans le rectangle et dans le
polygone ; une position sur un bord est intérieure. Le polygone doit tenir dans le
rectangle, qui reste le filtre de lecture. Des bornes stockées en float simple
précision sont acceptées : un sommet qui dépasse une borne d’au plus cet arrondi
est intérieur, et le rectangle est élargi jusqu’à lui. Un polygone absent, invalide ou qui
déborde arrête la règle avec area-boundary-missing, area-boundary-invalid ou
area-boundary-outside-box au lieu de revenir au rectangle. Découpez une zone qui
traverse le méridien de 180°. boundaryProperty s’applique à tous les types de
règles.
Chaque position doit avoir un identifiant stable d’entité et d’observation, des coordonnées valides et un horodatage d’événement. Conservez les positions hors de la zone dans la source cible afin que les sorties puissent être observées.
La première observation intérieure admissible produit une présence. Une
entrée exige une position extérieure antérieure dans l’intervalle
maxTransitionGapSeconds. Les positions intérieures successives ne produisent
pas d’alertes répétées. Une sortie confirmée autorise un nouvel épisode. Les
observations périmées, futures, dupliquées ou désordonnées ne créent pas de
transition. Modifier les limites de la zone ou redessiner son polygone ne peut pas fabriquer
une entrée.
Si une source prioritaire corrige la position retenue au même horodatage, la règle
met à jour l’épisode. Une correction de l’extérieur vers l’intérieur est une
présence, car des horodatages identiques ne prouvent pas un franchissement.
Les corrections suivantes au même instant ne créent pas une nouvelle alerte.
Pour signaler aussi un stationnement (loiter), ajoutez zone.dwell avec
target.speedProperty, la propriété de la cible qui porte la vitesse fond en nœuds :
target: { /* comme ci-dessus */ speedProperty: 'speed' },
zone: { maxTransitionGapSeconds: 300, dwell: { minSeconds: 900, maxSpeedKnots: 2 } },Une détection de stationnement se déclenche lorsqu’une entité est restée dans la
zone à maxSpeedKnots au plus pendant minSeconds, compté depuis la première
position lente à l’intérieur. Une position plus rapide, une position sans vitesse,
une sortie, un intervalle entre positions supérieur à maxTransitionGapSeconds ou
une zone redessinée met fin à cette période lente ; la période lente suivante peut
de nouveau déclencher. Une période lente produit au plus une détection de
stationnement. Déclarer dwell sans speedProperty, ou l’inverse, est refusé.
Définissez requireSourceHealth: true pour les flux opérationnels. Sans preuve
récente et complète de l’état de la source, la règle attend au lieu de traiter
des données manquantes comme un mouvement confirmé. Configurez le rapport d’état
de la source avant de l’activer.
Les règles de zone omettent signature, threshold, suppression et
target.roleVia. Le type de détection expose kind (presence, entry ou loiter),
watchRevisionId, entityId, observationId, targetObjectType et evidence, en
plus des champs communs detectionId, watchSlug, areaId, firedAt,
windowSeconds, clearanceCeiling et contributorsMarking. Les preuves contiennent
une position pour la présence, la paire extérieure/intérieure ordonnée pour
l’entrée, ou la première et la dernière position lente pour le stationnement. La configuration facultative dispatch reste disponible. L’évaluation
et la reprise des envois fonctionnent indépendamment des vues d’application ouvertes.