Files
NSCT---Neutral-Search-Crawl…/HANDOFF.md
2026-09-07 12:17:38 +02:00

22 KiB
Raw Blame History

NSCT Handoff für neue Threads

Diese Datei ist der aktuelle, committebare Übergabestand für einen Reset oder einen neuen Thread. Zugangsdaten gehören weder hier noch in Git-Remotes hinein.


Aktueller Stand — 2026-09-07

Planungsinformationen in Research-Details umgesetzt — 2026-09-07

Issue Frontend #1 ist lokal umgesetzt und in beide Container deployed:

  • Das Backend speichert den strukturierten, bereits validierten Research-Plan unmittelbar nach der Planungsphase. GET /v1/research/{id}/plan liefert ihn authentifiziert als plan mit available; weder System-Prompt noch rohe Modellantwort werden offengelegt. Der Plan bleibt auch bei Fehlern in einer späteren Pipeline-Phase abrufbar.
  • Die Research-Detailseite enthält den Tab Planung. Er zeigt Thema, Zeitraum, Suchanfragen samt Zweck/Kategorie, Perspektiven, Entitäten, vorgesehene Quelltypen, Gegenhypothesen und Maßnahmen gegen Search-Bias. Vor Ende der Planungsphase erscheint ein eindeutiger Wartehinweis.

Validierung: zwei neue Endpoint-Tests erfolgreich, Backend-Syntaxprüfung, Frontend-Produktionsbuild, beide Docker-Rebuilds sowie /health und /api/health HTTP 200. npm run check hat weiterhin die 18 bereits bekannten, unabhängigen TypeScript-Fehler; die Planansicht fügt keinen hinzu.

Browser-E2E: Fehlerpfade und Quick-Budgets weiter repariert — 2026-09-07

Die nachfolgenden echten Browser-/Proxy-Tests erreichten erstmals die Crawler- und Analysephasen. Drei weitere Fehler sind lokal repariert, durch gezielte Regressionstests abgedeckt und mit docker compose up -d --build nsct-api deployed:

  1. Der Crawler erzeugte für einzelne Fetch-Fehler ein NormalizedDocument mit leerem content_hash. Der Fehlerpfad verwendet nun from_text(), das auch für leeren Inhalt einen gültigen SHA-256-Hash erzeugt. Einzelne kaputte Quellen brechen damit nicht mehr die gesamte Recherche ab.
  2. Quick-Runs buchten beim Start einen nicht existierenden Planner-Request und anschließend eine Claim-LLM-Anfrage für jede Quelle, einschließlich Fehlerquellen. Bei 15 Quellen standen so vor der Analyse 17 statt maximal 15 Requests im Budget. Der Phantom-Eintrag entfällt; nur erfolgreiche Quellen werden für Claims verarbeitet und ein Request bleibt für die Synthese reserviert. Ein voll ausgelasteter Quick-Run nutzt damit höchstens 1 Planung + 13 Claims + 1 Synthese = 15 LLM-Requests.
  3. BudgetTracker.record_time_elapsed() addierte bei jedem Aufruf erneut die gesamte Zeit seit Run-Start. Der Tracker verbucht nun ausschließlich das Intervall seit der letzten Messung. Für das lokale 35B-Modell mit ca. 8 Tokens/s gelten jetzt Zeitlimits von 30 Minuten (Quick), 60 Minuten (Normal) und 120 Minuten (Deep).

Validierung: 68 gezielte Tests (test_backend_pipeline_repairs.py, test_crawler.py, test_search.py) erfolgreich; Backend-Container neu gebaut und /health liefert HTTP 200. Der vollständige neue Research-Run wurde nicht abgewartet, weil die lokale 35B-Inferenz absichtlich mehrere Minuten dauern kann. Beim nächsten Test eine frische Recherche starten und insbesondere Quellen, Claims und Bericht nach Abschluss prüfen.

Für die laufende Testphase ist es akzeptiert, dass Research-Runs nur im Arbeitsspeicher liegen und ein API-Neubau vorhandene Run-IDs verwirft.

