SIDE_SLOT et SLOT_PERSIST ne gardent plus la conversation au Go. La
machinerie reste au Go (configuration, requêtes en vol, tampon du slot) ;
la façade la consulte avant chaque requête au moteur local.
Go :
- /internal/v1/turn/slot (facade_slots.go) rend engineSlotFor et, pour
une étape de tour, recharge d'abord l'état gardé de la discussion
(slotPersistRestore). La sauvegarde à la bascule voit les étapes de la
façade : /internal/v1/oai/served marque le slot (engineMarkMain).
- facadeChatBlocker : SIDE_SLOT et SLOT_PERSIST retirés.
Rust :
- TurnHost::engine_slot : l'id_slot posé dans chaque requête (0 pour le
fil de la discussion, 1 pour la vérification), le ticket « en vol »
ouvert sur le second slot.
- Cache KV plein en plein calcul (sideSlotPoolError) : rejoué deux fois
tel quel, sans compaction, puis l'erreur.
- Résumés de compaction comptés en vol comme postSummary : transcription
sur le second slot, continuation sur le slot 0.
- La passe de vérification est un travail annexe (engineSideJob) : le Go
efface le slot à la fin s'il a servi (écart du lot 7 levé).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
main a reçu en parallèle la télémétrie du tour tenu par la façade
(/internal/v1/turn/perf), les tickets « en vol » du moteur et la
conversation tenue par la façade par défaut (LOKI_CHAT=go pour revenir
au Go). Le lot 29 faisait la même chose par /internal/v1/perf/record :
un seul chemin est gardé, celui de main.
- TurnHost::perf_record (main) remplace TurnHost::perf ; la nature est
posée par l'hôte (verify pour la passe isolée seulement, main pour les
corrections du builder, comme le Go).
- Les résumés de compaction passent par le même point d'entrée, nature
compact : chat/perf.rs ne garde que le relevé de la réponse entière
(perfRecFromWire) et l'envoi.
- La sonde du gabarit reste à la façade (lot 23) : /internal/v1/turn/perf
ne la lance plus côté Go.
- facade_perf.go retiré ; ses cas (perte, intercalé, alerte, preset
externe, incomplète, GET) rejoignent web_internal_turnperf_test.go.
- README : LOKI_CHAT défaut Rust, avec ce que les lots 19, 23, 29 et 30
y ajoutent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
La surcharge retry_patterns (tableau JSON de regex du Go, chacune en
(?mi)) ne garde plus la conversation au Go : la façade la lit au
démarrage de sa conversation, comme le Go la compile une fois par
processus ; illisible ou vide, les motifs embarqués s'appliquent, une
regex illisible est sautée.
Les regex restent celles du Go : chat::stream::go_regex réécrit pour le
crate regex ce qui n'a pas le même sens — classes Perl et limites de mot
ASCII (\w \d \s \b et leurs contraires, dans et hors d'une classe),
\Q…\E (refusé dans une classe, comme le Go), [ && -- ~~ dans une classe,
octal permis, référence arrière refusée.
Parité : parity_retry_test.go compile côté Go une soixantaine de regex
(dont celles qu'il refuse) et note leur première correspondance sur onze
textes (accents, chiffres non ASCII, espaces insécables, crochets) ;
tests/retry.rs rejoue le journal à l'identique et vérifie la lecture de
la surcharge au démarrage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Quand la façade tient la conversation (LOKI_CHAT=rust), ses complétions
rejoignent l'anneau de télémétrie du Go (perf_log.go) au lieu de passer
inaperçues : /api/perf/summary les compte, l'optimiseur en tire ses
poids, et l'interface reçoit à nouveau la perte de cache.
- chat/perf.rs : perfRecFromStats, perfRecFromWire (lu sans échec
possible, mêmes tolérances que perfNum, timings d'un autre type
présents mais vides comme le Go) et perfPrefix (FNV-1a cumulé) ;
- la boucle du tour range chaque complétion lue, numérotée dans le tour,
avec ses empreintes si elle est complète ; une complétion coupée par un
stop est rangée incomplète ; la dernière statistique porte la nature,
la perte, ce qui s'est intercalé et l'alerte ;
- natures : main (tour), verify (vérification du mode Code), compact
(résumé de compaction, rangé dès que la réponse se lit) ;
- le Go (/internal/v1/perf/record) range le relevé comme les siens et
calcule l'alerte au seuil du preset actif, jamais pour un preset
externe.
Tests : relevés et empreintes (chat/perf.rs), télémétrie de la boucle
(complète, coupée), du vrai hôte et des résumés (tests/lot6.rs),
TestFacadePerf côté Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Port de chat_tplprobe.go : la façade sonde le gabarit du moteur après ses
complétions (/health, /props, /apply-template), avec les verdicts
preserves_history, prefix_stable et renders_reasoning, le cache par
build/modèle/gabarit/forme et la relance bornée.
- l'écho du raisonnement suit le verdict de la sonde (echo_policy_for) ;
- NUDGE_IN_TOOL ne garde plus la conversation au Go : le rappel de budget
va dans le dernier résultat d'outil quand le préfixe n'est pas stable ;
- le Go lit le verdict de la façade (/internal/facade/v1/chat/tpl) quand
elle tient la conversation.
Parité : parity_tplprobe_test.go tire du Go un journal d'échanges rejoué
octet pour octet par tests/tplprobe.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Trois choses manquaient au tour tenu par la façade, actives même sans
clé opt-in, et qu'il fallait avant d'en faire le défaut :
- la télémétrie de chaque complétion (perfRecord) : /api/perf/summary et
l'alerte « cache perdu » posée sur les stats finales d'une étape. La
boucle Rust la remet au Go (/internal/v1/turn/perf) au même moment que
la boucle Go, avec ses empreintes de messages ; le Go range, calcule la
perte et rend nature, jetons perdus et alerte, posés sur la copie finale
des stats ;
- la sonde du gabarit, lancée dans les mêmes conditions (requête de forme
normale du moteur local) ;
- le comptage des requêtes en vol : chaque requête au moteur local ouvre
un ticket (/internal/v1/oai/begin), marqué servi à la réponse 200
(engineServed, engineMarkMain pour une étape de la discussion), rendu en
fin de lecture du flux. Le slot de la discussion n'est ainsi ni effacé
pendant une requête ni pris pour un autre.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Avec LOKI_CHAT=rust, changer de projet passait par projectSwitch du Go,
qui enregistrait SA copie de la discussion — chargée au démarrage, périmée
— par-dessus celle de la façade, ouvrait une autre discussion que la façade
ignorait, et ne voyait pas un tour de la façade en cours. Désormais :
- /api/projects (switch) remet le changement à la façade
(/internal/facade/v1/project/switch) : elle enregistre sa discussion avec
le projet quitté, fait changer le projet actif au Go
(/internal/v1/project/activate), ouvre la plus récente du nouveau projet
(une neuve s'il n'en a pas) ; refusé pendant un tour (409) ;
- supprimer un projet : la façade le quitte d'abord s'il est actif, puis
supprime ses discussions (/internal/facade/v1/project/drop).
Réglages que la façade ne sait pas honorer (PROJ_SNAPSHOT,
KEEP_TURN_IMAGES, NUDGE_IN_TOOL, SIDE_SLOT, SLOT_PERSIST, PREWARM, motifs
retry_patterns) : le Go garde la conversation, décidé une fois au démarrage
(facadeChatBlocker) ; la façade le lit (/internal/v1/chat/holder) avant de
servir quoi que ce soit, au lieu d'échouer en plein tour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Port de codeVerifyLoop (rust/loki-rs/src/chat/verify.rs) : à la fin d'un
tour de build en mode Code, relances du builder sur les critères encore
ouverts, passe de vérification sur un contexte isolé, corrections, abandon
dit dans le fil après deux corrections — mêmes deltas que le Go (role,
verify_done, mesures ctx_isolated), relances et corrections rangées dans
l'historique, vérifications non.
Le Go garde les critères (l'outil criteria s'y exécute) : la façade les lit
en base (chat/crit:<id>) et reçoit le contexte isolé du vérificateur par
POST /internal/v1/turn/verifier (prompt du rôle et faits de la machine,
outils fermés, rôle verifier, seul autorisé à marquer passed). Toute
compaction en mode Code rend l'état des critères au résumé, comme
compactMessages.
generate : vue du tour factorisée (turn_view), question à l'utilisateur
suivie (une question posée suspend la vérification).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Une requête qui porte le jeton interne vient du Go, qui l'a déjà
authentifiée (tunnel du relais) : les routes du chat la servent sans
redemander la clé. L'API interne de la façade, réservée à ce jeton, reçoit
les événements d'affichage nés au Go (mode Code, critères) et le
rechargement après déverrouillage : une discussion chargée vide mémoire
verrouillée revient au déverrouillage, jamais par-dessus un fil rempli
(sinon le premier message aurait écrasé la discussion chiffrée).
Le relais par la façade de /api/chat/mode et /api/chat/criteria et les
critères rendus par l'outil disparaissent : le Go pousse ses événements
lui-même, une seule source quel que soit le chemin.
README : LOKI_CHAT=rust et ce qu'il ne prend pas encore en charge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Avec LOKI_CHAT=rust, la façade charge la discussion active au démarrage
et sert elle-même /api/chat (flux SSE : rejeu puis direct, battement de
cœur toutes les 4 s, trames regroupées), /api/chat/send, stop, reset,
state, compact, tool-result et /api/conversations{,/new,/switch,/rename,
/delete}, avec les réponses des handlers Go. /api/chat/mode et
/api/chat/criteria restent au Go ; la façade relaie puis journalise
l'état rendu, pour que tous les appareils suivent. Pièces jointes,
fichiers, images et export restent au Go, qui suit la discussion active.
Le Go reçoit LOKI_CHAT=rust et l'adresse de la façade (étape suivante :
lui remettre le trafic de chat du tunnel). Sans la variable, rien ne
change : tout part au Go comme avant.
ChatService gagne reset (fichiers effacés par le Go), la compaction
manuelle, le résultat complet d'un outil et le relais d'un événement ;
les critères changés par l'outil criteria sont journalisés pendant le
tour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
Port d'EnqueueOrStart, StartTurn, generate, drainQueued,
startQueuedIfAny, dropQueued et compactAndPublish :
- envoi : réessai reconnu (cid), tour préparé par le Go (/turn/start), mis
en file si un tour tourne, sinon moteur prêt (/health), verrou du tour
puis bail du moteur du Go, bulle journalisée et enregistrée tout de suite ;
- tour : compaction de début de tour, vue d'envoi (tête du Go, historique
sans <context_update>, préambule fusionné comme InjectSkills), boucle
dont chaque événement devient un delta du journal, historique rangé
(outils, réponse, raisonnement renvoyé, rappels en porte-à-faux retirés),
contexte estimé si le moteur ne le compte pas, compaction de fin de tour ;
- fin : turn_done, journal coalescé, verrou et bail rendus, discussion
enregistrée, file abandonnée après un stop ou message suivant lancé,
sinon Web Push ;
- stop : le tour en cours, ou le détenteur Go du moteur.
chat::history porte historyFromView, dropStrayNudges, le rappel des pages
mémoire lues, l'assemblage d'InjectSkills et la forme des tool_used du
journal, avec leurs tests Go. ConvState garde ctxUsedLen et genPeak en
mémoire seulement. EngineLease::interrupted ne garde plus de verrou à
travers une attente.
Écarts : boucle de vérification du mode Code, critères pour la
compaction, préchauffage, télémétrie, retry_patterns personnalisés.
Tests de bout en bout : tour complet (outil, réponse, bail rendu,
discussion enregistrée, doublon), message en file injecté entre deux
étapes, moteur tenu par une tâche planifiée (409, stop), moteur pas prêt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv