✓ Microprogettazione v1.1 — APPROVATO (25 aprile 2026). Doc canonico approvato dopo simulazione end-to-end del 25/4/2026, allineato con l'Architettura v1.1 e con il Dialogo sugli executor e la memoria distribuita. Riferimento normativo per l'implementazione. Concetto nuovo rispetto alla microprogettazione precedente.
← Indice documentazione Microprogettazione › mnestoma

Metnos

mnestoma — il grafo emergente di tutti i mnest
Microprogettazione v1.1 — 24 aprile 2026
Allineata con Architettura v1.1 (cap. 9, Figura 6) e Dialogo sugli executor.
Nuovo concetto introdotto dalla v1.1 (non sostituisce nulla di esistente).

Pubblico: chi implementerà lo schema dati, l'ager, gli snapshot.
Lettura: 16 minuti.

Indice

  1. Scopo e confini
  2. Cos'è il mnestoma
  3. Cosa il mnestoma NON è
  4. Schema dati
  5. Operazioni: insert, query, update
  6. L'ager: come opera il decadimento
  7. Pruning, snapshot, archiviazione
  8. Variante linguistica: mnestoma vs mnestome
  9. Bootstrap: il primo mnestoma
  10. Osservabilità e debug
  11. Domande aperte

1. Scopo e confini

Questo 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.

Confini

Il documento copre:

Non copre, e demanda altrove:

2. Cos'è il mnestoma

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.

Perché un grafo, non una lista. La forma «grafo» cattura una proprietà che la lista non catturerebbe: la vicinanza operativa. Due executor che compaiono spesso uno dopo l'altro nello stesso turno sono più vicini di due che non si incontrano mai. Il grafo lo rende esplicito; la lista lo nasconde. Quasi tutte le decisioni di Vaglio, ager e synt sono più semplici da formulare in termini di grafo.

3. Cosa il mnestoma NON è

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ù.

4. Schema dati

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.

Tabella 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);

Tabella mnests

CREATE 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);

Tabella events

Append-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);

Vista 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');

5. Operazioni: insert, query, update

Insert / rinforzo: record_passing

La 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 principali

QueryUso
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.

Update di stato

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é.

6. L'ager: come opera il decadimento

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:

  1. Decadimento: per ogni mnest 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.
  2. Decay state: ogni mnest che scende sotto la soglia decay weight passa ad decaying; lo segnala nel canale di proposte al gateway.
  3. Archive proposal: ogni mnest decaying che è sotto archive weight e con ts_last > 90 giorni entra nella lista delle proposte di archiviazione mostrate a Roberto.
  4. Proto purge: ogni proto-mnest che scende sotto min proto weight è eliminato (anti-rumore).
  5. Recurring proto detection: cerca proto-mnest con uses >= SYNTH_TRIGGER_USES e weight >= SYNTH_TRIGGER_WEIGHT; li segnala al synt come candidati per la sintesi.
  6. Snapshot: il primo del mese, copia il file SQLite in 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.

7. Pruning, snapshot, archiviazione

Snapshot mensile

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.

Pruning del file vivo

Il file vivo si manterrebbe in piedi anche tutto pieno, ma per prestazioni e per pulizia conviene una potatura periodica:

Archiviazione di un executor

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.

8. Variante linguistica: mnestoma vs mnestome

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!»).

9. Bootstrap: il primo mnestoma

Al primo avvio, il mnestoma è vuoto. La domanda «da dove si parte, allora?» ha tre risposte concrete:

  1. Si parte dal vuoto. Per la maggior parte delle istanze, il mnestoma è vuoto al primo avvio e si forma in un mese di uso. È lento ma corretto: la specificità dell'utente entra subito nella forma del grafo.
  2. Seed minimo (consigliato). Esiste un seed di 12-15 mnest noti, codificati nel repo, che cablano i passaggi più comuni fra gli executor seed (es. fs_read → pdf_extract, web_fetch → markdown_render). Hanno state = 'seed' per distinguerli e peso BOOTSTRAP_WEIGHT (vedi mnest.html cap. 6).
  3. Import da snapshot. Per migrazioni o per condivisione (futuro), si può importare uno snapshot pulito. L'import passa per una validazione: gli executor citati devono esistere e essere firmati.

10. Osservabilità e debug

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.

11. Domande aperte

  1. Concorrenza in scrittura. Il gateway è un singolo processo, quindi le scritture sono naturalmente seriali. Quando in futuro arriveranno gli executor remoti (cap. 4 dell'Architettura), il gateway resta unico ma le chiamate possono arrivare da più turni in parallelo. SQLite WAL basta? Aperta.
  2. Schema migration. Il file SQLite vive a lungo. Come gestiamo le migrazioni dello schema fra versioni di Metnos? Migrazioni dichiarative numerate, tipo Alembic? Aperta.
  3. Privacy degli snapshot. Gli snapshot mensili contengono nomi di executor e tag, ma non contenuti. La superficie di privacy è bassa, ma se si voglia condividere uno snapshot per debug servirebbe una funzione di redazione dei tag «personali». Da progettare se serve.
  4. Integrazione con la episodic memory. Il mnestoma e la memoria episodica delle conversazioni sono separati per scelta (cap. 3). Può aver senso un cross-reference esplicito (un mnest che cita il turn_id che lo ha generato)? L'inverso (un turno che cita i mnest che ha rinforzato) è già presente nell'audit. Aperta.

primo della triade
executor
Il nodo del mnestoma.
secondo della triade
mnest
L'arco del mnestoma.
livello 1
Architettura, cap. 9
Il quadro d'insieme.
indice
Microprogettazione
Tutti i doc.

Metnos — mnestoma microprogettazione v1.1 — 2026-04-24
Doc canonico nuovo (concetto introdotto dalla v1.1).