Nytt CLI-verktøy for å hente og vise en node med alle tilkoblede edges. Støtter rekursiv graf-traversering (--depth) og to output-formater (markdown og JSON). Brukes av Claude og maskinrommet for å inspisere graf-tilstand. Features: - Hent node med alle edges (inn og ut) - Berik edges med peer-tittel og node_kind for lesbarhet - --depth 0: bare noden, --depth 1: + edges (default), --depth 2+: traverser - --format md (default) eller json - Kompakt metadata-visning, forkortet innhold Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
223 lines
7.9 KiB
Markdown
223 lines
7.9 KiB
Markdown
# Maskinrommet
|
|
|
|
**Status: Besluttet.**
|
|
|
|
> Én Rust-tjeneste med et fast grensesnitt. Alt som krever tunge
|
|
> ressurser eller eksterne tjenester går gjennom dette laget.
|
|
> Fang, prosesser, lever. Maskinrommet er det eneste som skriver
|
|
> noder og edges.
|
|
|
|
## Tre operasjoner
|
|
|
|
### 1. Fang (input-absorpsjon)
|
|
Ta imot råmateriale i alle modaliteter:
|
|
- Tekst (melding, URL, dokument)
|
|
- Lyd (voice memo, live stream, filopplasting)
|
|
- Bilde (foto, skjermbilde, tegning)
|
|
- Video (stream, opptak)
|
|
- Strukturert data (JSON, metadata, edges)
|
|
|
|
### 2. Prosesser (transformasjon)
|
|
Analyser, transformer, berik og systematiser:
|
|
- **STT** — lyd → tekst (Whisper)
|
|
- **TTS** — tekst → lyd (ElevenLabs / lokal modell)
|
|
- **AI-analyse** — oppsummering, klassifisering, edge-forslag
|
|
- **Beriking** — URL → metadata, bilde → beskrivelse
|
|
- **Søk** — fulltekst, semantisk (pgvector), graftraversering
|
|
- **Mediaprosessering** — transcode, thumbnail, waveform
|
|
|
|
### 3. Lever (output-distribusjon)
|
|
Lever resultat i riktig modalitet til riktig mottaker:
|
|
- Tekst (melding, notifikasjon, digest)
|
|
- Lyd (TTS-opplesning, lydstream)
|
|
- Video/bilde (stream, thumbnail)
|
|
- Strukturert data (noder, edges tilbake i grafen)
|
|
- Push (SpacetimeDB-reducer)
|
|
|
|
## Maskinrommet eier all skriving
|
|
|
|
Frontend sender intensjoner. Maskinrommet utfører.
|
|
|
|
```
|
|
Frontend: "legg til Trond i møtet"
|
|
→ Maskinrommet validerer
|
|
→ Skriver edge til SpacetimeDB (instant)
|
|
→ Oppdaterer tilgangsmatrise
|
|
→ Persisterer til PG (asynk)
|
|
→ Reagerer på konsekvensene (koble inn LiveKit, starte transkripsjon)
|
|
```
|
|
|
|
Alt i én operasjon. Maskinrommet er ikke reaktivt i en pub/sub-
|
|
forstand — det orkestrerer hele sekvensen. Enklere å forstå,
|
|
enklere å debugge.
|
|
|
|
Skrivestien: validering → SpacetimeDB (instant) → PG (asynk).
|
|
Se [synkronisering](../infra/synkronisering.md).
|
|
|
|
## Edge-drevet ressursorkestrering
|
|
|
|
Maskinrommet leser edges for å vite hva det skal gjøre. Noden
|
|
er alltid enkel. Edges bestemmer hvilke ressurser som spinnes opp.
|
|
|
|
### Privat er default
|
|
Input uten mottaker-edge er automatisk privat. Ingen ressurser
|
|
kobles inn utover det grunnleggende (fang + transkriber).
|
|
|
|
### Ressurser er proporsjonale med edges
|
|
|
|
```
|
|
Dagboknotat (privat voice memo):
|
|
node → fang lyd → transkriber (Whisper) → lagre
|
|
Ressurser: minimal
|
|
|
|
Samtale med Trond:
|
|
node + mottaker-edge(Trond)
|
|
→ fang lyd → transkriber → lever tekst/lyd til Trond
|
|
Ressurser: STT + levering til én
|
|
|
|
Redaksjonsmøte (5 deltakere):
|
|
node + mottaker-edges(5) + rolle-edges
|
|
→ fang lyd fra alle → transkriber → lever til alle → AI-referent
|
|
Ressurser: STT + levering til 5 + LLM
|
|
|
|
Livesending (1000 lyttere):
|
|
node + mottaker-edges(∞) + stream-edge
|
|
→ fang lyd → transkriber → stream via LiveKit → distribuer
|
|
→ generer segmenter → kjør live AI → publiser
|
|
Ressurser: STT + LiveKit + LLM + mediaprosessering
|
|
```
|
|
|
|
### Naturlig eskalering
|
|
Du starter en privat voice-note. Deler den med Trond → legg til
|
|
edge, maskinrommet begynner å levere. Trond foreslår møte → flere
|
|
edges, maskinrommet kobler inn sanntidsstrømming. Møtet blir
|
|
innspilling → publiserings-edge, maskinrommet aktiverer
|
|
produksjonspipeline. Hvert steg er bare å legge til edges.
|
|
|
|
## Grensesnittet
|
|
|
|
```
|
|
fang(input: RåInput) → NodeId
|
|
prosesser(node: NodeId, operasjon: Operasjon) → Resultat
|
|
lever(node: NodeId, mottaker: Mottaker, format: Format) → Status
|
|
```
|
|
|
|
I praksis er mye av dette implisitt: maskinrommet ser hvilke edges
|
|
som ble skrevet og handler deretter. Primitivene manipulerer edges
|
|
via maskinrommet, og maskinrommet kobler inn riktige ressurser.
|
|
|
|
## CAS og intelligent pruning
|
|
|
|
### CAS som lagringsprimitiv
|
|
All binærdata (lyd, bilde, video) lagres content-addressable.
|
|
CAS-noder i grafen bærer metadata (`cas_hash`, `mime`, `size`).
|
|
Selve biten lever på disk.
|
|
|
|
- **Deduplisering gratis** — samme fil delt i tre kontekster = én kopi
|
|
- **Separasjon** — "innholdet eksisterer" er adskilt fra "innholdet
|
|
er tilgjengelig"
|
|
- **Enkel opprydning** — slett filen fra CAS, noden beholder metadata
|
|
|
|
### Lagringsregler per modalitet
|
|
|
|
| Modalitet | Default levetid | Begrunnelse |
|
|
|-----------|----------------|-------------|
|
|
| Tekst | Evig | Billig, essensen av innholdet |
|
|
| Transkripsjon | Evig | Tekstlig representasjon — bevarer meningen |
|
|
| Lyd | 30 dager | Transkripsjon bevarer innholdet |
|
|
| Bilde | 30 dager | Beskrivelse/metadata bevarer kontekst |
|
|
| Video | 14 dager | Dyrest, transkripsjon + thumbnail bevarer det meste |
|
|
|
|
### Signaler som forlenger levetid
|
|
|
|
- **Edges.** Lydfil med publiserings-edge = beholdes. Privat
|
|
voice-memo uten edges = 30-dagers TTL.
|
|
- **Aksesslog.** Avspilt i løpet av TTL-perioden = forlenges.
|
|
- **Transkripsjonsstatus.** Utranskribert lyd kan trenge lengre TTL.
|
|
- **Edge-type.** Publisert = behold. Arkivert møte = transkripsjon
|
|
holder.
|
|
|
|
### Generert innhold er en cache
|
|
TTS, thumbnails, AI-oppsummeringer, waveforms — alt som kan
|
|
regenereres er en cache i CAS med samme TTL-mekanisme.
|
|
|
|
### Samlings-node-styrt aggressivitet
|
|
Hver samlings-node kan justere sin pruning-profil:
|
|
- **Konservativt** — behold alt lenge (arkiv-node)
|
|
- **Aggressivt** — tekst bevares, binærdata prunes raskt
|
|
- **Tilpasset** — egne regler per modalitet og edge-type
|
|
|
|
### Disk-nødventil
|
|
Maskinrommet overvåker diskbruk:
|
|
- **>85 %:** Genererte filer slettes (kan regenereres)
|
|
- **>90 %:** Aggressiv pruning for alle samlings-noder
|
|
- **>95 %:** Kritisk alarm. Alt uten publiserings-edge slettes.
|
|
Tekst og transkripsjoner bevares alltid.
|
|
|
|
## Isolasjon og observerbarhet
|
|
|
|
### Isolasjon
|
|
Bytt Whisper med noe annet? Endre maskinrommet. Frontend vet
|
|
ingenting. Legg til bildegenerering? Ny operasjon. Primitivene
|
|
kaller den uten å vite hva som skjer under.
|
|
|
|
### Observerbarhet
|
|
Alt går gjennom ett punkt. Logging, metrikker, kostnadsrapportering
|
|
— alt på ett sted. "Hva bruker vi AI-ressurser på?" har ett svar.
|
|
|
|
### Kapasitetsstyring
|
|
Prioritering, kø, rate limiting, fallback mellom leverandører.
|
|
Live transkripsjon prioriteres over bakgrunns-oppsummering.
|
|
|
|
## Compute-separasjon
|
|
|
|
Maskinrommet orkestrerer — tunge jobber trenger ikke kjøre på
|
|
samme maskin.
|
|
|
|
- **Nå:** Alt på én VPS. Jobbkøen prioriterer sanntid over batch.
|
|
- **Snart:** Trekk ut tunge workers til separat node (billig
|
|
ARM-instans) som poller jobbkøen. Maskinrommet ruter transparent.
|
|
- **Kildevern-modus:** Lokal LLM krever dedikert compute med
|
|
fysisk isolasjon.
|
|
|
|
Compute-separasjon er en konfigurasjon, ikke en arkitekturendring.
|
|
|
|
## Evolusjon: Maskinrommet → Portvokteren
|
|
|
|
Maskinrommet ble bygget som en monolitt — auth, validering,
|
|
prosessering, jobbkø, STDB-synk i én binær. Med unix-filosofi-
|
|
retningen (se `docs/retninger/unix_filosofi.md`) flyttes all
|
|
prosessering til CLI-verktøy. Det som blir igjen er:
|
|
|
|
1. **Auth** — JWT-validering, "hvem er denne requesten?"
|
|
2. **HTTP-ruting** — frontend → riktig CLI-verktøy
|
|
3. **STDB-synk** — push PG-endringer til SpacetimeDB
|
|
4. **Jobbkø-dispatch** — poll PG, spawn CLI-verktøy
|
|
|
|
Dette er en **portvokter**, ikke et maskinrom. Når uttynningen er
|
|
ferdig, renames `maskinrommet/` til `portvokteren/` og systemd-
|
|
tjenesten oppdateres. Navnet skal reflektere rollen: vokter porten,
|
|
gjør ikke jobben.
|
|
|
|
**Hva dette gir:**
|
|
- Portvokteren dør → frontend stopper, men CLI-verktøy fungerer.
|
|
Claude jobber videre, scripts kjører, terminalen funker.
|
|
- Et CLI-verktøy dør → bare den funksjonen stopper. Alt annet
|
|
er upåvirket.
|
|
- Portvokteren blir så enkel at den nesten aldri feiler.
|
|
|
|
**Edge-validering og tilgangskontroll** flyttes til `synops-common`
|
|
(delt lib) — brukes av både portvokteren og CLI-verktøy.
|
|
|
|
## Forhold til andre retninger
|
|
|
|
Maskinrommet er infrastrukturen *under* de tre primitivene i
|
|
[universell input og mottak](universell_input.md):
|
|
- Input-primitiven → `fang()` + `prosesser()`
|
|
- Mottak-primitiven → `lever()`
|
|
- Kommunikasjonsnoden → alle tre
|
|
|
|
- [Noder er sentrum](bruker_ikke_workspace.md) — maskinrommet
|
|
eier tilgangsmatrise-oppdatering
|
|
- [Datalaget](datalaget.md) — maskinrommet skriver SpacetimeDB
|
|
først, PG asynk
|