← Indice documentazione Architettura › lifecycle

Metnos

lifecycle — un solo oggetto per ogni cambiamento al sistema
Architettura canonica.
Moduli: runtime/change_intents.py, change_intent_adapters/,
change_applier.py, change_observer.py, change_rollback.py.

Pubblico: chi opera la dashboard /admin/changes,
chi vuole capire dove va una proposta dopo l'accept.
Lettura: 8 minuti.

Indice

  1. L'oggetto unico: change_intent
  2. Il ciclo di vita in 5 atti
  3. Le 6 sorgenti come adapter
  4. I 3 daemon: materializer, applier, observer
  5. Esempio end-to-end: find_recipes
  6. Riferimenti operativi
proposto accettato applicato osservato finalizzato rami laterali: staged · rejected · failed · rolled_back
Figura 1 — Ciclo di vita di un cambiamento: una sola macchina a stati, dalla proposta alla finalizzazione, con rami laterali (in stage / respinto / fallito / annullato).

1. L'oggetto unico: change_intent

Tutti i cambiamenti al sistema convergono in un singolo schema in ~/.local/state/metnos/change_intents.sqlite:

id UUID
fingerprint sha256[:32] # deterministico per dedup cross-source
state PROPOSED|ACCEPTED|APPLIED|OBSERVED|FINALIZED|
 STAGED|REJECTED|FAILED|ROLLED_BACK
origin_family telos|introvertiva|synt|multi_tool|canonical|user
origin_module scamper|dedupe|request_new_executor|L1|L2|feedback|...
intent_kind create_executor|extend_executor|dedupe_executors|
 materialize_pipeline|cache_pattern|reject_pattern
intent_target nome executor o pattern
intent_summary 1 frase user-facing
intent_body dict kind-specific (arg_name, tools_sequence,...)
score 0–1 normalizzato cross-source
confidence 0–1
convergence N. sorgenti che propongono cose equivalenti
decision_* registro accept/reject/stage utente
applied_effect diff applicato + rollback_blob path
observed_metrics metriche grace period

Il fingerprint NON include origin_family: cosi' due sorgenti diverse che propongono cose equivalenti (es. telos:scamper + introvertiva:specialize sullo stesso executor) coalescono in un solo record, con convergence bumpato.

2. Il ciclo di vita in 5 atti

 +-----------+
 | PROPOSED | ← qualche sorgente l'ha generata
 +-----------+
 / | \
 / | \
 (utente) | (utente decide piu' tardi)
 / | \
 v v v
+----------+ +--------+ +---------+
| ACCEPTED | | STAGED | |REJECTED |
+----------+ +--------+ +---------+
 | (daemon applier)
 v
+----------+ +----------+
| APPLIED | ----> | FAILED | (retry possibile)
+----------+ +----------+
 | (daemon observer, grace period default 7gg)
 v
+----------+ +-------------+
| OBSERVED | ----> | ROLLED_BACK | (fisico, per kind)
+----------+ +-------------+
 |
 v
+-----------+
| FINALIZED | ← consolidato, rimosso dalle viste default
+-----------+

Da QUALSIASI stato si puo' transizionare a ROLLED_BACK (escape hatch audit umano). Da REJECTED e' possibile re-proporre (transition a PROPOSED).

3. Le 6 sorgenti come adapter

Le sorgenti storiche non vengono cancellate: continuano ad esistere come «input feed» che alimenta il materializer. Per ognuna c'e' un adapter in runtime/change_intent_adapters/ che proietta i record legacy in ChangeIntent.

SorgenteAdapterKind output
telos (10 lenti)telos.py create_executor (default) / extend_executor (parametric) / materialize_pipeline
introvertivaintrovertiva.py dedupe_executors / extend_executor (generalize) / cache_pattern (specialize)
synt (request_new_executor)synt.py create_executor (importato come FINALIZED se gia' installed)
multi_tool_paths (L2)multi_tool.py materialize_pipeline
canonical_query_log (L1)canonical.py cache_pattern
turn_feedback utenteuser_feedback.py reject_pattern (solo se ≥ 2 rifiuti)

Score normalization per family:

4. I 3 daemon: materializer, applier, observer

DaemonTriggerCosa fa
change_intent_materialize daily@01:00 Concat 6 adapter → upsert con dedup via fingerprint → bump convergence.
change_applier every_10m Legge ACCEPTED, applica fisicamente per kind. Cap 20/fire.
change_observer daily@03:15 Legge APPLIED+OBSERVED, calcola metriche, transition a FINALIZED o ROLLED_BACK.

Applier handler per kind:

Observer verifica metrics post-applied_at e applica grace period (default 7 giorni, env METNOS_CHANGE_GRACE_DAYS). Trigger di rollback:

Rollback fisico delegato a change_rollback.py (per kind: archive synth dir, restore manifest da blob + re-sign, rimuovi alias, demote state, rimuovi linea jsonl).

5. Esempio end-to-end: find_recipes

Telos engine SCAMPER suggerisce: «Estendi find_files con kind=recipe per matchare file .md in ~/Documents/Recipes

AttoStatoDove succede
1. Sistema crea ChangeIntentPROPOSED materializer @01:00 da telos_proposals.jsonl
2. Utente clicca ACCEPTED POST /admin/changes/{id}/accept
3. Applier modifica manifest + re-signAPPLIED change_applier @every_10m
4. 5 chiamate find_files(kind=recipe), tutte OK OBSERVEDchange_observer @03:15 quando age ≥ 0
5. Dopo 7gg senza problemiFINALIZED change_observer al settimo passaggio

Se invece dopo apply Roberto preme in chat su una risposta usando il nuovo arg, observer vede new_rejects≥2 per la query target e transiziona a ROLLED_BACK — physical restore del manifest dal blob.

6. Riferimenti operativi


— allineato con il codice.