Files
swp-01-ingest/NOTES.md
T
irrlichtandClaude Sonnet 5 ac7d8c7e69 Initiales Ingest-Repo (aus gdelt-bot/ingest überführt)
Poller, Schema, Quadlet-Units und Quellenregister aus dem Monorepo
gdelt-bot in ein eigenes Repo ausgelagert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VzNVf1KaHPZ1fzJT2jd18j
2026-09-04 20:08:22 +02:00

4.6 KiB

Ingest

Stufe 0 und 1 der Pipeline: Quellenregister und Roh-Erfassung. Keine Kodierung — was hier landet, soll sich beliebig oft neu kodieren lassen.

Dateien

Datei Zweck
sources.toml Quellenregister, einzige Wahrheit ueber die Quellen
schema.sql Postgres-Schema (quellen, raw_items, codings, poll_laeufe)
poller.py Poller, zwei Senken: Postgres und gzip-JSONL
Containerfile Image fuer Bebop
lagebild-ingest.container, lagebild.network Quadlet-Units, rootless
ingest.env.example Vorlage fuer die Zugangsdaten

Bebop

# 1. Schema einspielen
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql

# 2. Image bauen
podman build -t localhost/lagebild-ingest:latest .

# 3. Konfiguration ablegen
mkdir -p ~/.config/lagebild
cp ingest.env.example ~/.config/lagebild/ingest.env
cp sources.toml       ~/.config/lagebild/sources.toml
chmod 600 ~/.config/lagebild/ingest.env
$EDITOR ~/.config/lagebild/ingest.env

# 4. Quadlet installieren
mkdir -p ~/.config/containers/systemd
cp lagebild-ingest.container lagebild.network ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start lagebild-ingest
journalctl --user -u lagebild-ingest -f

# Damit der Dienst ohne offene Sitzung weiterlaeuft:
loginctl enable-linger "$USER"

sources.toml ist eingehaengt, nicht ins Image gebacken: eine neue Quelle ist ein systemctl --user restart lagebild-ingest, kein Neubau.

Pi 5 — Schatten-Ingest

Ohne Postgres, ohne Container:

python3 poller.py --sink jsonl:/var/lib/lagebild/schatten

Legt <dir>/YYYYMMDD/YYYYMMDDHHMMSS.jsonl.gz an, dedupliziert ueber eine SQLite daneben. Als systemd --user-Unit mit Restart=always einrichten.

Der Sinn ist nicht Redundanz um ihrer selbst willen: RSS-Feeds haben kein Archiv. Steht Bebops Poller einen Tag still, ist dieser Tag unwiederbringlich weg. Kodierungen lassen sich wiederholen, Rohdaten nie.

Betrieb

# Lizenzstatus im Register gegen die aktuelle robots.txt pruefen
python3 poller.py --check-robots        # Exit != 0 bei Abweichung

# ein einzelner Durchlauf
python3 poller.py --sink "$DATABASE_URL" --once

--check-robots gehoert in einen woechentlichen Cron. Ein Verlag, der seine robots.txt aendert, aendert damit seinen Nutzungsvorbehalt — und das ist der Punkt, an dem eine Quelle stillgelegt werden muss.

Aendert sich etwas, wird sources.toml angepasst, nie der Code. Eine gesperrte Quelle bleibt im Register stehen (aktiv = false), damit nachvollziehbar bleibt, warum sie fehlt. Der Poller verweigert den Start, wenn eine als gesperrt gefuehrte Quelle aktiv geschaltet ist.

Waechter

-- aktive Quellen, die seit ueber sechs Stunden nichts Neues liefern
select * from quellen_stillstand;

-- Fehler der letzten Stunde
select quelle, http_status, fehler, begonnen_am from poll_laeufe
where fehler is not null and begonnen_am > now() - interval '1 hour';

Arbeitsvorrat fuer Yantra

select * from unkodiert('qwen3-14b-q4/prompt-1') limit 500;

Liefert alle Items, die diese Kodierer-Version noch nicht gesehen hat. Eine neue Prompt-Version ist damit automatisch ein vollstaendiger Recode-Auftrag ueber die gesamte Historie, ohne dass ein Feed erneut abgerufen wird.

Verhalten

  • 15-Minuten-Takt, an den Slotgrenzen ausgerichtet (+30 s Versatz), identisch zu GDELTs Paketgrenzen — damit bleiben die Slots vergleichbar.
  • Bedingter GET ueber ETag/Last-Modified, im Register gespeichert. Im Test antworteten 4 von 12 Quellen im zweiten Durchlauf mit 304.
  • Dedup ueber unique (quelle, item_key); item_key ist guid, ersatzweise Link, ersatzweise ein Titel-Hash.
  • Fehlertoleranz: eine kaputte Quelle beendet den Durchlauf nicht, der Fehler landet in poll_laeufe.
  • Kein Volltext-Abruf. Nur der Feed selbst wird geholt. Titel und Teaser reichen als Kodierungsinput, und damit stellt sich die TDM-Frage nach § 44b UrhG gar nicht erst.

Gemessen (2026-09-04)

Erster Lauf ueber 12 aktive Quellen: 820 Items gesehen, 810 neu, gesamter Durchlauf unter 3 s. Zweiter Lauf unmittelbar danach: 1 neues Item.

Das Trigramm-Clustering findet quellenuebergreifende Dubletten sofort:

zeit    | handelsblatt | 1.00 | Bekennerschreiben: Erneut Sabotage am Stromnetz
spiegel | derstandard  | 0.92 | Niederlage fuer Donald Trump - Gericht in Missouri

Offen

  • Telegram-Fetcher (Telethon/MTProto). Register ist vorbereitet, Eintraege stehen auf aktiv = false. Die Bot-API kann fremde Kanaele nicht lesen.
  • Ersatz-URL fuer den BR24-Feed (aktuell 404).
  • Quellenpool von 12 auf ~40 erweitern; Regionalzeitungen ueber SearXNG auf Debby suchen.