Lot 31 : slots du moteur pour le tour tenu par la façade

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
This commit is contained in:
Claude committed 2026-10-16 02:13:20 +00:00
1 parent 89ed527c96
commit a005626e66
14 files changed
+679 -58

No files matched your search

+22 -1
View File
@@ -127,6 +127,11 @@ pub struct FakeGo {
pub service_os_fail: Mutex<Option<(String, String)>>,
/// /internal/v1/turn/perf reçus (corps entiers).
pub perf_records: Mutex<Vec<serde_json::Value>>,
/// /internal/v1/turn/slot : second slot en service (le fil de la
/// discussion sur le 0, le reste sur le 1 ; sinon aucun) ; demandes
/// reçues (« conv main »).
pub turn_side_live: Mutex<bool>,
pub turn_slots: Mutex<Vec<String>>,
}
impl FakeGo {
@@ -666,10 +671,11 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
let body = req.into_body().collect().await.unwrap().to_bytes();
let v: serde_json::Value = serde_json::from_slice(&body).unwrap();
if let Some(conv) = v["main_conv"].as_str() {
let side = if v["side"] == true { " side" } else { "" };
st.oai_log
.lock()
.unwrap()
.push(format!("begin main_conv={conv}"));
.push(format!("begin main_conv={conv}{side}"));
} else {
st.oai_log.lock().unwrap().push(format!(
"begin read={} side={} post_v1={}",
@@ -681,6 +687,21 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
}
resp(200, r#"{"ticket":7}"#)
}
"/internal/v1/turn/slot" => {
let body = req.into_body().collect().await.unwrap().to_bytes();
let v: serde_json::Value = serde_json::from_slice(&body).unwrap();
let main = v["main"] == true;
st.turn_slots
.lock()
.unwrap()
.push(format!("{} {main}", v["conv"].as_str().unwrap_or("")));
let slot = match (*st.turn_side_live.lock().unwrap(), main) {
(false, _) => -1,
(true, true) => 0,
(true, false) => 1,
};
resp(200, serde_json::json!({ "slot": slot }).to_string())
}
"/internal/v1/oai/served" => {
let body = req.into_body().collect().await.unwrap().to_bytes();
let v: serde_json::Value = serde_json::from_slice(&body).unwrap();