Documenta la decisione architetturale di non deployare un broker dedicato. agent_messages su Postgres copre il flow normale; webhook n8n diretto gestisce il bypass high-priority. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
187 lines
8.9 KiB
Markdown
187 lines
8.9 KiB
Markdown
# ALPHA_PROJECT — Changelog
|
|
|
|
Tutte le modifiche significative al progetto ALPHA_PROJECT sono documentate qui.
|
|
|
|
---
|
|
|
|
## [2026-03-21] ADR — Message Broker: nessun broker dedicato
|
|
|
|
### Decisione
|
|
|
|
**Non verrà deployato un message broker dedicato** (né NATS JetStream né Redis Streams). Il blackboard pattern viene implementato interamente su PostgreSQL + webhook n8n.
|
|
|
|
### Ragionamento
|
|
|
|
Al momento della progettazione iniziale, il broker era necessario per disaccoppiare gli agenti dall'Arbiter. Con l'introduzione della tabella `agent_messages` nel database `pompeo`, questo obiettivo è già raggiunto:
|
|
|
|
```
|
|
Agente n8n → INSERT agent_messages (arbiter_decision = NULL)
|
|
Arbiter → SELECT WHERE arbiter_decision IS NULL (polling a cron)
|
|
→ UPDATE arbiter_decision = 'notify' | 'defer' | 'discard'
|
|
```
|
|
|
|
Il flusso high-priority (bypass immediato dell'Arbiter) viene gestito con una chiamata diretta al **webhook n8n dell'Arbiter** da parte dell'agente — zero infrastruttura aggiuntiva.
|
|
|
|
### Alternative valutate
|
|
|
|
| Opzione | Esito | Motivazione |
|
|
|---|---|---|
|
|
| `agent_messages` su PostgreSQL | ✅ **Adottata** | Già deployata, persistente, queryabile, audit log gratuito |
|
|
| Redis Streams | ⏸ Rimandato | Già in cluster, valutabile se volume cresce |
|
|
| NATS JetStream | ❌ Scartato | Nuovo componente da operare, overkill per il volume attuale (pochi msg/ora) e per il caso d'uso single-household |
|
|
|
|
### Impatto su README.md
|
|
|
|
La sezione "Message Broker (Blackboard Pattern)" rimane valida concettualmente. Il campo `agent` e il message schema definiti nel README vengono rispettati nella tabella `agent_messages` — cambia solo il mezzo di trasporto (Postgres invece di NATS/Redis).
|
|
|
|
---
|
|
|
|
## [2026-03-21] PostgreSQL — Database "pompeo" e schema ALPHA_PROJECT
|
|
|
|
### Overview
|
|
|
|
Creato il database `pompeo` sul cluster Patroni (namespace `persistence`) e applicato lo schema iniziale per la memoria strutturata di Pompeo. Seconda milestone della Phase 0 — Infrastructure Bootstrap.
|
|
|
|
---
|
|
|
|
### Modifica manifest Patroni
|
|
|
|
Aggiunto `pompeo: martin` nella sezione `databases` di `infra/cluster/persistence/patroni/postgres.yaml`. Il database è stato creato automaticamente dallo Zalando Operator senza downtime sugli altri database.
|
|
|
|
Script DDL idempotente disponibile in: `alpha/db/postgres.sql`
|
|
|
|
---
|
|
|
|
### Design decision — Multi-tenancy anche in PostgreSQL
|
|
|
|
Coerentemente con la scelta adottata per Qdrant, tutte le tabelle includono il campo `user_id TEXT NOT NULL DEFAULT 'martin'`. I valori `'martin'` e `'shared'` sono seedati in `user_profile` come utenti iniziali del sistema.
|
|
|
|
Aggiungere un nuovo utente in futuro non richiede modifiche allo schema — è sufficiente inserire una riga in `user_profile` e usare il nuovo `user_id` negli INSERT.
|
|
|
|
---
|
|
|
|
### Design decision — agent_messages come blackboard persistente
|
|
|
|
La tabella `agent_messages` implementa il **blackboard pattern** del message broker: ogni agente n8n inserisce le proprie osservazioni con `arbiter_decision = NULL` (pending). Il Proactive Arbiter legge i messaggi in coda, decide (`notify` / `defer` / `discard`) e aggiorna `arbiter_decision`, `arbiter_reason` e `processed_at`.
|
|
|
|
Rispetto a usare solo NATS/Redis come broker, questo approccio garantisce un **audit log permanente** di tutte le osservazioni e decisioni, interrogabile via SQL per debug, tuning e analisi storiche.
|
|
|
|
---
|
|
|
|
### Schema creato
|
|
|
|
**5 tabelle** nel database `pompeo`:
|
|
|
|
| Tabella | Ruolo |
|
|
|---|---|
|
|
| `user_profile` | Preferenze statiche per utente (lingua, timezone, stile notifiche, quiet hours). Seed: `martin`, `shared` |
|
|
| `memory_facts` | Fatti episodici prodotti da tutti gli agenti, con TTL (`expires_at`) e riferimento al punto Qdrant (`qdrant_id`) |
|
|
| `finance_documents` | Documenti finanziari strutturati: bollette, fatture, cedolini. Include `raw_text` per embedding |
|
|
| `behavioral_context` | Contesto IoT/comportamentale per l'Arbiter: DND, home presence, tipo evento |
|
|
| `agent_messages` | Blackboard del message broker — osservazioni agenti + decisioni Arbiter |
|
|
|
|
**15 index** totali:
|
|
|
|
| Index | Tabella | Tipo |
|
|
|---|---|---|
|
|
| `idx_memory_facts_user_source_cat` | `memory_facts` | `(user_id, source, category)` |
|
|
| `idx_memory_facts_expires` | `memory_facts` | `(expires_at)` WHERE NOT NULL |
|
|
| `idx_memory_facts_action` | `memory_facts` | `(user_id, action_required)` WHERE true |
|
|
| `idx_finance_docs_user_date` | `finance_documents` | `(user_id, doc_date DESC)` |
|
|
| `idx_finance_docs_correspondent` | `finance_documents` | `(user_id, correspondent)` |
|
|
| `idx_behavioral_ctx_user_time` | `behavioral_context` | `(user_id, start_at, end_at)` |
|
|
| `idx_behavioral_ctx_dnd` | `behavioral_context` | `(user_id, do_not_disturb)` WHERE true |
|
|
| `idx_agent_msgs_pending` | `agent_messages` | `(user_id, priority, created_at)` WHERE pending |
|
|
| `idx_agent_msgs_agent_type` | `agent_messages` | `(agent, event_type, created_at)` |
|
|
| `idx_agent_msgs_expires` | `agent_messages` | `(expires_at)` WHERE pending AND NOT NULL |
|
|
|
|
---
|
|
|
|
### Phase 0 — Stato aggiornato
|
|
|
|
- [x] ~~Deploy **Qdrant** sul cluster~~ ✅ 2026-03-21
|
|
- [x] ~~Collections Qdrant con multi-tenancy `user_id`~~ ✅ 2026-03-21
|
|
- [x] ~~Payload indexes Qdrant~~ ✅ 2026-03-21
|
|
- [x] ~~Database `pompeo` + schema PostgreSQL~~ ✅ 2026-03-21
|
|
- [ ] Verify embedding endpoint via Copilot (`text-embedding-3-small`)
|
|
- [ ] Migrazione a Ollama `nomic-embed-text` (quando LLM server è online)
|
|
|
|
---
|
|
|
|
## [2026-03-21] Qdrant — Deploy e setup collections (Phase 0)
|
|
|
|
### Overview
|
|
|
|
Completato il deploy di **Qdrant v1.17.0** sul cluster Kubernetes (namespace `persistence`) e la creazione delle collections per la memoria semantica di Pompeo. Questa è la prima milestone della Phase 0 — Infrastructure Bootstrap.
|
|
|
|
---
|
|
|
|
### Deploy infrastruttura
|
|
|
|
Qdrant deployato via Helm chart ufficiale (`qdrant/qdrant`) nel namespace `persistence`, coerente con il pattern infrastrutturale esistente (Longhorn storage, Sealed Secrets, ServiceMonitor Prometheus).
|
|
|
|
**Risorse create:**
|
|
|
|
| Risorsa | Dettaglio |
|
|
|---|---|
|
|
| StatefulSet `qdrant` | 1/1 pod Running, image `qdrant/qdrant:v1.17.0` |
|
|
| PVC `qdrant-storage-qdrant-0` | 20Gi Longhorn RWO |
|
|
| Service `qdrant` | ClusterIP — porte 6333 (REST), 6334 (gRPC), 6335 (p2p) |
|
|
| SealedSecret `qdrant-api-secret` | API key cifrata, namespace `persistence` |
|
|
| ServiceMonitor `qdrant` | Prometheus scraping su `:6333/metrics`, label `release: monitoring` |
|
|
|
|
**Endpoint interno:** `qdrant.persistence.svc.cluster.local:6333`
|
|
|
|
Manifest in: `infra/cluster/persistence/qdrant/`
|
|
|
|
---
|
|
|
|
### Design decision — Multi-tenancy collections (Opzione B)
|
|
|
|
**Problema affrontato**: nominare le collections `martin_episodes`, `martin_knowledge`, `martin_preferences` avrebbe vincolato Pompeo ad essere esclusivamente un assistente personale singolo, rendendo impossibile — senza migration — estendere il sistema ad altri membri della famiglia in futuro.
|
|
|
|
**Scelta adottata**: architettura multi-tenant con 3 collection condivise e isolamento via campo `user_id` nel payload di ogni punto vettoriale.
|
|
|
|
```
|
|
episodes ← user_id: "martin" | "shared" | <futuri utenti>
|
|
knowledge ← user_id: "martin" | "shared" | <futuri utenti>
|
|
preferences ← user_id: "martin" | "shared" | <futuri utenti>
|
|
```
|
|
|
|
Il valore `"shared"` è riservato a dati della casa/famiglia visibili a tutti gli utenti (es. calendario condiviso, documenti di casa, finanze comuni). Le query n8n usano un filtro `should: [user_id=martin, user_id=shared]` per recuperare sia il contesto personale che quello condiviso.
|
|
|
|
**Vantaggi**: aggiungere un nuovo utente domani non richiede alcuna modifica infrastrutturale — solo includere il nuovo `user_id` negli upsert e nelle query.
|
|
|
|
---
|
|
|
|
### Collections create
|
|
|
|
Tutte e 3 le collections sono operative (status `green`):
|
|
|
|
| Collection | Contenuto |
|
|
|---|---|
|
|
| `episodes` | Fatti episodici con timestamp (email, IoT, calendario, conversazioni) |
|
|
| `knowledge` | Documenti, note Outline, newsletter, knowledge base |
|
|
| `preferences` | Preferenze, abitudini e pattern comportamentali per utente |
|
|
|
|
**Payload schema comune** (5 index su ogni collection):
|
|
|
|
| Campo | Tipo | Scopo |
|
|
|---|---|---|
|
|
| `user_id` | keyword | Filtro multi-tenant (`"martin"`, `"shared"`) |
|
|
| `source` | keyword | Origine del dato (`"email"`, `"calendar"`, `"iot"`, `"paperless"`, …) |
|
|
| `category` | keyword | Dominio semantico (`"finance"`, `"work"`, `"personal"`, …) |
|
|
| `date` | datetime | Timestamp del fatto — filtrabile per range |
|
|
| `action_required` | bool | Flag per il Proactive Arbiter |
|
|
|
|
**Dimensione vettori**: 1536 (compatibile con `text-embedding-3-small` via GitHub Copilot — bootstrap phase). Da rivedere alla migrazione verso `nomic-embed-text` su Ollama.
|
|
|
|
---
|
|
|
|
### Phase 0 — Stato al momento del deploy Qdrant
|
|
|
|
- [x] ~~Deploy **Qdrant** sul cluster~~
|
|
- [x] ~~Creazione collections con multi-tenancy `user_id`~~
|
|
- [x] ~~Payload indexes: `user_id`, `source`, `category`, `date`, `action_required`~~
|
|
- [x] ~~Run **PostgreSQL migrations** su Patroni~~ ✅ completato nella sessione stessa
|