From 6bb1665b302b54fc34eda12651ab2c1cd54a4024 Mon Sep 17 00:00:00 2001 From: vegard Date: Wed, 18 Mar 2026 13:58:50 +0000 Subject: [PATCH] =?UTF-8?q?Validering=2023.1:=20fase=201=E2=80=932=20(infr?= =?UTF-8?q?a=20+=20maskinrommet)=20verifisert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Systematisk gjennomgang av PG-skjema, auth-middleware, intensjoner, skrivestien og WebSocket-laget. Alle kjernetabeller matcher docs. Auth fungerer korrekt (401 for ugyldig/manglende token). Skrivestien er konsistent: direkte PG-skriving → NOTIFY → WebSocket. Fikser: - Fjern død kode: pg_writes enqueue-funksjoner (aldri kalt etter STDB-migrering) - Fjern ubrukt truncate() i tts.rs - Legg til #[allow(dead_code)] for sqlx-structs med ubrukte felt - Rett feilaktig doc-påstand i api_grensesnitt.md om jobbkø - Fjern utdatert STDB-referanse i agent_api.md - Kompilerer uten warnings Se logs/validering-23.1.md for fullstendig rapport. --- docs/infra/agent_api.md | 2 +- docs/infra/api_grensesnitt.md | 2 +- logs/validering-23.1.md | 105 ++++++++++++++++++++++++++ maskinrommet/src/ai_process.rs | 1 + maskinrommet/src/intentions.rs | 1 + maskinrommet/src/pg_writes.rs | 131 +++------------------------------ maskinrommet/src/tts.rs | 9 --- tasks.md | 3 +- 8 files changed, 120 insertions(+), 134 deletions(-) create mode 100644 logs/validering-23.1.md diff --git a/docs/infra/agent_api.md b/docs/infra/agent_api.md index afbee38..a501ea9 100644 --- a/docs/infra/agent_api.md +++ b/docs/infra/agent_api.md @@ -112,7 +112,7 @@ med `job_type: 'spec_update'`. Oppretter `revision`-node med forrige versjon for historikk. #### `POST /agent/respond` -Send et svar i en samtale (erstatter dagens direkte STDB-skriving). +Send et svar i en samtale. ```json { diff --git a/docs/infra/api_grensesnitt.md b/docs/infra/api_grensesnitt.md index 985da90..6aa7222 100644 --- a/docs/infra/api_grensesnitt.md +++ b/docs/infra/api_grensesnitt.md @@ -143,7 +143,7 @@ Skriver til PG `mixer_channels`-tabell; NOTIFY-trigger propagerer til WS. - Intensjoner fra frontend → `POST /intentions/*` endepunkter i maskinrommet. - Tunge spørringer fra frontend → `GET /query/*` endepunkter i maskinrommet. - Frontend (SvelteKit) har ingen direkte databasetilgang. -- Bakgrunnsjobber trigges av maskinrommet, ikke via en separat jobbkø-tabell. +- Bakgrunnsjobber trigges av maskinrommet via `job_queue`-tabellen (se `docs/infra/jobbkø.md`). > **Historisk merknad:** Tidligere beskrev dette dokumentet en arkitektur > der SvelteKit var web-API og Rust kun var workers. Denne ble erstattet diff --git a/logs/validering-23.1.md b/logs/validering-23.1.md new file mode 100644 index 0000000..1c16452 --- /dev/null +++ b/logs/validering-23.1.md @@ -0,0 +1,105 @@ +# 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. diff --git a/maskinrommet/src/ai_process.rs b/maskinrommet/src/ai_process.rs index 6ab2493..6be27d3 100644 --- a/maskinrommet/src/ai_process.rs +++ b/maskinrommet/src/ai_process.rs @@ -29,6 +29,7 @@ use crate::jobs::JobRow; use crate::resource_usage; #[derive(sqlx::FromRow)] +#[allow(dead_code)] struct SourceNodeRow { content: Option, title: Option, diff --git a/maskinrommet/src/intentions.rs b/maskinrommet/src/intentions.rs index 4bd6370..fa63ded 100644 --- a/maskinrommet/src/intentions.rs +++ b/maskinrommet/src/intentions.rs @@ -1388,6 +1388,7 @@ pub struct DeleteEdgeResponse { } #[derive(sqlx::FromRow)] +#[allow(dead_code)] struct FullEdgeRow { source_id: Uuid, target_id: Uuid, diff --git a/maskinrommet/src/pg_writes.rs b/maskinrommet/src/pg_writes.rs index 3b02c01..71872d7 100644 --- a/maskinrommet/src/pg_writes.rs +++ b/maskinrommet/src/pg_writes.rs @@ -1,10 +1,10 @@ // pg_writes — Jobbkø-handlere for PG-skriveoperasjoner. // -// Erstatter fire-and-forget `tokio::spawn()` med retry via jobbkøen. -// Hver skriveoperasjon (insert/update/delete for nodes og edges) er en -// egen jobbtype som behandles av den eksisterende worker-loopen med -// eksponentiell backoff (30s × 2^n) og dead letter queue (status='error' -// etter max_attempts). +// Historisk kontekst: Disse handlene ble opprettet da skrivestien gikk +// via jobbkøen (STDB → async PG-skriving). Etter STDB-migreringen (fase 22) +// skriver intensjonene direkte til PG, og NOTIFY-triggere sender +// sanntidsoppdateringer. Handlene beholdes for å prosessere eventuelle +// gjenværende jobber i køen. // // Jobbtyper: // pg_insert_node, pg_insert_edge, pg_update_node, @@ -19,122 +19,11 @@ use uuid::Uuid; use crate::jobs::JobRow; use crate::publishing::IndexCache; -/// Prioritet for PG-skriveoperasjoner. Høy — data-konsistens er kritisk. -const PG_WRITE_PRIORITY: i16 = 8; - -// ============================================================================= -// Enqueue-funksjoner (erstatter spawn_pg_*) -// ============================================================================= - -/// Legger en insert_node-operasjon i jobbkøen. -pub fn enqueue_insert_node( - db: PgPool, - node_id: Uuid, - node_kind: String, - title: String, - content: String, - visibility: String, - metadata: serde_json::Value, - created_by: Uuid, -) { - let payload = json!({ - "node_id": node_id, - "node_kind": node_kind, - "title": title, - "content": content, - "visibility": visibility, - "metadata": metadata, - "created_by": created_by, - }); - tokio::spawn(async move { - if let Err(e) = crate::jobs::enqueue(&db, "pg_insert_node", payload, None, PG_WRITE_PRIORITY).await { - tracing::error!(node_id = %node_id, error = %e, "Kunne ikke legge pg_insert_node i jobbkø"); - } - }); -} - -/// Legger en insert_edge-operasjon i jobbkøen. -pub fn enqueue_insert_edge( - db: PgPool, - edge_id: Uuid, - source_id: Uuid, - target_id: Uuid, - edge_type: String, - metadata: serde_json::Value, - system: bool, - created_by: Uuid, -) { - let payload = json!({ - "edge_id": edge_id, - "source_id": source_id, - "target_id": target_id, - "edge_type": edge_type, - "metadata": metadata, - "system": system, - "created_by": created_by, - }); - tokio::spawn(async move { - if let Err(e) = crate::jobs::enqueue(&db, "pg_insert_edge", payload, None, PG_WRITE_PRIORITY).await { - tracing::error!(edge_id = %edge_id, error = %e, "Kunne ikke legge pg_insert_edge i jobbkø"); - } - }); -} - -/// Legger en update_node-operasjon i jobbkøen. -pub fn enqueue_update_node( - db: PgPool, - node_id: Uuid, - node_kind: String, - title: String, - content: String, - visibility: String, - metadata: serde_json::Value, -) { - let payload = json!({ - "node_id": node_id, - "node_kind": node_kind, - "title": title, - "content": content, - "visibility": visibility, - "metadata": metadata, - }); - tokio::spawn(async move { - if let Err(e) = crate::jobs::enqueue(&db, "pg_update_node", payload, None, PG_WRITE_PRIORITY).await { - tracing::error!(node_id = %node_id, error = %e, "Kunne ikke legge pg_update_node i jobbkø"); - } - }); -} - -/// Legger en delete_node-operasjon i jobbkøen. -pub fn enqueue_delete_node(db: PgPool, node_id: Uuid) { - let payload = json!({ "node_id": node_id }); - tokio::spawn(async move { - if let Err(e) = crate::jobs::enqueue(&db, "pg_delete_node", payload, None, PG_WRITE_PRIORITY).await { - tracing::error!(node_id = %node_id, error = %e, "Kunne ikke legge pg_delete_node i jobbkø"); - } - }); -} - -/// Legger en delete_edge-operasjon i jobbkøen. -pub fn enqueue_delete_edge( - db: PgPool, - edge_id: Uuid, - source_id: Uuid, - target_id: Uuid, - edge_type: String, -) { - let payload = json!({ - "edge_id": edge_id, - "source_id": source_id, - "target_id": target_id, - "edge_type": edge_type, - }); - tokio::spawn(async move { - if let Err(e) = crate::jobs::enqueue(&db, "pg_delete_edge", payload, None, PG_WRITE_PRIORITY).await { - tracing::error!(edge_id = %edge_id, error = %e, "Kunne ikke legge pg_delete_edge i jobbkø"); - } - }); -} +// Enqueue-funksjonene (enqueue_insert_node, enqueue_insert_edge, etc.) er fjernet. +// Etter STDB-migreringen (fase 22) skriver intensjonene direkte til PG. +// NOTIFY-triggere sender sanntidsoppdateringer via WebSocket. +// Handle-funksjonene under beholdes for å prosessere eventuelle gjenværende +// jobber i køen fra den gamle arkitekturen. // ============================================================================= // Job-handlere (kalles fra dispatch i jobs.rs) diff --git a/maskinrommet/src/tts.rs b/maskinrommet/src/tts.rs index 90872f7..7795d42 100644 --- a/maskinrommet/src/tts.rs +++ b/maskinrommet/src/tts.rs @@ -135,12 +135,3 @@ async fn resolve_voice_id( .unwrap_or_else(|_| "21m00Tcm4TlvDq8ikWAM".to_string())) } -/// Forkorter en streng til maks `max_len` tegn med "..." suffix. -fn truncate(s: &str, max_len: usize) -> String { - if s.len() <= max_len { - s.to_string() - } else { - let end = s.char_indices().nth(max_len - 3).map(|(i, _)| i).unwrap_or(s.len()); - format!("{}...", &s[..end]) - } -} diff --git a/tasks.md b/tasks.md index 9c02bf6..32abde5 100644 --- a/tasks.md +++ b/tasks.md @@ -295,8 +295,7 @@ verifiserer mot spec, og sjekker at ting faktisk fungerer. Ved funn: fiks direkte hvis det er småting, eller opprett nye work_items (tasks) med spesifikasjon for det som trenger en dedikert sesjon. -- [~] 23.1 Valider fase 1–2 (infra + maskinrommet): PG-skjema, indekser, auth-middleware, intensjoner, STDB-klient (nå erstattet av WS). Verifiser at skjema matcher docs, at auth fungerer, at skrivestien er konsistent. - > Påbegynt: 2026-03-18T13:50 +- [x] 23.1 Valider fase 1–2 (infra + maskinrommet): PG-skjema, indekser, auth-middleware, intensjoner, STDB-klient (nå erstattet av WS). Verifiser at skjema matcher docs, at auth fungerer, at skrivestien er konsistent. - [ ] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering. - [ ] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet. - [ ] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.