Legger til username-kolonne i auth_identities med UNIQUE constraint.
Ved innlogging sender SvelteKit preferred_username fra Authentik til
maskinrommet POST /auth/sync, som oppdaterer kolonnen. Grunnlaget
for epost-ruting i fase 26: vegard@synops.no → username-oppslag.
Gjør synops-clip tilgjengelig i orkestreringer ved å:
1. Registrere synops-clip som cli_tool-node (migration 026) med norske
aliases (clip, klipp, hent artikkel) og args_hints for script-kompilatoren.
Orkestreringer kan nå skrive "1. clip fra event (lagre node, bruker)"
som kompileres til "synops-clip --url {event.url} --write --created-by ...".
2. Legge til clip_url som jobbtype i jobbkøen (clip.rs) — spawner
synops-clip med riktige env-variabler (DATABASE_URL, AI_GATEWAY_URL, etc).
3. Legge til POST /intentions/clip_url API-endepunkt slik at frontend
og andre klienter kan trigge URL-klipping direkte.
4. Utvide trigger-konteksten med event.url og event.created_by slik at
orkestreringer som reagerer på URL-deling kan videresende URL til
synops-clip via variabel-substitusjon.
Når en bruker limer inn en URL i chatten, gjenkjenner synops-respond
URL-en automatisk, kaller synops-clip --write for å hente, parse og
oppsummere artikkelen, og inkluderer resultatet i prompten slik at
Claude kan presentere oppsummeringen naturlig.
Ved betalingsmur: Claude informerer brukeren og ber om innlimt innhold.
Maks 3 URL-er per melding, 60s timeout per klipp.
Endringer:
- synops-respond: URL-deteksjon (regex), synops-clip-kall, prompt-kontekst
- maskinrommet/agent.rs: videresend env-variabler for synops-clip
- maskinrommet-env.sh: SYNOPS_CLIP_SCRIPTS env-variabel
- docs/infra/claude_agent.md: dokumentert URL-klipping-flyten
Legger til --write-modus som oppretter:
- content-node med artikkelinnhold og metadata.source_url
- tagged-edge "clipped" (self-tag)
- AI-oppsummering via LiteLLM (integrert i node-innhold)
- mentions-edges til gjenkjente entiteter i kunnskapsgrafen
AI-analysen er robust: feiler den, opprettes noden uten oppsummering.
Gjenbruker eksisterende topic-noder der navnene matcher (case-insensitive).
Nye entiteter opprettes som topic-noder med entity_type i metadata.
Ressursforbruk logges til resource_usage_log.
Nye CLI-flagg: --write, --created-by <uuid>
Payload-JSON utvides med write + created_by for jobbkø-integrasjon.
Nytt verktøy som henter og parser webartikler til ren tekst + metadata.
Bruker Mozilla Readability (via Node.js) for artikkelekstraksjon, med
Playwright som fallback for JS-rendrede sider.
Arkitektur:
- Rust CLI (clap, reqwest) håndterer HTTP-henting, paywall-deteksjon, JSON-output
- Node.js-hjelpeskript (readability.mjs) bruker @mozilla/readability + jsdom
- Playwright-script (playwright.mjs) for headless browser-fallback
- Støtter --payload-json for maskinrommet/jobbkø-integrasjon
Paywall-deteksjon basert på:
- Kort innhold (<200 tegn)
- Norske/engelske paywall-fraser i innholdet
- CSS-klasser/HTML-attributter (piano, schibsted, amedia, etc.)
- Schema.org isAccessibleForFree meta-tagg
Output: JSON med title, author, date, content, url, paywall, excerpt, source
Fem standard-orkestreringer opprettet som seed-data:
- Podcast-pipeline (transkriber → oppsummer → RSS)
- Publiseringsflyt (render → indeks → RSS)
- AI-beriking (foreslå koblinger ved nytt innhold)
- Planlagt publisering (render ved tidspunkt)
- Podcast TTS (kaskade fra pipeline → les opp oppsummering)
Podcast-pipeline → TTS demonstrerer kaskade via triggers-edge.
Script-kompilatoren utvidet med flerords-verbstøtte: aliaser som
"generer feed", "les opp", "foreslå koblinger" matcher nå korrekt
selv om parseren splitter ved første mellomrom. Prøver verb + N
første ord av objekt opptil 3 ord.
8 oppgaver: iTunes/Podcasting 2.0 RSS-tags, nedlastingsstatistikk
(IAB-kompatibel), embed-spiller, import fra eksisterende podcast
med prøveimport-flyt (importer → test → re-importer nye → 301),
og feed-redirect for å flytte bort.
Feature-spec: docs/features/podcast_hosting.md
Ingen castopod — podcasten er noder med riktige edges og en feed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Etter vellykket pipeline-utførelse sjekker handle_orchestrate() om
orkestreringen har utgående triggers-edges til andre orchestration-noder.
Hvert gyldig mål enqueues som ny orchestrate-jobb med kaskade-kontekst.
Syklusdeteksjon via cascade_chain i jobb-payload:
- Sporer alle orchestration-IDer allerede utført i kjeden
- Blokkerer target som allerede finnes i kjeden (direkte + indirekte syklus)
- Dybdegrense på 10 ledd (MAX_CASCADE_DEPTH)
- Blokkerte kaskader logges i orchestration_log med status=skipped
Nedstrøms orkestreringer mottar:
- trigger_event: "cascade"
- upstream_orchestration_id i trigger_context
- {event.upstream_orchestration_id} tilgjengelig i script
Kaskade-feil er ikke-fatale — selve orkestreringen rapporteres som suksess.
8 nye enhetstester for syklusdeteksjon og dybdegrense.
12 oppgaver: skjermklipp, RSS/feed-abonnement, webhook (universell
ekstern input med templates), video-opptak, geolokasjon, håndskrift/
tegning, kalender-import (ICS + CalDAV).
Feature-spec: docs/features/universell_input.md
Prinsipp: modaliteten er transport, noden er det som lever videre.
Alt fra screenshot til GitHub-webhook ender som noder i grafen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ny modul script_executor.rs som tar en kompilert pipeline fra
script_compiler og kjører stegene sekvensielt:
- Substituerer {event.*}-variabler fra trigger-kontekst
- Spawner hvert CLI-verktøy som subprosess via generisk dispatch
- VED_FEIL-håndtering: steg-fallback → global fallback → stopp
- Spesialhåndtering av work_item (oppretter oppgave-node i grafen)
- Logger hvert steg i ny orchestration_log-tabell
handle_orchestrate i jobs.rs utvides: kompilerer + utfører i
samme jobb (var tidligere kun kompilering).
Migration 023: orchestration_log-tabell med indekser for
effektiv spørring per orkestrering og per jobb.
Alle eksisterende CLI-verktøy har nå cli_tool-noder i PG med:
- aliases: norske verb for script-kompilatoren ("transkriber", "oppsummer", etc.)
- args_hints: mapping fra menneskelige argumenter til CLI-flagg
("stor modell" → "--model large", "lydfilen" → "--cas-hash {event.cas_hash}")
Muliggjør at script-kompilatoren (24.3) kan slå opp verktøy fra PG
og kompilere menneskelig scriptspråk til faktiske CLI-kall.
Parser menneskelig scriptspråk og kompilerer til tekniske CLI-kall.
"transkriber lydfilen (stor modell)" → "synops-transcribe --cas-hash {event.cas_hash} --model large"
Kompilatoren:
- Parser nummererte steg, ved_feil-fallbacks, og globale feilhåndterere
- Matcher verb mot cli_tool-noders aliases (case-insensitive)
- Mapper argumenter i parentes via args_hints
- Validerer variabelreferanser ({event.*}) mot kjent liste
- Fuzzy-matching med Levenshtein-avstand for forslag ved feil
- Rust-stil kompileringsrapport med ✓/✗ per linje
Integrert i jobbkøen: orchestrate-jobb kompilerer scriptet og
lagrer pipeline i metadata. Utførelse kommer i oppgave 24.5.
12 unit-tester dekker parser, kompilator, feilhåndtering og fuzzy-matching.
Ved node/edge-events fra PG LISTEN/NOTIFY evaluerer portvokteren nå
om noen orchestration-noder matcher triggeren. Implementert som non-blocking
async task som ikke blokkerer WebSocket-flyten.
Ny modul orchestration_trigger.rs:
- Mapper NOTIFY-events til trigger-typer (node.created, edge.created)
- Effektiv lookup via funksjonell B-tree-indeks på metadata->trigger->event
- Evaluerer observes-edges (eksplisitt) vs conditions (implisitt)
- Betingelser: node_kind, edge_type, has_trait, has_tag (AND-logikk)
- Legger matchende orkestreringer i jobbkøen som "orchestrate"-jobb
Ny migration 021: indeks for trigger-event lookup på orchestration-noder.
Jobbkø-dispatcher håndterer "orchestrate" med placeholder (24.3 implementerer utførelse).
Verifisert: content-node trigrer matching orchestration, communication-node hoppes over.
To lag av samme script:
- Menneskelig: "transkriber lydfilen (stor modell)"
- Teknisk: "synops-transcribe --cas-hash {event.cas_hash} --model large"
Kompilator matcher verb mot cli_tool-aliases, argumenter mot
args_hints, variabler fra trigger-kontekst. Rust-stil feilmeldinger.
Tre visninger i editoren (Enkel/Teknisk/Kompilert).
Oppgaver restrukturert: kompilator, alias-metadata, executor,
UI med tre visninger, AI-assistert oppretting, kaskade, seed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ny node_kind 'orchestration' med strukturert metadata-validering:
- trigger.event valideres mot kjent liste (node.created, edge.created,
communication.ended, node.published, scheduled.due, manual)
- trigger.conditions må være objekt hvis satt
- executor valideres mot script/bot/dream
- intelligence og effort valideres som heltall 1-3
- compiled valideres som boolean
- pipeline valideres som array
Valideringen kjører i både create_node og update_node, identisk
mønster som validate_collection_traits og validate_ai_preset_metadata.
Ref: docs/concepts/orkestrering.md
Validering av fase 22 (SpacetimeDB-migrering) bekrefter:
1. WebSocket-sanntid fungerer:
- maskinrommet lytter på PG NOTIFY-kanaler (node_changed, edge_changed,
access_changed, mixer_channel_changed)
- Enrichment av events med fulle rader fra PG
- Broadcast via tokio::broadcast til WebSocket-klienter
- Tilgangskontroll filtrerer events per bruker
- Frontend kobler til /ws med JWT, mottar initial_sync + inkrementelle events
2. PG LISTEN/NOTIFY-triggere verifisert i database:
- 4 notify-funksjoner: notify_node_change, notify_edge_change,
notify_access_change, notify_mixer_channel_change
- 4 triggere: nodes_notify, edges_notify, node_access_notify,
mixer_channels_notify
3. Ingen STDB-rester i aktiv kode/konfig:
- maskinrommet/src/: rent
- Cargo.toml: ingen spacetimedb-avhengigheter
- docker-compose.yml: ingen spacetimedb-tjeneste
- Caddyfile: ingen spacetimedb-proxy
- Eneste funn: frontend/src/lib/spacetime/ katalognavn —
omdøpt til frontend/src/lib/realtime/ (32 filer oppdatert)
- Historiske referanser i docs/arkiv og scripts/synops.md er OK
7 oppgaver:
- synops-ai: lettvekts LLM-kall via LiteLLM (ikke claude -p)
- AI-rutingskontroll i admin: modell per kontekst, endres uten redeploy
- Kostnadstak per bruker/samling med budsjett-sjekk
- synops-notify, synops-validate, synops-backup, synops-health
Nøkkelprinsipp: admin styrer hvilken modell som brukes til hva.
synops-ai uten --model bruker ai_job_routing-tabellen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validering:
- Alle 15 synops-* verktøy kompilerer uten feil
- --help fungerer for alle verktøy med norske beskrivelser
- Feilhåndtering: exit(1) + stderr for alle feiltilfeller
- JSON-output validert (prune, render, node --format json)
- Markdown-output validert (search, context, node --format md)
- XML-output validert (rss)
- synops-common brukes av 14/15 verktøy (db, cas, logging)
- synops-tasks bruker ikke synops-common (som dokumentert)
Funn fikset:
- Installerte manglende binaries i /usr/local/bin: synops-tts,
synops-audio, synops-render (maskinrommet dispatcher fant dem ikke)
Notat: --payload-json (generisk dispatch) er spesifisert i
docs/retninger/unix_filosofi.md men ikke implementert — verktøyene
bruker individuelle CLI-args, og maskinrommet mapper payload→args
i dedikerte dispatcher-moduler. Fungerer korrekt som det er.
3 oppgaver: MindMap Svelte-komponent med radial layout,
BlockShell-panel, og mindmap-trait for samlinger.
Feature-spec i docs/features/tankekart.md.
Ren frontend-visning av eksisterende grafdata — ingen ny backend.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fikser funnet under validering:
- Gjør collection-prop valgfri i alle trait-komponenter slik at de
fungerer i personlig arbeidsflate uten collection-kontekst
- Legger til null-guards for collection.id i alle derived-blokker
og funksjoner som oppretter edges
- Fjerner microsSinceUnixEpoch-rester fra STDB-migrasjonen —
createdAt er nå et tall (Unix µs), ikke et objekt
- Retter saveTimeout-lekkasje i collection-sida: timer ryddes nå
ved navigasjon mellom samlinger
- Fikser TypeScript-feil i editorial (number vs string, uoppnåelig
'scheduled'-sammenligning), studio (bigint vs number),
RecordingTrait ($state-generics)
- Typefeil redusert fra 55 → 4 (gjenværende er pre-eksisterende
i mixer.ts/livekit.ts, ikke fase 19-20)
Validert: Canvas pan/zoom, BlockShell, layout-persistering,
snarveier, transfer service, alle panelreworks. Frontend bygger OK.
- SoundPadGrid: spor setTimeout-IDer og rydd opp ved komponent-destroy
(unngår oppdatering av tilstand etter unmount)
- Admin usage: fiks skrivefeil "1 ar" → "1 år"
- tasks.md: marker 23.7 som fullført
Feil funnet og fikset:
1. truncate() UTF-8-panikkfeil: Brukte byte-indeksering s[..max] som
panikker på flerbyte-tegn (æ, ø, å). Byttet til char_indices().
2. VALID_TRAITS manglet 'mixer' og 'ai_tool': Dokumentert i
docs/primitiver/traits.md men avvist av backend-validering.
3. Planlagte artikler synlige før publish_at: serve_article og alle
listevisninger (forside, arkiv, kategori, søk) eksponerte artikler
med fremtidig publish_at. Lagt til tidsfiltere i alle spørringer.
4. A/B klikk-attribusjon logget alle varianter: serve_article logget
klikk for ALLE aktive varianter ved direkte artikkelbesøk, ikke
bare den viste. Fjernet feilaktig attribusjon — klikk logges kun
via track_click-endepunktet med spesifikk variant-parameter.
5. JSON-LD XSS via </script>: serde_json escaper ikke </script>-
sekvenser, så brukertitler kunne bryte ut av <script>-blokken.
Lagt til .replace("</", "<\\/") etter serialisering.
6. Hardkodet farge i search.html: Brukte rgba(233,69,96,0.1) i stedet
for tema-variabel. Byttet til color-mix() med --color-accent.
Nye tester: truncate med UTF-8, truncate kort streng, JSON-LD XSS-escape.
Fase 11 (produksjon) validert — LiveKit, pruning og podcast-RSS:
- rss.rs + synops-rss: Les filstørrelse fra både 'size_bytes' (intentions)
og 'size' (publishing) med COALESCE — forhindrer manglende enclosure-
størrelse i podcast-feeds avhengig av opplastingsmetode.
- pruning.rs + synops-prune: Samme COALESCE-fix for konsistent size-tracking.
- rss.rs + synops-rss: Fiks truncate_description til å bruke char-indeksering
istedenfor byte-indeksering — forhindrer panic på norsk tekst (å, ø, æ).
LiveKit kjører i Docker (healthy), token-generering via join_communication,
pruning-loop aktiv, RSS-endepunkt returnerer korrekt 404 for ukjent slug.
Alle 61 maskinrommet-tester bestått.
Fase 9 (visninger):
- graph: fiks TypeScript-feil (string|undefined → string|null)
- kanban board: les kolonner fra metadata.traits.kanban.columns
(konsistent med KanbanTrait), behold fallback til metadata.columns
- dagbok: fiks createdAt-type (number, ikke BigInt med microsSinceUnixEpoch)
Fase 10 (AI):
- summarize.rs: refaktorer til cli_dispatch helper (DRY, konsistent
med ai_edges.rs og tts.rs)
- ai_process.rs: feil tidlig hvis LITELLM_MASTER_KEY mangler
(var unwrap_or_default → tom streng → forvirrende 401)
Alle 61 maskinrommet-tester bestått, alle CLI-verktøy kompilerer.
LiteLLM kjører med riktig modellruting (rutine/resonering).