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:
@ -187,7 +187,10 @@ async fn structured_run_turn_without_plan_does_not_sandbox() {
|
||||
.expect("run_turn natif réussit");
|
||||
|
||||
assert_eq!(lines, vec![RESULT_LINE.to_owned()]);
|
||||
assert!(allowed_marker.exists(), "écriture in-grant réussit (sans plan)");
|
||||
assert!(
|
||||
allowed_marker.exists(),
|
||||
"écriture in-grant réussit (sans plan)"
|
||||
);
|
||||
assert!(
|
||||
denied_marker.exists(),
|
||||
"sans plan, l'écriture hors-grant DOIT réussir: {denied_marker:?} absent — restriction ambiante anormale"
|
||||
@ -278,7 +281,10 @@ async fn structured_run_turn_fail_closed_no_child_on_enforce_err() {
|
||||
async fn structured_run_turn_none_plan_is_native_path() {
|
||||
let dir = fresh_dir("p4");
|
||||
let marker = dir.join("native.txt");
|
||||
let script = format!("printf '%s\\n' '{RESULT_LINE}'; echo ok > '{}'", marker.display());
|
||||
let script = format!(
|
||||
"printf '%s\\n' '{RESULT_LINE}'; echo ok > '{}'",
|
||||
marker.display()
|
||||
);
|
||||
let spec = SpawnLine {
|
||||
command: "sh".to_owned(),
|
||||
args: vec!["-c".to_owned(), script],
|
||||
@ -327,7 +333,10 @@ async fn structured_two_turns_disjoint_grants_are_confined() {
|
||||
run_turn(&spec_a, None, Some(&enforcer))
|
||||
.await
|
||||
.expect("tour A ok");
|
||||
assert!(a_in.exists(), "tour A: écriture dans son grant (A) doit réussir");
|
||||
assert!(
|
||||
a_in.exists(),
|
||||
"tour A: écriture dans son grant (A) doit réussir"
|
||||
);
|
||||
assert!(
|
||||
!a_into_b.exists(),
|
||||
"tour A: écriture dans B (hors grant A) doit être bloquée"
|
||||
@ -419,7 +428,9 @@ async fn structured_sandboxed_turn_preserves_conversation_id() {
|
||||
use super::factory::StructuredSessionFactory;
|
||||
|
||||
if !landlock_is_enforced() {
|
||||
eprintln!("skip structured_sandboxed_turn_preserves_conversation_id: Landlock indisponible");
|
||||
eprintln!(
|
||||
"skip structured_sandboxed_turn_preserves_conversation_id: Landlock indisponible"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -448,6 +459,7 @@ async fn structured_sandboxed_turn_preserves_conversation_id() {
|
||||
let ctx = PreparedContext {
|
||||
content: MarkdownDoc::new("# ctx"),
|
||||
relative_path: "CLAUDE.md".to_owned(),
|
||||
project_root: run_dir.to_string_lossy().into_owned(),
|
||||
};
|
||||
let cwd = ProjectPath::new(run_dir.to_string_lossy().into_owned()).expect("cwd absolu");
|
||||
let plan = rw_plan(&run_dir); // plan write-only ⇒ reads/exec du fake non gênés
|
||||
@ -466,7 +478,10 @@ async fn structured_sandboxed_turn_preserves_conversation_id() {
|
||||
.iter()
|
||||
.filter(|e| matches!(e, ReplyEvent::Final { .. }))
|
||||
.count();
|
||||
assert_eq!(finals, 1, "un Final attendu malgré le sandbox, vu: {events:?}");
|
||||
assert_eq!(
|
||||
finals, 1,
|
||||
"un Final attendu malgré le sandbox, vu: {events:?}"
|
||||
);
|
||||
|
||||
// LE POINT : l'id de conversation a bien été capté sous enforcement actif.
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user