# 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=<JWT>`.

## 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.
