Testlauf dokumentiert, README vervollstaendigt

This commit is contained in:
2026-09-20 12:50:12 +02:00
parent efe7f50c31
commit 6a1dda0fc9

217
docs/testlauf.md Normal file
View File

@@ -0,0 +1,217 @@
# Testlauf-Protokoll
Durchgefuehrt am 20.09.2026 gegen die echten Systeme, nicht simuliert.
Alle Executions liegen in n8n und sind dort nachvollziehbar.
---
## Vorbereitung
`artikel-index.json` wurde so gesetzt, dass nur ein Artikel auf `offen` stand,
um NeuronWriter-Kontingent zu sparen:
```
brief_bereit handgeschriebene-werbebriefe
pausiert handschriftliche-mailings-kundenbindung
pausiert response-rate-direktmarketing
offen dummy-testlauf
```
---
## Lauf 1: Workflow 1, Execution 167
Start per Webhook um 10:41:00, beendet 10:43:07, Status `success`.
24 Nodes gelaufen, kein einziger Fehlerpfad.
Der Poll-Loop arbeitete wie ausgelegt:
| Node | Durchlaeufe |
|---|---|
| `Warten` | 6 |
| `Analyse abfragen` | 6 |
| `Versuch zaehlen` | 5 |
| `Poll-Limit erreicht?` | 5 |
Die Analyse war nach dem sechsten Poll fertig, also nach rund 120 Sekunden.
Von 30 erlaubten Versuchen wurden 6 gebraucht.
**Ergebnis:**
```
Briefe vorbereitet: 1, Fehler: 0
Fertig:
dummy-testlauf | Zielwortzahl 839 | 12 Pflichtbegriffe, 29 Fragen
Datei: briefe/brief-dummy-testlauf.json
Analyse: https://app.neuronwriter.com/analysis/view/ff324721305a0a60
```
**Gegenprobe im Repo:**
- `briefe/brief-dummy-testlauf.json` angelegt, 19437 Bytes
- Commit `150017a9` "Brief erzeugt: dummy-testlauf (handgeschriebene briefe roboter)"
- Commit `4c4fc0f2` "Status auf brief_bereit gesetzt (1 Artikel)"
- Zeile in `artikel-index.json` steht auf `brief_bereit`, `query_id` nachgetragen
Der Brief enthaelt alle geforderten Felder sowie den Zusatzblock:
```
query_id ff324721305a0a60 | keyword handgeschriebene briefe roboter | wortzahl_ziel 839
begriffe_pflicht 12 | begriffe_erweitert 65 | fragen 29
top-3 Fragen (nach Gewicht):
10 Wo kann ich handschriftliche Briefe schreiben lassen?
9 Wie kann ich Handschriften in digitalen Text umwandeln?
9 Wie kann ich schnell handschriftlich schreiben?
```
---
## Lauf 2a: Workflow 2, Nachbesserungspfad, Execution 168
Zielwert 72, Testartikel hatte Score 44. 24 Nodes, alle `success`.
```
Importiert: 0 | Nachbessern: 1 | Fehler: 0
Score zu niedrig, Nachbesserung liegt im Repo:
handgeschriebene-werbebriefe: Score 44 von 72
9 Pflichtbegriffe fehlen, 71 Zusatzbegriffe
Wortzahl 96 von 1178 (-1082)
Datei: nachbessern/nachbessern-handgeschriebene-werbebriefe.json
Kein Beitrag wurde veroeffentlicht. Alle Importe stehen auf Entwurf.
```
Der WordPress-Zweig wurde korrekt nicht betreten.
---
## Lauf 2b: Workflow 2, Importpfad, Execution 169
Zielwert per Webhook auf 40 abgesenkt (`{"score_ziel":40}`), damit derselbe
Artikel den Importpfad nimmt. 32 Nodes, alle `success`.
```
Importiert: 1 | Nachbessern: 0 | Fehler: 0
Als Entwurf in WordPress:
handgeschriebene-werbebriefe (Score 44, neu angelegt)
Vorschau: https://skrift.de/?p=4210&preview=true
Bearbeiten: https://skrift.de/wp-admin/post.php?post=4210&action=edit
PREISE: 2 ausgeschriebene(r) Preis(e) im Text: 2,56 EUR, 0,95 €.
Bitte durch [skrift_preis key="..."] ersetzen.
Hinweis: Cache-Endpunkt antwortete mit HTTP 403. Kein Abbruchgrund.
```
**Gegenprobe in WordPress** (`GET /wp-json/wp/v2/posts/4210?context=edit`):
```
id 4210 | status draft | slug handgeschriebene-werbebriefe
kategorien [17]
kurzantwort gesetzt
cta_ziel https://skrift.de/muster-anfordern
stand_datum 2026-09-20
_seopress_titles_title Handgeschriebene Werbebriefe: wann sie wirken
_seopress_titles_desc gesetzt
_seopress_analysis_target_kw handgeschriebene werbebriefe
faq 2 Eintraege
```
Die Kategorie `Direktmarketing` existierte nicht und wurde als ID 17 angelegt.
---
## Lauf 2c: Idempotenz, Execution 170
Derselbe Artikel ein zweites Mal, gleiche Parameter.
```
post_id 4210 | aktion: aktualisiert | alter_status: draft | status: draft
Kategorie erneut angelegt? nein (bestehende wiederverwendet)
```
`GET /wp-json/wp/v2/posts?slug=handgeschriebene-werbebriefe&status=any`
liefert genau **einen** Treffer. Es entstand kein Duplikat.
`status-importe.json` enthaelt eine Zeile, die beim zweiten Lauf ueberschrieben
statt angehaengt wurde:
```json
[{"slug":"handgeschriebene-werbebriefe","score":44,
"datum":"2026-09-20T10:47:54.336Z","post_id":4210,
"vorschau_url":"https://skrift.de/?p=4210&preview=true",
"aktion":"aktualisiert","kategorie":"Direktmarketing"}]
```
---
## Zwei Fehler, die der Testlauf gefunden hat
### 1. Webhook mit responseMode "lastNode"
Der erste Versuch endete in einem 504 von openresty, waehrend der Workflow im
Hintergrund weiterlief. Ursache: Der Webhook hielt die HTTP-Verbindung bis zum
Workflow-Ende offen, der Reverse Proxy brach nach 60 Sekunden ab.
Beide Workflows nutzen jetzt `responseMode: "onReceived"`.
### 2. body statt data bei fullResponse
n8n 1.120 liefert den Antwortkoerper bei `fullResponse: true` im Feld `data`,
nicht `body`. Alle Existenzpruefungen griffen auf `.body` zu und haetten immer
"nicht vorhanden" ergeben. Folge waere gewesen: Workflow 2 legt bei jedem Lauf
einen neuen Beitrag an, statt den bestehenden zu aktualisieren.
An sieben Stellen korrigiert und versionsfest gemacht:
```js
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
```
Lauf 2c belegt, dass die Idempotenz jetzt haelt.
---
## Netzwerkbefund: Gitea war aus n8n nicht erreichbar
Der erste Lauf scheiterte mit `timeout of 60000ms exceeded` beim Lesen der
Artikeltabelle. Die Diagnose aus n8n heraus ergab:
| Ziel | Ergebnis |
|---|---|
| `https://gitea.lucas-orth.de/api/v1/version` | `ECONNABORTED` |
| `http://gitea.lucas-orth.de/api/v1/version` | HTTP 301, Server openresty |
| `https://app.neuronwriter.com/...` | HTTP 401 (erreichbar) |
| `https://skrift.de/wp-json/` | HTTP 200 |
| `http://gitea:3000/api/v1/version` | **HTTP 200** |
`gitea.lucas-orth.de` loest auf `100.98.99.19` auf, eine NetBird-Overlay-Adresse.
Der n8n-Host erreichte den dortigen openresty auf Port 80, aber nicht auf 443.
Geloest ueber das Docker-Netz: beide Workflows sprechen Gitea jetzt als
`http://gitea:3000` an. Der Weg laeuft nicht ueber den Reverse Proxy und
nicht ueber das Overlay, ist damit schneller und faellt nicht aus, wenn am
Proxy etwas geaendert wird.
Zum Nachtesten liegt der Hilfsworkflow `netzcheck` in n8n:
```bash
curl -X POST https://n8n.lucas-orth.de/webhook/probe \
-H "Content-Type: application/json" \
-d '{"url":"http://gitea:3000/api/v1/version"}'
```
---
## Offene Punkte nach dem Testlauf
**Cache leeren gibt HTTP 403.** Der Benutzer `ai-agent` hat als Redakteur nicht
die Berechtigung fuer `POST /wp-json/seopress/v1/commands/clear-cache`.
Der Workflow behandelt das als Hinweis, nicht als Fehler. Bei Entwuerfen ist ein
Cache-Purge ohnehin wirkungslos. Relevant wird es erst, wenn ein bereits
veroeffentlichter Beitrag aktualisiert wird. Wer das braucht, gibt der Rolle
Redakteur die noetige Capability oder leert nach dem Veroeffentlichen von Hand.
**Testreste.** In WordPress steht Beitrag 4210 als Entwurf, dazu die Kategorie
`Direktmarketing` (ID 17). In NeuronWriter liegen zwei Analysen
(`565abcca58f65e52`, `ff324721305a0a60`) mit je einer importierten Revision.
Beides kann bleiben oder geloescht werden.