Browser-E2E: Such- und Crawler-Pipeline repariert — 2026-09-07

Während des Browser-E2E-Tests traten drei aufeinanderfolgende Backend-Fehler auf. Alle sind lokal repariert, durch gezielte Tests abgedeckt und mit docker compose up -d --build nsct-api deployed:

  1. SearXNG liefert NormalizedResult-Pydantic-Objekte. Der Orchestrator behandelte optionale leere Felder fälschlich als Dictionary und rief .get() auf. Die Ergebnisnormalisierung unterscheidet nun sauber Modelle, Mappings und ungültige Werte.
  2. AsyncFetcher konfigurierte bei httpx.Timeout connect/read/write, aber keinen pool-Timeout. Der Crawler konnte deshalb nicht initialisiert werden. pool ist nun konfigurierbar über NSCT_CRAWLER_POOL_TIMEOUT (Default 10 Sekunden).
  3. Die Budgetierung buchte für jede Ergebnis-URL vor dem Abruf pauschal 500 KB. Ein Quick-Run mit 22 URLs überschritt so fälschlich das 500-KB-Budget, obwohl die tatsächlichen Downloads deutlich kleiner waren. Abrufe werden jetzt auf verbleibende Quellen- und Bytebudgets begrenzt; die Buchung erfolgt nach tatsächlich abgerufenen Response-Bytes. Budgetobergrenzen sind inklusiv. Das Quick-Zeitlimit betrug in diesem Zwischenstand 300 Sekunden und wurde im späteren Budget-Fix für die lokale 35B-Inferenz auf 30 Minuten erhöht.

Validierung: 63 gezielte Tests (test_backend_pipeline_repairs.py, test_crawler.py, test_search.py) erfolgreich; Docker-Container und /health erfolgreich. Die komplette REST-Suite startet echte externe Background-Retries und wurde deshalb nicht abgewartet. Pytest ist lokal in der ignorierten .nsct-test-venv installiert.

Wichtig für den nächsten Browser-Test: Research-Runs werden derzeit nur in _research_store im Arbeitsspeicher gehalten. Jeder API-Neubau/-neustart entfernt bisherige Run-IDs; die alten Runs liefern danach erwartungsgemäß 404. Persistente Research-Runs sind ein offener Production-Readiness-Punkt. Vor dem erneuten Test zuerst eine neue Recherche starten, nicht eine alte Detail-URL wiederverwenden.

