Quando Metnos ha già scelto un executor e ne ha preparato gli argomenti, esegue un ultimo controllo locale prima di avviarlo. Questo controllo, chiamato guardia di Vaglio, riconosce alcuni percorsi e comandi esplicitamente vietati. Nel codice esiste anche un giudice a punteggio, ma oggi non partecipa al normale percorso di esecuzione.
La guardia riceve il nome dell'executor e i suoi argomenti ormai definitivi. La risposta è binaria: passa oppure blocca. Se blocca, il runtime non invoca l'executor e interrompe il piano.
Il suo compito è volutamente ristretto. Vaglio non sceglie l'executor, non stabilisce se la richiesta sia utile, non concede autorizzazioni e non sostituisce la policy, il consenso umano, la sandbox o i controlli propri dell'executor. Sono protezioni diverse, che devono restare indipendenti.
| Parte del modulo | Uso nel normale runtime |
|---|---|
| Guardia deterministica | Attiva prima dell'invocazione. |
| Giudice a punteggio | Disponibile come API separata, ma non collegato al normale dispatcher. |
guard_check(executor_name, args, context) percorre gli argomenti
annidati e cerca stringhe che possono indicare una destinazione o una risorsa.
Ignora invece i valori di campi dichiaratamente testuali, come
content, body, comment e
message: un documento che cita ~/.ssh non sta
necessariamente tentando di leggerla.
| Controllo | Che cosa blocca |
|---|---|
| Percorsi sempre vietati | Fra gli altri:
~/.ssh, .gnupg, i comuni file di credenziali AWS,
/etc/passwd, /etc/shadow, /etc/ssh,
/root, /boot, parti di /proc e i
dispositivi a blocchi. |
| Modifiche agli alberi di sistema | Scritture,
spostamenti, creazioni e cancellazioni sotto le directory protette del sistema
operativo ospite, come /etc e /usr su Linux. Le letture
non sono bloccate da questa regola. |
| Comandi shell quasi irreversibili | Pattern chiusi come la formattazione di un filesystem, la scrittura diretta su un dispositivo, la cancellazione ricorsiva della radice e una fork bomb. |
Il controllo sugli alberi di sistema riconosce le azioni mutanti dal prefisso
canonico del nome dell'executor, per esempio write_,
delete_ o move_. Il controllo shell usa sempre il nome
shell_exec; può anche usare capability=code:exec quando
il chiamante fornisce quel contesto. Il normale collegamento del runtime, oggi,
passa soltanto nome e argomenti.
Quando non trova una regola violata, la guardia restituisce
(True, None). Significa soltanto «nessuno dei divieti conosciuti
è stato riconosciuto», non «questa azione è sicuramente innocua».
La richiesta «Leggi /etc/hosts e mostrami le righe non
commentate» può passare: /etc/hosts non appartiene alla lista dei
percorsi sempre vietati e read_files non modifica il sistema.
Se la richiesta diventa «Sostituisci /etc/hosts con questo
contenuto» e il runtime prepara un write_files, la combinazione fra
azione mutante e percorso protetto viene bloccata prima dell'invocazione. Anche la
semplice lettura di /etc/shadow, invece, viene fermata: quel file
appartiene alla lista sempre vietata.
Il modulo espone anche
judge(intent, executor_name, args, context). Questa funzione esegue
prima la guardia e poi, se la guardia lascia passare l'azione, restituisce un
Verdict completo:
| Campo | Significato |
|---|---|
approved | Esito complessivo della chiamata. |
reason | Motivazione tecnica prodotta dal modulo. |
ts | Data e ora Unix della decisione. |
judge_kind | rule-based-v1,
llm-v1 oppure safe-verb-shortcut. |
score | Punteggio da 0 a 1; vale 0 quando blocca la guardia. |
blocked_by | guard, judge o
nessun valore quando la chiamata approva. |
I verbi di sola lettura o di calcolo elencati in SAFE_VERBS, come
read, find e compare, vengono approvati
dopo la guardia senza chiamare il giudice a punteggio. L'esito usa
judge_kind=safe-verb-shortcut.
rule-based-v1. È il backend predefinito
dell'API judge(). Parte da 0.7, aggiunge un piccolo bonus
se il testo della richiesta contiene una parte del nome dell'executor e applica
penalità per un possibile attraversamento di directory o per chiavi di argomento
anomale. Con le penalità oggi implementate il punteggio minimo è
0.4; la soglia predefinita è 0.30. Con questa
configurazione il giudice segnala anomalie, ma non respinge un'azione che ha già
superato la guardia.
llm-v1. È facoltativo e usa il carico di lavoro
vaglio.judge, oggi assegnato al tier middle. Riceve
l'intento, il nome dell'executor, i nomi delle chiavi degli argomenti e pochi campi
di contesto; non riceve i valori degli argomenti. Il modello di prompt viene scelto
nella lingua attiva, ma il testo che presenta questi dati usa ancora etichette
italiane: questa API interna non è quindi ancora completamente allineata alla
struttura i18n.
Se il router, il modello o l'analisi della risposta falliscono,
llm-v1 restituisce 0.5. Con la soglia predefinita il
ripiego approva. Il giudice è perciò un'euristica sperimentale, non un controllo
di sicurezza fail closed e non una prova che l'azione corrisponda ai fini
dell'utente.
Il dispatcher passa guard_check al motore condiviso come
vaglio_guard. Il motore lo usa nel controllo preliminare delle
letture eseguite in parallelo e, per i passi ordinari, immediatamente prima di
invocare l'executor. Un rifiuto produce la classe di errore
vaglio_guard e ferma il piano senza eseguire quel passo.
Il motore accetta anche un callback chiamato vaglio_judge, ma il
dispatcher di produzione non glielo fornisce. Inoltre, il punto di estensione
attuale si trova dopo il risultato di un passo: se venisse collegato così
com'è, potrebbe fermare i passi successivi, non impedire l'effetto appena
avvenuto. Non va quindi descritto come un secondo controllo preventivo.
Sempre nello stesso modulo esiste
check_cross_user_send(), che consente gli invii dell'host e verso se
stessi e rifiuta gli altri. È una funzione disponibile ai chiamanti, non una
prova che ogni percorso di messaggistica la invochi.
Ogni chiamata a judge() aggiunge un record JSONL al file mensile
nella directory utente vaglio/. Il record contiene il verdetto,
l'intento, il nome dell'executor, i nomi delle chiavi degli argomenti e quelli
del contesto. Non contiene i valori degli argomenti. L'intento, però, può
contenere informazioni personali e il registro va trattato come dato riservato.
La guardia usata direttamente dal normale runtime non scrive questi record:
un blocco compare nell'esito del passo e nei log del motore. Se la scrittura del
registro mensile fallisce, judge() conserva comunque il proprio
verdetto.
| Impostazione | Valore predefinito | Effetto |
|---|---|---|
METNOS_JUDGE_KIND | rule-based-v1 | Backend usato soltanto dai chiamanti di judge(). |
METNOS_JUDGE_THRESHOLD | 0.30 | Soglia applicata dal giudice a punteggio. |
runtime/vaglio.py: guardia, giudici, verdetto e log.runtime/platform_policy.py: alberi protetti per piattaforma.runtime/engine/executor.py: guardia pre-invocazione.runtime/agent_runtime.py: collegamento del dispatcher corrente.