En conteneur, start/stop/restart/status du moteur passent par
`loki-rs engine <action>`, port à l'identique de la supervision Go :
`loki serve` lancé chef de session, fichier PID et journal aux mêmes
chemins (serviceIsActive, l'UI et `loki logs` lisent les mêmes fichiers),
contrôle à 2 s avec la fin du journal en cas d'échec, arrêt de tout
l'arbre — session, groupe et filiation, pour le moteur de Strata qui prend
sa propre session — avec les mêmes délais (SIGTERM, 4 s, SIGKILL, 20 s).
Le Go garde ses garde-fous (optimisation en cours, preset externe) puis
délègue au loki-rs voisin de son binaire ; la dernière ligne d'erreur du
superviseur devient l'erreur montrée par l'UI. LOKI_ENGINE_SUPERVISOR=go
revient à l'ancienne supervision. `loki serve`, qui construit la ligne de
commande du moteur, ne change pas : il aura son propre lot.
Le contrôle « démarré ? » regarde si l'enfant est sorti plutôt que le
signal 0 : un enfant mort reste un zombie tant que son parent vit, et un
zombie répond encore au signal 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
En conteneur, userSvcStop n'attendait que le processus `loki serve`. Avec
Strata, le moteur qui tient la VRAM (cache d'experts, ~9 Go) est un autre
processus qui finit de s'arrêter après le serveur Python : la relance
suivante démarrait llama-server sur une carte encore pleine (« cudaMalloc
failed: out of memory » à l'encodeur de vision) et Strata mesurait la RAM
disponible avec l'ancien moteur encore chargé (mode mmap choisi à tort).
stopProcTree relève l'arbre (session, groupe et descendants) avant tout
signal, SIGTERM puis SIGKILL aux survivants, et ne revient qu'une fois
tout parti.
Diagnostic : une pile d'appels citant load_model ne passe plus pour une
nouvelle tentative (la cause mémoire était perdue), et le chat donne
l'échec de chargement au lieu de « il démarre, réessaie ».
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wfx8uW1un1WwWJ6xzAbkV
- Désactivation du chiffrement (amont cac0cda, 19918c6) : une valeur
illisible ne bloque plus tout (quarantaine datée + copie du keyvault), et la
reprise au démarrage déchiffre aussi les conversations au lieu de retirer la
clé après les seules pages. Propre à Loki : les images de conversation
(chatimg/) sont maintenant déchiffrées elles aussi — elles restaient
chiffrées sans clé. Les .bak chiffrés devenus illisibles sont retirés.
- Preset externe (amont #95) : `loki serve` sort sans erreur (plus de boucle
systemd « MODEL non défini »), le pré-vol l'accepte, le superviseur du
conteneur ne le prend plus pour un plantage.
- Unité systemd du moteur : TimeoutStopSec=5 (bascule de preset bloquée 90 s
en pleine génération).
- Heartbeat SSE (amont #105) : plus d'écriture après le retour du handler.
- Paramètres → Configuration : commande exacte du moteur copiable (clé API
masquée, Strata compris) et nombre de couches du modèle à côté de NGL, lu
dans l'en-tête GGUF (amont #108, #43) ; aussi dans l'éditeur de preset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nouveau sys_service_container.go : supervision par fichier PID portée du mode
utilisateur macOS (Setsid, SIGTERM sur le groupe puis SIGKILL, log fichier).
sys_service_linux.go bascule automatiquement quand /run/systemd/system est
absent ou que LOKI_CONTAINER=1 ; une install systemd classique est inchangée.
Le tunnel ajean.link suit la même logique (uiServiceCtl / uiServiceActive).
Sans ce repli, changer de modèle depuis l'UI (serviceAction restart)
échouait sur un systemctl absent — le conteneur était inutilisable.
Testé sans systemd : start / status / restart / stop, PID suivi,
processus enfant arrêté avec le groupe. build linux+darwin+windows OK,
go vet + go test verts.