# Validering 23.1 — Fase 1–2 (infra + maskinrommet) Dato: 2026-03-18 ## PG-skjema vs. docs ### nodes-tabell - **Match:** Alle kolonner fra `docs/primitiver/nodes.md` finnes i PG med korrekte typer og defaults. - **Ekstra kolonner fra senere faser:** `last_accessed_at` (migrasjon 010, pruning), `search_vector` (migrasjon 011, fulltekstsøk). Disse er dokumentert i sine respektive migrasjoner. - **Indekser:** Alle tre dokumenterte indekser (`idx_nodes_kind`, `idx_nodes_created_by`, `idx_nodes_visibility`) er på plass. I tillegg 4 ytelsesindekser fra migrasjon 017. - **Triggere:** `nodes_notify` (PG NOTIFY), `trg_nodes_search_vector` (fulltekstsøk). Begge korrekte. - **RLS:** `node_select`-policy korrekt — sjekker created_by, aliaser, node_access, og visibility. ### edges-tabell - **Match:** Eksakt match med `docs/primitiver/edges.md` — alle kolonner, constraints, defaults. - **UNIQUE constraint:** `(source_id, target_id, edge_type)` korrekt. - **Indekser:** Alle tre dokumenterte + 3 ekstra ytelsesindekser. OK. - **Trigger:** `edges_notify` for PG NOTIFY. Korrekt. - **RLS:** `edge_select`-policy sjekker system-flagg, created_by, aliaser, og node_access. ### node_access-tabell - **Match:** Eksakt match med migrasjon 001. `(subject_id, object_id)` PK, `via_edge` med CASCADE. - **CASCADE-oppbygning:** Når en tilgangsgivende edge slettes, fjernes tilhørende `node_access`-rader automatisk via `ON DELETE CASCADE` på `via_edge`. Elegant og korrekt. - **Trigger:** `node_access_notify` for sanntidsoppdatering av klientenes tilgangsmatrise. ### auth_identities-tabell - **Match:** Eksakt match. `node_id` PK, `authentik_sub` UNIQUE, `email` UNIQUE. - **Seed-data:** Vegard er opprettet med korrekt node_id og authentik_sub. ### Enums - `visibility`: hidden, discoverable, readable, open — matcher docs. - `access_level`: reader, member, admin, owner — matcher docs. - `job_status`: pending, running, completed, error, retry — matcher jobbkø-spec. ### recompute_access-funksjon - Korrekt implementert i migrasjon 001. Håndterer direkte tilgang, transitiv belongs_to, og team-propagering. ## Auth-middleware - **JWKS:** Hentes fra Authentik ved oppstart. Støtter kid-matching. - **JWT-validering:** RS256, issuer og audience valideres. Korrekt. - **Identitetsoppslag:** `auth_identities.authentik_sub` → `node_id`. Fungerer. - **401-respons:** Verifisert med curl — returnerer 401 for manglende token og ugyldig token. - **WebSocket:** Bruker samme JWT-validering via query-parameter `?token=`. ## Skrivestien (intensjoner) ### create_node - Direkte PG-skriving med NOTIFY-trigger. Kontekst-arv (automatisk belongs_to-edge) fungerer. - Alias-oppløsning for kontekstbasert identitet (fase 8.2). - Agent-trigger og AI edge-forslag spawnes asynkront. Korrekt. - Validering: visibility-enum, traits for samlingsnoder, AI-preset-metadata. ### create_edge - Direkte PG-skriving. For tilgangsgivende edges (owner/admin/member_of/reader): transaksjon med recompute_access. - Publiseringsvalidering: submitted_to og belongs_to til require_approval-samlinger. - source_material-validering: context + excerpt påkrevd. - A/B-test-trigger for presentasjonselement-edges. ### update_node / delete_node - Tilgangskontroll: `user_can_modify_node` sjekker created_by, owner/admin-edge, og alias. - Partial update: kun oppgitte felter endres, resten beholdes fra eksisterende node. - Re-rendering trigges ved custom_domain- eller temaendring. ### update_edge / delete_edge - Tilgangskontroll: `user_can_modify_edge` sjekker created_by, owner/admin til source-noden, og alias. - submitted_to status-endring krever owner/admin av samlingen. - Cache-invalidering ved belongs_to-sletting. ## WebSocket / sanntid - PG LISTEN/NOTIFY-triggere: `node_changed`, `edge_changed`, `access_changed`, `mixer_channel_changed`. - Berikelse: full raddata hentes fra PG etter NOTIFY (ikke bare ID). - Tilgangsfiltrering: `should_send_to_user` sjekker `visible_nodes` (HashSet). - Initial sync: alle noder, edges, access og mixer_channels brukeren kan se. - Resync ved lag: sender full initial_sync. - `visible_nodes` oppdateres dynamisk ved access_changed-events. ## Jobbkø - PostgreSQL-basert: `SELECT ... FOR UPDATE SKIP LOCKED`. - Retry med eksponentiell backoff (30s × 2^n). - Ressursstyring: semaphore (3 samtidige), CPU-vekt, LiveKit-bevisst governor. - Vedlikeholdsmodus: pauser dequeue. - CLI-dispatch: spawner `synops-*`-verktøy for tunge jobber. ## Funn og fikser ### Fjernet død kode 1. **pg_writes.rs: enqueue_*-funksjoner** — Aldri kalt etter STDB-migreringen. Intensjonene skriver nå direkte til PG. Funksjoner fjernet, kommentar lagt til. 2. **tts.rs: truncate()** — Ubrukt hjelpefunksjon. Fjernet. 3. **ai_process.rs: SourceNodeRow** — `#[allow(dead_code)]` lagt til (struct-felt brukes av sqlx men ikke lest direkte i kode). 4. **intentions.rs: FullEdgeRow** — `#[allow(dead_code)]` lagt til (samme mønster). ### Oppdaterte docs 1. **docs/infra/api_grensesnitt.md** — Rettet feilaktig påstand om at bakgrunnsjobber ikke bruker jobbkø-tabell. 2. **docs/infra/agent_api.md** — Fjernet utdatert STDB-referanse. ### Kompilering - Maskinrommet kompilerer uten warnings etter fiks. - Maskinrommet kjører og svarer på `/health` med `{ "status": "ok" }`. ## Konklusjon Fase 1–2 er solid implementert. PG-skjema matcher docs eksakt for kjernetabellene. Auth-middleware fungerer korrekt. Skrivestien er konsistent: direkte PG-skriving → NOTIFY → WebSocket. Ingen funksjonelle feil funnet. Kun død kode og småjusteringer i docs.