Implementer source_material edge-validering (oppgave 20.2)

Legger til maskinrommet-validering for source_material edges i både
create_edge og update_edge. Metadata må inneholde:
- context: "quoted", "summarized" eller "referenced"
- excerpt: ikke-tom streng med kildeteksten

Oppdaterer edges.md med dokumentasjon av metadata-formatet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-18 08:04:02 +00:00
parent 4ed58a3684
commit d4fc271e1e
3 changed files with 68 additions and 2 deletions

View file

@ -90,6 +90,9 @@ JSONB-feltet bærer kontekstspesifikk data om relasjonen:
- `submitted_to`-edge: `{ "status": "pending", "submitted_at": "2026-03-17T10:00:00Z" }`
Status-verdier: `pending`, `in_review`, `revision_requested`, `rejected`, `approved`.
Ved tilbakemelding: `feedback`, `feedback_by`, `feedback_at`.
- `source_material`-edge: `{ "context": "quoted", "excerpt": "Den aktuelle teksten..." }`
Context-verdier: `quoted` (sitert verbatim), `summarized` (oppsummert/omskrevet),
`referenced` (referert uten sitat). Begge felt er påkrevd og valideres i maskinrommet.
Metadata er fleksibelt og spørrbart uten migrering.

View file

@ -808,6 +808,39 @@ pub async fn create_edge(
}
}
// -- Validering av source_material-metadata --
if req.edge_type == "source_material" {
if let Some(obj) = metadata.as_object() {
// context er påkrevd og må være en av tre gyldige verdier
match obj.get("context").and_then(|v| v.as_str()) {
Some("quoted" | "summarized" | "referenced") => {}
Some(other) => {
return Err(bad_request(&format!(
"source_material context må være 'quoted', 'summarized' eller 'referenced', fikk '{other}'"
)));
}
None => {
return Err(bad_request(
"source_material krever 'context'-felt (quoted, summarized eller referenced)",
));
}
}
// excerpt er påkrevd og må være en ikke-tom streng
match obj.get("excerpt").and_then(|v| v.as_str()) {
Some(s) if !s.trim().is_empty() => {}
_ => {
return Err(bad_request(
"source_material krever et ikke-tomt 'excerpt'-felt",
));
}
}
} else {
return Err(bad_request(
"source_material krever metadata med 'context' og 'excerpt'",
));
}
}
let metadata_str = metadata.to_string();
// -- Generer UUIDv7 --
@ -1273,6 +1306,37 @@ pub async fn update_edge(
}
}
// -- Validering av source_material-metadata ved oppdatering --
if edge_type == "source_material" {
if let Some(obj) = metadata.as_object() {
match obj.get("context").and_then(|v| v.as_str()) {
Some("quoted" | "summarized" | "referenced") => {}
Some(other) => {
return Err(bad_request(&format!(
"source_material context må være 'quoted', 'summarized' eller 'referenced', fikk '{other}'"
)));
}
None => {
return Err(bad_request(
"source_material krever 'context'-felt (quoted, summarized eller referenced)",
));
}
}
match obj.get("excerpt").and_then(|v| v.as_str()) {
Some(s) if !s.trim().is_empty() => {}
_ => {
return Err(bad_request(
"source_material krever et ikke-tomt 'excerpt'-felt",
));
}
}
} else {
return Err(bad_request(
"source_material krever metadata med 'context' og 'excerpt'",
));
}
}
let metadata_str = metadata.to_string();
let edge_id_str = req.edge_id.to_string();

View file

@ -224,8 +224,7 @@ Ref: `docs/retninger/arbeidsflaten.md`, `docs/features/canvas_primitiv.md`
Ref: `docs/features/universell_overfoering.md`, `docs/retninger/arbeidsflaten.md` § "Kompatibilitetsmatrise"
- [x] 20.1 message_placements tabell: PG-migrasjon + SpacetimeDB-modul med `place_message`, `remove_placement`, `move_on_canvas` reducers. Synk STDB→PG. Ref: `docs/features/universell_overfoering.md` § 2.
- [~] 20.2 source_material edge-type: legg til i edge-skjema + maskinrommet-validering. Støtt kontekst-metadata (quoted, summarized, referenced) og excerpt-felt. Ref: `docs/retninger/arbeidsflaten.md` § "source_material-edge".
> Påbegynt: 2026-03-18T08:00
- [x] 20.2 source_material edge-type: legg til i edge-skjema + maskinrommet-validering. Støtt kontekst-metadata (quoted, summarized, referenced) og excerpt-felt. Ref: `docs/retninger/arbeidsflaten.md` § "source_material-edge".
- [ ] 20.3 BlockReceiver interface: implementer `canReceive()`, `receive()`, `renderDropZone()` i alle trait-komponenter (Chat, Kanban, Kalender, Editor, Studio). Kompatibilitetsmatrise bestemmer godkjente drops. Ref: `docs/features/universell_overfoering.md` § 45.
- [ ] 20.4 Transfer service: `innholdstransfer`-modus (ny node + source_material edge) og `lettvekts-triage` (eksisterende node + ny edge/placement). Bestem modus fra verktøy-par. Shift-modifier for override. Ref: `docs/features/universell_overfoering.md` § 1, 3.
- [ ] 20.5 Panelrework — Chat: gjør ChatTrait til fullverdig BlockShell-panel med BlockReceiver, fullskjerm-toggle, og responsivt design innenfor begrenset container.