mnestoma — il grafo emergente di tutti i mnestQuesto documento definisce il mnestoma: la struttura dati che raccoglie l'insieme di tutti i mnest attivi e ne governa il ciclo di vita. È il terzo dei tre doc canonici introdotti dal Dialogo sugli executor e la memoria distribuita (24 aprile 2026), ed è un concetto nuovo: la microprogettazione precedente non lo aveva. Tecnicamente è un grafo orientato pesato persistito in SQLite; ontologicamente è la memoria relazionale di Metnos — ciò che ricorda di aver fatto insieme.
Il documento copre:
Non copre, e demanda altrove:
Il mnestoma è un grafo orientato pesato in cui:
Il mnestoma emerge. Nessuno lo disegna a priori: nasce vuoto al primo avvio e si forma turno dopo turno, mentre il gateway osserva quali executor passano output a quali altri. Le forme che prende riflettono come il sistema viene usato: un mnestoma di un utente «archivio fatture» ha cluster diversi da quello di un utente «rassegna stampa quotidiana», anche se il seed degli executor è lo stesso.
La parola «memoria» in un agente AI ha troppi significati. Vale la pena dire chiaramente cosa il mnestoma non è:
| Cosa il mnestoma NON è | Dov'è quel concetto, allora |
|---|---|
| La memoria conversazionale dell'LLM (turni recenti, contesto in token). | Nel working memory dell'execution trace, vedi memory.html (da riscrivere). |
| La memoria episodica delle conversazioni passate (cosa Roberto disse ieri). | Nella episodic memory, indicizzata per sender. Vedi memory.html. |
| La memoria semantica dei fatti su Roberto e il suo mondo («il cane si chiama Fido»). | Nella semantic memory, estratta via reflection e approvata dall'utente. |
| L'audit log delle azioni svolte. | In workspace/.audit/, append-only, JSONL. |
| Il workspace dei file dell'utente (note, fatture, foto). | In workspace/, gestito separatamente. |
| La definizione delle capacità (i singoli executor). | In workspace/executors/, file per file. |
Il mnestoma è la relazione osservata fra executor: chi ha lavorato con chi, quanto spesso, quanto recentemente. Niente di più.
Il mnestoma vive in workspace/.mnestoma/mnest.sqlite, un
singolo file SQLite. La scelta di SQLite è deliberata: zero
servizi da avviare, zero dipendenze esterne, backup banale (copia del
file), affidabilità provata.
executors
Replica leggera del manifest, in lettura-veloce per le query del
gateway. Il manifest canonico resta sempre workspace/executors/<nome>/manifest.toml;
questa tabella è un indice.
CREATE TABLE executors (
name TEXT NOT NULL,
version TEXT NOT NULL,
state TEXT NOT NULL, -- seed | active | quarantine | archived
loaded_at TEXT NOT NULL, -- ISO 8601
manifest_hash TEXT NOT NULL, -- blake3
PRIMARY KEY (name, version)
);
CREATE INDEX idx_executors_state ON executors(state);
mnestsCREATE TABLE mnests (
id TEXT PRIMARY KEY, -- ULID
src_executor TEXT NOT NULL,
src_version TEXT NOT NULL,
dst_executor TEXT NOT NULL, -- nome canonico O nome desiderato (proto)
dst_version TEXT, -- NULL per proto
weight REAL NOT NULL CHECK (weight BETWEEN 0 AND 1),
uses INTEGER NOT NULL CHECK (uses >= 1),
ts_first TEXT NOT NULL,
ts_last TEXT NOT NULL,
decay_lambda REAL NOT NULL DEFAULT 0.018,
state TEXT NOT NULL, -- proto | active | decaying | superseded
tags TEXT, -- JSON array
desired_sig TEXT, -- JSON, solo per proto
CHECK (ts_last >= ts_first),
UNIQUE (src_executor, src_version, dst_executor, dst_version, state)
);
CREATE INDEX idx_mnests_dst ON mnests(dst_executor);
CREATE INDEX idx_mnests_src ON mnests(src_executor);
CREATE INDEX idx_mnests_weight ON mnests(weight DESC);
CREATE INDEX idx_mnests_state ON mnests(state);
eventsAppend-only, registra ogni rinforzo o decadimento applicato. Permette di ricostruire la traiettoria del peso di un mnest e di ricalcolare posteriormente in caso di cambio della formula.
CREATE TABLE events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mnest_id TEXT NOT NULL,
ts TEXT NOT NULL,
kind TEXT NOT NULL, -- reinforce | decay | state_change
delta REAL, -- variazione del peso (NULL per state_change)
new_state TEXT, -- solo per state_change
reason TEXT, -- es. "ager nightly", "synt approved"
FOREIGN KEY (mnest_id) REFERENCES mnests(id)
);
CREATE INDEX idx_events_mnest ON events(mnest_id);
CREATE INDEX idx_events_ts ON events(ts);
v_mnestoma
Il grafo «vivo» per le query di lettura. Esclude
superseded e mostra active + proto:
CREATE VIEW v_mnestoma AS
SELECT id, src_executor, src_version, dst_executor, dst_version,
weight, uses, ts_last, state, tags, desired_sig
FROM mnests
WHERE state IN ('active', 'proto');
record_passingLa sola operazione di scrittura in fase di turno. Atomica per coppia. Pseudocodice:
def record_passing(src, dst, turn_ctx) -> mnest_id:
with conn.transaction():
if dst.exists:
row = SELECT * FROM mnests
WHERE src_executor = src.name AND src_version = src.version
AND dst_executor = dst.name AND dst_version = dst.version
AND state = 'active'
if row:
w = decay(row.weight, now() - row.ts_last, row.decay_lambda) + REINFORCE_DELTA
UPDATE mnests SET weight = clamp01(w), uses = uses + 1, ts_last = now()
INSERT INTO events (mnest_id, ts, kind, delta, reason)
VALUES (row.id, now(), 'reinforce', REINFORCE_DELTA, turn_ctx.id)
return row.id
else:
id = ulid()
INSERT INTO mnests (id, src_*, dst_*, weight, uses, ts_first, ts_last, state, tags)
VALUES (id, ..., BOOTSTRAP_WEIGHT, 1, now(), now(), 'active', tags)
INSERT INTO events (mnest_id, ts, kind, delta, reason)
VALUES (id, now(), 'reinforce', BOOTSTRAP_WEIGHT, turn_ctx.id)
return id
else:
# proto-mnest
id = ulid()
desired = build_desired_signature(turn_ctx)
INSERT INTO mnests (..., dst_executor=dst.desired_name, dst_version=NULL,
..., state='proto', desired_sig=desired)
return id
| Query | Uso |
|---|---|
top_k_outgoing(executor, k) | Dato un executor, restituisce i k mnest uscenti più pesanti. |
top_k_incoming(executor, k) | Dato un executor, restituisce i k mnest entranti più pesanti. |
walk(start, max_depth) | Visita BFS pesata dal nodo di partenza, fino a una profondità massima. Usato dal gateway per costruire il context d'esecuzione. |
recurring_protos(min_uses, since) | Lista dei proto-mnest che hanno superato una soglia di ricorrenza. Innesco del synt. |
by_tag(tag) | Tutti i mnest con un tag dato. Usato dall'osservabilità e dall'ager per cluster. |
decaying() | Mnest in stato decaying. Usato dall'ager per la propost à di archiviazione. |
Le transizioni di stato sono fatte da componenti specifici (ager, synt,
gateway in caso di quarantena di un executor). Tutte sono accompagnate
da una riga events con kind = 'state_change'
e una reason obbligatoria; questo è il principio di
reversibilità (cap. 14 dell'Architettura): non si cambia stato
senza traccia del perché.
L'ager è il processo che applica il decadimento e segnala le transizioni di stato che il puro tempo richiede. Gira una volta al giorno, in finestra notturna (default: 04:00 ora locale), in una transazione lunga ma a basso impatto:
active, calcola weight_new = weight_old · exp(-λ · Δt) dove Δt è il tempo trascorso dall'ultimo evento. Aggiorna il peso e scrive una riga events di tipo decay.decay weight passa ad decaying; lo segnala nel canale di proposte al gateway.decaying che è sotto archive weight e con ts_last > 90 giorni entra nella lista delle proposte di archiviazione mostrate a Roberto.min proto weight è eliminato (anti-rumore).uses >= SYNTH_TRIGGER_USES e weight >= SYNTH_TRIGGER_WEIGHT; li segnala al synt come candidati per la sintesi.workspace/.mnestoma/snapshots/YYYY-MM.sqlite.L'ager è un esempio puro di componente che fa solo manutenzione: non modifica la struttura dei mnest, non crea executor, non parla con l'utente. Propone; chi decide è il synt + Roberto, oppure la policy di archiviazione che il gateway applica nel turno successivo.
Il primo dell'mese (UTC), l'ager produce uno snapshot del file vivo:
workspace/.mnestoma/snapshots/2026-04.sqlite # snapshot del mese
workspace/.mnestoma/snapshots/2026-03.sqlite.zst # vecchio, compresso
workspace/.mnestoma/snapshots/2026-02.sqlite.zst
...
Lo snapshot serve a tre cose: rollback in caso di danneggiamento del
file vivo, analisi storica del grafo, traccia per chi vuole capire
come Metnos «si è formato» nel tempo. Snapshot
oltre 12 mesi vengono compressi in .zst ma mai
eliminati: la storia è un dato di prim'ordine.
Il file vivo si manterrebbe in piedi anche tutto pieno, ma per prestazioni e per pulizia conviene una potatura periodica:
superseded e archived vengono spostati alla tabella mnests_archive dopo 90 giorni (sempre nello stesso file SQLite);events viene partizionata per anno (tabelle events_2026, events_2027, ...). Solo l'anno corrente è nello schema vivo; le precedenti vengono spostate in un secondo file SQLite events_history.sqlite;VACUUM di SQLite gira mensilmente subito dopo lo snapshot.
Quando un executor passa a archived, i suoi mnest passano
a superseded con reason = 'executor archived';
restano leggibili, sono esclusi dalla vista v_mnestoma,
e dopo 90 giorni vanno alla tabella di archivio.
Il termine ha due forme normative:
La doppia forma è intenzionale e va mantenuta. Tradurre mnestoma con mnestome in EN dà al lettore inglese il riflesso giusto (il suffisso biologico evoca un grafo emergente, come il microbiome). Tradurre mnestome con mnestoma in IT segue la regola fonetica italiana che evita suffissi sentiti come incongrui (mnestome in italiano sembrerebbe un imperativo verbale, «tu memorizzati!»).
Al primo avvio, il mnestoma è vuoto. La domanda «da dove si parte, allora?» ha tre risposte concrete:
state = 'seed' per distinguerli e peso BOOTSTRAP_WEIGHT (vedi mnest.html cap. 6).
L'utente può ispezionare il mnestoma da CLI (tramite il comando
Metnos mnestoma):
Metnos mnestoma list # tutti i mnest attivi
Metnos mnestoma list --tag fattura # filtrati per tag
Metnos mnestoma top 20 # i 20 più pesanti
Metnos mnestoma graph executor fs_read # vicinato di un executor
Metnos mnestoma proto # i proto-mnest correnti
Metnos mnestoma history mnest_01HW... # storia eventi di un mnest
Metnos mnestoma snapshot --month 2026-03 # apre lo snapshot mensile
La dashboard web (vedi observability.html, da riscrivere) ha una vista grafica dello stesso contenuto, con filtri e drill-down. La regola di trasparenza: l'utente può sempre sapere cosa Metnos pensa di sapere.
Metnos — mnestoma microprogettazione v1.1 — 2026-04-24
Doc canonico nuovo (concetto introdotto dalla v1.1).