feat(orchestrator): modèle de désignation d'orchestrateur + sink de diagnostic

Introduit le modèle AgentManifest { version, entries, orchestrator } et la
garde d'écriture directe may_write_directly(..., &OrchestratorDesignation) :
seul l'orchestrateur désigné peut écrire directement, les autres passent par
le rendez-vous médié. Câble la désignation à travers domain → application →
infrastructure → app-tauri (context_guard, service, lifecycle, ports).

Ajoute crates/application/src/diag.rs : sink de diagnostic best-effort, sans
dépendance, qui miroite les traces du rendez-vous inter-agents de
l'orchestrateur vers un fichier de log persistant (utile au lancement via
AppImage où stderr est jeté), avec la même discipline « zéro dépendance,
ne casse jamais le rendez-vous ».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 08:56:17 +02:00
parent 40982d44da
commit 287681c198
57 changed files with 1758 additions and 420 deletions

View File

@ -172,6 +172,16 @@ pub enum DomainEventDto {
/// badge the source.
source: OrchestrationSourceDto,
},
/// The project's orchestrator designation changed (T1).
#[serde(rename_all = "camelCase")]
OrchestratorChanged {
/// The project whose designation changed.
project_id: String,
/// The newly designated orchestrator agent, or `None` for the default
/// (the oldest agent orchestrates).
#[serde(skip_serializing_if = "Option::is_none")]
orchestrator: Option<String>,
},
/// A memory note was created or updated.
#[serde(rename_all = "camelCase")]
MemorySaved {
@ -401,6 +411,13 @@ impl From<&DomainEvent> for DomainEventDto {
ok: *ok,
source: (*source).into(),
},
DomainEvent::OrchestratorChanged {
project_id,
orchestrator,
} => Self::OrchestratorChanged {
project_id: project_id.to_string(),
orchestrator: orchestrator.as_ref().map(|a| a.to_string()),
},
DomainEvent::MemorySaved { slug } => Self::MemorySaved {
slug: slug.as_str().to_string(),
},