# 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-06 ### 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**: ```text 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: ```bash 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. --- ## 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 | `10a083a` | 8 | ~20 || |||| 12 | **Research Orchestrator** — State Machine + Budget Limits + Pipeline-Steuerung | `2ef7b67` | 4 | 0 || |||| 13 | **Iterative Research / Gap Analysis** — Lückenerkennung, max 3 Runden, GapSearchQuery | `0b7a624` | 5 | 17 || ||| **14** | ~~REST API~~ (✅ **ABGESCHLOSSEN** — `rest_research.py` + `main.py` + `tests/test_rest_research.py`) | ||| **15** | ~~CLI~~ (✅ **ABGESCHLOSSEN** — `cli.py` + `tests/test_cli.py`) | |||| **16** | ~~Observability~~ (✅ **ABGESCHLOSSEN** — `logging_config.py` + `metrics.py` + `test_logging.py` + `test_metrics.py`) | ||| **17** | ~~Neutralitäts-Tests~~ (✅ **ABGESCHLOSSEN** — `test_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 (1–11) 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~~ (✅ **ABGESCHLOSSEN** — `state.py` + `budget.py` + `models.py` + `orchestrator.py`) | | **13** | ~~Iterative Research / Gap Analysis~~ (✅ **ABGESCHLOSSEN** — `gap_analysis.py` + `stage13_gap_analysis.py` + `orchestrator.py` + tests) | ||| **14** | ~~REST API — POST/GET/DELETE für research, status, sources, claims, evidence, report.~~ (✅ **ABGESCHLOSSEN** — `rest_research.py` + `main.py` + `tests/test_rest_research.py`) | ||| **15** | ~~CLI~~ (✅ **ABGESCHLOSSEN** — `cli.py` + `tests/test_cli.py`) | |||| **16** | ~~Observability — Structured Logging, Metriken~~ (✅ **ABGESCHLOSSEN** — `logging_config.py` + `metrics.py` + `test_logging.py` + `test_metrics.py`) | ||| **17** | ~~Tests für Neutralitätsmethodik~~ (✅ **ABGESCHLOSSEN** — `test_neutrality_a_syndication.py` + `test_neutrality_b_political_statements.py` + `test_neutrality_c_scientific_disagreement.py` + `test_neutrality_d_prompt_injection.py` + `test_neutrality_e_missing_evidence.py`) | |||| **18** | ~~Docker Hardening~~ (`6067908`) | 1 | – || ||| **19** | ~~Performanceoptimierung — LLM Concurrency Semaphore(3), Priorisierung (HIGH/NORMAL/LOW)~~ (`4335a40`) | 5 | 14 || || 20 | ~~Context Budgeting — Pro Stage Kontext-Limits (Planner 12k, Claim 16k, Contradiction 24k, Synthesis 48k)~~ (✅ `context_budget.py` + `orchestrator.py` context_budget + `_track_context_tokens()` + `__init__.py` + `test_context_budget.py` + `test_context_budget_integration.py` + `priority_queue.py` async_fix — 34 Tests) | | 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 add` → `git commit` → `git 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.