synops/docs/infra/robusthet.md
vegard fd0b75ee13 Orkestrering: tre nivåer (script/fritekst/drøm) + rename portvokter→vaktmester
Orkestrering restrukturert med deklarativt script som primærnivå:
- Nivå 1: eksakte CLI-kall med {event.*}-variabler, ingen AI
- Nivå 2: fritekst tolket av bot med function calling
- Nivå 3: drømmemodus — bruker skriver fritt, mangler→work_items
- Auto-eskalering: script→bot ved uventet feil

Rename portvokter→vaktmester i alle docs — bedre navn for en
tjeneste som gjør ting, ikke bare sjekker legitimasjon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:59:29 +00:00

146 lines
4.6 KiB
Markdown

# Robusthet og fallback
## Lagmodell
```
Lag 1: LLM-leverandør (Claude API, OpenAI, etc.) → utenfor vår kontroll
Lag 2: LiteLLM (AI Gateway) → lokal Docker
Lag 3: Vaktmesteren → lokal native (systemd)
Lag 4: CLI-verktøy (synops-*) → per-kall, isolert
Lag 5: PostgreSQL → lokal Docker, SPOF
```
## Deteksjon
### Bot-nedetid
Vaktmesteren overvåker `synops-respond` sin exit-kode. Ved feil:
```
@bot (ingen respons på 30 sek)
→ Vaktmesteren sender automatisk i chatten:
"⚠ Boten er midlertidig utilgjengelig.
Meldingen din er lagret og blir besvart
når tjenesten er tilbake."
→ Oppretter work_item i innboks: "Bot-nedetid" + tagged "bug"
→ Logger i ai_usage_log med error-status
```
Brukeren vet at meldingen er mottatt. Når boten er tilbake,
kan den prosessere ubesvarte meldinger.
### Healthcheck
Vaktmesteren eksponerer `/health` som sjekker:
- PG-tilkobling
- LiteLLM-tilgjengelighet
- Disk-status
Systemd restarter vaktmesteren ved gjentatte feil.
## LLM fallback-kjede
LiteLLM håndterer modell-fallback. `@bot` fungerer uansett
hvilken modell som svarer:
```
synops-respond → LiteLLM
├── Claude (primær)
├── GPT-4 (fallback 1)
├── Gemini (fallback 2)
└── Lokal modell (fallback 3, alltid oppe)
```
Brukeren merker kanskje kvalitetsforskjell, men tjenesten er
oppe. Fallback-kjeden konfigureres i LiteLLM — ingen endring
i vaktmesteren eller synops-respond.
## Ekstern API-bot og CLI-verktøy
En LLM via API har ikke shell-tilgang. Den trenger det heller
ikke — vaktmesteren er mellomleddet.
### Function calling / tool use
```
Bruker: "@bot sjekk om RSS-feeden oppdaterte seg"
→ vaktmesteren → synops-respond → LLM API
LLM svarer med structured output:
{
"response": "Jeg sjekker RSS-feeden for deg.",
"actions": [
{ "tool": "synops-rss",
"args": { "collection_id": "abc123" } }
]
}
Vaktmesteren:
1. Poster chat-svaret i samtalen
2. Spawner: synops-rss --payload-json '{"collection_id":"abc123"}'
3. Poster resultatet som oppfølgingsmelding
```
LLM-en beskriver *hva* som skal gjøres. Vaktmesteren *gjør*
det. Navnekonvensjonen (`synops-{tool}`) betyr at vaktmesteren
kan dispatche uten hardkodet mapping — samme generiske dispatch
som jobbkøen (se `docs/retninger/unix_filosofi.md`).
### Tilgangskontroll for actions
Ikke alle brukere skal kunne trigge alle verktøy via `@bot`.
Vaktmesteren sjekker:
1. Brukerens rolle i konteksten (owner/admin/member/reader)
2. Verktøyets tilgangsnivå (fra `cli_tool`-nodens metadata)
3. Rate limiting per bruker
En `reader` kan spørre `@bot` om informasjon, men ikke trigge
`synops-render` eller `synops-audio`.
## Fallback per situasjon
| Situasjon | Deteksjon | Fallback | Brukeropplevelse |
|-----------|-----------|----------|------------------|
| Claude API nede | LiteLLM timeout | Neste modell i kjeden | Svarer, kanskje litt dårligere |
| Alle LLM-er nede | synops-respond exit != 0 | Statisk "utilgjengelig" + work_item | Vet at meldingen er mottatt |
| Vaktmesteren nede | Systemd healthcheck → restart | CLI fungerer for Claude Code | Web-brukere venter, terminal funker |
| PG nede | Connection refused | Alt stopper | Eneste reelle SPOF |
| WebSocket nede | Vaktmesteren restarter | Frontend rekobler automatisk | Sanntid midlertidig borte, data trygt |
## PG som eneste SPOF
PostgreSQL er den eneste komponenten der nedetid stopper alt.
Men det er også den mest stabile — PG krasjer sjelden, og
gjenoppbygging fra backup er veldokumentert
(se `docs/setup/produksjon.md`).
Mitigering:
- Automatisk PG-dump (se oppgave 12.2)
- `synops-snapshot` sikrer at docs-fallback finnes i repo
- CAS-filer er uavhengig av PG (filsystem)
## Onboarding som statisk dispatch
Første `@bot` i en ny brukers velkomst-chat trenger ikke
LLM-roundtrip. Vaktmesteren gjenkjenner mønsteret og serverer
onboarding-noden direkte:
```rust
if is_welcome_chat && is_first_bot_mention {
return serve_static_node(ONBOARDING_NODE_UUID);
}
```
Null latency, null AI-kostnad, fungerer selv om alle LLM-er
er nede. Onboarding-teksten er en vanlig node — oppdaterbar
uten redeploy.
Etter første melding fungerer chatten normalt med LLM.
## Bygger på
- `docs/infra/ai_gateway.md` — LiteLLM fallback-kjeder
- `docs/retninger/unix_filosofi.md` — generisk dispatch
- `docs/retninger/maskinrommet.md` — vaktmester-rollen
- `docs/concepts/arbeidstavlen.md`@bot-konvensjonen
- `docs/concepts/selvdokumenterende_system.md` — onboarding-node