Notebooks Marimo
Notebooks Python limités à un espace de travail et à vos tables gérées — réactifs, gouvernés, sans stack de data science séparée.
Les notebooks Marimo sont des notebooks Python qui s’exécutent dans votre cluster Scrydon, limités à un espace de travail et préconnectés à vos tables gérées. Ils sont réactifs — les cellules se réexécutent lorsque leurs entrées changent — et ils passent par la même gouvernance que tout le reste.
Ouvrir d’abord, démarrer le calcul à la demande
Ouvrir un notebook est volontairement distinct de l’exécution de Python. Scrydon authentifie la page, lit le document du notebook et affiche des cellules Marimo natives et modifiables sans démarrer de noyau ni allouer de charge isolée. Vous pouvez inspecter et modifier les cellules immédiatement tandis que le statut reste Non connecté.
Le calcul démarre de deux façons :
- Connecter prépare un runtime isolé, réconcilie les dépendances et connecte le noyau Marimo sans exécuter de cellule.
- Exécuter une cellule hors connexion effectue cette même préparation, puis envoie l’exécution sélectionnée exactement une fois lorsque le noyau est prêt.
Les deux chemins affichent la phase en cours : autorisation, provisionnement du calcul isolé, chargement de la source, synchronisation des dépendances, connexion au stockage gouverné et prêt. Les clics répétés, les nouvelles tentatives du navigateur ou un autre onglet rejoignant la même préparation ne créent pas de runtimes en double.
Les modifications effectuées avant la connexion sont incluses au démarrage du runtime. Ouvrir ou modifier simplement le document n’installe aucun paquet, ne crée aucune délégation de stockage et n’appelle pas le Runtime Plane.
Tailles de runtime
Chaque runtime de notebook s’exécute à l’une de quatre tailles nommées. Une taille fixe la mémoire et le CPU disponibles pour le noyau Python :
| Taille | Mémoire | CPU |
|---|---|---|
| Très petit | 512 Mo | 0,25 CPU |
| Petit | 1 Go | 1 CPU |
| Moyen | 4 Go | 2 CPU |
| Grand | 8 Go | 4 CPU |
Une organisation choisit une taille pour les notebooks ouverts en modification et une pour les applications publiées. Par défaut, les éditeurs s’exécutent en Petit et les applications publiées en Très petit. Un administrateur de l’organisation modifie l’une ou l’autre dans Paramètres → Calcul (Taille de l’éditeur de notebooks, Taille des apps publiées). Les tailles plus grandes permettent de loger moins de notebooks sur la même capacité.
Votre déploiement peut plafonner la plus grande taille autorisée. Les tailles au-dessus de ce plafond apparaissent comme Non disponible sur ce déploiement dans Paramètres → Calcul et ne peuvent pas être sélectionnées. Scrydon n’exécute jamais en silence une taille plus petite que celle choisie : un runtime qui dépasserait le plafond, ou qui ne tient pas dans le calcul disponible, est refusé.
Quand un changement de taille prend effet :
- Un éditeur ouvert garde sa taille jusqu’au redémarrage de son runtime, par exemple après une inactivité suffisamment longue pour qu’il soit arrêté.
- Une application publiée démarre à la nouvelle taille dès la prochaine session de lecture.
Quand un runtime est refusé ou manque de mémoire
- Capacité. Si le calcul est utilisé ou si la taille dépasse le plafond du déploiement, l’éditeur indique que tout le calcul de l’espace de travail est utilisé ou que la taille du runtime dépasse ce que le déploiement autorise. Une application publiée indique qu’elle n’a pas pu démarrer parce que le calcul est à pleine capacité ou que la taille de son runtime n’est pas disponible. Fermez les éditeurs ou applications que vous n’utilisez pas. Réessayer ne sert à rien tant que la taille dépasse le plafond : un administrateur doit choisir une autre taille, ou l’opérateur doit relever le plafond.
- Mémoire épuisée. Lorsque le noyau utilise plus de mémoire que sa taille ne l’autorise, il est arrêté et ses variables sont perdues. L’éditeur nomme la limite de mémoire atteinte ; une application publiée indique qu’elle a manqué de mémoire et a été arrêtée. Lorsque Scrydon ne peut pas déterminer pourquoi le runtime s’est arrêté, l’éditeur indique qu’il s’est arrêté de façon inattendue et a peut-être manqué de mémoire.
Pour les administrateurs : si un notebook ou une application manque régulièrement de mémoire, choisissez une taille d’éditeur ou d’application publiée plus grande dans Paramètres → Calcul. Si la taille requise n’est pas disponible, demandez à l’opérateur de votre plateforme de relever la taille maximale du déploiement.
Créer une application adossée à une ontologie
Choisissez Nouvelle application dans Horizon → Applications ou Analytics → Notebooks. Sélectionnez une ontologie, puis Application vierge ou Situation opérationnelle en direct. Le modèle en direct demande un type d’objet et des propriétés scalaires de latitude, longitude, horodatage d’observation, horodatage de réception et libellé. Le cap est facultatif. Définissez la limite d’objets et les intervalles de fraîcheur ; l’intervalle d’interpolation ne peut pas dépasser l’intervalle de péremption.
Le modèle en direct crée une carte, une table et un panneau de détails liés, avec des déclarations de requête correspondantes. Si une propriété n’est pas disponible, modifiez d’abord l’ontologie ou sa liaison de source. Le modèle ne normalise pas les flux et ne prouve pas l’état de santé des sources. Une application vierge enregistre la dépendance d’ontologie sans ajouter de requêtes.
Créer le notebook d’application enregistre un notebook marimo et un brouillon privé de publication, puis ouvre l’éditeur. Cette opération ne démarre pas le calcul et ne publie rien. Ouvrez Publier comme application pour vérifier les déclarations enregistrées et suivre les étapes de validation et de publication ci-dessous. Le serveur revérifie la révision sélectionnée et votre espace de travail avant la création. Si la création n’est pas confirmée, consultez Notebooks avant de réessayer : le notebook existe peut-être déjà. Sinon, rouvrez Nouvelle application pour actualiser le contexte et le schéma.
Lire les données de l’application dans l’éditeur
Enregistrez la cellule apps.declare(...) du notebook, puis exécutez ses cellules de composants SDK. Les tables, cartes et détails peuvent lire directement les données d’ontologie déclarées dans l’éditeur, y compris avec le runtime de développement local. Les lectures utilisent vos autorisations actuelles et la révision d’ontologie publiée accessible dans votre espace de travail actif. L’éditeur actualise les données toutes les cinq secondes tant que l’accès reste valide. Les contrôles d’action opérationnelle sont désactivés dans l’éditeur.
Modifier la source ou perdre l’accès ferme les connexions des composants. Un bref problème de connexion ne les ferme pas : l’éditeur continue de réessayer et les composants restent connectés. Si votre ordinateur s’est mis en veille, réexécutez les cellules des composants. Après avoir enregistré des modifications, réexécutez les cellules de composants concernées. Si les données de l’application restent indisponibles, vérifiez que l’ontologie déclarée est installée et accessible dans l’espace de travail et l’environnement actuels. L’édition ne valide pas une version ; utilisez les étapes distinctes de validation, d’aperçu et de publication ci-dessous pour préparer une application pour Horizon.
Préparer et publier une version d’application
Choisissez Publier comme application dans la barre d’outils du notebook. L’ouverture du panneau lit l’identité de la source enregistrée et les ontologies publiées auxquelles vous avez accès ; elle ne démarre pas de calcul. Enregistrez les modifications du notebook avant de valider.
Choisissez Enregistrer le brouillon pour conserver le titre, le slug, la description et le public de votre application pour votre prochaine visite. La déclaration d’accès appartient à la source enregistrée du notebook. Les paramètres du brouillon appartiennent à votre utilisateur, au notebook et à l’environnement de l’espace de travail, et restent disponibles après une nouvelle connexion si vous avez toujours accès au notebook. Enregistrer un brouillon ne publie pas de version. La validation enregistre d’abord les paramètres actuels ; la publication enregistre aussi les notes de version.
Si un autre onglet enregistre des paramètres plus récents, vos modifications locales restent visibles et l’enregistrement s’arrête sur un conflit. Charger les paramètres enregistrés remplace les paramètres locaux par la version enregistrée et efface l’ancien candidat afin que vous puissiez relire et valider à nouveau. Si la réponse d’un enregistrement est perdue, Réessayer l’enregistrement du brouillon répète exactement la même demande d’enregistrement ; cela ne crée pas de seconde version.
- Définissez le titre, le slug stable, la description et le public. Le public par défaut est Moi uniquement. Sélectionner Espace de travail n’accorde pas aux lecteurs d’accès supplémentaire aux données.
- Dans une cellule du notebook, utilisez
apps.declare(...)pour nommer l’ontologie ainsi que les requêtes, liens, surveillances et actions utilisés par vos composants SDK. Enregistrez le notebook. Le panneau compile cette déclaration et affiche un résumé d’accès en lecture seule avec les épingles exactes des révisions publiées. Il ne peut pas modifier l’accès séparément de la source. Les déclarations contraignent l’accès à l’exécution ; elles ne remplacent pas l’autorisation. - Vérifiez l’empreinte de la source enregistrée et choisissez Valider le notebook enregistré. Cela démarre la préparation isolée des dépendances et la validation de l’exécution initiale. Le panneau affiche la progression, l’annulation et des diagnostics d’échec bornés. Modifier le notebook invalide ce candidat, même si la modification a été enregistrée depuis.
- Choisissez Prévisualiser l’application pour ouvrir la source validée dans une vue d’exécution isolée. La bannière de non-publication affiche l’empreinte exacte de la source. Les requêtes utilisent vos autorisations actuelles ; les actions opérationnelles sont désactivées. Modifier le notebook met fin à l’aperçu, y compris les modifications enregistrées par la suite. Validez à nouveau pour prévisualiser une source modifiée. Fermer l’aperçu met fin à sa session.
- Vérifiez la version actuelle et vos notes de version, puis choisissez Publier ce candidat. Sous Environnement d’exécution et paquets, le panneau montre ce que couvre la validation : l’image d’exécution, les versions de marimo et du SDK Scrydon, et l’empreinte de l’ensemble de paquets résolu. Les noms de paquets individuels ne sont pas listés. Sous Requêtes en direct et fraîcheur déclarée, chaque requête en direct affiche la limite d’obsolescence fixée par sa déclaration (obsolète après un nombre de secondes). Il s’agit de la limite déclarée, et non d’une mesure de la fraîcheur actuelle de la source. La validation seule ne publie pas. Une publication concurrente est refusée afin que vous puissiez examiner la nouvelle version actuelle. Après une publication confirmée, choisissez Ouvrir dans Horizon pour afficher l’application avec vos autorisations actuelles.
Lorsque vous rouvrez Publier comme application pour une application enregistrée, le panneau affiche sa version actuelle et Ouvrir dans Horizon sans nouvelle validation. Une version retirée n’a pas de lien d’ouverture.
Pour retirer une application publiée, choisissez Retirer l’application dans le même panneau et confirmez. Les nouvelles sessions sont bloquées et toutes les sessions ouvertes sont révoquées. Seul le notebook qui a publié la version actuelle peut la retirer : lorsque la version en ligne provient d’un autre notebook, le panneau ne propose pas Retirer l’application et une demande directe reçoit la réponse « introuvable ». Pour rendre l’application de nouveau disponible, publiez une nouvelle version.
Pour revenir à une version antérieure, ouvrez Publier comme application, trouvez-la sous Versions précédentes et choisissez Revenir à cette version. Les nouvelles sessions ouvrent cette version ; les sessions ouvertes restent sur la leur. Le retour arrière ne restaure ni les données, ni les autorisations, ni les paramètres de surveillance, et il revérifie la politique et les dépendances actuelles. Vous ne pouvez revenir qu’à une version publiée par ce notebook, uniquement tant que l’application est publiée, et uniquement lorsque la version en ligne a elle aussi été publiée par ce notebook. Sinon, le panneau ne propose pas Revenir à cette version et une demande directe reçoit la réponse « introuvable ». Une version publiée avant la liaison à l’environnement nécessite une nouvelle validation et une nouvelle publication à la place.
Une version ne s’exécute que sur l’image d’exécution avec laquelle elle a été validée. Lorsque la plateforme est mise à jour et admet une nouvelle image d’exécution Marimo, une version validée sur l’image précédente ne peut pas démarrer sur celle-ci. Revalidation après une mise à jour de la plateforme décrit comment Scrydon la fait passer sur la nouvelle image sans intervention de l’auteur.
L’aperçu est une vue en tant qu’auteur, et non une usurpation d’identité du public visé. Une session perdue ou expirée retire le cadre. Réessayer démarre une nouvelle session seulement si la source enregistrée et la validation sont toujours à jour ; sinon, enregistrez, actualisez et validez à nouveau. Prévisualiser ne modifie jamais la version publiée et ne démarre aucune surveillance.
Par exemple, dans une cellule marimo qui reçoit apps depuis from scrydon import apps :
@app.cell
def _(apps):
access = apps.declare(
ontologies=[apps.ontology("maritime", alias="data")],
queries=[apps.query(
"vessels", ontology="data", object_type="Vessel",
properties=["name", "latitude", "longitude", "observedAt"],
max_objects=1000, live=True, stale_after_ms=60_000,
max_interpolation_gap_ms=10_000,
)],
)
return accessUtilisez des valeurs littérales dans cette déclaration. Les variables dynamiques et les appels calculés ne peuvent pas accorder d’accès à la publication. Le serveur résout le nom de l’ontologie vers une révision publiée accessible et valide le permis avant la préparation. Les notebooks existants qui n’ont enregistré que du JSON d’accès dans un brouillon doivent ajouter cette cellule avant de créer un autre candidat. Les versions publiées restent inchangées.
Si la préparation ne renvoie aucun résultat confirmé, Réessayer la même demande de préparation utilise la demande d’origine. Si elle avait déjà été acceptée, le serveur renvoie l’état actuel de ce candidat même si la source enregistrée ou le profil d’exécution a changé. Il ne reconstruit pas le candidat. Une source de notebook modifiée nécessite toujours une nouvelle validation avant la publication.
Si la validation signale Le profil d’exécution de l’application publiée est indisponible, aucun candidat n’a été accepté. Le déploiement doit fournir un runtime Marimo publié avant que la validation puisse continuer. Vous pouvez réessayer Valider le notebook enregistré une fois ce runtime disponible ; cela démarre une nouvelle demande de préparation.
La validation vérifie l’exécution initiale du candidat enregistré. Elle ne peut pas prouver chaque chemin d’entrée possible ni que chaque membre du public peut accéder à ses données.
Si un ancien candidat nécessite une revalidation de l’environnement, choisissez Modifier les paramètres et valider à nouveau et publiez le candidat nouvellement validé. L’historique des versions existantes reste disponible. Pour une publication antérieure incertaine, vérifiez son résultat d’origine avant de lancer une demande de remplacement.
Si la publication a un résultat inconnu, choisissez Vérifier le résultat de la publication. Cela lit le résultat de la même demande sans publier à nouveau. Un commit confirmé identifie la version créée par cette demande ; l’historique des versions identifie séparément la version actuelle.
Après un rechargement de la page ou une nouvelle connexion, ouvrez Publier comme application, trouvez l’entrée d’origine sous Demandes de publication et choisissez Récupérer la demande. Vérifiez son titre enregistré, l’identifiant de la demande, les notes de version et l’empreinte du candidat, puis choisissez Vérifier le résultat de la publication. La récupération fonctionne pour vos propres demandes tant que vous conservez l’accès au notebook et à l’application. Elle reste utile après une modification du notebook ou après l’expiration de la validation. Elle ne relance pas la validation, ne modifie pas les notes de version et ne publie pas une autre version. Les demandes plus anciennes sont disponibles via Demandes plus anciennes.
Un résultat inconnu n’est pas la confirmation d’un échec. Continuez à vérifier cette même demande ; ne créez pas de publication de remplacement pour résoudre un résultat incertain. Une fois un résultat confirmé, Modifier les paramètres et valider à nouveau ramène à votre brouillon enregistré. Les préparations qui n’ont pas atteint une demande de publication ne peuvent pas encore être restaurées après un rechargement de la page.
Revalidation après une mise à jour de la plateforme
Lorsqu’un opérateur a activé la revalidation automatique (la valeur Helm analytics.appRevalidation.enabled, désactivée par défaut), Scrydon revalide chaque application publiée sur la nouvelle image sans intervention de l’auteur. Pour chaque application, il :
- Restaure sur la nouvelle image l’ensemble de paquets enregistré avec la version.
- Si cet ensemble ne correspond pas à la nouvelle image, le reconstruit en épinglant les versions exactes des paquets avec lesquelles la version a été publiée.
marimoetscrydonsuivent la nouvelle image ; tous les autres paquets restent à la version validée par l’auteur. Un paquet que la nouvelle version de la plateforme épingle à une autre version fait échouer la reconstruction au lieu d’être ignoré ou mis à niveau. La reconstruction installe depuis votre index de paquets : elle nécessite donc la même sortie réseau approuvée pour les paquets que la construction d’un auteur. - Exécute l’exécution initiale de l’application sur la nouvelle image, comme le fait la validation.
- Publie une nouvelle version sur la nouvelle image. C’est la plateforme qui la publie, et non une personne ; ses notes de version indiquent Re-validated on runtime image … (was …). La version précédente reste dans l’historique des versions. Un retour arrière vers une version validée sur une image antérieure est revalidé de la même manière.
La revalidation ne modifie que le runtime et l’ensemble de paquets. Elle ne modifie jamais la source du notebook, l’accès aux données de l’application, son public, ses révisions d’ontologie épinglées ni son marquage de classification. Si l’un de ces éléments devait changer, la plateforme ne republie pas l’application et son auteur doit la publier à nouveau.
Tant qu’une version ne peut pas démarrer sur la nouvelle image, Horizon affiche L’environnement requis par cette application est indisponible avec l’un de ces quatre messages :
- Mise à jour de cette application pour la nouvelle version de la plateforme. La revalidation est en file d’attente ou en cours. Personne n’a à intervenir ; réessayez dans un instant.
- Cette application nécessite que son auteur la publie à nouveau. La revalidation a échoué, ou elle attend quelque chose que seul l’auteur ou un administrateur peut corriger.
- Une version plus récente de cette application est disponible. Réessayez pour l’ouvrir. L’auteur a publié l’application à nouveau après l’ouverture de cet onglet. Réessayer ouvre la version la plus récente.
- Cette version a été validée sur un environnement d’exécution antérieur et ne peut pas démarrer sur celui-ci. Demandez à son éditeur de valider et de publier à nouveau le notebook. La plateforme ne connaît aucune revalidation pour cette version : la revalidation automatique est désactivée, ou elle n’a pas encore atteint l’application.
En tant qu’auteur, ouvrez Publier comme application. Tant que la plateforme travaille sur la version en ligne de l’application, ou n’y est pas parvenue, la version actuelle affiche un avis avec l’empreinte courte de l’image de plateforme cible :
| Avis | Signification et marche à suivre |
|---|---|
| Mise à jour de cette application pour la nouvelle version de la plateforme. | La revalidation est en file d’attente ou en cours. Rien à faire. |
| Cette application n’a pas encore pu être revalidée pour la nouvelle version de la plateforme. Une nouvelle tentative aura lieu. La publier à nouveau la met à jour immédiatement. | La plateforme n’a pas pu restaurer ou reconstruire les paquets enregistrés pour le moment, par exemple parce que l’index de paquets est bloqué par votre politique de sortie réseau, ou parce que la version a été publiée avant que les environnements soient enregistrés avec elle. Scrydon réessaie en attendant de plus en plus longtemps, jusqu’à un jour. Autorisez les hôtes de paquets, ou validez et publiez à nouveau le notebook. |
| L’exécution initiale de l’application a échoué sur la nouvelle version de la plateforme. Vérifiez les cellules et les paquets du notebook, puis publiez à nouveau. | L’exécution initiale a échoué sur la nouvelle image. Choisissez Valider le notebook enregistré pour voir les diagnostics de l’échec, corrigez-le, puis publiez à nouveau. |
| Les paquets avec lesquels cette application a été publiée ne peuvent pas être installés sur la nouvelle version de la plateforme. Publiez-la à nouveau avec des paquets à jour. | Mettez à jour les paquets du notebook vers des versions qui s’installent avec la nouvelle plateforme, puis validez et publiez. |
| Une dépendance d’ontologie épinglée n’est plus valide. Publiez à nouveau l’application avec ses ontologies actuelles. | Une révision d’ontologie épinglée par l’application a changé ou n’est plus visible. Validez et publiez le notebook avec les ontologies actuelles. |
| La plateforme a refusé de ré-épingler automatiquement cette version. Publiez à nouveau l’application pour la mettre à jour. | Un élément que la plateforme n’a pas le droit de modifier automatiquement aurait dû changer. Validez et publiez à nouveau le notebook. |
Un échec est définitif pour cette image de plateforme : Scrydon ne le réessaie pas, et la prochaine mise à jour de la plateforme refait une tentative. Un échec de l’exécution initiale ou de l’installation des paquets est tenté deux fois avant d’être signalé, car un premier échec peut être temporaire. L’avis indique seulement la raison ; il ne liste ni la cellule, ni le paquet, ni l’ontologie en cause. Publier à nouveau l’application remplace toujours la version et efface l’avis.
À quoi ils servent
| Cas d’usage | Pourquoi marimo |
|---|---|
| Analyse ad hoc sur une table gérée | Pas besoin d’exporter — interrogez la table depuis Python avec les masques de l’utilisateur déjà appliqués |
| Construire un rapport ponctuel | Les cellules réactives rendent l’itération rapide |
| Esquisser un pipeline de feature engineering avant d’en faire un workflow | Même surface de données, même gouvernance |
| Exécuter des évaluations de modèles sur des données historiques | Les notebooks peuvent rappeler le moteur de workflows pour l’inférence |
Comment ils sont délimités
Un notebook appartient à un espace de travail et est authentifié auprès de l’utilisateur qui l’a ouvert :
- Ouvrir le document n’accorde aucun identifiant de calcul ou de stockage.
- Lorsque du calcul est demandé, Scrydon crée une délégation de courte durée, liée au notebook et au runtime, à l’intérieur d’un broker de confiance. Le noyau Python ne reçoit ni jeton bearer, ni mot de passe de base de données, ni identifiant cloud, ni identité Dapr, ni jeton Kubernetes.
- Les lectures appliquent vos masques de colonnes — les mêmes politiques que l’aperçu de table d’Analytics.
- Les lectures et écritures revérifient votre appartenance active à l’espace de travail et votre politique d’accès à chaque opération intermédiée, et sont inscrites dans la piste d’audit sous votre identité.
- Le runtime ne peut atteindre ni le catalogue Iceberg brut, ni les identifiants du fournisseur de stockage.
Il n’existe aucun super-utilisateur marimo-admin qui contourne la gouvernance — le notebook n’est qu’un appelant de plus.
Le SDK de données scrydon
Chaque notebook dispose de la bibliothèque Python scrydon préinstallée. La création d’applications inclut aussi automatiquement anywidget et jsonschema ; vous n’avez pas besoin de les installer dans une cellule du notebook. Elle vous offre une boucle de lecture/écriture gouvernée sur les tables gérées de votre espace de travail :
import scrydon
from scrydon import tables
scrydon.whoami() # who am I connected as, and until when?
tables.list() # DataFrame of the workspace's managed tables
tables.get("suppliers") # schema + governance flags (masked/hidden per column)
# Read — column masking already applied, paginated under the hood
df = tables.read("suppliers", limit=10_000)
df.attrs["scrydon"] # {"table_id": ..., "masked_columns": [...], ...}
# Write back — append | upsert | replace
tables.write("suppliers", df, mode="append")
# Publish a brand-new managed table from a DataFrame
tables.create("supplier_risk_scores", scores_df, classification="internal")
# Idempotent create for re-run notebooks: reuse the table if it already exists
# instead of raising (its schema and rows are left as-is — add rows with write()).
tables.create("supplier_risk_scores", scores_df, classification="internal", exist_ok=True)
# Declare a primary key: upserts, and any ontology binding over the table, need one
tables.create("supplier_risk_scores", scores_df, primary_key=["supplier_id"], exist_ok=True)Tout ce que produit un create ou un write est une table gérée de premier rang adossée au lakehouse Iceberg — le même stockage que toute table créée dans Analytics. Elle apparaît immédiatement dans Analytics → Tables (jamais comme une table « Legacy » native StarRocks), accepte les politiques d’accès aux colonnes, peut être liée à des types d’objets d’ontologie et est lisible par les workflows, les outils de chat et les moteurs Iceberg BYO.
Garde-fou d’aller-retour des masques. Si votre rôle voit des valeurs de substitution masquées dans une colonne, tables.write refuse de réécrire ces colonnes — écrire les valeurs de substitution corromprait silencieusement la table. Retirez d’abord les colonnes masquées de votre DataFrame (elles sont listées dans df.attrs["scrydon"]["masked_columns"]).
Les objets de l’espace de travail sont aussi disponibles via des assistants de stockage gouvernés et bornés, ainsi que l’interface standard fsspec :
from scrydon import fsspec, storage
with fsspec.open("workspace://reports/summary.json", "rb") as source:
summary = source.read()
content, observed_digest = storage.read_bytes_with_digest("reports/summary.json")
storage.write_bytes(
"reports/summary.json",
updated_content,
expected_sha256=observed_digest, # prevents overwriting a concurrent edit
)Si un autre onglet ou job a modifié un objet après votre lecture, l’écriture renvoie un conflit au lieu d’écraser la valeur plus récente. Relisez la version actuelle, fusionnez délibérément, puis réessayez.
Vous pouvez aussi utiliser toute bibliothèque Python installée — pandas, numpy, matplotlib, altair, … — ou installer des paquets supplémentaires (par ex. plotly) directement depuis le notebook. Consultez Paquets Python et sortie réseau ci-dessous.
Instances d’ontologie
Les tables gérées sont la couche physique ; l’ontologie est la couche sémantique au-dessus — des types d’objets comme aircraft ou supplier liés à une table, avec des colonnes d’identité qui définissent ce qui rend une ligne unique. scrydon.ontology permet à un notebook de lire et d’écrire ces types d’objets par leur nom, sans savoir quelle table les soutient :
from scrydon import ontology
# Which object types have data bound in this workspace?
ontology.list_types() # DataFrame: ontology_slug, object_type_slug, label
# Read instances — each row is `id` (the instance's canonical key) plus one
# column per property. Masking, row filters, and clearance apply exactly as
# they do for the underlying table.
df = ontology.read("aircraft", limit=1_000)
df = ontology.read(
"aircraft",
where=[{"property": "status", "op": "eq", "value": "active"}], # AND-combined, max 8
)
# Write instances back — an upsert keyed on the object type's identity columns.
# Existing instances are updated in place; new ones are inserted. Don't include
# the `id` column — it's computed server-side from the identity columns.
ontology.write("aircraft", df.drop(columns=["id"]))Un write passe par le même chemin d’écriture gouverné que tables.write — la plateforme résout la table gérée liée, applique le plafond de classification et le garde-fou d’aller-retour des masques, et audite l’écriture sous votre utilisateur. Les lignes apparaissent immédiatement dans l’aperçu de table d’Analytics et dans le graphe d’instances de l’ontologie.
Les colonnes d’identité sont requises pour écrire. Upserter des instances exige que la liaison du type d’objet déclare identityColumns dans l’Ontology Workbench — c’est ce qui indique à la plateforme quelles lignes existantes mettre à jour. Sans elles, ontology.write lève OntologyIdentityError. Les lectures fonctionnent dans tous les cas.
Recherche de connaissances et assistants LLM
Le même jeton de session alimente aussi la recherche gouvernée dans les bases de connaissances et les complétions LLM — aucune clé d’API à gérer, et l’analyse de prévention des pertes de données, la facturation et l’audit de la plateforme s’appliquent automatiquement :
from scrydon import knowledge, llm, embed
# Semantic search over the knowledge bases in this workspace environment.
hits = knowledge.search("What is the Q3 maintenance schedule?", top_k=5)
for hit in hits:
print(round(hit["score"], 2), hit["content"][:100])
# Restrict to one knowledge base by id
hits = knowledge.search("supplier onboarding", collection="kb-id-here")
# LLM completion through your organization's default LLM integration.
answer = llm.complete("Summarize these findings in two sentences: ...")
# Full transcript + response metadata
result = llm.complete(
messages=[
{"role": "system", "content": "You are a terse analyst."},
{"role": "user", "content": "Why partition large tables?"},
],
detail=True,
)
print(result["content"], result.get("tokens"))
# Embeddings through your organization's embedding integration.
vectors = embed(
["the quick brown fox", "lorem ipsum"],
model="openai/text-embedding-3-small",
)
print(len(vectors), len(vectors[0]))Toutes les capacités de la plateforme
Chaque capacité d’IA de la plateforme est disponible via la famille d’opérations gouvernées /api/platform/v1/** derrière de simples assistants. Chaque appel s’exécute via les intégrations de votre organisation, avec identifiants, DLP, facturation et audit appliqués côté serveur ; le notebook ne voit jamais de clé d’API de fournisseur :
from scrydon import stt, ocr, tts, image, video, moderation
# Transcribe audio — pass a file path or raw bytes.
transcript = stt.transcribe("interview.mp3", language="en")
# Extract text from a document (PDF / image).
text = ocr.extract("scan.pdf")
result = ocr.extract(pdf_bytes, mime_type="application/pdf", detail=True)
# Synthesize speech — returns decoded audio bytes.
audio = tts.synthesize("The pipeline finished successfully.", voice="alloy")
with open("status.mp3", "wb") as f:
f.write(audio)
# Generate images — entries carry a URL and/or inline base64, per vendor.
images = image.generate("A schematic of an Iceberg table layout", n=2)
# Generate video — returns a URL or inline bytes, per vendor.
clip = video.generate("A drone flyover of a container port", duration=5)
# Classify text for content-safety categories.
# Each result carries flagged, categories, categoryScores, and orgVerdict.
results = moderation.moderate("Text to classify for harmful content.")
for r in results:
if r["orgVerdict"] == "fail":
print("Policy fail:", r.get("triggeredCategories", []))Chaque assistant accepte un remplacement facultatif model="vendor/model" et lève une <Capability>NotConfiguredError explicite lorsque votre organisation n’a aucune intégration correspondante — un administrateur de l’organisation peut en activer une sous Paramètres → Plateforme → Extensions. Les entrées binaires (audio, documents) acceptent un chemin de fichier (type MIME déduit de l’extension) ou des octets bruts, et sont plafonnées à la limite d’envoi de la plateforme.
Recherche web et outils d’intégration
Le jeton donne aussi accès à la recherche web gouvernée de la plateforme et aux outils d’intégration activés pour votre organisation :
from scrydon import search, tools
# Web search through the org's configured search integration.
for hit in search.web("Apache Iceberg snapshot expiry", max_results=5):
print(hit["title"], hit["url"])
# Discover the org's enabled integration tools (name, description, input schema).
for tool in tools.list("send a message"):
print(tool["id"], "-", tool["description"])
# Run one — parameters are validated server-side against the tool's schema.
output = tools.run(
"org:acme:slack:send-message",
{"channel": "#alerts", "text": "Pipeline finished."},
)tools.run s’exécute via le même pont gouverné que les workflows et le chat : la politique de l’organisation, la résolution des identifiants côté serveur, la DLP et l’audit s’appliquent, et le code du fournisseur ne s’exécute que dans le bac à sable d’intégration de la plateforme. search.web accepte un provider= facultatif pour choisir une intégration de recherche configurée précise (les identifiants restent résolus côté serveur), et un recency= facultatif valant "day", "week", "month" ou "year" pour ne conserver que les résultats publiés dans cette fenêtre. Chaque résultat porte une publishedDate (ISO 8601) lorsque le fournisseur la fournit.
Notes de gouvernance :
- Les résultats de recherche respectent votre habilitation et votre appartenance à l’espace de travail — la vérification s’exécute à chaque appel, de sorte que les changements d’accès prennent effet immédiatement, et non à l’expiration du jeton.
llm.completeutilise l’intégration LLM par défaut de l’organisation (ou passezmodel="vendor/model"pour en choisir une activée). Si aucune n’est configurée, vous obtiendrez uneLlmNotConfiguredErrorexplicite — un administrateur de l’organisation peut en activer une sous Paramètres → Plateforme → Extensions.embedexige unmodelexplicite (contrairement àllm.complete) — les dimensions d’embedding doivent correspondre à l’endroit où vous stockez les vecteurs, il n’y a donc aucune valeur par défaut silencieuse. Si aucune intégration d’embedding n’est configurée, vous obtiendrez uneEmbeddingNotConfiguredError.- Les capacités et outils qui fonctionnent réellement sont déterminés par les intégrations activées de votre organisation — le jeton du notebook indique seulement que vous pouvez demander. Une intégration manquante renvoie une
...NotConfiguredErrortypée, jamais un repli silencieux.
Notebooks issus d’extensions
Les extensions installées peuvent fournir des notebooks prêts à l’emploi. Dans Analytics → Notebooks, utilisez Depuis une extension pour parcourir les notebooks fournis par les extensions installées de votre organisation et en ajouter un à l’espace de travail actuel — il devient un notebook d’espace de travail normal que vous pouvez ouvrir, modifier et resynchroniser comme n’importe quel autre.
Créer et importer des notebooks
Analytics → Notebooks → Nouveau notebook crée un notebook neuf à partir d’un modèle — ou importe un fichier marimo .py existant (utilisez Importer un fichier .py dans la même boîte de dialogue).
Des notebooks de démonstration prêts à l’emploi se trouvent dans le dépôt scrydon/packs, dossier notebooks/ : un démarrage rapide du lakehouse, un pas-à-pas de publication d’un jeu de données et une démonstration d’écriture gouvernée en retour. Téléchargez un fichier, importez-le dans votre espace de travail et exécutez-le de haut en bas.
Réactivité
La réactivité de Marimo est ce qui le rend utile ici. Changez un paramètre en haut du notebook (par ex. le nom de la table, la plage de dates, le filtre) et chaque cellule dépendante se réexécute. Pas d’état périmé, pas de rituel « tout exécuter ».
Partage
Les notebooks sont limités à l’espace de travail. Partager un notebook avec un autre membre de l’espace de travail se fait en un clic — il obtient une vue en lecture seule qui se réexécute dans sa propre session, avec ses propres masques appliqués.
Les notebooks n’exportent pas de données brutes. Un utilisateur de faible habilitation qui ouvre un notebook produit par un utilisateur de plus haute habilitation réexécute les requêtes sous sa propre identité — il ne voit pas les résultats mis en cache de l’utilisateur de plus haute habilitation.
Ce qu’ils ne font pas
- Les notebooks Marimo ne remplacent pas le moteur de workflows. Ils servent à l’analyse, pas aux déclencheurs de production.
- Les exécutions de pipeline utilisent un calcul isolé neuf et à usage unique et ne réutilisent jamais les variables ni les fichiers de votre session interactive. Pour une planification stable ou un déclencheur de production, appelez ce job depuis un workflow ou une automatisation.
- Ils n’exposent pas d’API HTTP publique. Ce sont une surface d’interface.
Paquets Python et sortie réseau
Le runtime des notebooks est livré avec un environnement de base épinglé et la bibliothèque d’aide scrydon. Tout le reste que le notebook utilise est déclaré dans le notebook lui-même, dans son bloc de métadonnées de script PEP 723, et réconcilié avec uv avant que le noyau soit déclaré prêt :
# /// script
# requires-python = ">=3.12"
# dependencies = ["marimo", "pandas", "plotly", "scrydon"]
# ///Les nouveaux notebooks sont créés avec ce bloc déjà en place.
Ajouter un paquet
Utilisez n’importe lequel des moyens d’installation de Marimo — ils font tous la même chose, de façon gouvernée :
- le bouton Installer d’une bannière
ModuleNotFoundError, - le panneau Paquets de la barre latérale gauche,
- le lien d’installation à côté d’un import manquant dans la sortie d’une cellule.
Scrydon ajoute le paquet au bloc de dépendances du notebook, le résout et l’installe, puis enregistre le notebook — dans cet ordre. Si l’installation échoue, le notebook reste exactement tel qu’il était et la raison est affichée. En cas de succès, réexécutez la cellule pour prendre en compte le nouveau module.
Comme le paquet est enregistré dans la source du notebook, il survit à un rechargement, à un runtime de remplacement et à un job de pipeline à usage unique. Il n’existe pas de paquet installé mais non déclaré.
Paquets gérés par la plateforme
marimo et scrydon sont installés par la plateforme à partir d’artefacts vérifiés. Vous pouvez les laisser listés dans le bloc de dépendances — les nouveaux notebooks le font — mais une contrainte de version ou un extra sur l’un ou l’autre est ignoré plutôt qu’honoré, car c’est la construction propre de la plateforme qui est installée dans tous les cas. Les retirer du bloc est refusé.
Les notebooks écrits avant la livraison de ce comportement peuvent contenir une épingle générée automatiquement comme marimo>=0.24.0. Elle est ignorée lors de la prochaine préparation ; vous n’avez rien à modifier.
Restrictions
Une dépendance déclarée doit être une exigence simple — un nom, des extras facultatifs et un spécificateur de version facultatif. Les références directes (package @ https://…, git+https://…, un chemin local, -e) sont refusées : elles ne sont pas reproductibles à partir de la source du notebook, ce qui est tout l’intérêt de les déclarer.
Les paquets livrés dans l’image de base du runtime (pandas, numpy et les dépendances propres de Marimo) sont épinglés par la plateforme. En déclarer un est sans effet, mais demander sa mise à niveau ne le fait pas sortir de la version épinglée.
La réconciliation des dépendances exige une sortie réseau approuvée pour les paquets. Pour le PyPI public, pypi.org et files.pythonhosted.org doivent être autorisés par la politique de sortie de votre organisation. Un hôte refusé fait échouer la préparation avant l’exécution de la cellule demandée.
La connexion ou la préparation des dépendances échoue
- Isolation indisponible — aucun niveau de calcul qualifié ne peut satisfaire la politique de votre organisation. Demandez à un opérateur de rétablir le Runtime Plane ou la capacité Kata/KVM ; Scrydon ne se rabat pas sur l’hôte Analytics.
- Sortie réseau des paquets refusée — l’index de paquets ou l’hôte de téléchargement est absent de la liste d’autorisation de sortie.
- Un paquet ne s’installe pas — la raison est affichée à l’endroit où vous l’avez demandé.
No compatible version could be resolvedsignifie qu’aucune distribution ne correspond à la version de Python et à l’architecture de ce runtime ;The notebook's dependency block is invalidsignifie qu’une entrée du bloc n’est pas une exigence simple ;The notebook changedsignifie qu’un autre onglet a enregistré en premier — rechargez et réessayez. - La préparation a expiré ou échoué — choisissez Réessayer. Réessayer crée une nouvelle génération clôturée et nettoie celle qui a échoué ; cela ne rejoue pas une cellule qui a peut-être déjà franchi la frontière d’exécution.
- Conflit de source — un autre onglet ou job a enregistré une version plus récente du notebook. Rechargez, fusionnez vos modifications et enregistrez à nouveau.
- Connexion obsolète après un remplacement ou une mise en veille pour inactivité — reconnectez-vous. L’ancien bail ne peut pas se rattacher au runtime de remplacement.
Solutions pour une réconciliation des dépendances bloquée :
-
Demandez à un administrateur informatique d’activer la sortie réseau. Un administrateur de l’organisation peut ouvrir Paramètres → Gouvernance → Sortie réseau et activer Autoriser le trafic par défaut de Scrydon (couvre PyPI :
pypi.orgetfiles.pythonhosted.org) ou ajouter un domaine personnalisé à la liste d’autorisation. Consultez le guide Gouvernance de la sortie réseau des notebooks. Une politique modifiée remplace le runtime avant la prochaine exécution. -
Importez le paquet manuellement. Une prochaine version permettra d’importer directement des fichiers wheel Python dans la plateforme, les rendant disponibles sans aucune sortie réseau. C’est la voie pour les déploiements totalement isolés (air-gapped). (Cette capacité n’est pas encore disponible — consultez les notes de version pour sa date de livraison.)
Si Autoriser le trafic par défaut de Scrydon est activé, les paquets ont tout de même besoin d’une distribution compatible avec la version de Python et l’architecture du runtime. Les détails du résolveur restent dans les journaux de l’opérateur ; le notebook reçoit une raison d’échec stable et sûre.
Cartes et autres ressources rendues par le navigateur
Certaines bibliothèques produisent une sortie qui récupère des ressources depuis le navigateur plutôt que depuis le noyau — par exemple, une carte Plotly (go.Scattermap) charge ses tuiles de fond de carte côté client. Ces requêtes sont régies par la Content-Security-Policy du document du notebook, et non par la liste d’autorisation de sortie du bac à sable ; autoriser un hôte pour l’installation de paquets ne suffit donc pas à lui seul à faire charger les tuiles d’une carte.
- Les fonds de carte fonctionnent d’emblée lorsque Autoriser le trafic par défaut de Scrydon est activé. Le fond de carte agréé par la plateforme (CARTO) est autorisé pour la sortie des notebooks ; utilisez donc un style CARTO sans jeton —
style="carto-positron"oustyle="carto-darkmatter"— et la carte s’affiche. Si votre organisation a désactivé le trafic par défaut de Scrydon, aucun fond de carte n’est autorisé et la zone de la carte reste vide. - Tout autre hôte — y compris
style="open-street-map"— nécessite un choix explicite de l’opérateur. Le CDN public de tuiles d’OpenStreetMap est un tiers distinct qui observe la fenêtre d’affichage de chaque lecteur ; il ne fait donc pas partie des valeurs par défaut agréées. Un opérateur peut l’autoriser : dans Paramètres → Gouvernance → Sortie réseau, ajoutez l’hôte (tile.openstreetmap.org) et activez Ressources du navigateur pour cette entrée. Ajouter un hôte sans cet interrupteur n’autorise que le noyau à l’atteindre, ce qui explique pourquoi une carte peut rester vide alors que l’hôte figure dans la liste d’autorisation. Consultez Gouvernance de la sortie réseau des notebooks. - Le notebook vous prévient lorsque cela se produit. Si une ressource est refusée, un avis apparaît au-dessus du notebook en nommant l’hôte exact — vous n’avez pas à ouvrir la console du navigateur pour savoir pourquoi une carte est vide. Il n’apparaît que pour les ressources qu’un administrateur peut autoriser (images et récupérations de données) ; un script bloqué est refusé par conception et n’est jamais présenté comme quelque chose à demander.
- Les tuiles ne sont pas le seul cas. Toute sortie qui récupère des images, des polices ou des données directement depuis un hôte externe dans le navigateur est soumise à la même politique de document. Gardez la sortie des notebooks autonome, ou utilisez le fond de carte agréé, sauf si un opérateur a élargi la politique.
En rapport
- Architecture → Pile Analytics — où marimo se situe dans le cluster.
- Tables gérées — ce que les notebooks lisent.
- Classification et masquage — la gouvernance appliquée.
- Gouvernance de la sortie réseau des notebooks — configurer les hôtes externes que les notebooks peuvent atteindre.
- Connecter un moteur externe — votre notebook et un cluster Spark ou Trino lisent le même catalogue Iceberg gouverné ; un jeton de moteur suffit.
Composants d’application d’ontologie
Le module scrydon.apps fournit des composants pour l’hôte d’applications d’ontologie. Dans Horizon, la table lit une requête déclarée de la version publiée de l’application avec vos autorisations actuelles. Les filtres et les révisions d’ontologie proviennent de cette version ; un widget ne peut pas choisir une autre source. La table exige l’hôte d’application de confiance. Le transport du cadre publié utilise un document d’exécution isolé ; les contrôles natifs et les interactions des widgets n’accordent pas l’accès à l’édition du notebook ni à la gestion des paquets. Une session de lecteur expirée ou révoquée ne peut pas maintenir sa connexion au runtime en vie grâce à l’activité des widgets.
Les composants suivent le thème clair ou sombre du lecteur et le langage visuel de Scrydon : chacun est une carte avec un titre et une pastille d’état qui associe une forme à un mot (En direct, un triangle d’avertissement en cas de dégradation, un anneau en pointillés pendant l’attente), de sorte que l’état ne dépend jamais de la seule couleur. Disposez les composants avec mo.hstack et mo.vstack ; l’exemple MIK place la carte à côté des détails de la sélection, avec les tables en dessous.
Horizon ouvre une version publiée autorisée depuis Applications et affiche les états d’échec de démarrage, d’exécution et de session. Une application en cours d’exécution conserve sa version jusqu’à ce que vous choisissiez Ouvrir la mise à jour disponible. Partager copie un lien authentifié ; il n’accorde aucun accès supplémentaire. Ouvrir dans le notebook n’apparaît que si vous pouvez modifier le notebook source. L’expiration, un renouvellement refusé, un changement d’espace de travail et le départ de la page retirent le cadre entier de l’application. Réessayer ouvre une nouvelle session.
Pendant le démarrage d’une session, Horizon garde l’application derrière un indicateur de chargement jusqu’au rendu de son premier composant : vous ne voyez jamais une page à moitié construite. L’application occupe ensuite toute la page, sans menus de notebook ni marges de cellule.
L’exécuter dans un notebook autonome ordinaire affiche un état indisponible au lieu d’ouvrir une connexion directe à une source de données.
from scrydon import apps
vessels = apps.table(
"vessels",
columns={"name": "Vessel", "speed": "Speed"},
selection_group="contacts",
title="Live vessels",
)
vesselsDéclarez vessels et les deux propriétés dans la configuration de l’application. Les composants du même groupe de sélection partagent la sélection si leurs résultats autorisés contiennent l’objet sélectionné. Dans une cellule marimo dépendante, lisez vessels.value["selection"] : sa valeur est None ou une référence contenant ontology, objectType et objectId. La valeur d’ontologie est l’alias de la dépendance.
Les actualisations de données mettent à jour les lignes existantes sans réexécuter les cellules Python dépendantes. La sélection est une interaction sémantique et met bien à jour Python. Perdre l’accès efface les lignes et la sélection. La table ne peut exécuter aucune action opérationnelle. Fournissez les libellés traduits des colonnes et une locale prise en charge (en, es, fr, de ou nl) pour les messages d’état. Le runtime de la plateforme fournit le SDK et les ressources de ses widgets ; les environnements de développement local ont besoin de l’extra scrydon[apps].
Cliquez n’importe où dans une ligne pour la sélectionner. Utilisez Rechercher dans les objets chargés pour filtrer les colonnes affichées. Cliquez sur un en-tête de colonne pour passer successivement à l’ordre croissant, décroissant et à l’ordre de la source. Les nombres sont triés numériquement ; les valeurs manquantes restent en dernier. Ces contrôles agissent sur le résultat borné et autorisé déjà chargé. Ils n’élargissent pas la requête de la version et ne récupèrent pas d’objets supplémentaires. Les réglages de recherche et de tri survivent aux mises à jour en direct et aux pannes temporaires de requête. Masquer une ligne sélectionnée par la recherche conserve la sélection partagée ; son marqueur de carte et ses détails restent donc disponibles tant que la requête la contient encore.
Les requêtes en direct adossées à des sources Iceberg gérées peuvent s’actualiser à partir de notifications de source validées lorsque le pipeline d’événements de source est activé. Horizon réconcilie aussi lorsqu’il renouvelle l’autorité de l’application, normalement toutes les cinq secondes. Un échec de lecture de la source efface les lignes et la sélection de la requête concernée, puis réessaie tant que la session reste autorisée. Les autres requêtes conservent leurs données. La récupération préserve le cadre du notebook. Les résultats incomplets ou trop volumineux affichent des données indisponibles au lieu d’une table partielle. Pour les objets d’ontologie adossés à des tables Iceberg gérées, chaque page d’une actualisation lit le même instantané validé. De nouveaux rapports de navires peuvent arriver pendant cette actualisation sans mélanger anciennes et nouvelles pages. Si une notification de source validée est en avance sur l’instantané qui vient d’être lu, la plateforme relit une fois par rapport à cette frontière de version. Un lecteur qui reste en retard affiche des données indisponibles et réessaie ; la notification elle-même n’est jamais traitée comme des lignes à jour. Un instantané expiré, ou un changement de source, de schéma, de mappage ou de décision d’accès, rend l’actualisation indisponible et exige une nouvelle lecture. Les types de source qui ne peuvent pas fournir cette garantie de cohérence sont indisponibles dans les requêtes des applications publiées. Les reconnexions et les continuations expirées obtiennent automatiquement un nouvel instantané autorisé.
Une lecture réussie ne suffit pas à établir la santé du flux amont. Les flux de pistes adossés à une collecte installée utilisent des preuves liées à la configuration, issues de chaque source déclarée, pour indiquer sain, dégradé ou inconnu. Une collecte échouée mais validée envoie un point de contrôle afin que les requêtes connectées puissent actualiser cet état même si aucune position de navire ne change. Les sources sans preuve d’état faisant autorité restent inconnues. La fraîcheur des pistes est affichée séparément sur la carte.
Détails de l’objet sélectionné
details = apps.details(
"vessels",
fields={"name": "Vessel", "speed": "Speed"},
selection_group="contacts",
title="Vessel details",
)
detailsLe panneau suit l’objet sélectionné dans une carte ou une table utilisant le même groupe de sélection. Déclarez chaque champ affiché dans la requête. Il affiche les valeurs scalaires autorisées, les met à jour sur place et les efface lorsque l’objet quitte la requête ou que la requête devient indisponible. Aucun objet n’est sélectionné automatiquement. Une panne de requête efface la sélection ; sélectionnez à nouveau un objet après la récupération. Les valeurs de propriété sont affichées sous forme de texte ; les valeurs manquantes sont représentées par un tiret. Les tables et les détails affichent les nombres avec au plus six chiffres significatifs : une valeur stockée 0.91 s’affiche 0.91 et non sa représentation en virgule flottante, et les horodatages s’affichent sous la forme 2026-10-12 03:31:00Z. Les valeurs longues passent à la ligne au lieu d’élargir le panneau.
Ajoutez une table de relations à côté des détails pour inspecter des observations liées ou d’autres objets autorisés :
reports = apps.related(
"reports",
columns={"name": "Report", "observedAt": "Observed"},
source_selection_group="contacts",
selection_group="reports",
title="Vessel observations",
)
reportsDéclarez reports comme dépendance de lien de l’application avec sa requête source (vessels), sa requête cible (par exemple observations), le type de lien et le nombre maximal d’objets. Les colonnes doivent être des propriétés autorisées de cette requête cible. Les deux types d’extrémité doivent être concrets ; les extrémités de lien génériques (wildcards) ne sont pas prises en charge dans les applications publiées. Seules les cibles présentes dans la requête cible autorisée et reliées à la source sélectionnée sont affichées. Aucune correspondance de propriétés côté navigateur ne déduit une relation.
Sélectionner un rapport utilise son propre groupe de sélection et conserve le navire sélectionné. Un panneau apps.details("observations", ..., selection_group="reports") peut inspecter ce rapport. Changer ou effacer la sélection du navire efface immédiatement les anciennes lignes de relation. Les échecs affectent la vue des relations sans effacer les données saines des navires. Les mises à jour des requêtes d’extrémité et le battement normal de l’autorité actualisent les lignes liées. Les lectures couvrant des sources différentes sont autorisées indépendamment ; elles ne prétendent pas offrir un instantané atomique unique sur ces sources.
Examen des alertes
Utilisez une requête de détections déclarée pour afficher des filtres de gravité et de statut à côté des contrôles de recherche et de tri de la table :
alerts = apps.alerts(
"detections",
columns={"title": "Alert", "severity": "Severity", "status": "Status"},
severity="severity",
status="status",
acknowledge_action="acknowledge-detection",
response_watch="restricted-area",
acknowledge_input="detectionId",
selection_group="alerts",
title="Detection review",
)
evidence = apps.related(
"detection-evidence",
columns={"name": "Observation", "observedAt": "Observed"},
source_selection_group="alerts",
selection_group="evidence",
title="Alert evidence",
)
mo.vstack([alerts, evidence])Déclarez chaque propriété affichée et les deux propriétés de filtre dans detections. L’ontologie définit le vocabulaire de gravité et de statut ; le composant en déduit les options à partir du résultat autorisé. Les filtres s’appliquent localement à ce résultat borné. Ils persistent pendant les mises à jour en direct et la récupération. Filtrer une ligne sélectionnée hors de la vue conserve la sélection et affiche son titre à côté du contrôle d’acquittement. Une requête indisponible ou le retrait du résultat autorisé efface sa sélection, ses détails, ses preuves et le contrôle d’acquittement. La récupération ne la sélectionne pas à nouveau.
detection-evidence doit être un lien déclaré depuis la requête de détections vers une requête d’observations autorisée. Ajoutez apps.details("detections", fields=..., selection_group="alerts") pour les détails scalaires de l’alerte. Lisez alerts.value["selection"] en Python pour les changements sémantiques de sélection ; les actualisations de données en direct restent dans le navigateur.
Omettez acknowledge_action pour une liste en lecture seule. Lorsqu’il est fourni, il désigne une déclaration d’action de l’application autorisant acknowledge_input (par défaut detectionId). Le composant fixe cette entrée à l’identifiant de l’objet sélectionné. L’action de l’ontologie gère les changements de statut, la préservation des preuves et l’enregistrement d’audit de l’acquittement ; le widget n’écrit lui-même aucun statut. Son bouton utilise le flux de confirmation et de vérification du résultat d’Horizon décrit ci-dessous. Le rendu, la sélection et les actualisations de données ne soumettent jamais. alerts.value["action_result"] expose le résultat borné du widget enfant actuel. Horizon conserve une intention confirmée non résolue même si la ligne sélectionnée disparaît.
Pour les détections de surveillance, déclarez le comportement d’acquittement de l’ontologie. Il n’accepte que l’identifiant de détection et enregistre côté serveur qui l’a acquittée et quand. Associez status="acknowledgementStatus" pour filtrer l’acquittement séparément de la condition de la détection. Le premier acquittement est conservé malgré les nouvelles tentatives et les opérateurs concurrents.
Définissez response_watch sur l’identifiant d’une déclaration de surveillance du permis de l’application pour ajouter Voir la réponse dans Horizon à l’alerte sélectionnée. La surveillance doit émettre le type de détection lu par cette requête. Horizon vérifie l’accès actuel à la détection et à son flux de réponse enregistré avant d’afficher Ouvrir la réponse au-dessus du notebook. Cliquez sur ce lien pour naviguer. La recherche ne crée ni ne fait jamais avancer de flux, et aucun identifiant ni URL de flux n’entre dans Python ou dans le cadre du notebook. Les réponses absentes, ambiguës et refusées utilisent le même message d’indisponibilité.
Changer la sélection, perdre les données de la requête ou mettre fin à la session supprime le résultat. Les résultats expirent aussi après 30 secondes ; demandez une nouvelle recherche si nécessaire. Une lecture échouée peut être réessayée avec le même contrôle du widget. L’aperçu ne propose pas la navigation vers la réponse. Les surveillances et la configuration de dispatch ont leur propre cycle de vie ; publier ce composant n’active ni la surveillance ni la réponse automatique.
Actions opérateur
Utilisez une déclaration d’action des paramètres de l’application pour créer un bouton de proposition :
acknowledge = apps.action(
"acknowledge",
inputs={"id": "ship-1"},
label="Acknowledge vessel",
)
acknowledgeLa déclaration sélectionne le type d’action de l’ontologie, les propriétés d’entrée autorisées et le budget d’octets d’entrée. Les entrées peuvent être des chaînes, des nombres finis ou des booléens, avec au plus 64 champs et 16 Kio de JSON UTF-8. Les chaînes autorisent au plus 4 096 unités de code UTF-16 ; NUL et les substituts isolés sont refusés. Les entiers Python doivent être exactement représentables en JavaScript (2**53 - 1 au plus en valeur absolue). Une déclaration peut fixer un budget d’octets plus petit. Le schéma de l’action valide à nouveau les champs requis et les types à la soumission.
Pour agir sur une sélection, créez le widget dans une cellule dépendante en utilisant l’identifiant de l’objet sélectionné, par exemple vessels.value["selection"]["objectId"], après avoir vérifié qu’une sélection existe. D’autres entrées peuvent provenir de contrôles de formulaire marimo ordinaires. Chaque instance de widget fixe ses entrées ; reconstruisez-la pour les modifier.
Cliquer sur le widget ouvre une boîte de dialogue de confirmation Horizon affichant l’identifiant d’action déclaré et les entrées exactes. Annuler reçoit le focus initial du clavier. Seule la confirmation soumet. Le chargement, le rendu, la réexécution, l’actualisation des données et la reconnexion ne soumettent pas d’actions. Les actions opérationnelles sont désactivées dans l’aperçu de la source enregistrée.
Horizon affiche le résultat au-dessus de l’application. Un résultat inconnu a peut-être déjà été appliqué : utilisez Vérifier le résultat pour réconcilier cette demande. Il n’y a aucune nouvelle soumission automatique. Une seule intention non résolue est conservée par lecteur monté, y compris lors des réexécutions du notebook ; résolvez-la avant de proposer une autre action. Fermez un panneau de résultat terminal avant de lancer l’action suivante. L’autorisation actuelle et les exigences d’approbation existantes s’appliquent toujours ; le widget n’accorde aucune approbation.
acknowledge.value["action_result"] expose le résultat borné du widget. Utilisez-le pour la présentation, jamais comme permission de réessayer automatiquement. L’intention en attente d’Horizon appartient à la navigation actuelle du lecteur. Fermer ou recharger toute l’application supprime ce panneau ; un résultat inconnu doit être vérifié dans le dossier opérationnel avant de créer délibérément une nouvelle action. Il n’est pas récupéré depuis le stockage du navigateur.
Carte d’ontologie en direct
picture = apps.map(
"vessels",
latitude="latitude",
longitude="longitude",
observed_at="observedAt",
received_at="receivedAt",
label="name",
heading="heading",
center=(4, 54), # longitude, latitude
zoom=5,
selection_group="contacts",
title="North Sea",
)
pictureDéclarez toutes les propriétés mappées dans la requête. Les coordonnées sont des degrés WGS84 numériques ; les heures d’observation et de réception sont des chaînes ISO en UTC. Le cap est facultatif et s’exprime en degrés dans le sens horaire à partir du nord. Les positions invalides ou datées dans le futur sont omises avec un diagnostic de mappage. La carte reçoit d’Horizon la politique de fraîcheur de la version.
Les mises à jour conservent la vue de la carte, les marqueurs et la sélection partagée. Les nouvelles positions s’animent depuis la position affichée pendant 500 ms au plus, sans extrapolation. Les positions périmées, les grands écarts d’observation et les sauts invraisemblables s’alignent directement sur la position acceptée. max_speed_mps contrôle cette vérification visuelle de plausibilité (100 par défaut) ; il ne crée pas de règle de détection. Les corrections à horodatage égal s’alignent directement, et les observations plus anciennes ne ramènent pas un marqueur existant en arrière.
Les marqueurs périmés affichent une étiquette de péremption et un contour en pointillés. Leurs info-bulles montrent les heures réelles d’observation et de réception. Les traces courtes conservent au plus 64 positions acceptées et se rompent au niveau des écarts alignés. Le fond de carte d’ensemble Natural Earth fourni dans le paquet ne nécessite aucun service de tuiles externe. Le panoramique, la navigation au clavier et les contrôles de zoom restent disponibles pendant les mises à jour. Une panne de requête efface les pistes et la sélection ; la récupération garde la carte montée.
Couches de zones gouvernées
Ajoutez des couches de zones à apps.map à l’aide de requêtes déclarées séparément :
areas = apps.zones(
"zones",
geometry="boundary",
label="name",
classification="category",
title="Operational areas",
)
# Add to the apps.map(...) call above:
# zone_layers=[areas]La requête zones doit autoriser les trois propriétés mappées. boundary contient du texte de géométrie GeoJSON (une chaîne JSON avec type et coordinates), par exemple :
{"type":"Polygon","coordinates":[[[3,52],[4,52],[4,53],[3,52]]]}Les trous de polygone et les géométries MultiPolygon sont pris en charge. Les coordonnées sont deux valeurs numériques WGS84 longitude/latitude, la longitude étant comprise entre ±180° et la latitude entre ±85°. Les anneaux doivent être fermés et avoir au moins trois sommets distincts. Découpez la géométrie à l’antiméridien. L’affichage n’accepte ni URL, ni Features, ni systèmes de coordonnées personnalisés, ni géométrie arbitraire intégrée au code du notebook.
Une géométrie est limitée à 16 Kio de texte UTF-8 et 1 024 positions, avec au plus 32 anneaux par polygone et 16 polygones. Chaque couche autorise au plus 1 000 zones et 32 000 positions ; une carte autorise huit couches. Le libellé et la classification doivent être des chaînes non vides d’au plus 512 caractères. Un mappage ou une géométrie invalide, ou une limite dépassée, efface cette couche et affiche un diagnostic ; l’affichage ne tronque jamais silencieusement la couverture des zones. Des données corrigées se rétablissent via le même abonnement.
Chaque couche dispose d’un interrupteur de visibilité sur la carte et, en dessous, d’une légende avec les noms et classifications autorisés et son propre état de source. Masquer une couche ne met pas sa requête en pause et ne modifie pas la surveillance. La visibilité survit aux mises à jour et à la récupération de la requête. Une requête de zones en échec efface ses polygones et sa légende tandis que les mises à jour des navires continuent ; une requête de navires en échec n’efface pas les zones disponibles. La couleur d’une couche identifie la couche, et non une gravité ou une classification. L’état de santé actuel de la source reste inconnu sauf s’il est fourni par un contrat d’état faisant autorité.
Le rendu des zones ne valide pas la topologie complète des polygones et n’active aucune surveillance. Les règles de surveillance et la validation de leur géométrie relèvent du service de détection indépendant. Le rapport d’état des sources, les autres composants COP et la qualification de bout en bout de la latence et de la charge sont encore en cours de développement.
Couches de points
Les objets dotés d’une dernière position connue mais sans mouvement en direct — un registre de navires, des capteurs fixes, des ports — s’affichent dans leur propre couche avec apps.points, passée dans apps.map(point_layers=[...]) :
registry = apps.points(
"vessels",
latitude="lastLatitude",
longitude="lastLongitude",
label="name",
classification="riskLevel",
heading="heading", # facultatif, degrés depuis le nord
selection_group="vessels", # sélectionner un point le sélectionne dans ce groupe
title="Vessels of interest",
)
# apps.map(..., point_layers=[registry])Chaque point est un symbole de navire orienté selon son heading ; un objet sans cap, ou une couche qui n’en déclare pas, s’affiche comme un anneau. Une classification critical ou high, elevated, medium ou moderate, et low ou info prend la couleur de gravité correspondante ; toute autre valeur prend la couleur de la couche. Le nom apparaît au survol, au focus et à la sélection. Sélectionner un point le publie dans le selection_group de la couche : un tableau ou un panneau de détails du même groupe le suit, et une sélection faite là met le point en évidence.
La requête doit autoriser chaque propriété mappée. La latitude reste dans ±85° et la longitude dans ±180° ; un cap vaut 0–360 ou null. Un objet dont la position est invalide est laissé hors de la carte et la couche le signale ; au-delà de 1 000 objets, la couche est effacée. Une carte autorise huit couches de points, chacune avec un interrupteur de visibilité et une légende qui compte ses classes.
Alimenter une app depuis un notebook de pipeline
Une app publiée ne lit que ses requêtes déclarées ; elle n’exécute jamais de SQL. Pour afficher un résultat dérivé — une jointure d’une table gérée avec des objets d’ontologie — calculez-le dans un notebook de pipeline distinct, écrivez le résultat dans une table gérée et liez un type d’objet à cette table. L’app déclare ensuite une requête sur ce nouveau type comme sur n’importe quel autre.
from scrydon import ontology, sql, tables
vessels = sql.query("SELECT vessel_id, name, last_latitude, last_longitude FROM mik_vessel_registry")
zones = ontology.read("MaritimeZone", ontology_slug="scrydon-pack-mik-north-sea-v2", limit=100)
exposure = join_positions_to_zones(vessels, zones) # pandas ordinaire
created = tables.create(
"mik_vessel_zone_exposure", exposure, exist_ok=True, primary_key=["exposure_id"],
)
if not created["created"]:
tables.write("mik_vessel_zone_exposure", exposure, mode="replace")La table est créée dans l’environnement d’espace de travail où s’exécute le notebook, là où une liaison silver_table résout son source.table. Créez-la avec primary_key égal aux identityColumns de la liaison : une lecture gouvernée ne sert une table liée que si sa clé primaire est cette identité, sinon l’app affiche la requête comme indisponible. Une clé ne change pas en place : avec exist_ok=True, une table existante dotée d’une autre clé lève TableExistsError. mode="replace" avec un DataFrame vide vide la table : une exécution qui ne trouve rien efface le résultat précédent. Construisez un résultat vide avec des dtypes explicites : tables.create en déduit les types de colonnes. Le pipeline s’exécute sous l’identité de la personne qui le lance, avec son habilitation et son masquage ; les spectateurs de l’app lisent ensuite les objets dérivés sous les leurs. Le notebook de pipeline déclare duckdb et sqlglot dans son bloc de dépendances, car sql.query en a besoin (Interroger les tables en SQL). L’exemple MIK en fournit un : exposure.py.