Laufende Deployments

  • Backend-Repository: /home/faligam/apps/NSCT---Neutral-Search-Crawler-Tool
    • Stack läuft mit nsct-api, nsct-postgres und nsct-searxng.
    • Liveness: curl http://localhost:8080/health → HTTP 200.
    • Research-API: /v1/research/*.
  • Frontend-Repository: /home/faligam/apps/NSCT-FrontEnd
    • Stack läuft mit nsct-web und nsct-caddy.
    • Frontend: http://localhost; direkter Webserver: http://localhost:3000.
    • Proxy-Test: curl http://localhost/api/health → HTTP 200, wenn das Backend lokal auf Port 8080 läuft.

Getrennte Rechner: verbindliche Architektur

Frontend und Backend sollen auf unterschiedlichen Rechnern betrieben werden. Sie verwenden kein gemeinsames Docker-Netzwerk:

Browser → Frontend-Caddy (/api/*) → Backend-Host:8080 → nsct-api
  • Das Frontend setzt NSCT_API_UPSTREAM=backend.example.com:8080 in seiner .env (Host:Port, ohne Schema und ohne Pfad).
  • Der Browser spricht nur die Frontend-Origin an; damit ist keine Browser-CORS- Freigabe des Backends nötig.
  • Am Backend Port 8080 ausschließlich für den Frontend-Rechner bzw. dessen Netz freigeben. Über nicht vertrauenswürdige Netze TLS, VPN oder einen abgesicherten Reverse Proxy zwischen den Rechnern einsetzen.

Relevante gepushte Commits:

  • Frontend 37636e1 — reproduzierbarer Docker-Build und Caddy-Serving.
  • Frontend fac3d1c — externer Backend-Upstream via Caddy.
  • Frontend c6f1889 — Dokumentation für getrennte Deployments.
  • Frontend 8eb0383 — API-Key-Login, Navigation und Research-API-Vertrag korrigiert.
  • Frontend e5b37ae — Error-Banner-Store repariert; Browser-Login kann Fehlerbanner wieder ohne update is not a function anzeigen.
  • Frontend 25530b3 und 77b71c6 — Research-Listen-/Status-Vertrag ans Backend angepasst und Browser-Session beim Reload wiederhergestellt.
  • Frontend 5022ef4 — dynamische Research-Detailroute von {id} nach SvelteKit-konform [id] korrigiert.
  • Frontend d5c270c — UUID der Detailroute aus $page.params.id übernommen; Polling ruft nicht mehr /research/undefined/* auf.
  • Frontend 6117c4f und 7acf1b9 — abgeschlossene Reports sind in der UI nicht löschbar; Detailansicht lädt Status, Quellen, Claims, Evidenz und Bericht über den API-Vertrag.
  • Backend 9830acf — Dokumentation für Frontend-Integration auf separatem Host.
  • Backend 1aacf4a — persistente API-Key-Authentifizierung und Admin-CLI.

API-Key-Authentifizierung — implementiert und lokal deployed

/v1/research/* prüft jetzt X-API-Key; /health und /ready bleiben für Infrastruktur-Probes öffentlich. Die in .env gesetzten NSCT_LLM_API_KEY, NSCT_VISION_API_KEY und NSCT_AUDIO_API_KEY sind ausschließlich Credentials für externe Modellanbieter — niemals als Benutzer- oder Frontend-Keys verwenden.

Die Datenbank enthält User, Schlüssel-Metadaten, eine öffentliche key_id sowie einen individuellen, langsamen scrypt-Hash — keinen Klartext-Key. Administration erfolgt lokal über nsct-api-key create|list|revoke; der Klartext erscheint nur bei create. Die CLI nutzt für Research-Aufrufe optional NSCT_API_KEY.

Vor dem Deployment einen Key erzeugen und als Frontend-Key hinterlegen:

docker compose exec nsct-api nsct-api-key create --username admin --name frontend

Die Implementierung ist durch Tests für gültige, fehlende, ungültige, abgelaufene und widerrufene Keys abgedeckt. Backend und Frontend wurden lokal neu gebaut; der Proxy liefert ohne Key für /api/v1/research erwartungsgemäß HTTP 401.

Nächster Schritt: gemeinsamer End-to-End-Test

Mit einem gültigen, bereits erzeugten Key im Browser testen:

  1. http://localhost öffnen, Login durchführen und auf /research/new landen.
  2. Eine kurze Recherche starten; es muss eine research_id zurückkommen und die Detailseite erreichbar sein.
  3. Recherche-Liste, Status, Report und Abmelden verifizieren.
  4. Negativtest mit falschem Key: Login muss HTTP 401 anzeigen, nicht 404/302.
  5. Browser-Konsole, docker compose logs beider Repositories und die Antwortcodes gemeinsam auswerten. Klartext-Keys niemals in Chat oder Logs kopieren.

Browser-Flow: Backend-Blocker lokal behoben — 2026-09-06

Die drei Backend-Ursachen für leere, scheinbar erfolgreiche Researches sind lokal implementiert, getestet und mit docker compose up -d --build deployed:

  1. LLMProvider._create_client() normalisiert die Basis-URL und hängt /v1 nur an, wenn sie nicht bereits enthalten ist. Ein authentifizierter, sanitisiert ausgegebener Chat-Completions-Probe war erfolgreich.
  2. SearXNGProvider ist in src/nsct/providers/searxng.py implementiert und wird vom Orchestrator registriert. Compose mountet eine minimale SearXNG- Konfiguration, die format=json erlaubt, und nutzt den vom aktuellen SearXNG-Image erwarteten Variablennamen SEARXNG_SECRET. Ein echter, sanitisiert ausgegebener Search-Probe lieferte ein Ergebnis.
  3. Die Pipeline führt wieder fetching → extracting → analyzing aus. Fehler beim Planen, Suchen, Abrufen oder Extrahieren werden nicht mehr als leere Fallbacks als Erfolg gemeldet: Der Run wird FAILED, mit Fehlergrund im REST-Status (error). Fehlende Provider führen ebenfalls zu FAILED.

Validierung: Syntaxprüfung, Compose-Konfigurationsprüfung und 29 fokussierte Tests (inklusive neuer Regressionen für URL-Normalisierung, SearXNG und State-Flow) sind erfolgreich. tests/test_rest_research.py wurde nicht als Gesamtsuite abgewartet, da seine Background-Tasks echte externe Retries auslösen; die neuen deterministischen Tests decken den geänderten Fehlerpfad.

Nächster Schritt: Den Browser-End-to-End-Test mit einem gültigen, nicht im Chat offengelegten Frontend-API-Key durchführen. Dabei insbesondere prüfen, dass Quellen, Claims und Bericht nach einem echten Research-Lauf erscheinen und ein Provider-/LLM-Ausfall in der UI den REST-Fehlergrund zeigt.

Frontend-Nachbrenner: Löschen-Weiterleitung behoben — 2026-09-06

Nach dem Löschen einer Recherche navigierte die Detailseite auf die nicht existierende Route /research und zeigte deshalb Not found: /research. Im Frontend-Repository wurde die Weiterleitung in src/routes/research/[id]/+page.svelte auf /research/new korrigiert, lokal neu gebaut und deployed (HTTP 200). Der Produktionsbuild ist erfolgreich.

npm run check meldet weiterhin 18 bereits bestehende, unabhängige TypeScript-Fehler in API-Typen und Share-Komponenten; sie sind nicht Teil dieser Routenreparatur und bleiben für die nächste Session offen.

Frontend-Fixes des laufenden Browser-Tests (alle im Frontend-Repository /home/faligam/apps/NSCT-FrontEnd, main, gepusht):

  • e5b37ae: Error-Banner-Store repariert.
  • 25530b3: Research-Liste normalisiert research_id/state zu id/status.
  • 77b71c6: Browser-Session wird nach Reload aus localStorage restauriert; Statusvertrag normalisiert.
  • 5022ef4 und d5c270c: SvelteKit-Detailroute [id] und $page.params.id korrigiert.
  • 6117c4f: Löschaktion für immutable, abgeschlossene Researches ausgeblendet.
  • 7acf1b9: Detailansicht lädt die fünf Research-Unterressourcen.

Sicherheitsnotiz: Ein im Browser-Test verwendeter Frontend-API-Key wurde in einem Chat-/Netzwerkdump offengelegt. Diesen Key lokal über nsct-api-key revoke <key_id> widerrufen und einen neuen Key erzeugen. Den Klartext nie in Handoff, Git oder Chat eintragen.


Projekt: NSCT Neutral Search Crawler Tool

Ziel: Vollständig lokal betreibbares, containerisiertes Recherche- und Analyse-System. Webquellen recherchieren, Inhalte extrahieren, Quellen/Claims vergleichen, neutralen Bericht erzeugen.

Repository: https://git.frerkc.de/opencode/NSCT---Neutral-Search-Crawler-Tool.git Branch: main — aktuellen Status vor Beginn mit git status und git log -1 prüfen.


Bisher abgeschlossene Stages

Stage Beschreibung Commit Files Tests
0 Repository & Architekturgrundlage e9410be 28 6
1 Model Provider Layer (LLM/Vision/Audio, Metriken, Debug) 9280d69 6
2 Search Provider Abstraction (DuckDuckGo, Multi-Provider, POST /search) a1ef260 5 25
3 Crawler & Content Extraction (SSRF, trafilatura, PDF, Batch) a8595cc 10 ~15
4 Research Planner (LLM-basierte Recherchestrategie, Search-Bias-Reduktion) b8181de 6 25
5 Claim Extraction (atomare, überprüfbare Claims mit Provenance) e8b6515 7 36
6 Source Independence & Citation Graph (Syndication-Erkennung, similarity) a60cf21 4 43
7 Claim Clustering & Contradiction Candidates (LLM-Clustering, numerische Normalisierung) d1e6bb6 6 79
8 Evidence Scoring (6-dimensionale Scores, evidence_type, raw_scores_json) 719e218 6 ~60
9 Neutral Synthesis Engine d87e2b4 1 25
10 Vision Integration — Qwen2.5-VL-3B für Diagramme, Screenshots, Infografiken, PDF-Layouts 3ab875d 6 ~25
10 11 Audio Integration — STT-Transkription mit timestamped Claims
12 Research Orchestrator — State Machine + Budget Limits + Pipeline-Steuerung
13 Iterative Research / Gap Analysis — Lückenerkennung, max 3 Runden, GapSearchQuery
14 REST API ( ABGESCHLOSSENrest_research.py + main.py + tests/test_rest_research.py)
15 CLI ( ABGESCHLOSSENcli.py + tests/test_cli.py)
16 Observability ( ABGESCHLOSSENlogging_config.py + metrics.py + test_logging.py + test_metrics.py)
17 Neutralitäts-Tests ( ABGESCHLOSSENtest_neutrality_a.py + test_neutrality_b.py + test_neutrality_c.py + test_neutrality_d.py + test_neutrality_e.py)

Gesamt: ~105 Dateien, ~17400 Zeilen Code, ~428 Tests.


Stage 12 Research Orchestrator (abgeschlossen)

Implementiert die zentrale Orchestrator-Klasse, die alle Stages (111) verbindet.

Kernkomponenten

src/nsct/orchestration/state.py — State Machine

  • ResearchRunState Enum: CREATED, PLANNING, SEARCHING, FETCHING, EXTRACTING, ANALYZING, EXPANDING, COMPARING, SYNTHESIZING, COMPLETED, FAILED, CANCELLED
  • Transition Matrix mit validierten Übergängen
  • FAILED/CANCELLED/COMPLETED sind Terminal-States (keine ausgehenden Transitionen)
  • StateMachine.transition(new_state) mit Logging und Validierung

src/nsct/orchestration/budget.py — Hard Budget Limits

  • HardBudgetConfig (Pydantic, frozen=True): 7 Limits (max_search_queries, max_sources, max_pages_per_domain, max_total_download_bytes, max_llm_requests, max_research_duration_seconds, max_context_per_llm_call)
  • BudgetTracker: Counter für alle Limits mit increment_*() Methoden
  • BudgetExhaustedError: Exception bei Limit-Überschreitung
  • check_budget(), get_usage(), is_exhausted()

src/nsct/orchestration/models.py — ResearchRun Pydantic Model

  • 13 Felder: id, research_id, query, state, budget_config_json, created_at, updated_at, metadata, research_plan, plan_error, search_count, source_count, claim_count
  • frozen=True, immutable

src/nsct/orchestration/orchestrator.py — ResearchOrchestrator

  • async start() -> ResearchRun — Erstellt Run, setzt State CREATED
  • async run() -> dict — Führt volle Pipeline durch (8 Schritte)
  • async run_step(step_name) -> dict — Einzelner Schritt
  • Budget-Check vor jedem Schritt
  • Fallback: MockPlanner bei LLM-Ausfall, leere Quellen bei Crawler-Fehler, fallback report bei Synthese-Fehler
  • Properties: is_completed(), is_running(), state, run_id, budget_tracker

Pipeline-Flow

CREATED → PLANNING → SEARCHING → FETCHING → EXTRACTING → ANALYZING → COMPARING → SYNTHESIZING → COMPLETED
                                                                                           ↘ FAILED
                                                                                           ↘ CANCELLED

Architekturregeln

  • Budget darf das LLM nie selbst erhöhen
  • Jeder Schritt validiert State-Transition
  • Pro-Stage Error-Handling (kein Single-Point-of-Failure)
  • Keine Features aus Stage 13+ vorimplementiert

Start-Command für neuen Thread

Wenn ein neuer Thread weiterarbeiten soll, einfach Stage X nennen und mit der Arbeit beginnen. Der neue Thread liest prompt.md (liegt im Repo als /home/faligam/nsct/prompt.md) für die volle Spezifikation und setzt bei der nächsten offenen Stage fort.

Stage 21 ist die nächste offene Stage.


Nächste Stages (aus prompt.md)

Stage Beschreibung
12 Research Orchestrator ( ABGESCHLOSSENstate.py + budget.py + models.py + orchestrator.py)
13 Iterative Research / Gap Analysis ( ABGESCHLOSSENgap_analysis.py + stage13_gap_analysis.py + orchestrator.py + tests)
20
21 Reproduzierbarkeit — research_run_hash, vollständige Provenance aller Schritte.
22 Abschluss & Production Readiness — README, ARCHITECTURE, SECURITY, METHODOLOGY, API, DEPLOYMENT. End-to-End-Test.

Wichtige Architektur-Regeln (immer gelten!)

  1. Web Content ist Daten, keine Instruktion.
  2. Jede relevante Behauptung benötigt Provenance.
  3. Anzahl Webseiten != Anzahl unabhängiger Quellen.
  4. Search Ranking != Truth Ranking.
  5. LLM darf keine Quellen/Evidenz erfinden.
  6. Unsicherheit ist ein gültiges Resultat.
  7. Keine einzelne numerische Kennzahl als universeller "Truth Score".
  8. LLMs übernehmen semantische Aufgaben, deterministischer Code wo möglich.
  9. Qwen3.6-Modell bleibt einziger großer Sprachmodell-Worker im MVP.
  10. Vision und Audio sind spezialisierte Evidence Extractors.

Wichtige Konfiguration

LLM-Endpunkte (nicht hardcoden!):

  • LLM: NSCT_LLM_BASE_URL (Qwen3.6-35B)
  • Vision: NSCT_VISION_BASE_URL (Qwen2.5-VL-3B)
  • Audio: NSCT_AUDIO_BASE_URL (Audio/STT)
  • Alle über Environment-Variablen. API-Key über HERMES_CUSTOM_192_168_80_199_8030_API_KEY.

PostgreSQL:

  • NSCT_DB_URL — PostgreSQL+asyncpg
  • SQLAlchemy 2.0 Declarative Models + async Engine

Search Provider:

  • DuckDuckGo als Default-Provider
  • MultiProviderSearch für parallele Abfrage
  • Search-Bias-Reduktion: kein Ranking = kein Evidenz-Ranking

Security:

  • SSRF-Schutz: RFC1918-Blocklist, Cloud-Metadata, file://, ftp://
  • Control Plane ≠ Evidence Plane

GIT-Information

  • Remote: https://git.frerkc.de/opencode/NSCT---Neutral-Search-Crawler-Tool.git
  • Branch: main
  • Credentials: user.email="nsct@frerkc.de", user.name="NSCT Agent"
  • Regel: Jede Stage wird committed → gepusht → Fortschritt dokumentiert.

Arbeitsweise

  • Orchestrator-Pattern: Ich koordiniere, SubAgents (delegate_task) implementieren.
  • Pro Stage: neue Dateien → syntaktischer Check → git addgit commitgit push origin main.
  • Keine Features aus späteren Stages vorimplementieren.
  • Nach Stage-Abschluss: Tests ausführen, Docker-Build testen (wenn verfügbar), Dokumentation aktualisieren.
  • ** Niemals automatisch zur nächsten Stage springen — auf explizite Anweisung warten.**

Start-Command für neuen Thread

Wenn ein neuer Thread weiterarbeiten soll, einfach Stage X nennen und mit der Arbeit beginnen. Der neue Thread liest prompt.md (liegt im Repo als /home/faligam/nsct/prompt.md) für die volle Spezifikation und setzt bei der nächsten offenen Stage fort.