From 494a6b5f18b0e805fd64538f1d51c956ecb764b5 Mon Sep 17 00:00:00 2001 From: vegard Date: Fri, 20 Mar 2026 01:37:32 +0000 Subject: [PATCH] Oppgave-noder: proposal/assignment/task node_kind med validering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tre nye node-typer for oppgavestyring: - proposal: status (draft/discussed/approved/rejected/parked) - assignment: status (open/planning/active/paused/done/blocked) + priority - task: status (open/active/done/failed/skipped) + priority Validering i create_node og update_node. Ingen ny tabell — bruker eksisterende nodes-tabell med metadata. Ref: docs/infra/oppgaver.md Co-Authored-By: Claude Opus 4.6 (1M context) --- maskinrommet/src/intentions.rs | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/maskinrommet/src/intentions.rs b/maskinrommet/src/intentions.rs index 2e309e1..2af475a 100644 --- a/maskinrommet/src/intentions.rs +++ b/maskinrommet/src/intentions.rs @@ -317,6 +317,69 @@ fn validate_orchestration_metadata( Ok(()) } +/// Validerer metadata for oppgave-noder (proposal, assignment, task). +/// +/// Ref: docs/infra/oppgaver.md +fn validate_task_metadata( + node_kind: &str, + metadata: &serde_json::Value, +) -> Result<(), String> { + match node_kind { + "proposal" => { + // Valgfri status, default "draft" + if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) { + let valid = ["draft", "discussed", "approved", "rejected", "parked"]; + if !valid.contains(&status) { + return Err(format!( + "proposal metadata.status må være en av: {}", + valid.join(", ") + )); + } + } + Ok(()) + } + "assignment" => { + // Valgfri status, default "open" + if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) { + let valid = ["open", "planning", "active", "paused", "done", "blocked"]; + if !valid.contains(&status) { + return Err(format!( + "assignment metadata.status må være en av: {}", + valid.join(", ") + )); + } + } + // Valgfri priority (heltall) + if let Some(val) = metadata.get("priority") { + if !val.is_number() { + return Err("assignment metadata.priority må være et tall".into()); + } + } + Ok(()) + } + "task" => { + // Valgfri status, default "open" + if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) { + let valid = ["open", "active", "done", "failed", "skipped"]; + if !valid.contains(&status) { + return Err(format!( + "task metadata.status må være en av: {}", + valid.join(", ") + )); + } + } + // Valgfri priority (heltall) + if let Some(val) = metadata.get("priority") { + if !val.is_number() { + return Err("task metadata.priority må være et tall".into()); + } + } + Ok(()) + } + _ => Ok(()), + } +} + #[derive(Serialize)] pub struct ErrorResponse { pub error: String, @@ -649,6 +712,9 @@ pub async fn create_node( // -- Valider metadata for orchestration-noder (oppgave 24.1) -- validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Valider metadata for oppgave-noder (proposal/assignment/task) -- + validate_task_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Kontekstbasert identitet (oppgave 8.2) -- // Hvis context_id er satt, sjekk om brukeren har et alias som er // deltaker i kommunikasjonsnoden. I så fall brukes aliaset som created_by. @@ -1186,6 +1252,9 @@ pub async fn update_node( // -- Valider metadata for orchestration-noder (oppgave 24.1) -- validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Valider metadata for oppgave-noder -- + validate_task_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Beskytt model_profile for egendefinerte AI-presets (oppgave 18.6) -- // Kun admin/owner på en samling kan endre model_profile. Vanlige brukere // som eier et custom preset kan redigere alt annet (prompt, icon, farge osv.)