synops/docs/infra/robusthet.md
vegard b5aa5bb243 Fjern SpacetimeDB komplett (oppgave 22.4)
SpacetimeDB er nå helt fjernet fra Synops. Sanntid håndteres av
PG LISTEN/NOTIFY + WebSocket i portvokteren (maskinrommet).

Kode fjernet:
- spacetimedb/ Rust-modul og spacetime.json
- maskinrommet/src/stdb.rs (HTTP-klient for STDB-reducers)
- frontend module_bindings/ (23 auto-genererte filer)
- spacetimedb npm-avhengighet fra package.json
- scripts/test-sanntid.sh (testet STDB-flyt)

Infrastruktur:
- Docker-container stoppet og fjernet fra docker-compose.yml
- Caddy: fjernet /spacetime/* reverse proxy
- maskinrommet-env.sh: fjernet STDB_IP og SPACETIMEDB_*-variabler
- .env.example: fjernet SpacetimeDB-seksjoner

Dokumentasjon oppdatert:
- CLAUDE.md: stack, lagmodell, kjerneprinsipper, driftsmodell
- docs/arkitektur.md: skrivestien, lesestien, datalag, teknologivalg
- docs/retninger/datalaget.md: migrasjonshistorikk, status "fjernet"
- 37 andre docs oppdatert (features, concepts, infra, ops, retninger)
- Alle kode-kommentarer med STDB-referanser oppdatert

Verifisert: maskinrommet bygger og starter OK, frontend bygger OK,
helsesjekk returnerer 200. Caddy reloadet.
2026-03-18 13:39:09 +00:00

4.6 KiB

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: Portvokteren                                 → lokal native (systemd)
Lag 4: CLI-verktøy (synops-*)                       → per-kall, isolert
Lag 5: PostgreSQL                                   → lokal Docker, SPOF

Deteksjon

Bot-nedetid

Portvokteren overvåker synops-respond sin exit-kode. Ved feil:

@bot (ingen respons på 30 sek)
  → Portvokteren 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

Portvokteren eksponerer /health som sjekker:

  • PG-tilkobling
  • LiteLLM-tilgjengelighet
  • Disk-status

Systemd restarter portvokteren 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 portvokteren eller synops-respond.

Ekstern API-bot og CLI-verktøy

En LLM via API har ikke shell-tilgang. Den trenger det heller ikke — portvokteren er mellomleddet.

Function calling / tool use

Bruker: "@bot sjekk om RSS-feeden oppdaterte seg"
  → portvokteren → synops-respond → LLM API

LLM svarer med structured output:
  {
    "response": "Jeg sjekker RSS-feeden for deg.",
    "actions": [
      { "tool": "synops-rss",
        "args": { "collection_id": "abc123" } }
    ]
  }

Portvokteren:
  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. Portvokteren gjør det. Navnekonvensjonen (synops-{tool}) betyr at portvokteren 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. Portvokteren 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
Portvokteren 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 Portvokteren 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. Portvokteren gjenkjenner mønsteret og serverer onboarding-noden direkte:

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 — portvokter-rollen
  • docs/concepts/arbeidstavlen.md — @bot-konvensjonen
  • docs/concepts/selvdokumenterende_system.md — onboarding-node