Unknown è un errore o un risultato?
Quando inizi a classificare le interazioni come Human, Human + AI, Agent o Unknown, il bucket Unknown è spesso più grande di quanto le persone si aspettino. È naturale tentare di trattarlo come una lacuna da nascondere, sia assorbendo Unknown in Human sia considerandolo sospetto. Entrambe le scelte creano problemi.
Unknown significa che le evidenze disponibili non supportano una determinazione affidabile. Una request da un client che non esegue JavaScript, una call a un endpoint in cui non raccogli segnali, una sessione terminata dopo una sola pagina: tutto questo può essere perfettamente legittimo, e nessuno di questi casi ti dà abbastanza elementi per dire chi o cosa stava agendo.
Rendere conto di Unknown in modo onesto è ciò che mantiene affidabili le altre classi. Se il tuo sistema non dice mai Unknown, ogni risultato Human è in parte un'ipotesi, e non puoi distinguere quale parte lo sia. Il nostro articolo su perché Unknown è un risultato valido quando si classifica il traffico AI spiega il ragionamento in modo più approfondito.
Questa guida tratta come gestire Unknown nella pratica: fallback espliciti per ogni route, le regole che evitano che si riversi in altre classi, come monitorarlo e come ridurlo dove conta.
Passo 1: non usare mai Human come valore predefinito
L'errore più comune è una funzione di classificazione che restituisce Human ogni volta che non trova un segnale di automazione. Sembra ragionevole, ma è sbagliata. L'assenza di un segnale bot non equivale alla presenza di un segnale umano.
// Wrong: silence becomes Human
function classifyWrong(e: Evidence) {
if (e.signatureValid) return { actor: "agent", basis: "verified" };
if (e.declaredAgent) return { actor: "agent", basis: "declared" };
return { actor: "human", basis: "inferred" };
}
// Right: Human requires positive evidence, otherwise Unknown
function classify(e: Evidence) {
if (e.signatureValid) return { actor: "agent", basis: "verified" };
if (e.declaredAgent) return { actor: "agent", basis: "declared" };
if (e.interactiveSession) return { actor: "human", basis: "inferred" };
return { actor: "unknown", basis: "unknown" };
}Applica la stessa regola ovunque vengano prodotti risultati: timeout, errori, entry di cache obsolete e telemetria mancante producono tutti Unknown. Scrivi un test per ciascuno di questi percorsi, così il comportamento non può regredire in silenzio. L'esempio qui sotto usa il Node.js test runner integrato.
import { test } from "node:test";
import assert from "node:assert/strict";
test("missing evidence is unknown, not human", () => {
const r = classify({ signatureValid: false, declaredAgent: false, interactiveSession: false });
assert.equal(r.actor, "unknown");
});Passo 2: assegna a ogni route un fallback esplicito
Unknown ha bisogno di un comportamento definito, e il comportamento giusto dipende dalla route. Decidilo per ogni route, scrivilo e tienilo nella configurazione. Per capire come questi fallback si inseriscono in un modello di policy più ampio, vedi progettare policy a livello di app per umani e agenti AI.
| Tipo di route | Esempio | Fallback sensato per Unknown |
|---|---|---|
| Contenuti pubblici | Pagine marketing, documentazione | Consentire, risposta standard |
| Dati in sola lettura | Catalogo, search API | Consentire con il rate limit standard |
| Creazione account | Signup | Mantenere i controlli esistenti, coda di review opzionale |
| Modifica sensibile | Password, email, dettagli di fatturazione | Reautenticazione esistente, nessuna allentamento |
| Azione ad alto valore | Export massivo, operazioni admin | Autorizzazione forte esistente |
Il pattern è semplice. Per le route a basso rischio, Unknown si comporta come traffico normale. Per le route ad alto rischio, Unknown riceve la stessa protezione già prevista per la route. In nessuno dei due casi il risultato dell'actor peggiora la situazione per un utente non classificato ma legittimo.
type Fallback = "allow" | "standard_limit" | "existing_checks" | "review";
const unknownFallback: Record<string, Fallback> = {
"GET /docs/*": "allow",
"GET /api/catalog": "standard_limit",
"POST /signup": "existing_checks",
"POST /account/password": "existing_checks",
"POST /exports": "review",
};Passo 3: tratta timeout ed errori allo stesso modo
La valutazione dell'actor si trova nel percorso della request, quindi deve avere un budget di tempo rigoroso. Quando il budget viene superato, produci Unknown e applica il fallback della route. Non bloccare mai una request perché la valutazione è stata lenta.
async function withBudget<T>(work: Promise<T>, ms: number, onTimeout: T): Promise<T> {
let timer: NodeJS.Timeout;
const timeout = new Promise<T>((resolve) => {
timer = setTimeout(() => resolve(onTimeout), ms);
});
try {
return await Promise.race([work, timeout]);
} finally {
clearTimeout(timer!);
}
}
const result = await withBudget(evaluateActor(req), 150, { actor: "unknown", basis: "unknown" });Registra il motivo per cui un risultato è Unknown: nessuna evidenza, timeout, errore di valutazione o evidenza obsoleta. Questi motivi ti dicono cosa correggere.
Passo 4: non trattare Unknown come sospetto
Unknown non è uno score di rischio. Molti client legittimi saranno sempre Unknown su alcune route: strumenti da riga di comando, integrazioni server-side senza firme, strumenti di accessibilità, browser orientati alla privacy e semplici lettori di feed. Anche i principali operatori AI oggi identificano per lo più i loro fetcher tramite user agent e range IP pubblicati. La documentazione del crawler di OpenAI, per esempio, elenca una stringa user agent e un file di indirizzi IP pubblicato per ciascuno dei suoi bot a partire da novembre 2026.
Se vuoi intervenire su comportamenti sospetti, basati su comportamenti che puoi descrivere, come tassi di request, pattern di login falliti o segnalazioni di abuso, con una propria evidenza. Mantieni questa logica separata dalla classe dell'actor, così nessuna delle due distorce l'altra.
Passo 5: come monitori il tuo tasso di Unknown?
Il tasso di Unknown è la quota di interazioni classificate Unknown. Traccialo per route, per contesto di integrazione e nel tempo. È una delle metriche di salute più utili che hai.
type Row = { route: string; actor: string };
export function unknownRate(rows: Row[]) {
const byRoute = new Map<string, { total: number; unknown: number }>();
for (const r of rows) {
const s = byRoute.get(r.route) ?? { total: 0, unknown: 0 };
s.total += 1;
if (r.actor === "unknown") s.unknown += 1;
byRoute.set(r.route, s);
}
return [...byRoute].map(([route, s]) => ({ route, rate: s.unknown / s.total, total: s.total }));
}Cosa ti dicono i numeri:
- Un tasso alto e stabile su una route di solito significa che lì ti manca un segnale. Una pagina che non carica mai la tua integrazione browser, o una API che non vede mai request firmate, resterà per lo più Unknown.
- Un aumento improvviso spesso significa che qualcosa è cambiato nel tuo stack, per esempio un rilascio che ha rimosso un header, una regola CDN che elimina gli header di firma, o una modifica frontend che ha smesso di inviare le dichiarazioni della tua app.
- Un calo improvviso merita attenzione anche lui. Se Unknown scende mentre Human sale, verifica che sia arrivata nuova evidenza invece di un fallback cambiato in silenzio.
Allerta sui cambiamenti bruschi, non sui livelli assoluti. Ogni application ha il proprio normale.
Passo 6: come riduci Unknown dove conta?
Non devi portare Unknown a zero. Ti serve abbastanza evidenza sulle route in cui le decisioni contano. Lavora in ordine di impatto:
- Aggiungi evidenza prima sulle route ad alto impatto. Se le modifiche all'account sono per lo più Unknown, è lì che un'integrazione browser o un controllo server-side dà ritorno.
- Invita i client automatici a identificarsi. Pubblica documentazione per la tua API che spieghi come gli agenti possono firmare le request con HTTP Message Signatures e con le convenzioni IETF Web Bot Auth, e offri ai client verificati un'esperienza migliore, come limiti più alti o risposte strutturate. I client che possono verificarsi inizieranno a farlo.
- Usa la conoscenza della tua application. Se gli utenti interagiscono con il tuo assistant integrato, registralo come dichiarazione. La tua app spesso sa più della rete.
- Sistema l'infrastruttura. Assicurati che i proxy inoltrino gli header su cui fai affidamento e che la valutazione abbia abbastanza budget di tempo per completarsi.
Per uno sguardo pratico ai segnali che spostano il traffico fuori da Unknown, leggi come capire se il traffico di un sito proviene da agenti AI.
Passo 7: mostra Unknown in modo onesto nelle dashboard
Mostra Unknown come una serie a sé, con lo stesso peso visivo delle altre classi. Non nasconderlo in un bucket "other" e non colorarlo come un alert. Quando gli stakeholder vedono una quota Unknown elevata, la reazione giusta è "dove ci serve più evidenza", non "dove sono i bot".
Passo 8: rivedi Unknown guardando agli esiti, non alle ipotesi
Ogni poche settimane, prendi un campione di interazioni Unknown dalle tue route più importanti e osserva cosa è successo davvero. La sessione ha completato un acquisto, creato un progetto, letto tre articoli o fallito ripetutamente al login? Gli esiti ti dicono che tipo di traffico si trova nel bucket senza forzargli addosso un'etichetta prematura.
Raggruppa ciò che trovi in tre categorie pratiche:
- Legittimo e a basso rischio. Feed reader, anteprime dei link, strumenti di monitoraggio e persone con impostazioni di privacy. Mantieni il fallback della route com'è.
- Automazione legittima che potrebbe identificarsi. Integrazioni e agenti che userebbero volentieri un percorso strutturato o firmerebbero le request se glielo offristi. Pubblica linee guida e contatta i destinatari dove puoi.
- Comportamento che richiede un proprio controllo. Pattern di credential stuffing o scraping, entrambi catalogati nel progetto OWASP Automated Threats to Web Applications. Affrontali con controlli basati sul comportamento che abbiano una propria evidenza, come i tassi di login falliti, e tienili separati dalla classe dell'actor.
Questa review mantiene i tuoi fallback ancorati al traffico reale e ti dà un elenco chiaro di dove aggiungere evidenza in seguito.
Domande comuni
Unknown deve rientrare nei rate limit? Usa i tuoi limiti standard. Il rate limiting per classe va bene per gli agenti verificati, che possono ottenere limiti più alti, ma Unknown deve ricevere il limite normale, non uno punitivo.
Possiamo challenge gli utenti Unknown? Solo dove la route sfida già tutti in quella situazione. Aggiungere una challenge solo perché un risultato è Unknown penalizza utenti legittimi i cui client inviano meno segnali.
Unknown si ridurrà man mano che gli standard maturano? Man mano che più client automatici firmeranno le request, più traffico agent passerà da Unknown o declared a verified. Il tuo monitoraggio mostrerà quel cambiamento route per route.
Dove si inserisce Proof of Actor
Proof of Actor riporta Unknown come risultato di prima classe, con il motivo, e non lo converte mai in Human. La tua application sceglie il fallback per ogni route, e le analytics mostrano dove finisce la copertura così puoi aggiungere evidenza dove conta.
Per configurarlo su una application di produzione con il nostro team, richiedi l'accesso anticipato. Per capire esattamente cosa può stabilire l'evidenza, leggi Detection & Limitations.
Fonti
- RFC 9421: HTTP Message Signatures: lo standard che i client automatici possono usare per firmare le request
- draft-ietf-webbotauth-httpsig-protocol: bozza IETF Web Bot Auth per traffico automatico firmato (work in progress a novembre 2026)
- OpenAI: Overview of OpenAI Crawlers: stringhe user agent e file di indirizzi IP pubblicati per i bot di OpenAI
- OWASP Automated Threats to Web Applications: tassonomia di minacce automatizzate come credential stuffing e scraping
- Node.js test runner: il modulo
node:testusato nell'esempio