# 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 (WebSocket via PG LISTEN/NOTIFY) ## Maskinrommet eier all skriving Frontend sender intensjoner. Maskinrommet utfører. ``` Frontend: "legg til Trond i møtet" → Maskinrommet validerer → Skriver edge til PG → Oppdaterer tilgangsmatrise → PG NOTIFY → WebSocket → frontend oppdateres i sanntid → 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 → PG → NOTIFY → WebSocket (sanntid). ## 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ø 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. **Sanntid** — PG LISTEN/NOTIFY → WebSocket til frontend 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 PG, sanntid via LISTEN/NOTIFY + WebSocket