Modellvergleich beim Ingest unter GitHub Copilot – Werkzeug: Runner, Goldinventar und Bewertung in chemenu-testfiles, Trockenlauf unter Linux #228

Closed
opened 2026-10-13 20:59:27 +00:00 by torben · 7 comments
Owner

Abgespalten aus #224 (E4 vom 2026-10-13), am 2026-10-19/20 zum automatisierten Vergleich mit 50-USD-Deckel erweitert und am 2026-10-21 geteilt (Betreiber): Dieses Issue baut das Werkzeug, #240 betreibt es (Gold prüfen, bezahlte Läufe, Bewertung, Bericht). Am Stack ändert sich keine Datei: gebaut wird in torben/chemenu-testfiles unter harness/ingest-bench/.

Stand 2026-10-21: abgeschlossen. Gebaut und gepusht als chemenu-testfiles ba1eb95. Die vier Belege aus § Abschluss der Bauphase liegen vor, dazu ein grüner Lauf des converters-Workflows (Run 781, § Belege). Abweichungen vom Entwurf sind an ihrer Stelle eingearbeitet und mit (Bau) markiert. Die Messung läuft in #240.

Wozu das Werkzeug dient

#240 beantwortet vier Fragen: Recall eines Ingests nach Modell × Effort, ob Auto zu klein routet und im Lauf wechselt, die Pareto-Front Recall/Kosten, und ob günstige Modelle kürzere Seiten schreiben und dabei Fakten verlieren. Dazu muss das Werkzeug je Lauf liefern:

  • ein Urteil je Gold-Fakt, mit der Seite, auf der der Fakt steht;
  • die Modellfolge bei Auto bzw. HydraFusion;
  • die Kosten aus usage.json;
  • mechanische Seitenkennzahlen.

Außerdem muss es den 50-USD-Deckel selbst durchsetzen.

Entscheidungen (Betreiber, 2026-10-20/21)

  • Automatisierter Runner statt Handlauf (E4 geändert).
  • Abrechnung AI Credits, Deckel 50 USD für alles, was über Copilot läuft: Kandidaten, Gold-Extraktion 2, Richter 2.
  • Claude Code läuft separat über das Abo des Betreibers und zählt nicht zum Deckel. Dort laufen Richter 1 und Gold-Extraktion 1.
  • Ohne Astra und Fable. Claude Opus 5.5 ist die obere Referenz. Gemessen wird gegen das Goldinventar, berichtet wird absolut und relativ zu Opus.
  • Harness: Copilot CLI für den Runner. Die Copilot Desktop App bekommt zwei Handläufe (P3).
  • Rechner: Windows (pwsh 7) bevorzugt, Linux als Plan B. Gebaut und trocken getestet wird unter Linux.
  • Bau und Messung getrennt (2026-10-21): eigenes Issue #240, damit dieses Issue mit dem Bau abschließt (§ Abschluss der Bauphase).
  • Commits in chemenu-testfiles gehen per git und werden ohne Einzelfreigabe gepusht (2026-10-21, § Abschluss der Bauphase).

Was über Copilot feststeht

Recherche 2026-10-19 (Session) und 2026-10-20 (Betreiber über Perplexity, nur GitHub-eigene Quellen, von der Session nicht einzeln nachgeprüft). P0 in #240 prüft es auf dem Rechner des Betreibers nach.

  • Auto routet nicht nur am Anfang. GitHub-Doku: „Routing occurs along natural cache boundaries and large drifts in conversation complexity.“ Copilot CLI 1.0.81 (2026-08-27): „Auto mode adapts model selection as the task evolves during a conversation.“ Auto hat Tiers (Efficiency / Balance / Intelligence). Abgerechnet wird das jeweils gewählte Modell, mit 10 % Rabatt. Die CLI zeigt das Modell bei jeder Antwort an. Quelle: docs.github.com/en/copilot/concepts/models/auto-model-selection.

  • HydraFusion / HydraFusion Max: CLI-Optionen, die mehrere Modelle orchestrieren und den Effort schrittweise wählen. Kein eigener Tarif, Kosten nur aus usage.json.

  • Die CLI lässt sich skripten:

    • -p, --model <id|auto>;
    • --reasoning-effort/--effort mit low, medium, high, xhigh, max. Eine Stufe, die das Modell nicht anbietet, wird gemeldet und nicht angewendet (1.0.88). Ohne Flag wählt der Server den Standard (1.0.77);
    • --usage-output-file (JSON, Kennzahlen je Agent), --output-format json, --allow-all-tools, --trust-folder (1.0.100).

    Quellen: docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference, github/copilot-cli changelog.md.

  • Effort je Modell ist nicht als Tabelle dokumentiert. Das Session-Protokoll der CLI (JSONL) enthält den Modellkatalog mit supportedReasoningEfforts, beobachtet in github/gh-aw, actions/setup/js/fixtures/session-contract/. GPT-6 Luna und Claude Haiku 5.5 bieten dort low bis max. none steht im Katalog, aber nicht in der CLI-Referenz, also nicht verwenden.

  • Preise in AI Credits je 1 M Tokens (1 Credit = 0,01 USD; docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing). Grundlage der Kostenschätzungen in queue.toml:

    Modell Input Output Cache Read Cache Write
    GPT-6 Luna (≤ 272 k) 10 50 1 12,5
    Claude Haiku 5.5 (≤ 100 k; darüber 50/250/5/62,5) 10 50 1 12,5
    GPT-5.6 Luna (≤ 200 k) 20 120 2 25
    MAI-Code-1.1-Flash 20 120 2 –
    Gemini 3.8 Flash (Aktionspreis bis 2026-12-31) 75 375 7,5 –
    Claude Sonnet 5.5 200 1.000 10 250
    GPT-6.1 Sol (≤ 272 k) 200 1.000 10 250
    Gemini 4 Argon (Aktionspreis bis 2026-12-01) 200 1.000 10 –
    Claude Opus 5.5 400 2.000 20 500

    Nur bei Bedarf (P7): Grok 4.7 (200/600), Kimi K3 (300/1.500), Claude Haiku 4.5 (100/500).

    Bewusst nicht im Vergleich:

    • GPT-6 Astra, Claude Fable 5/5.1 (Entscheidung des Betreibers);
    • Opus 4.8, 4.8 Fast und 5 (Opus 5.5 ist neuer und günstiger);
    • GPT-6 Sol und Sonnet 5 (gleicher Preis wie die neueren 6.1 Sol und Sonnet 5.5);
    • Grok 4.5/4.6 (gleicher Preis wie 4.7);
    • GPT-5.6 Sol/Terra (ältere Generation);
    • GPT-5.3-Codex (Code-Modell);
    • Sonnet 4.6 (nicht im Credit-Plan).

    Messungen mit Gemini nach Ablauf der Aktionspreise sind kostenseitig nicht vergleichbar.

  • Pipeline (2) gibt es: #225/#226 gebaut (10.1.0), die Ableitung ist nach #231 endgültig. Gemessen wird ab dem Stand, den der Runner exportiert. engine-Zeile aus derived.md und VERSION stehen je Lauf in den Laufmetadaten.

Effort-Stufen: was die Warteschlange misst und warum

Stufe Wo Begründung
Standard (kein Flag) jedes Modell Das bekommt der Betreiber im Alltag. P0 hält fest, worauf der Standard je Modell auflöst.
high, max nur GPT-6 Luna und Claude Haiku 5.5 Die Frage, an der eine Entscheidung hängt: Holt ein günstiges Modell mit mehr Nachdenken ein mittleres ein, zu einem Bruchteil des Preises? Am günstigen Ende kostet selbst max nur Cent.
medium nur, wenn P0 zeigt, dass der Standard nicht medium ist sonst eine Wiederholung des Standards
low nicht Ingest ist eine Vollständigkeitsaufgabe. low spart bei günstigen Modellen nur Cent und provoziert bei teuren genau den Verlust, den wir messen.
xhigh nicht (P7) liegt zwischen high und max; nur nachmessen, wenn high → max einen Sprung zeigt
high bei Sonnet 5.5 nicht (P7) Effort erhöht vor allem den Output, die teuerste Position. Das Budget kauft dafür ein bis zwei Läufe, die wenig aussagen.

Entwurf

Ablageort: torben/chemenu-testfiles (privat) unter harness/ingest-bench/, neben harness/compare/. Die Fixtures liegen dort (corpus/pdf/bhv-dfb-2026-teil3.pdf, corpus/pdf/ihf-regeln-2025.pdf), und Goldinventare dürfen dort Fremdtext zitieren. Python, lauffähig unter Windows (pwsh 7) und Linux.

  • Interpreter: wie bei harness/compare das Python aus tools/.venv des Chemenu-Checkouts. (Bau) Es reicht: pyyaml und pypdf sind dort, tomllib ist Standardbibliothek, die Diagramme schreibt report.py als SVG von Hand. Keine eigene venv.
  • Pfade: --stack <pfad> zeigt auf den Chemenu-Checkout. Standard ist das Elternverzeichnis von testfiles/, so wird es geklont.
  • <bench> ist ein Arbeitsverzeichnis außerhalb beider Repos (Standard %LOCALAPPDATA%\chemenu-bench bzw. ~/.cache/chemenu-bench, per --workdir änderbar) und wird nie eingecheckt.
  • (Bau) Programmnamen (copilot, claude) werden über PATH aufgelöst, damit unter Windows auch .cmd-Shims gefunden werden.
Datei Inhalt
README.md Einrichtung unter Windows und Linux, Ablauf, Deckel, Fortsetzen nach Abbruch, Ausfüllen des Prüfbogens
bench.py Runner: Vorlage bauen, Lauf-Verzeichnis wiederherstellen, Copilot starten, Ergebnis einsammeln, Kosten summieren, Deckel prüfen. --dry-run ruft statt copilot den Stub auf. Unterbefehle refresh-instance, template, plan, run, prepare/import (Handläufe), status, forget
copilot_stub.py Stub für den Trockenmodus: schreibt eine erfundene Seite über tools/wikitool new in der Wegwerf-Instanz, ein usage.json mit festen Tokenzahlen und ein JSON-Protokoll mit Modellanzeige. Steuerbar (--stub-mode), um Zeitlimit, Gate und „Effort nicht angewendet“ nachzustellen.
queue.toml Warteschlange P0–P7 (unten): je Eintrag Modell, Effort, Fixture, Wiederholung und Haltepunkte; dazu Preistabelle, Token-Profil, Fixtures, Inventare, Deckel und die Kommandozeilen von copilot/claude
choices.example.toml (Bau) Form der Betreiber-Wahl nach P2 (results/choices.toml); Platzhalter @<name> in queue.toml
prompt.txt der feste Ingest-Prompt, für alle Läufe wörtlich gleich: ingest incoming/<datei>
instance/ vorbefüllte Instanz-Dateien für die Vorlage (USER.md, SOUL.md, kb/CONVENTIONS.md, kb/*/COLLECTION.md, Seiten-Typ-Specs), übernommen aus dem Demo-Stand des Ursprungs-Repos, damit doctor ohne Setup-Interview grün ist. (Bau) Die Liste ergibt sich aus den .template-Dateien eines Exports (ohne ENVIRONMENT.md); bench.py refresh-instance erneuert sie
fixtures.py erzeugt Fixture B (IHF, PDF-Seiten 39–43) zur Laufzeit per pypdf aus dem Korpus-PDF; nichts davon wird eingecheckt
gold/extract-prompt.md der feste Extraktions-Prompt mit den Regeln aus § Goldinventar
gold/judge-prompt.md (Bau) der feste Richter-Prompt
gold.py Goldinventar herstellen; Unterbefehle für die acht Schritte in § Goldinventar
gold/<inventar>.yaml, .passages.yaml, .review.md je Inventar die Fakten, die nummerierten Passagen und der Prüfbogen. (Bau) Dazu <inventar>.derived.md (Schritt 1) und <inventar>.extract-claude.yaml / .extract-gpt.yaml (Schritte 3/4). Inventare: bhv-dfb-2026-teil3 (A), ihf-regel16 (B, zugleich Kapitel 1 für P6), ihf-kapitel (die zwei weiteren Kapitel für P6)
page_metrics.py mechanische Kennzahlen je Lauf ohne LLM (§ Bewertung). (Bau) Nicht metrics.py: harness/compare/metrics.py belegt den Modulnamen im selben pytest-Lauf
judge.py Richter: je Gold-Fakt und Lauf ein Urteil, Ausgabe JSON. Richter 1 über claude -p, Richter 2 über copilot -p. Dazu consolidate (Widersprüche) und sample (Stichprobe)
report.py Tabellen und Diagramme aus results/ (Pareto Recall/Kosten, Länge/Recall)
test_ingest_bench.py, testdata/ pytest für page_metrics.py, gold.py, judge.py, report.py, Deckelrechnung, Warteschlange und die Stub-Fälle, ohne Netz und ohne Copilot
results/<lauf-id>/ je Lauf: Seiten-Diff, Seiten, usage.json, JSON-Protokoll, Trace, Laufmetadaten, Kennzahlen, Urteile. Dazu results/ledger.json (Verbrauch). Wird in #240 eingecheckt, Trockenläufe nicht (die liegen unter <bench>/dry-run/).

Vorlage und Lauf-Verzeichnis. Einmal (bench.py template):

  1. tools/wikitool dist export <bench>/run aus dem Checkout unter --stack.
  2. instance/ hineinkopieren.
  3. git init, lokale Identität bench, erster Commit, kein Remote.
  4. Preflight einschließlich tools/.venv.
  5. (Bau) instructions sync, index rebuild, sources rebuild-index, Commit: ohne sie meldet doctor FAIL (keine Skills, fehlende kb/index.md/kb/provenance.md).
  6. doctor muss mit Exit 0 enden (WARN für den fehlenden Remote ist gewollt). Endet der Preflight mit Exit 42, hält bench.py an und zeigt die Ausgabe wörtlich, ohne etwas zu installieren.

Danach wird <bench>/run als <bench>/template gesichert, mit einem Manifest aller Dateien (SHA-256). Vor jedem Lauf wird <bench>/run aus template wiederhergestellt, am selben absoluten Pfad: venvs lassen sich nicht verschieben. Danach wird es gegen das Manifest geprüft. Läufe gehen nacheinander, nie parallel. Gemessen: Vorlage bauen ~18 s, Wiederherstellen ~2 s.

Ein Lauf:

  1. <bench>/run wiederherstellen, Fixture nach incoming/ legen.

  2. copilot -p "<prompt>" --model <m> [--reasoning-effort <e>] --allow-all-tools --trust-folder --usage-output-file usage.json --output-format json mit Zeitlimit: A und B 30 min, P6 90 min. (Bau) Mit eigenem WIKITOOL_SESSION_ID=bench-<eintrag> (eigenes Iterationsbudget; Copilot registriert keine Session-Variable) und WIKI_TRACE=1.

  3. Einsammeln:

    • Diff des Arbeitsbaums und der Commits gegen den Vorlagen-Commit;
    • usage.json, Protokoll, Laufzeit, Exit-Code;
    • wikitool lint --json und page_metrics.py. (Bau) Ein wikitool validate gibt es nicht; lint prüft die Frontmatter mit;
    • Modellfolge aus dem Protokoll;
    • ob ein Gate erreicht wurde (Mass-Update, Iteration-Budget, Loop-Breaker). (Bau) Aus dem wikitool-Trace des Laufs (gate.refused), nicht aus dem Copilot-Protokoll;
    • ob die CLI eine Effort-Stufe als nicht angewendet gemeldet hat (Muster in queue.toml).

    Ein Gate macht den Lauf nicht ungültig: Die Seiten im Arbeitsbaum werden bewertet. Eine nicht angewendete Effort-Stufe zählt nicht unter dieser Stufe.

  4. Ergebnis nach results/<lauf-id>/ schreiben, Verbrauch addieren. Der Verbrauch wird in results/ledger.json fortgeschrieben, damit ein abgebrochener Runner beim nächsten Start weiß, was schon verbraucht und gelaufen ist.

Deckel.

  • Der Runner startet einen Lauf nur, wenn verbraucht + Schätzung des Laufs ≤ 45 USD. Die 5 USD darüber sind Reserve für Läufe, die teurer werden als geschätzt.
  • (Bau) Die Schätzung ist das Token-Profil aus queue.toml (~50 Anfragen × ~60 k Kontext: 250 k Input, 2,7 M Cache Read, 50 k Cache Write, 100 k Output), bewertet mit der Preistabelle. Effort skaliert den Output (high 1,5, xhigh 2, max 2,5), Fixture L das Ganze (Faktor 4, Kontext 120 k). Auto wird als Sonnet 5.5 × 0,9 geschätzt, Auto-Intelligence und HydraFusion als Opus 5.5. Preise ohne Cache-Angabe (Grok, Kimi, Haiku 4.5) werden zum Input-Preis gerechnet.
  • Nach P0 ersetzt der Runner die Schätzungen der übrigen Einträge durch die gemessenen Kosten je Lauf, hochgerechnet über die Preistabelle. (Bau) Konkret: Das Profil wird durch den Mittelwert der in P0 gemessenen Tokens ersetzt.
  • Liegt P0 um mehr als Faktor 2 über der Schätzung, hält er an. (Bau) Weiter nur mit --accept-calibration.
  • Er hält ebenso nach P2 an, damit die „besten“ Konfigurationen für P4–P6 festgelegt werden (#240). Er wählt sie nie selbst. (Bau) Die Einträge tragen Platzhalter (@best_cheap_model …); ohne results/choices.toml verweigert der Runner sie.
  • Er verweigert P1 und alles danach, solange das Inventar A nicht eingefroren ist, und P4 bzw. P6, solange die IHF-Inventare es nicht sind. (Bau) Die Sperre hängt an der Fixture: auch P5-B wartet auf ihf-regel16.
  • (Bau) Ein Lauf, der zusammen mit dem Runner abbricht, wird mit seiner Schätzung gebucht und nicht wiederholt. P7 läuft nur mit --include-optional. Ein Modell, das die Preistabelle nicht kennt, wird zum Preis des teuersten gerechnet.
  • (Bau, Befund für #240) Mit diesem Profil schätzt der Runner bis P6 ≈ 47 USD statt der 44,50 der Session-Tabelle unten (P1 16,06; P3 ohne Handläufe 10,61; P6-Auto allein 6,82). Ohne die P0-Messung würde er P6-Auto am Deckel verweigern. P0 ersetzt das Profil; nach P0 in #240 mit bench.py plan neu ansehen.

Warteschlange (Fixture A und Standard-Effort, wo nichts anderes steht). Schätzungen der Session vom 2026-10-20 unter der Annahme ~50 Anfragen × ~60 k Kontext, ~90 % Cache Read, ~100 k Output; P0 misst nach.

P Läufe Schätzung (USD)
Gold zweiter Extraktionsdurchgang mit GPT-6.1 Sol über alle drei Inventare 1,00
P0 Kalibrierung GPT-6 Luna, Sonnet 5.5. Dazu: Flags, Modellliste, Effort-Matrix und Standard-Effort aus dem Session-Protokoll; wird das Modell je Anfrage erfasst? 2,70
P1 Kern Opus 5.5 (Referenz), Haiku 5.5, GPT-6.1 Sol, Gemini 4 Argon, Gemini 3.8 Flash, GPT-5.6 Luna, MAI-Code-1.1-Flash, Auto (Standard-Tier) × 3 12,50
P2 Effort Luna × {high, max}, Haiku 5.5 × {high, max}; zweiter Standard-Lauf Luna und Haiku 5.5 1,80
P3 Routing Auto Intelligence-Tier × 2, HydraFusion × 1; Desktop App mit Auto × 2 von Hand (der Runner erfasst sie über einen Import-Befehl, der Diff und Kosten nachträgt) 9,00
P4 Fixture B Luna und Haiku 5.5, je mit Standard und der besten Effort-Stufe aus P2; Auto × 2; das beste Mittelklasse-Modell aus P1; Opus 5.5 9,50
P5 Streuung zweiter Lauf Sonnet 5.5 auf A; dritter Lauf der besten günstigen Konfiguration auf A und B 3,00
P6 Lang ganzes IHF-Dokument im kapitelweisen Pfad: beste günstige Konfiguration × 1, Auto × 1. Achtung: Haiku 5.5 wird über 100 k Kontext fünfmal teurer. 3,00
Richter 2 GPT-6.1 Sol über Copilot 2,00
Summe ≈ 44,50
P7 nur aus Rest Grok 4.7, Kimi K3, Haiku 4.5, Sonnet 5.5 high, Luna/Haiku 5.5 xhigh, HydraFusion Max, Auto mit einem Prompt, der den Umfang benennt –

(Bau) Wie P0 Auto-Intelligence-Tier und HydraFusion auf der Kommandozeile wählt, ist offen; die Einträge tragen die Modell-IDs auto-intelligence/hydrafusion als Platzhalter, P0 korrigiert sie samt extra_args in queue.toml. Das gilt für alle Modell-IDs, Flags und usage.json-Feldnamen (bench.py TOKEN_KEYS). Ebenso prüft P0, ob copilot -p den Prompt über stdin nimmt: Gold 2 und Richter 2 übergeben ihn sonst als Argument, was unter Windows bei ~32 k Zeichen endet.

Fixtures:

  • A (klein): BHV DFB 2026/27 Teil III, 7 Seiten, ~4 k Tokens, unter der Längenschwelle aus #226.
  • B: IHF-Regeln 2025, Regel 16 „Die Strafen“ als Ausschnitt. (Bau) Regel 16 steht auf den PDF-Seiten 39–43 (gedruckt S. 38–42), nicht 39–42: PDF-Seite 43 trägt den Rest von 16:11. Fixture B nimmt die fünf Seiten; die Randpassagen aus Regel 15 und 17 werden im Gold kein_fakt.
  • P6: das ganze IHF-Dokument (96 Seiten), bewertet an Regel 16 und zwei weiteren Kapiteln.

Goldinventar

Das Goldinventar ist das Maß des ganzen Vergleichs. Ein Fakt, der im Gold fehlt, ist in jedem Lauf unsichtbar, und ein falscher Gold-Fakt bestraft jedes Modell, das richtig liegt. Deshalb entsteht es aus zwei unabhängigen Extraktionen verschiedener Hersteller, wird mechanisch auf Abdeckung geprüft und erst nach der Prüfung durch den Betreiber eingefroren.

Grundlage ist der abgeleitete Text, nicht das PDF. Gold ist, was das Modell zu lesen bekommt: derived.md aus raw derive des exportierten Stacks. Was die Ableitung verliert (etwa Bilder), ist kein Verlust des Modells und gehört nicht ins Gold. Jedes Inventar trägt die engine-Zeile und den SHA-256 der derived.md, aus der es entstand. (Bau) Gehasht wird derived.md ohne ihre derived:-Zeile, die einzige, die sich bei gleicher Ableitung ändert. Ändert sich die Ableitung, wird das Inventar gegen die neue geprüft, bevor weiter gemessen wird.

Was ein Gold-Fakt ist:

  • Eine prüfbare Aussage: Man kann auf einer Wiki-Seite entscheiden, ob sie dort steht. „Die Spielzeit beträgt 2 × 30 Minuten“ ist einer, „Regel 4 regelt die Mannschaft“ ist keiner.
  • Atomar mit Feldern: Bedingung, Ausnahme, Zahl/Frist und Modalität (muss / soll / kann / darf nicht) gehören zum Fakt, nicht in eigene Fakten. Eine Ausnahme, die selbst eine eigene Regel ist, wird ein eigener Fakt mit Verweis.
  • Nicht aufgenommen: Überschriften, Inhaltsverzeichnis, Kopf- und Fußzeilen, Seitenzahlen, reine Querverweise ohne eigene Aussage, Wiederholungen derselben Aussage (einmal, mit allen Fundstellen).
  • kritisch: true für Fakten mit Zahl/Frist, Verbot, Ausnahme oder Sanktion. Recall wird gesamt und für die kritischen Fakten getrennt berichtet.

Schema je Fakt:

- id: A-017
  passagen: [p12]
  fundstelle: "S. 3, Nr. 4.2"
  aussage: "…"
  modalitaet: darf nicht     # muss | soll | kann | darf nicht | –
  bedingung: "…"             # optional
  ausnahme: "…"              # optional
  zahl: "…"                  # optional, Zahl oder Frist mit Einheit
  kritisch: true
  extrahiert_von: [claude, gpt]
  status: offen              # offen | ok | geaendert | gestrichen

(Bau) Dazu nach dem Zusammenführen strittig: {feld: {claude: …, gpt: …}}, wo die Extraktionen in Modalität, Bedingung, Ausnahme, Zahl oder kritisch auseinandergehen.

Herstellung (gold.py, je Inventar):

  1. Ableiten: Fixture mit raw derive ableiten, engine und Hash festhalten. (Bau) In der frisch wiederhergestellten Wegwerf-Instanz, also mit dem exportierten Stand des Checkouts unter --stack; nichts wird im Checkout selbst abgeleitet.
  2. Passagen: derived.md deterministisch in nummerierte Passagen schneiden, je Absatz bzw. Listeneintrag, mit Seitenangabe aus der Gliederung → <inventar>.passages.yaml. Jeder Fakt zitiert seine Passagen. (Bau) Seite aus den <!-- page N -->-Markern; eine Zeile, die einen Gliederungsabschnitt eröffnet, beginnt eine eigene Passage und setzt den Abschnitt (Zeilen des Inhaltsverzeichnisses nicht). Listeneintrag ist auch eine Zeile mit genau einem führenden Leerzeichen: so viel bleibt vom PDF-Aufzählungszeichen, das die Ableitung verliert.
  3. Extraktion 1: Claude Opus über Claude Code (claude -p) mit gold/extract-prompt.md und den Passagen.
  4. Extraktion 2: GPT-6.1 Sol über copilot -p, gleicher Prompt, ohne Kenntnis von Extraktion 1 (Budgetzeile „Gold“).
  5. Zusammenführen: je Passage beide Ergebnisse nebeneinander. Eine Session paart gleichbedeutende Fakten und behält die Vereinigung. Sie markiert, was nur ein Durchgang fand (extrahiert_von mit einem Eintrag) und wo sich beide in einem Feld widersprechen. (Bau) Die Session liefert nur die Paare (pairs.yaml); Vereinigung, extrahiert_von und strittig setzt gold.py merge.
  6. Abdeckungsprüfung (mechanisch): Jede Passage hat mindestens einen Fakt oder ist ausdrücklich als kein_fakt markiert, mit Grund (Überschrift, Verzeichnis, Fußzeile …). Eine Passage ohne beides bricht ab und wird gelistet.
  7. Prüfbogen: <inventar>.review.md zeigt je Passage ihren Wortlaut und darunter ihre Fakten mit Feldern; markiert ist, was nur ein Durchgang fand oder strittig ist. Bei Stichproben-Inventaren ist markiert, welche Fakten und Passagen zum Prüfumfang gehören.
    • Der Betreiber setzt je Fakt ok / ändern: … / streichen und je Passage fehlt: …, wo ein Fakt fehlt.
    • Er prüft im Editor oder in der Gitea-Weboberfläche des privaten Repos (geht auch mobil).
    • Der Prüfbogen verlässt das private Repo nicht. Insbesondere wird er nicht als claude.ai-Artifact oder anderswo veröffentlicht (Fremdtext).
  8. Übernehmen und Einfrieren: gold.py schreibt die Entscheidungen ins YAML zurück und setzt geprueft: <datum> und den Hash.

Prüfumfang:

  • A vollständig: jeder Fakt und jede Passage. Grobe Größe: ~1.600 Wörter, schätzungsweise 60–120 Fakten, Prüfung ~1–1,5 Stunden. (Bau) Extraktion 1 fand 116 Fakten auf 133 Passagen.
  • B (Regel 16) und die zwei weiteren Kapitel als Stichprobe:
    • alle kritischen Fakten;
    • alle Fakten, die nur ein Durchgang fand oder die strittig sind;
    • ein Drittel der übrigen Passagen, deterministisch gezogen.

Die zwei weiteren IHF-Kapitel wählt die Gold-Session in #240 nach drei Kriterien: viele Zahlen/Fristen, Ausnahmen und Modalitäten wie in Regel 16, aber ein anderer Regeltyp (z. B. eine Regel zu Spielfeld/Ausrüstung und eine zu Regelwidrigkeiten).

Was davon in diesem Issue lief:

  • Für A die Schritte 1–3 und 6, also der Claude-Entwurf mit grüner Abdeckungsprüfung (§ Belege).
  • Schritte 4, 5, 7 und 8 sind gebaut und an erfundenen Daten getestet, laufen aber erst in #240: Schritt 4 braucht die Copilot CLI, die auf dem Linux-Entwicklungsrechner nicht eingerichtet ist, und ein Prüfbogen vor der zweiten Extraktion hieße, den Betreiber zweimal prüfen zu lassen.

Bewertung

  • Urteil: je Gold-Fakt und Lauf korrekt vorhanden / fehlt / verfälscht (Negation, Ausnahme, Modalität, Zahl), gesucht auf allen entstandenen Seiten. Die Felder des Gold-Fakts bestimmen die Art einer Verfälschung. Das Urteil hält fest, auf welcher Seite der Fakt steht (Source-Seite oder Entity-/Concept-Seite).
  • Richter 1: Claude Opus über Claude Code (claude -p) für alle Läufe.
  • Richter 2: GPT-6.1 Sol über Copilot für alle Läufe von Claude-Kandidaten (Haiku 5.5, Sonnet 5.5, Opus 5.5), damit kein Kandidat nur vom eigenen Hersteller bewertet wird.
  • Widersprüche: judge.py legt jeden Fall, in dem sich die Richter widersprechen, als offenen Fall für den Betreiber ab. (Bau) results/<lauf>/streitfaelle.yaml mit Feld entscheidung; judge.py consolidate schreibt urteil.json, offene Fälle als offen.
  • Stichprobe: judge.py zieht die geschichtete Stichprobe übereinstimmender Urteile je Modellklasse, die der Betreiber prüft. Ein Urteil allein durch ein LLM gilt nicht. (Bau) results/stichprobe.yaml; die Klasse steht je Modell in queue.toml (guenstig, mittel, oben, auto). Bei Nicht-Claude-Kandidaten gibt es nur Richter 1; deren Urteile gehen ebenso in die Stichprobe. report.py markiert Läufe als vorläufig, solange Streitfälle offen sind oder die Stichprobe ihrer Klasse ungeprüft ist.

Seitenlänge. Länge allein ist kein Qualitätsmaß; sie wird mechanisch gemessen und neben den Recall gelegt. page_metrics.py zählt je Lauf ohne LLM nur den Fließtext der Seiten, ohne Frontmatter, Fußnoten-Definitionen, Überschriften und generierte Blöcke. (Bau) Ebenso ohne Zeilen, die das Seiten-Template gesetzt hat und der Lauf unverändert ließ (TODO:-Zeilen, Platzhalter-Links wie [[Entity 1]] - kurze Beschreibung): sonst misst die Länge den Template-Text mit.

  • Wörter gesamt über alle entstandenen bzw. geänderten Seiten, und getrennt für Source-Seite und Entity-/Concept-Seiten;
  • Verdichtung: Wörter der Seiten ÷ Wörter der derived.md;
  • Wörter je Seite (Median, Minimum);
  • leere Template-Abschnitte: Überschriften aus dem Seiten-Template ohne Inhalt darunter ((Bau) außer unveränderten Template-Zeilen);
  • Seitenbild: Seiten, Stub-Seiten, Einträge in ## Nicht übernommen. (Bau) Stub-Seite: unter 40 Wörtern oder alle Template-Abschnitte leer.

report.py verbindet das mit den Urteilen zur Faktendichte (korrekt vorhandene Gold-Fakten je 100 Wörter) und schreibt die Tabellen und Diagramme, die #240 § Auswertung braucht.

Windows und #167. Unter Copilot CLI auf Windows öffnet tools/wikitool sporadisch im Hintergrund den Dialog „App auswählen“, einmal mit einem Hänger von über zwei Minuten (#167). Unbeaufsichtigt hängt ein solcher Lauf bis zum Zeitlimit. Deshalb markiert der Runner einen Lauf, der ins Zeitlimit läuft, als Harness-Abbruch:

  • nicht bewertet;
  • Kosten trotzdem gezählt ((Bau) aus usage.json, fehlt es, mit der Schätzung);
  • nicht automatisch wiederholt;
  • Protokoll für #167 bereitgelegt.

Invarianten

  • Jeder Lauf, auch ein Trockenlauf, findet in der Wegwerf-Instanz <bench>/run ohne Git-Remote statt. Ein publish dort darf lokal committen, es hat kein Ziel zum Pushen. Kein Lauf ändert den Chemenu-Checkout unter --stack: git status dort ist vor und nach einem Lauf gleich. (Bau) Der Runner prüft das nach jedem Lauf und bricht sonst ab.
  • Vor jedem Lauf ist <bench>/run inhaltlich identisch mit <bench>/template. Kein Rest eines früheren Laufs beeinflusst den nächsten. (Bau) Geprüft gegen das Manifest, Ergebnis in meta.json (template_identical).
  • Ein eingefrorenes Goldinventar ändert gold.py nur über einen neuen Prüfbogen. Jede Bewertung nennt den Hash des Inventars, gegen das sie lief.
  • Der Runner setzt Modell und Effort nur über Flags, nie über /model --repo, /settings oder Nutzer-Standardwerte. Die Konfiguration des Betreibers bleibt unberührt.
  • Fixtures, Inventare, Prüfbögen und Rohergebnisse verlassen torben/chemenu-testfiles nicht (Fremdinhalt).
  • Der Bau verbraucht keine Copilot-Credits: kein copilot-Aufruf außer dem Stub.

Abschluss der Bauphase

Der Prozess lässt stack-build mit einem grünen CI-Lauf nach wikitool publish enden. Das passt hier nicht: Im Chemenu-Repo ändert sich nichts, und chemenu-testfiles ist ein eigenes Repo ohne CI, das wikitool publish nicht kennt. Invariante 5 aus AGENTS.md gilt für das Chemenu-Repo. In chemenu-testfiles wird wie bisher (Konverter-Vergleich) per git commit und git push gearbeitet; der Betreiber hat das am 2026-10-21 ohne Einzelfreigabe je Push freigegeben. Commit-Nachrichten tragen die üblichen Trailer.

(Bau) Die Tests liegen unter harness/ und werden damit auch vom converters-Workflow des Stacks eingesammelt, der pytest ../testfiles/harness gegen main von chemenu-testfiles ausführt (bei einem Push auf Konverter-Pfade, von Hand oder vor einem Release). Sie brauchen dafür nur git und den Korpus. Weil release.yml denselben Harness vor einem Release ohne Suffix laufen lässt, hält ein rotes ingest-bench künftig auch einen Release an. Ihr erster Lauf dort ist grün (§ Belege, Punkt 1).

Die Bauphase endet daher, wenn

  1. pytest über harness/ingest-bench unter Linux grün ist,
  2. ein voller Trockenlauf grün ist (Akzeptanzkriterien unten),
  3. der Gold-Entwurf A vorliegt und
  4. alles als Commit in chemenu-testfiles gepusht ist.

Diese vier Belege mit Commit-Hash stehen im Body. stack-close schließt dieses Issue danach. Die Kette führt zu #240.

Belege (2026-10-21, Stack 10.1.1-beta.2, 55ddf652)

  1. pytest:

    • tools/.venv/bin/python -m pytest -c pytest.ini ../testfiles/harness/ingest-bench: 39 Tests grün, zusammen mit harness/compare 52 (keine Modul-Kollision).
    • Beim Abschluss (stack-close) der ganze Harness, pytest -c pytest.ini ../testfiles/harness auf ba1eb95: lokal (Python 3.14) 85 Tests grün in 9:13 min.
    • In CI derselbe Umfang über den von Hand gestarteten converters-Workflow: Run 781, Python 3.13, 85 passed in 531.48s.
  2. Trockenlauf: von leerem Zustand an:

    • run --dry-run hält nach P0 (Exit 3, Kalibrierung gebucht) und nach P2 (Exit 3);
    • danach P3 und P4-luna-B1, dann verweigert bei P4-luna-best-B1 mangels Wahl (Exit 4);
    • nach choices.toml der Rest bis P6 (Exit 0), die zwei Handläufe offen.

    34 Einträge ohne Wiederholung, alle mit template_identical: true; git status im Stack unverändert. Gegen die echte Instanz außerdem:

    • Loop-Breaker und „Effort nicht angewendet“ erfasst, Lauf gültig (P7-luna-xhigh-A1);
    • Zeitlimit 20 s → Harness-Abbruch, Kosten gezählt, beim Neustart nicht wiederholt (P7-grok-A1);
    • Handlauf über prepare/import (P3-desktop-A1);
    • forget mit Ablage als .verworfen-1.

    Gefunden und behoben im Trockenlauf: Der Stub las die raw/-Pfade aus umbrochener Ausgabe (B-Läufe ohne Source-Seite).

  3. Gold-Entwurf A:

    • gold/bhv-dfb-2026-teil3.passages.yaml: 133 Passagen, derived_sha256 a5733f08…5c48, engine: wikitool 10.1.1-beta.2 + pypdf 6.21.1 + pdfminer.six 20260107;
    • gold/bhv-dfb-2026-teil3.extract-claude.yaml: 116 Fakten, 54 kritisch, 31 kein_fakt;
    • gold.py check --extract claude grün.
  4. Commit: chemenu-testfiles ba1eb95, gepusht auf main. Im Chemenu-Repo kein Commit, kein Bump. Copilot-Verbrauch: 0 USD (kein copilot auf dem Rechner, nur der Stub).

Akzeptanzkriterien

  • Trockenlauf: bench.py --dry-run arbeitet unter Linux die ganze Warteschlange mit dem Stub ab: Vorlage bauen (doctor grün), wiederherstellen, einsammeln, page_metrics.py, Deckelrechnung, Fortschreiben des Verbrauchs. Er hält nach P0 und nach P2 an und setzt nach einem Neustart dort fort, ohne einen gelaufenen Eintrag zu wiederholen. Nach jedem Lauf ist <bench>/run vor dem nächsten wieder identisch mit template, und git status im Chemenu-Checkout ist unverändert.
  • Deckel: Ein Test belegt, dass der Runner einen Lauf nicht startet, wenn verbraucht + Schätzung > 45 USD; dass er nach P0 die Schätzungen aus den gemessenen Kosten neu rechnet; und dass er bei einem P0 über Faktor 2 anhält.
  • Sperren: Ein Test belegt, dass P1 und alles danach ohne eingefrorenes Inventar A verweigert wird, und P4/P6 ohne eingefrorene IHF-Inventare.
  • Stub-Fälle: Mit dem Stub nachgestellt, wird ein Zeitlimit als Harness-Abbruch markiert, nicht bewertet und nicht wiederholt. Ein erreichtes Gate wird festgehalten, ohne den Lauf ungültig zu machen. Eine als nicht angewendet gemeldete Effort-Stufe wird festgehalten.
  • page_metrics.py liefert für eine Seite mit bekanntem Inhalt (Test-Fixture im Harness) die erwartete Wortzahl und erkennt einen leeren Template-Abschnitt. Frontmatter, Fußnoten-Definitionen und Überschriften zählen nicht mit.
  • gold.py bricht ab, wenn eine Passage weder einen Fakt hat noch als kein_fakt markiert ist. Ein Prüfbogen mit ok / ändern: … / streichen / fehlt: … wird ins YAML zurückgeschrieben (Test an erfundenen Daten). Jedes eingefrorene Inventar trägt geprueft, den Hash seiner derived.md und deren engine-Zeile. Die Stichprobe ist deterministisch.
  • judge.py liefert mit Stub-Antworten je Gold-Fakt ein JSON-Urteil mit Seite. Ein Widerspruch zwischen zwei Richtern wird als offener Fall für den Betreiber abgelegt.
  • report.py erzeugt aus erfundenen Ergebnissen die Tabelle Modell × Effort × Fixture sowie die Diagramme Pareto Recall/Kosten und Länge/Recall.
  • Gold-Entwurf A: gold/bhv-dfb-2026-teil3.passages.yaml mit Hash und engine-Zeile, Claude-Extraktion im YAML ((Bau) gold/bhv-dfb-2026-teil3.extract-claude.yaml), Abdeckungsprüfung grün. Noch nicht zusammengeführt und nicht geprüft.
  • README beschreibt Einrichtung unter Windows (pwsh 7) und Linux, den Ablauf von #240, das Fortsetzen und das Ausfüllen des Prüfbogens.
  • Abschluss: Commit in chemenu-testfiles gepusht (ba1eb95). Im Chemenu-Repo kein Commit, kein wikitool publish, kein Versions-Bump. Copilot-Verbrauch des Baus: 0 USD.

Versionsteil

Keiner: Der Runner liegt in torben/chemenu-testfiles, am Stack ändert sich keine Datei. Braucht die Wegwerf-Instanz doch eine Stack-Änderung, bekommt diese ein eigenes Issue mit eigenem Versionsteil.

Verwandt

#240 (Messung und Bericht, Nachfolger), #224 (Ursprung), #21 (Abnehmer des Ergebnisses von #240), #167 (Windows-Dialog unter Copilot CLI), #175 (Stub-Seiten mit unbeschriebenen Template-Abschnitten: dieselbe Erscheinung, die page_metrics.py als „leere Template-Abschnitte“ zählt), #80 (Claude-Code-Runner für L3-Evals: ob dieser Runner später darin aufgeht, entscheidet #80), #69 (Reproduktionslauf, gleiche Wegwerf-Logik), #226 (Pipeline 2), #231 (Form der Ableitung), instructions/dev/converter-comparison.md (Vorbild für ein Harness in chemenu-testfiles).

Kette

Kette „Ingest-Modellvergleich“

Abgespalten aus #224 (E4 vom 2026-10-13), am 2026-10-19/20 zum automatisierten Vergleich mit 50-USD-Deckel erweitert und am 2026-10-21 geteilt (Betreiber): **Dieses Issue baut das Werkzeug**, **#240 betreibt es** (Gold prüfen, bezahlte Läufe, Bewertung, Bericht). **Am Stack ändert sich keine Datei**: gebaut wird in `torben/chemenu-testfiles` unter `harness/ingest-bench/`. **Stand 2026-10-21: abgeschlossen.** Gebaut und gepusht als `chemenu-testfiles` `ba1eb95`. Die vier Belege aus § Abschluss der Bauphase liegen vor, dazu ein grüner Lauf des `converters`-Workflows (Run 781, § Belege). Abweichungen vom Entwurf sind an ihrer Stelle eingearbeitet und mit *(Bau)* markiert. Die Messung läuft in #240. ## Wozu das Werkzeug dient #240 beantwortet vier Fragen: Recall eines Ingests nach Modell × Effort, ob Auto zu klein routet und im Lauf wechselt, die Pareto-Front Recall/Kosten, und ob günstige Modelle kürzere Seiten schreiben und dabei Fakten verlieren. Dazu muss das Werkzeug je Lauf liefern: - ein Urteil je Gold-Fakt, mit der Seite, auf der der Fakt steht; - die Modellfolge bei Auto bzw. HydraFusion; - die Kosten aus `usage.json`; - mechanische Seitenkennzahlen. Außerdem muss es den 50-USD-Deckel selbst durchsetzen. ## Entscheidungen (Betreiber, 2026-10-20/21) - **Automatisierter Runner** statt Handlauf (E4 geändert). - **Abrechnung AI Credits, Deckel 50 USD** für alles, was über Copilot läuft: Kandidaten, Gold-Extraktion 2, Richter 2. - **Claude Code läuft separat** über das Abo des Betreibers und zählt nicht zum Deckel. Dort laufen Richter 1 und Gold-Extraktion 1. - **Ohne Astra und Fable. Claude Opus 5.5 ist die obere Referenz.** Gemessen wird gegen das Goldinventar, berichtet wird absolut und relativ zu Opus. - **Harness:** Copilot CLI für den Runner. Die Copilot Desktop App bekommt zwei Handläufe (P3). - **Rechner:** Windows (pwsh 7) bevorzugt, Linux als Plan B. Gebaut und trocken getestet wird unter Linux. - **Bau und Messung getrennt** (2026-10-21): eigenes Issue #240, damit dieses Issue mit dem Bau abschließt (§ Abschluss der Bauphase). - **Commits in `chemenu-testfiles` gehen per `git`** und werden ohne Einzelfreigabe gepusht (2026-10-21, § Abschluss der Bauphase). ## Was über Copilot feststeht Recherche 2026-10-19 (Session) und 2026-10-20 (Betreiber über Perplexity, nur GitHub-eigene Quellen, von der Session nicht einzeln nachgeprüft). P0 in #240 prüft es auf dem Rechner des Betreibers nach. - **Auto routet nicht nur am Anfang.** GitHub-Doku: „Routing occurs along natural cache boundaries and large drifts in conversation complexity.“ Copilot CLI 1.0.81 (2026-08-27): „Auto mode adapts model selection as the task evolves during a conversation.“ Auto hat Tiers (Efficiency / Balance / Intelligence). Abgerechnet wird das jeweils gewählte Modell, mit 10 % Rabatt. Die CLI zeigt das Modell bei jeder Antwort an. Quelle: docs.github.com/en/copilot/concepts/models/auto-model-selection. - **HydraFusion / HydraFusion Max:** CLI-Optionen, die mehrere Modelle orchestrieren und den Effort schrittweise wählen. Kein eigener Tarif, Kosten nur aus `usage.json`. - **Die CLI lässt sich skripten:** - `-p`, `--model <id|auto>`; - `--reasoning-effort`/`--effort` mit `low`, `medium`, `high`, `xhigh`, `max`. Eine Stufe, die das Modell nicht anbietet, wird gemeldet und nicht angewendet (1.0.88). Ohne Flag wählt der Server den Standard (1.0.77); - `--usage-output-file` (JSON, Kennzahlen je Agent), `--output-format json`, `--allow-all-tools`, `--trust-folder` (1.0.100). Quellen: docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference, github/copilot-cli `changelog.md`. - **Effort je Modell** ist nicht als Tabelle dokumentiert. Das Session-Protokoll der CLI (JSONL) enthält den Modellkatalog mit `supportedReasoningEfforts`, beobachtet in `github/gh-aw`, `actions/setup/js/fixtures/session-contract/`. GPT-6 Luna und Claude Haiku 5.5 bieten dort `low` bis `max`. `none` steht im Katalog, aber nicht in der CLI-Referenz, also nicht verwenden. - **Preise** in AI Credits je 1 M Tokens (1 Credit = 0,01 USD; docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing). Grundlage der Kostenschätzungen in `queue.toml`: | Modell | Input | Output | Cache Read | Cache Write | |---|---:|---:|---:|---:| | GPT-6 Luna (≤ 272 k) | 10 | 50 | 1 | 12,5 | | Claude Haiku 5.5 (≤ 100 k; darüber 50/250/5/62,5) | 10 | 50 | 1 | 12,5 | | GPT-5.6 Luna (≤ 200 k) | 20 | 120 | 2 | 25 | | MAI-Code-1.1-Flash | 20 | 120 | 2 | – | | Gemini 3.8 Flash (Aktionspreis bis 2026-12-31) | 75 | 375 | 7,5 | – | | Claude Sonnet 5.5 | 200 | 1.000 | 10 | 250 | | GPT-6.1 Sol (≤ 272 k) | 200 | 1.000 | 10 | 250 | | Gemini 4 Argon (Aktionspreis bis 2026-12-01) | 200 | 1.000 | 10 | – | | Claude Opus 5.5 | 400 | 2.000 | 20 | 500 | Nur bei Bedarf (P7): Grok 4.7 (200/600), Kimi K3 (300/1.500), Claude Haiku 4.5 (100/500). **Bewusst nicht im Vergleich:** - GPT-6 Astra, Claude Fable 5/5.1 (Entscheidung des Betreibers); - Opus 4.8, 4.8 Fast und 5 (Opus 5.5 ist neuer und günstiger); - GPT-6 Sol und Sonnet 5 (gleicher Preis wie die neueren 6.1 Sol und Sonnet 5.5); - Grok 4.5/4.6 (gleicher Preis wie 4.7); - GPT-5.6 Sol/Terra (ältere Generation); - GPT-5.3-Codex (Code-Modell); - Sonnet 4.6 (nicht im Credit-Plan). Messungen mit Gemini nach Ablauf der Aktionspreise sind kostenseitig nicht vergleichbar. - **Pipeline (2)** gibt es: #225/#226 gebaut (10.1.0), die Ableitung ist nach #231 endgültig. Gemessen wird ab dem Stand, den der Runner exportiert. `engine`-Zeile aus `derived.md` und `VERSION` stehen je Lauf in den Laufmetadaten. ## Effort-Stufen: was die Warteschlange misst und warum | Stufe | Wo | Begründung | |---|---|---| | **Standard** (kein Flag) | jedes Modell | Das bekommt der Betreiber im Alltag. P0 hält fest, worauf der Standard je Modell auflöst. | | **`high`, `max`** | nur GPT-6 Luna und Claude Haiku 5.5 | Die Frage, an der eine Entscheidung hängt: Holt ein günstiges Modell mit mehr Nachdenken ein mittleres ein, zu einem Bruchteil des Preises? Am günstigen Ende kostet selbst `max` nur Cent. | | `medium` | nur, wenn P0 zeigt, dass der Standard **nicht** `medium` ist | sonst eine Wiederholung des Standards | | `low` | nicht | Ingest ist eine Vollständigkeitsaufgabe. `low` spart bei günstigen Modellen nur Cent und provoziert bei teuren genau den Verlust, den wir messen. | | `xhigh` | nicht (P7) | liegt zwischen `high` und `max`; nur nachmessen, wenn `high` → `max` einen Sprung zeigt | | `high` bei Sonnet 5.5 | nicht (P7) | Effort erhöht vor allem den Output, die teuerste Position. Das Budget kauft dafür ein bis zwei Läufe, die wenig aussagen. | ## Entwurf **Ablageort:** `torben/chemenu-testfiles` (privat) unter `harness/ingest-bench/`, neben `harness/compare/`. Die Fixtures liegen dort (`corpus/pdf/bhv-dfb-2026-teil3.pdf`, `corpus/pdf/ihf-regeln-2025.pdf`), und Goldinventare dürfen dort Fremdtext zitieren. Python, lauffähig unter Windows (pwsh 7) und Linux. - **Interpreter:** wie bei `harness/compare` das Python aus `tools/.venv` des Chemenu-Checkouts. *(Bau)* Es reicht: `pyyaml` und `pypdf` sind dort, `tomllib` ist Standardbibliothek, die Diagramme schreibt `report.py` als SVG von Hand. Keine eigene venv. - **Pfade:** `--stack <pfad>` zeigt auf den Chemenu-Checkout. Standard ist das Elternverzeichnis von `testfiles/`, so wird es geklont. - **`<bench>`** ist ein Arbeitsverzeichnis außerhalb beider Repos (Standard `%LOCALAPPDATA%\chemenu-bench` bzw. `~/.cache/chemenu-bench`, per `--workdir` änderbar) und wird nie eingecheckt. - *(Bau)* **Programmnamen** (`copilot`, `claude`) werden über `PATH` aufgelöst, damit unter Windows auch `.cmd`-Shims gefunden werden. | Datei | Inhalt | |---|---| | `README.md` | Einrichtung unter Windows und Linux, Ablauf, Deckel, Fortsetzen nach Abbruch, Ausfüllen des Prüfbogens | | `bench.py` | Runner: Vorlage bauen, Lauf-Verzeichnis wiederherstellen, Copilot starten, Ergebnis einsammeln, Kosten summieren, Deckel prüfen. `--dry-run` ruft statt `copilot` den Stub auf. Unterbefehle `refresh-instance`, `template`, `plan`, `run`, `prepare`/`import` (Handläufe), `status`, `forget` | | `copilot_stub.py` | Stub für den Trockenmodus: schreibt eine erfundene Seite über `tools/wikitool new` in der Wegwerf-Instanz, ein `usage.json` mit festen Tokenzahlen und ein JSON-Protokoll mit Modellanzeige. Steuerbar (`--stub-mode`), um Zeitlimit, Gate und „Effort nicht angewendet“ nachzustellen. | | `queue.toml` | Warteschlange P0–P7 (unten): je Eintrag Modell, Effort, Fixture, Wiederholung und Haltepunkte; dazu Preistabelle, Token-Profil, Fixtures, Inventare, Deckel und die Kommandozeilen von `copilot`/`claude` | | `choices.example.toml` | *(Bau)* Form der Betreiber-Wahl nach P2 (`results/choices.toml`); Platzhalter `@<name>` in `queue.toml` | | `prompt.txt` | der feste Ingest-Prompt, für alle Läufe wörtlich gleich: `ingest incoming/<datei>` | | `instance/` | vorbefüllte Instanz-Dateien für die Vorlage (`USER.md`, `SOUL.md`, `kb/CONVENTIONS.md`, `kb/*/COLLECTION.md`, Seiten-Typ-Specs), übernommen aus dem Demo-Stand des Ursprungs-Repos, damit `doctor` ohne Setup-Interview grün ist. *(Bau)* Die Liste ergibt sich aus den `.template`-Dateien eines Exports (ohne `ENVIRONMENT.md`); `bench.py refresh-instance` erneuert sie | | `fixtures.py` | erzeugt Fixture B (IHF, PDF-Seiten 39–43) zur Laufzeit per `pypdf` aus dem Korpus-PDF; nichts davon wird eingecheckt | | `gold/extract-prompt.md` | der feste Extraktions-Prompt mit den Regeln aus § Goldinventar | | `gold/judge-prompt.md` | *(Bau)* der feste Richter-Prompt | | `gold.py` | Goldinventar herstellen; Unterbefehle für die acht Schritte in § Goldinventar | | `gold/<inventar>.yaml`, `.passages.yaml`, `.review.md` | je Inventar die Fakten, die nummerierten Passagen und der Prüfbogen. *(Bau)* Dazu `<inventar>.derived.md` (Schritt 1) und `<inventar>.extract-claude.yaml` / `.extract-gpt.yaml` (Schritte 3/4). Inventare: `bhv-dfb-2026-teil3` (A), `ihf-regel16` (B, zugleich Kapitel 1 für P6), `ihf-kapitel` (die zwei weiteren Kapitel für P6) | | `page_metrics.py` | mechanische Kennzahlen je Lauf ohne LLM (§ Bewertung). *(Bau)* Nicht `metrics.py`: `harness/compare/metrics.py` belegt den Modulnamen im selben pytest-Lauf | | `judge.py` | Richter: je Gold-Fakt und Lauf ein Urteil, Ausgabe JSON. Richter 1 über `claude -p`, Richter 2 über `copilot -p`. Dazu `consolidate` (Widersprüche) und `sample` (Stichprobe) | | `report.py` | Tabellen und Diagramme aus `results/` (Pareto Recall/Kosten, Länge/Recall) | | `test_ingest_bench.py`, `testdata/` | pytest für `page_metrics.py`, `gold.py`, `judge.py`, `report.py`, Deckelrechnung, Warteschlange und die Stub-Fälle, ohne Netz und ohne Copilot | | `results/<lauf-id>/` | je Lauf: Seiten-Diff, Seiten, `usage.json`, JSON-Protokoll, Trace, Laufmetadaten, Kennzahlen, Urteile. Dazu `results/ledger.json` (Verbrauch). Wird in #240 eingecheckt, Trockenläufe nicht (die liegen unter `<bench>/dry-run/`). | **Vorlage und Lauf-Verzeichnis.** Einmal (`bench.py template`): 1. `tools/wikitool dist export <bench>/run` aus dem Checkout unter `--stack`. 2. `instance/` hineinkopieren. 3. `git init`, lokale Identität `bench`, erster Commit, kein Remote. 4. Preflight einschließlich `tools/.venv`. 5. *(Bau)* `instructions sync`, `index rebuild`, `sources rebuild-index`, Commit: ohne sie meldet `doctor` FAIL (keine Skills, fehlende `kb/index.md`/`kb/provenance.md`). 6. `doctor` muss mit Exit 0 enden (WARN für den fehlenden Remote ist gewollt). Endet der Preflight mit Exit 42, hält `bench.py` an und zeigt die Ausgabe wörtlich, ohne etwas zu installieren. Danach wird `<bench>/run` als `<bench>/template` gesichert, mit einem Manifest aller Dateien (SHA-256). Vor jedem Lauf wird `<bench>/run` aus `template` wiederhergestellt, **am selben absoluten Pfad**: venvs lassen sich nicht verschieben. Danach wird es gegen das Manifest geprüft. Läufe gehen nacheinander, nie parallel. Gemessen: Vorlage bauen ~18 s, Wiederherstellen ~2 s. **Ein Lauf:** 1. `<bench>/run` wiederherstellen, Fixture nach `incoming/` legen. 2. `copilot -p "<prompt>" --model <m> [--reasoning-effort <e>] --allow-all-tools --trust-folder --usage-output-file usage.json --output-format json` mit Zeitlimit: A und B 30 min, P6 90 min. *(Bau)* Mit eigenem `WIKITOOL_SESSION_ID=bench-<eintrag>` (eigenes Iterationsbudget; Copilot registriert keine Session-Variable) und `WIKI_TRACE=1`. 3. Einsammeln: - Diff des Arbeitsbaums **und** der Commits gegen den Vorlagen-Commit; - `usage.json`, Protokoll, Laufzeit, Exit-Code; - `wikitool lint --json` und `page_metrics.py`. *(Bau)* Ein `wikitool validate` gibt es nicht; `lint` prüft die Frontmatter mit; - Modellfolge aus dem Protokoll; - ob ein Gate erreicht wurde (Mass-Update, Iteration-Budget, Loop-Breaker). *(Bau)* Aus dem wikitool-Trace des Laufs (`gate.refused`), nicht aus dem Copilot-Protokoll; - ob die CLI eine Effort-Stufe als nicht angewendet gemeldet hat (Muster in `queue.toml`). Ein Gate macht den Lauf nicht ungültig: Die Seiten im Arbeitsbaum werden bewertet. Eine nicht angewendete Effort-Stufe zählt nicht unter dieser Stufe. 4. Ergebnis nach `results/<lauf-id>/` schreiben, Verbrauch addieren. Der Verbrauch wird in `results/ledger.json` fortgeschrieben, damit ein abgebrochener Runner beim nächsten Start weiß, was schon verbraucht und gelaufen ist. **Deckel.** - Der Runner startet einen Lauf nur, wenn *verbraucht + Schätzung des Laufs ≤ 45 USD*. Die 5 USD darüber sind Reserve für Läufe, die teurer werden als geschätzt. - *(Bau)* Die Schätzung ist das Token-Profil aus `queue.toml` (~50 Anfragen × ~60 k Kontext: 250 k Input, 2,7 M Cache Read, 50 k Cache Write, 100 k Output), bewertet mit der Preistabelle. Effort skaliert den Output (`high` 1,5, `xhigh` 2, `max` 2,5), Fixture L das Ganze (Faktor 4, Kontext 120 k). Auto wird als Sonnet 5.5 × 0,9 geschätzt, Auto-Intelligence und HydraFusion als Opus 5.5. Preise ohne Cache-Angabe (Grok, Kimi, Haiku 4.5) werden zum Input-Preis gerechnet. - Nach P0 ersetzt der Runner die Schätzungen der übrigen Einträge durch die gemessenen Kosten je Lauf, hochgerechnet über die Preistabelle. *(Bau)* Konkret: Das Profil wird durch den Mittelwert der in P0 gemessenen Tokens ersetzt. - Liegt P0 um mehr als Faktor 2 über der Schätzung, hält er an. *(Bau)* Weiter nur mit `--accept-calibration`. - Er hält ebenso nach P2 an, damit die „besten“ Konfigurationen für P4–P6 festgelegt werden (#240). Er wählt sie nie selbst. *(Bau)* Die Einträge tragen Platzhalter (`@best_cheap_model` …); ohne `results/choices.toml` verweigert der Runner sie. - Er verweigert P1 und alles danach, solange das Inventar A nicht eingefroren ist, und P4 bzw. P6, solange die IHF-Inventare es nicht sind. *(Bau)* Die Sperre hängt an der Fixture: auch P5-B wartet auf `ihf-regel16`. - *(Bau)* Ein Lauf, der zusammen mit dem Runner abbricht, wird mit seiner Schätzung gebucht und nicht wiederholt. P7 läuft nur mit `--include-optional`. Ein Modell, das die Preistabelle nicht kennt, wird zum Preis des teuersten gerechnet. - *(Bau, Befund für #240)* Mit diesem Profil schätzt der Runner bis P6 **≈ 47 USD** statt der 44,50 der Session-Tabelle unten (P1 16,06; P3 ohne Handläufe 10,61; P6-Auto allein 6,82). Ohne die P0-Messung würde er P6-Auto am Deckel verweigern. P0 ersetzt das Profil; nach P0 in #240 mit `bench.py plan` neu ansehen. **Warteschlange** (Fixture A und Standard-Effort, wo nichts anderes steht). Schätzungen der Session vom 2026-10-20 unter der Annahme ~50 Anfragen × ~60 k Kontext, ~90 % Cache Read, ~100 k Output; P0 misst nach. | P | Läufe | Schätzung (USD) | |---|---|---:| | Gold | zweiter Extraktionsdurchgang mit GPT-6.1 Sol über alle drei Inventare | 1,00 | | P0 Kalibrierung | GPT-6 Luna, Sonnet 5.5. Dazu: Flags, Modellliste, Effort-Matrix und Standard-Effort aus dem Session-Protokoll; wird das Modell je Anfrage erfasst? | 2,70 | | P1 Kern | Opus 5.5 (Referenz), Haiku 5.5, GPT-6.1 Sol, Gemini 4 Argon, Gemini 3.8 Flash, GPT-5.6 Luna, MAI-Code-1.1-Flash, Auto (Standard-Tier) × 3 | 12,50 | | P2 Effort | Luna × {`high`, `max`}, Haiku 5.5 × {`high`, `max`}; zweiter Standard-Lauf Luna und Haiku 5.5 | 1,80 | | P3 Routing | Auto Intelligence-Tier × 2, HydraFusion × 1; Desktop App mit Auto × 2 von Hand (der Runner erfasst sie über einen Import-Befehl, der Diff und Kosten nachträgt) | 9,00 | | P4 Fixture B | Luna und Haiku 5.5, je mit Standard und der besten Effort-Stufe aus P2; Auto × 2; das beste Mittelklasse-Modell aus P1; Opus 5.5 | 9,50 | | P5 Streuung | zweiter Lauf Sonnet 5.5 auf A; dritter Lauf der besten günstigen Konfiguration auf A und B | 3,00 | | P6 Lang | ganzes IHF-Dokument im kapitelweisen Pfad: beste günstige Konfiguration × 1, Auto × 1. Achtung: Haiku 5.5 wird über 100 k Kontext fünfmal teurer. | 3,00 | | Richter 2 | GPT-6.1 Sol über Copilot | 2,00 | | | **Summe** | **≈ 44,50** | | P7 nur aus Rest | Grok 4.7, Kimi K3, Haiku 4.5, Sonnet 5.5 `high`, Luna/Haiku 5.5 `xhigh`, HydraFusion Max, Auto mit einem Prompt, der den Umfang benennt | – | *(Bau)* Wie P0 Auto-Intelligence-Tier und HydraFusion auf der Kommandozeile wählt, ist offen; die Einträge tragen die Modell-IDs `auto-intelligence`/`hydrafusion` als Platzhalter, P0 korrigiert sie samt `extra_args` in `queue.toml`. Das gilt für alle Modell-IDs, Flags und `usage.json`-Feldnamen (`bench.py` `TOKEN_KEYS`). Ebenso prüft P0, ob `copilot -p` den Prompt über stdin nimmt: Gold 2 und Richter 2 übergeben ihn sonst als Argument, was unter Windows bei ~32 k Zeichen endet. **Fixtures:** - **A (klein):** BHV DFB 2026/27 Teil III, 7 Seiten, ~4 k Tokens, unter der Längenschwelle aus #226. - **B:** IHF-Regeln 2025, Regel 16 „Die Strafen“ als Ausschnitt. *(Bau)* Regel 16 steht auf den PDF-Seiten 39–43 (gedruckt S. 38–42), nicht 39–42: PDF-Seite 43 trägt den Rest von 16:11. Fixture B nimmt die fünf Seiten; die Randpassagen aus Regel 15 und 17 werden im Gold `kein_fakt`. - **P6:** das ganze IHF-Dokument (96 Seiten), bewertet an Regel 16 und zwei weiteren Kapiteln. ## Goldinventar Das Goldinventar ist das Maß des ganzen Vergleichs. Ein Fakt, der im Gold fehlt, ist in jedem Lauf unsichtbar, und ein falscher Gold-Fakt bestraft jedes Modell, das richtig liegt. Deshalb entsteht es aus **zwei unabhängigen Extraktionen verschiedener Hersteller**, wird **mechanisch auf Abdeckung geprüft** und erst nach der **Prüfung durch den Betreiber** eingefroren. **Grundlage ist der abgeleitete Text, nicht das PDF.** Gold ist, was das Modell zu lesen bekommt: `derived.md` aus `raw derive` des exportierten Stacks. Was die Ableitung verliert (etwa Bilder), ist kein Verlust des Modells und gehört nicht ins Gold. Jedes Inventar trägt die `engine`-Zeile und den SHA-256 der `derived.md`, aus der es entstand. *(Bau)* Gehasht wird `derived.md` ohne ihre `derived:`-Zeile, die einzige, die sich bei gleicher Ableitung ändert. Ändert sich die Ableitung, wird das Inventar gegen die neue geprüft, bevor weiter gemessen wird. **Was ein Gold-Fakt ist:** - **Eine prüfbare Aussage:** Man kann auf einer Wiki-Seite entscheiden, ob sie dort steht. „Die Spielzeit beträgt 2 × 30 Minuten“ ist einer, „Regel 4 regelt die Mannschaft“ ist keiner. - **Atomar mit Feldern:** Bedingung, Ausnahme, Zahl/Frist und Modalität (*muss / soll / kann / darf nicht*) gehören zum Fakt, nicht in eigene Fakten. Eine Ausnahme, die selbst eine eigene Regel ist, wird ein eigener Fakt mit Verweis. - **Nicht aufgenommen:** Überschriften, Inhaltsverzeichnis, Kopf- und Fußzeilen, Seitenzahlen, reine Querverweise ohne eigene Aussage, Wiederholungen derselben Aussage (einmal, mit allen Fundstellen). - **`kritisch: true`** für Fakten mit Zahl/Frist, Verbot, Ausnahme oder Sanktion. Recall wird gesamt und für die kritischen Fakten getrennt berichtet. Schema je Fakt: ```yaml - id: A-017 passagen: [p12] fundstelle: "S. 3, Nr. 4.2" aussage: "…" modalitaet: darf nicht # muss | soll | kann | darf nicht | – bedingung: "…" # optional ausnahme: "…" # optional zahl: "…" # optional, Zahl oder Frist mit Einheit kritisch: true extrahiert_von: [claude, gpt] status: offen # offen | ok | geaendert | gestrichen ``` *(Bau)* Dazu nach dem Zusammenführen `strittig: {feld: {claude: …, gpt: …}}`, wo die Extraktionen in Modalität, Bedingung, Ausnahme, Zahl oder `kritisch` auseinandergehen. **Herstellung (`gold.py`, je Inventar):** 1. **Ableiten:** Fixture mit `raw derive` ableiten, `engine` und Hash festhalten. *(Bau)* In der frisch wiederhergestellten Wegwerf-Instanz, also mit dem exportierten Stand des Checkouts unter `--stack`; nichts wird im Checkout selbst abgeleitet. 2. **Passagen:** `derived.md` deterministisch in nummerierte Passagen schneiden, je Absatz bzw. Listeneintrag, mit Seitenangabe aus der Gliederung → `<inventar>.passages.yaml`. Jeder Fakt zitiert seine Passagen. *(Bau)* Seite aus den `<!-- page N -->`-Markern; eine Zeile, die einen Gliederungsabschnitt eröffnet, beginnt eine eigene Passage und setzt den Abschnitt (Zeilen des Inhaltsverzeichnisses nicht). Listeneintrag ist auch eine Zeile mit genau einem führenden Leerzeichen: so viel bleibt vom PDF-Aufzählungszeichen, das die Ableitung verliert. 3. **Extraktion 1:** Claude Opus über Claude Code (`claude -p`) mit `gold/extract-prompt.md` und den Passagen. 4. **Extraktion 2:** GPT-6.1 Sol über `copilot -p`, gleicher Prompt, ohne Kenntnis von Extraktion 1 (Budgetzeile „Gold“). 5. **Zusammenführen:** je Passage beide Ergebnisse nebeneinander. Eine Session paart gleichbedeutende Fakten und behält die Vereinigung. Sie markiert, was nur ein Durchgang fand (`extrahiert_von` mit einem Eintrag) und wo sich beide in einem Feld widersprechen. *(Bau)* Die Session liefert nur die Paare (`pairs.yaml`); Vereinigung, `extrahiert_von` und `strittig` setzt `gold.py merge`. 6. **Abdeckungsprüfung (mechanisch):** Jede Passage hat mindestens einen Fakt oder ist ausdrücklich als `kein_fakt` markiert, mit Grund (Überschrift, Verzeichnis, Fußzeile …). Eine Passage ohne beides bricht ab und wird gelistet. 7. **Prüfbogen:** `<inventar>.review.md` zeigt je Passage ihren Wortlaut und darunter ihre Fakten mit Feldern; markiert ist, was nur ein Durchgang fand oder strittig ist. Bei Stichproben-Inventaren ist markiert, welche Fakten und Passagen zum Prüfumfang gehören. - Der Betreiber setzt je Fakt `ok` / `ändern: …` / `streichen` und je Passage `fehlt: …`, wo ein Fakt fehlt. - Er prüft im Editor oder in der Gitea-Weboberfläche des privaten Repos (geht auch mobil). - Der Prüfbogen verlässt das private Repo nicht. Insbesondere wird er nicht als claude.ai-Artifact oder anderswo veröffentlicht (Fremdtext). 8. **Übernehmen und Einfrieren:** `gold.py` schreibt die Entscheidungen ins YAML zurück und setzt `geprueft: <datum>` und den Hash. **Prüfumfang:** - **A vollständig:** jeder Fakt und jede Passage. Grobe Größe: ~1.600 Wörter, schätzungsweise 60–120 Fakten, Prüfung ~1–1,5 Stunden. *(Bau)* Extraktion 1 fand 116 Fakten auf 133 Passagen. - **B (Regel 16) und die zwei weiteren Kapitel als Stichprobe:** - alle kritischen Fakten; - alle Fakten, die nur ein Durchgang fand oder die strittig sind; - ein Drittel der übrigen Passagen, deterministisch gezogen. **Die zwei weiteren IHF-Kapitel** wählt die Gold-Session in #240 nach drei Kriterien: viele Zahlen/Fristen, Ausnahmen und Modalitäten wie in Regel 16, aber ein anderer Regeltyp (z. B. eine Regel zu Spielfeld/Ausrüstung und eine zu Regelwidrigkeiten). **Was davon in diesem Issue lief:** - Für A die Schritte 1–3 und 6, also der Claude-Entwurf mit grüner Abdeckungsprüfung (§ Belege). - Schritte 4, 5, 7 und 8 sind gebaut und an erfundenen Daten getestet, laufen aber erst in #240: Schritt 4 braucht die Copilot CLI, die auf dem Linux-Entwicklungsrechner nicht eingerichtet ist, und ein Prüfbogen vor der zweiten Extraktion hieße, den Betreiber zweimal prüfen zu lassen. ## Bewertung - **Urteil:** je Gold-Fakt und Lauf *korrekt vorhanden / fehlt / verfälscht (Negation, Ausnahme, Modalität, Zahl)*, gesucht auf allen entstandenen Seiten. Die Felder des Gold-Fakts bestimmen die Art einer Verfälschung. Das Urteil hält fest, **auf welcher Seite** der Fakt steht (Source-Seite oder Entity-/Concept-Seite). - **Richter 1: Claude Opus über Claude Code** (`claude -p`) für alle Läufe. - **Richter 2: GPT-6.1 Sol über Copilot** für alle Läufe von Claude-Kandidaten (Haiku 5.5, Sonnet 5.5, Opus 5.5), damit kein Kandidat nur vom eigenen Hersteller bewertet wird. - **Widersprüche:** `judge.py` legt jeden Fall, in dem sich die Richter widersprechen, als offenen Fall für den Betreiber ab. *(Bau)* `results/<lauf>/streitfaelle.yaml` mit Feld `entscheidung`; `judge.py consolidate` schreibt `urteil.json`, offene Fälle als `offen`. - **Stichprobe:** `judge.py` zieht die geschichtete Stichprobe übereinstimmender Urteile je Modellklasse, die der Betreiber prüft. Ein Urteil allein durch ein LLM gilt nicht. *(Bau)* `results/stichprobe.yaml`; die Klasse steht je Modell in `queue.toml` (`guenstig`, `mittel`, `oben`, `auto`). Bei Nicht-Claude-Kandidaten gibt es nur Richter 1; deren Urteile gehen ebenso in die Stichprobe. `report.py` markiert Läufe als vorläufig, solange Streitfälle offen sind oder die Stichprobe ihrer Klasse ungeprüft ist. **Seitenlänge.** Länge allein ist kein Qualitätsmaß; sie wird mechanisch gemessen und neben den Recall gelegt. `page_metrics.py` zählt je Lauf ohne LLM nur den Fließtext der Seiten, ohne Frontmatter, Fußnoten-Definitionen, Überschriften und generierte Blöcke. *(Bau)* Ebenso ohne Zeilen, die das Seiten-Template gesetzt hat und der Lauf unverändert ließ (`TODO:`-Zeilen, Platzhalter-Links wie `[[Entity 1]] - kurze Beschreibung`): sonst misst die Länge den Template-Text mit. - **Wörter gesamt** über alle entstandenen bzw. geänderten Seiten, und getrennt für **Source-Seite** und **Entity-/Concept-Seiten**; - **Verdichtung:** Wörter der Seiten ÷ Wörter der `derived.md`; - **Wörter je Seite** (Median, Minimum); - **leere Template-Abschnitte:** Überschriften aus dem Seiten-Template ohne Inhalt darunter (*(Bau)* außer unveränderten Template-Zeilen); - **Seitenbild:** Seiten, Stub-Seiten, Einträge in `## Nicht übernommen`. *(Bau)* Stub-Seite: unter 40 Wörtern oder alle Template-Abschnitte leer. `report.py` verbindet das mit den Urteilen zur **Faktendichte** (korrekt vorhandene Gold-Fakten je 100 Wörter) und schreibt die Tabellen und Diagramme, die #240 § Auswertung braucht. **Windows und #167.** Unter Copilot CLI auf Windows öffnet `tools/wikitool` sporadisch im Hintergrund den Dialog „App auswählen“, einmal mit einem Hänger von über zwei Minuten (#167). Unbeaufsichtigt hängt ein solcher Lauf bis zum Zeitlimit. Deshalb markiert der Runner einen Lauf, der ins Zeitlimit läuft, als *Harness-Abbruch*: - nicht bewertet; - Kosten trotzdem gezählt (*(Bau)* aus `usage.json`, fehlt es, mit der Schätzung); - nicht automatisch wiederholt; - Protokoll für #167 bereitgelegt. ## Invarianten - **Jeder Lauf, auch ein Trockenlauf, findet in der Wegwerf-Instanz `<bench>/run` ohne Git-Remote statt.** Ein `publish` dort darf lokal committen, es hat kein Ziel zum Pushen. Kein Lauf ändert den Chemenu-Checkout unter `--stack`: `git status` dort ist vor und nach einem Lauf gleich. *(Bau)* Der Runner prüft das nach jedem Lauf und bricht sonst ab. - **Vor jedem Lauf ist `<bench>/run` inhaltlich identisch mit `<bench>/template`.** Kein Rest eines früheren Laufs beeinflusst den nächsten. *(Bau)* Geprüft gegen das Manifest, Ergebnis in `meta.json` (`template_identical`). - **Ein eingefrorenes Goldinventar ändert `gold.py` nur über einen neuen Prüfbogen.** Jede Bewertung nennt den Hash des Inventars, gegen das sie lief. - **Der Runner setzt Modell und Effort nur über Flags**, nie über `/model --repo`, `/settings` oder Nutzer-Standardwerte. Die Konfiguration des Betreibers bleibt unberührt. - **Fixtures, Inventare, Prüfbögen und Rohergebnisse verlassen `torben/chemenu-testfiles` nicht** (Fremdinhalt). - **Der Bau verbraucht keine Copilot-Credits:** kein `copilot`-Aufruf außer dem Stub. ## Abschluss der Bauphase Der Prozess lässt `stack-build` mit einem grünen CI-Lauf nach `wikitool publish` enden. Das passt hier nicht: Im Chemenu-Repo ändert sich nichts, und `chemenu-testfiles` ist ein eigenes Repo ohne CI, das `wikitool publish` nicht kennt. Invariante 5 aus `AGENTS.md` gilt für das Chemenu-Repo. In `chemenu-testfiles` wird wie bisher (Konverter-Vergleich) per `git commit` und `git push` gearbeitet; der Betreiber hat das am 2026-10-21 ohne Einzelfreigabe je Push freigegeben. Commit-Nachrichten tragen die üblichen Trailer. *(Bau)* Die Tests liegen unter `harness/` und werden damit auch vom `converters`-Workflow des Stacks eingesammelt, der `pytest ../testfiles/harness` gegen `main` von `chemenu-testfiles` ausführt (bei einem Push auf Konverter-Pfade, von Hand oder vor einem Release). Sie brauchen dafür nur `git` und den Korpus. Weil `release.yml` denselben Harness vor einem Release ohne Suffix laufen lässt, hält ein rotes `ingest-bench` künftig auch einen Release an. Ihr erster Lauf dort ist grün (§ Belege, Punkt 1). Die Bauphase endet daher, wenn 1. `pytest` über `harness/ingest-bench` unter Linux grün ist, 2. ein voller Trockenlauf grün ist (Akzeptanzkriterien unten), 3. der Gold-Entwurf A vorliegt und 4. alles als Commit in `chemenu-testfiles` gepusht ist. Diese vier Belege mit Commit-Hash stehen im Body. `stack-close` schließt dieses Issue danach. Die Kette führt zu #240. ### Belege (2026-10-21, Stack 10.1.1-beta.2, `55ddf652`) 1. **pytest:** - `tools/.venv/bin/python -m pytest -c pytest.ini ../testfiles/harness/ingest-bench`: 39 Tests grün, zusammen mit `harness/compare` 52 (keine Modul-Kollision). - Beim Abschluss (`stack-close`) der ganze Harness, `pytest -c pytest.ini ../testfiles/harness` auf `ba1eb95`: lokal (Python 3.14) 85 Tests grün in 9:13 min. - In CI derselbe Umfang über den von Hand gestarteten `converters`-Workflow: [Run 781](https://gitea.nehmer.net/torben/chemenu/actions/runs/781), Python 3.13, `85 passed in 531.48s`. 2. **Trockenlauf:** von leerem Zustand an: - `run --dry-run` hält nach P0 (Exit 3, Kalibrierung gebucht) und nach P2 (Exit 3); - danach P3 und `P4-luna-B1`, dann verweigert bei `P4-luna-best-B1` mangels Wahl (Exit 4); - nach `choices.toml` der Rest bis P6 (Exit 0), die zwei Handläufe offen. 34 Einträge ohne Wiederholung, alle mit `template_identical: true`; `git status` im Stack unverändert. Gegen die echte Instanz außerdem: - Loop-Breaker und „Effort nicht angewendet“ erfasst, Lauf gültig (`P7-luna-xhigh-A1`); - Zeitlimit 20 s → Harness-Abbruch, Kosten gezählt, beim Neustart nicht wiederholt (`P7-grok-A1`); - Handlauf über `prepare`/`import` (`P3-desktop-A1`); - `forget` mit Ablage als `.verworfen-1`. Gefunden und behoben im Trockenlauf: Der Stub las die `raw/`-Pfade aus umbrochener Ausgabe (B-Läufe ohne Source-Seite). 3. **Gold-Entwurf A:** - `gold/bhv-dfb-2026-teil3.passages.yaml`: 133 Passagen, `derived_sha256` `a5733f08…5c48`, `engine: wikitool 10.1.1-beta.2 + pypdf 6.21.1 + pdfminer.six 20260107`; - `gold/bhv-dfb-2026-teil3.extract-claude.yaml`: 116 Fakten, 54 kritisch, 31 `kein_fakt`; - `gold.py check --extract claude` grün. 4. **Commit:** `chemenu-testfiles` `ba1eb95`, gepusht auf `main`. Im Chemenu-Repo kein Commit, kein Bump. Copilot-Verbrauch: 0 USD (kein `copilot` auf dem Rechner, nur der Stub). ## Akzeptanzkriterien - [x] **Trockenlauf:** `bench.py --dry-run` arbeitet unter Linux die ganze Warteschlange mit dem Stub ab: Vorlage bauen (`doctor` grün), wiederherstellen, einsammeln, `page_metrics.py`, Deckelrechnung, Fortschreiben des Verbrauchs. Er hält nach P0 und nach P2 an und setzt nach einem Neustart dort fort, ohne einen gelaufenen Eintrag zu wiederholen. Nach jedem Lauf ist `<bench>/run` vor dem nächsten wieder identisch mit `template`, und `git status` im Chemenu-Checkout ist unverändert. - [x] **Deckel:** Ein Test belegt, dass der Runner einen Lauf nicht startet, wenn *verbraucht + Schätzung > 45 USD*; dass er nach P0 die Schätzungen aus den gemessenen Kosten neu rechnet; und dass er bei einem P0 über Faktor 2 anhält. - [x] **Sperren:** Ein Test belegt, dass P1 und alles danach ohne eingefrorenes Inventar A verweigert wird, und P4/P6 ohne eingefrorene IHF-Inventare. - [x] **Stub-Fälle:** Mit dem Stub nachgestellt, wird ein Zeitlimit als Harness-Abbruch markiert, nicht bewertet und nicht wiederholt. Ein erreichtes Gate wird festgehalten, ohne den Lauf ungültig zu machen. Eine als nicht angewendet gemeldete Effort-Stufe wird festgehalten. - [x] **`page_metrics.py`** liefert für eine Seite mit bekanntem Inhalt (Test-Fixture im Harness) die erwartete Wortzahl und erkennt einen leeren Template-Abschnitt. Frontmatter, Fußnoten-Definitionen und Überschriften zählen nicht mit. - [x] **`gold.py`** bricht ab, wenn eine Passage weder einen Fakt hat noch als `kein_fakt` markiert ist. Ein Prüfbogen mit `ok` / `ändern: …` / `streichen` / `fehlt: …` wird ins YAML zurückgeschrieben (Test an erfundenen Daten). Jedes eingefrorene Inventar trägt `geprueft`, den Hash seiner `derived.md` und deren `engine`-Zeile. Die Stichprobe ist deterministisch. - [x] **`judge.py`** liefert mit Stub-Antworten je Gold-Fakt ein JSON-Urteil mit Seite. Ein Widerspruch zwischen zwei Richtern wird als offener Fall für den Betreiber abgelegt. - [x] **`report.py`** erzeugt aus erfundenen Ergebnissen die Tabelle Modell × Effort × Fixture sowie die Diagramme Pareto Recall/Kosten und Länge/Recall. - [x] **Gold-Entwurf A:** `gold/bhv-dfb-2026-teil3.passages.yaml` mit Hash und `engine`-Zeile, Claude-Extraktion im YAML (*(Bau)* `gold/bhv-dfb-2026-teil3.extract-claude.yaml`), Abdeckungsprüfung grün. Noch nicht zusammengeführt und nicht geprüft. - [x] **README** beschreibt Einrichtung unter Windows (pwsh 7) und Linux, den Ablauf von #240, das Fortsetzen und das Ausfüllen des Prüfbogens. - [x] **Abschluss:** Commit in `chemenu-testfiles` gepusht (`ba1eb95`). Im Chemenu-Repo kein Commit, kein `wikitool publish`, kein Versions-Bump. Copilot-Verbrauch des Baus: 0 USD. ## Versionsteil Keiner: Der Runner liegt in `torben/chemenu-testfiles`, am Stack ändert sich keine Datei. Braucht die Wegwerf-Instanz doch eine Stack-Änderung, bekommt diese ein eigenes Issue mit eigenem Versionsteil. ## Verwandt #240 (Messung und Bericht, Nachfolger), #224 (Ursprung), #21 (Abnehmer des Ergebnisses von #240), #167 (Windows-Dialog unter Copilot CLI), #175 (Stub-Seiten mit unbeschriebenen Template-Abschnitten: dieselbe Erscheinung, die `page_metrics.py` als „leere Template-Abschnitte“ zählt), #80 (Claude-Code-Runner für L3-Evals: ob dieser Runner später darin aufgeht, entscheidet #80), #69 (Reproduktionslauf, gleiche Wegwerf-Logik), #226 (Pipeline 2), #231 (Form der Ableitung), `instructions/dev/converter-comparison.md` (Vorbild für ein Harness in `chemenu-testfiles`). ## Kette Kette „Ingest-Modellvergleich“ - Vorgänger: keiner - erstes Glied - Nachfolger: #240
torben added the prio/plannedsize/Marea/processkind/build labels 2026-10-13 20:59:27 +00:00
Author
Owner

Hinweis aus #225/#231 (2026-10-14), keine Body-Änderung nötig:

  • Die Ableitung der Fixtures ändert sich: Seit 10.1.0-beta.1 trägt derived.md von IHF und BHV III eine Gliederung und Kennzeichnungen. Mit #231 wird die Form auf ~~/**/* reduziert (IHF ≈ +3 % statt deutlich mehr). Läufe vor und nach #231 sind deshalb nicht direkt vergleichbar. Im Bericht je Lauf die engine-Zeile aus dem Kopf von derived.md nennen; am besten erst nach #231 messen.
  • Die Fixtures müssen nicht mehr außerhalb liegen: Das private Korpus-Repo aus #232 (torben/chemenu-testfiles) nimmt auch nicht-öffentliche Quellen auf. IHF und BHV I–III liegen dort nach #232 bereits.
Hinweis aus #225/#231 (2026-10-14), keine Body-Änderung nötig: - Die Ableitung der Fixtures ändert sich: Seit 10.1.0-beta.1 trägt `derived.md` von IHF und BHV III eine Gliederung und Kennzeichnungen. Mit #231 wird die Form auf `~~`/`**`/`*` reduziert (IHF ≈ +3 % statt deutlich mehr). Läufe vor und nach #231 sind deshalb nicht direkt vergleichbar. Im Bericht je Lauf die `engine`-Zeile aus dem Kopf von `derived.md` nennen; am besten erst nach #231 messen. - Die Fixtures müssen nicht mehr außerhalb liegen: Das private Korpus-Repo aus #232 (`torben/chemenu-testfiles`) nimmt auch nicht-öffentliche Quellen auf. IHF und BHV I–III liegen dort nach #232 bereits.
torben changed title from Modellvergleich beim Ingest: Recall harter Fakten unter GPT-6 Luna, Claude Haiku 4.5 und Sonnet – Handlauf auf festem Fixture to Modellvergleich beim Ingest unter GitHub Copilot: Recall harter Fakten über alle verfügbaren Modelle, Effort-Stufen und Auto – automatisierter Lauf auf festen Fixtures 2026-10-19 20:28:36 +00:00
torben added size/Lkind/decision and removed size/Mkind/build labels 2026-10-19 20:28:37 +00:00
Author
Owner

Changelog (2026-10-19/20): Umfang auf Wunsch des Betreibers erweitert: Modellklassen × Effort × Auto statt Luna/Haiku 4.5/Sonnet von Hand, und als neue Teilfrage, ob Auto mitten im Lauf das Modell wechselt. Neu: Recherche (Auto routet laut Doku und CLI 1.0.81 auch während des Gesprächs; CLI skriptbar; Abrechnung über AI Credits; Preise und Effort-Katalog aus der Perplexity-Recherche des Betreibers), ein automatisierter Runner in chemenu-testfiles/harness/ingest-bench/ mit Dateiliste, Vorlage/Lauf-Verzeichnis am festen Pfad, priorisierte Warteschlange P0–P7 unter einem 50-USD-Deckel, Effort-Vorschlag (Standard überall, high/max nur bei Luna und Haiku 5.5, kein low/xhigh), zwei Richter (Claude Opus über Claude Code, GPT-6.1 Sol für Claude-Kandidaten), Umgang mit #167 unter Windows. Entschieden (Betreiber, 2026-10-20): E4 geändert auf automatisiert; AI Credits, Deckel 50 USD; ohne Astra/Fable, Opus 5.5 als obere Referenz; CLI plus zwei Handläufe in der Desktop App; Windows, Linux als Plan B. Korrigiert: Modellliste veraltet (Haiku 5.5 statt 4.5 als Gegenstück zu Luna, gleicher Preis), Pipeline (2) ist gebaut. Labels: size/M → size/L (Runner, Gold, mehrere Sitzungen); kind/build bleibt, die zwischenzeitlich offenen Fragen sind beantwortet.

**Changelog (2026-10-19/20):** Umfang auf Wunsch des Betreibers erweitert: Modellklassen × Effort × Auto statt Luna/Haiku 4.5/Sonnet von Hand, und als neue Teilfrage, ob Auto mitten im Lauf das Modell wechselt. Neu: Recherche (Auto routet laut Doku und CLI 1.0.81 auch während des Gesprächs; CLI skriptbar; Abrechnung über AI Credits; Preise und Effort-Katalog aus der Perplexity-Recherche des Betreibers), ein automatisierter Runner in `chemenu-testfiles/harness/ingest-bench/` mit Dateiliste, Vorlage/Lauf-Verzeichnis am festen Pfad, priorisierte Warteschlange P0–P7 unter einem 50-USD-Deckel, Effort-Vorschlag (Standard überall, `high`/`max` nur bei Luna und Haiku 5.5, kein `low`/`xhigh`), zwei Richter (Claude Opus über Claude Code, GPT-6.1 Sol für Claude-Kandidaten), Umgang mit #167 unter Windows. Entschieden (Betreiber, 2026-10-20): E4 geändert auf automatisiert; AI Credits, Deckel 50 USD; ohne Astra/Fable, Opus 5.5 als obere Referenz; CLI plus zwei Handläufe in der Desktop App; Windows, Linux als Plan B. Korrigiert: Modellliste veraltet (Haiku 5.5 statt 4.5 als Gegenstück zu Luna, gleicher Preis), Pipeline (2) ist gebaut. Labels: `size/M` → `size/L` (Runner, Gold, mehrere Sitzungen); `kind/build` bleibt, die zwischenzeitlich offenen Fragen sind beantwortet.
torben changed title from Modellvergleich beim Ingest unter GitHub Copilot: Recall harter Fakten über alle verfügbaren Modelle, Effort-Stufen und Auto – automatisierter Lauf auf festen Fixtures to Modellvergleich beim Ingest unter GitHub Copilot: Recall harter Fakten über die Modellklassen, Effort am günstigen Ende und Auto – automatisierter Lauf mit 50-USD-Deckel 2026-10-20 19:56:53 +00:00
torben added kind/build and removed kind/decision labels 2026-10-20 19:56:53 +00:00
Author
Owner

Changelog (2026-10-20, Nachtrag): Annahme zu Claude Code ist jetzt Entscheidung (läuft separat, zählt nicht zum Deckel). Neuer Abschnitt „Goldinventar“: Grundlage derived.md mit Hash, Fakt-Definition und YAML-Schema, kritisch-Markierung, Herstellung in acht Schritten (zwei unabhängige Extraktionen Claude Opus / GPT-6.1 Sol, Zusammenführung, mechanische Abdeckungsprüfung je Passage, Prüfbogen im privaten Repo, Einfrieren), Prüfumfang, Wahl der zwei weiteren IHF-Kapitel. Neu: Dateien gold.py, gold/extract-prompt.md, Passagen- und Prüfbogen-Dateien; Budgetzeile „Gold“ (1 USD, Summe jetzt ≈ 44,50); Invariante „eingefrorenes Gold ändert sich nur durch erneute Prüfung“; ein Akzeptanzkriterium für gold.py. Regel 16 dient zugleich als Fixture B und als Kapitel 1 für P6. Danach, auf Beobachtung des Betreibers („Seiten unter Luna zu kurz“): Frage 4 und Abschnitt „Seitenlänge“ – mechanische Kennzahlen (Wörter gesamt/Source/Entity-Concept, Verdichtung, Wörter je Seite, leere Template-Abschnitte) über neues metrics.py, Faktendichte, Streudiagramm Länge/Recall mit drei möglichen Befunden; Urteil hält die Seite fest, auf der ein Fakt steht; Akzeptanzkriterium für metrics.py; #175 verlinkt. Keine Kosten, Deckel unverändert.

**Changelog (2026-10-20, Nachtrag):** Annahme zu Claude Code ist jetzt Entscheidung (läuft separat, zählt nicht zum Deckel). Neuer Abschnitt „Goldinventar“: Grundlage `derived.md` mit Hash, Fakt-Definition und YAML-Schema, `kritisch`-Markierung, Herstellung in acht Schritten (zwei unabhängige Extraktionen Claude Opus / GPT-6.1 Sol, Zusammenführung, mechanische Abdeckungsprüfung je Passage, Prüfbogen im privaten Repo, Einfrieren), Prüfumfang, Wahl der zwei weiteren IHF-Kapitel. Neu: Dateien `gold.py`, `gold/extract-prompt.md`, Passagen- und Prüfbogen-Dateien; Budgetzeile „Gold“ (1 USD, Summe jetzt ≈ 44,50); Invariante „eingefrorenes Gold ändert sich nur durch erneute Prüfung“; ein Akzeptanzkriterium für `gold.py`. Regel 16 dient zugleich als Fixture B und als Kapitel 1 für P6. Danach, auf Beobachtung des Betreibers („Seiten unter Luna zu kurz“): Frage 4 und Abschnitt „Seitenlänge“ – mechanische Kennzahlen (Wörter gesamt/Source/Entity-Concept, Verdichtung, Wörter je Seite, leere Template-Abschnitte) über neues `metrics.py`, Faktendichte, Streudiagramm Länge/Recall mit drei möglichen Befunden; Urteil hält die Seite fest, auf der ein Fakt steht; Akzeptanzkriterium für `metrics.py`; #175 verlinkt. Keine Kosten, Deckel unverändert.
torben changed title from Modellvergleich beim Ingest unter GitHub Copilot: Recall harter Fakten über die Modellklassen, Effort am günstigen Ende und Auto – automatisierter Lauf mit 50-USD-Deckel to Modellvergleich beim Ingest unter GitHub Copilot – Werkzeug: Runner, Goldinventar und Bewertung in chemenu-testfiles, Trockenlauf unter Linux 2026-10-21 04:50:13 +00:00
Author
Owner

Changelog (2026-10-21): Bau und Messung auf Entscheidung des Betreibers getrennt. Dieses Issue ist jetzt nur noch das Bau-Issue; Fragen, Ablauf über die Sitzungen, Stand, Auswertung und die Mess-Kriterien sind nach #240 umgezogen.

Neu in diesem Body:

  • § Abschluss der Bauphase: endet mit grünem pytest, grünem Trockenlauf, Gold-Entwurf A und Push nach chemenu-testfiles, statt mit wikitool publish und CI. Der Push geht per git, ohne Einzelfreigabe.
  • Präzisierungen für einen Bau aus dem Body heraus: Interpreter, --stack, <bench> außerhalb beider Repos, copilot_stub.py, test_ingest_bench.py, fortgeschriebener Verbrauch für Neustarts, Import-Befehl für die App-Läufe, Preflight-Exit 42 hält den Runner an.
  • § Goldinventar: Hier laufen für A nur die Schritte 1–3 und 6; Schritte 4, 5, 7 und 8 laufen in #240.
  • Akzeptanzkriterien: auf den Bau zugeschnitten (Trockenlauf, Deckel, Sperren, Stub-Fälle, Tests je Modul, Gold-Entwurf A, README, Abschluss).
  • ## Kette „Ingest-Modellvergleich“ → #240.

Titel angepasst. #21 hängt jetzt an #240.

**Changelog (2026-10-21):** Bau und Messung auf Entscheidung des Betreibers getrennt. Dieses Issue ist jetzt nur noch das Bau-Issue; Fragen, Ablauf über die Sitzungen, Stand, Auswertung und die Mess-Kriterien sind nach #240 umgezogen. Neu in diesem Body: - **§ Abschluss der Bauphase:** endet mit grünem `pytest`, grünem Trockenlauf, Gold-Entwurf A und Push nach `chemenu-testfiles`, statt mit `wikitool publish` und CI. Der Push geht per `git`, ohne Einzelfreigabe. - **Präzisierungen für einen Bau aus dem Body heraus:** Interpreter, `--stack`, `<bench>` außerhalb beider Repos, `copilot_stub.py`, `test_ingest_bench.py`, fortgeschriebener Verbrauch für Neustarts, Import-Befehl für die App-Läufe, Preflight-Exit 42 hält den Runner an. - **§ Goldinventar:** Hier laufen für A nur die Schritte 1–3 und 6; Schritte 4, 5, 7 und 8 laufen in #240. - **Akzeptanzkriterien:** auf den Bau zugeschnitten (Trockenlauf, Deckel, Sperren, Stub-Fälle, Tests je Modul, Gold-Entwurf A, README, Abschluss). - **`## Kette`** „Ingest-Modellvergleich“ → #240. Titel angepasst. #21 hängt jetzt an #240.
Author
Owner

Changelog: Build-Session 2026-10-21: Werkzeug gebaut und als chemenu-testfiles ba1eb95 gepusht; alle Akzeptanzkriterien abgehakt, die vier Belege stehen in § Abschluss der Bauphase › Belege.

Abweichungen vom Entwurf, im Body mit (Bau) markiert:

  • metrics.py heißt page_metrics.py: Namenskollision mit harness/compare/metrics.py.
  • Es gibt kein wikitool validate, nur lint --json.
  • Fixture B umfasst die PDF-Seiten 39–43 statt 39–42 (dort endet Regel 16).
  • Die Vorlage braucht zusätzlich instructions sync, index rebuild und sources rebuild-index, sonst ist doctor nicht grün.
  • Der derived.md-Hash wird ohne die derived:-Zeile gebildet.
  • Unveränderte Template-Zeilen zählen in page_metrics weder als Wörter noch als Inhalt.
  • Gates werden aus dem wikitool-Trace gelesen.
  • P7 läuft nur mit --include-optional.
  • Die Wahl nach P2 steht in choices.toml.
  • Neue Dateien: gold/judge-prompt.md, choices.example.toml, testdata/, <inv>.derived.md, <inv>.extract-<von>.yaml.

Befund für #240: Die Runner-Schätzung über Profil × Preistabelle liegt bis P6 bei ≈ 47 USD statt 44,50. Nach P0 sollte bench.py plan neu angesehen werden.

**Changelog:** Build-Session 2026-10-21: Werkzeug gebaut und als `chemenu-testfiles` `ba1eb95` gepusht; alle Akzeptanzkriterien abgehakt, die vier Belege stehen in § Abschluss der Bauphase › Belege. Abweichungen vom Entwurf, im Body mit *(Bau)* markiert: - `metrics.py` heißt `page_metrics.py`: Namenskollision mit `harness/compare/metrics.py`. - Es gibt kein `wikitool validate`, nur `lint --json`. - Fixture B umfasst die PDF-Seiten 39–43 statt 39–42 (dort endet Regel 16). - Die Vorlage braucht zusätzlich `instructions sync`, `index rebuild` und `sources rebuild-index`, sonst ist `doctor` nicht grün. - Der `derived.md`-Hash wird ohne die `derived:`-Zeile gebildet. - Unveränderte Template-Zeilen zählen in `page_metrics` weder als Wörter noch als Inhalt. - Gates werden aus dem wikitool-Trace gelesen. - P7 läuft nur mit `--include-optional`. - Die Wahl nach P2 steht in `choices.toml`. - Neue Dateien: `gold/judge-prompt.md`, `choices.example.toml`, `testdata/`, `<inv>.derived.md`, `<inv>.extract-<von>.yaml`. Befund für #240: Die Runner-Schätzung über Profil × Preistabelle liegt bis P6 bei ≈ 47 USD statt 44,50. Nach P0 sollte `bench.py plan` neu angesehen werden.
Author
Owner

Changelog (stack-close, 2026-10-21):

  • Stand-Zeile: auf „abgeschlossen“ gesetzt, mit Verweis auf #240.
  • Belege, Punkt 1: neu ist der ganze Harness im Umfang des converters-Workflows (pytest ../testfiles/harness auf ba1eb95): 85 Tests grün.
  • § Abschluss der Bauphase: ergänzt, dass ein rotes ingest-bench künftig auch den Harness-Job vor einem Release ohne Suffix rot macht.
  • Docs-Prüfung: Keine Stack-Datei ist veraltet, weil am Stack nichts geändert wurde. instructions/dev/testing-conventions.md § Scope und docs/dev/development.md beschreiben harness/ weiterhin zutreffend.

Geschlossen; die Kette geht weiter mit #240.

**Changelog (stack-close, 2026-10-21):** - **Stand-Zeile:** auf „abgeschlossen“ gesetzt, mit Verweis auf #240. - **Belege, Punkt 1:** neu ist der ganze Harness im Umfang des `converters`-Workflows (`pytest ../testfiles/harness` auf `ba1eb95`): 85 Tests grün. - **§ Abschluss der Bauphase:** ergänzt, dass ein rotes `ingest-bench` künftig auch den Harness-Job vor einem Release ohne Suffix rot macht. - **Docs-Prüfung:** Keine Stack-Datei ist veraltet, weil am Stack nichts geändert wurde. `instructions/dev/testing-conventions.md` § Scope und `docs/dev/development.md` beschreiben `harness/` weiterhin zutreffend. Geschlossen; die Kette geht weiter mit #240.
Author
Owner

Nachtrag (2026-10-21): Der converters-Workflow wurde von Hand gestartet und ist grün: Run 781, Stack 55ddf652 gegen chemenu-testfiles ba1eb95. Ergebnis: 85 passed in 531.48s unter Python 3.13 im CI-Container. Damit sind die Tests von ingest-bench zum ersten Mal in CI gelaufen; der Body nennt den Lauf in § Abschluss der Bauphase und unter Belege, Punkt 1.

**Nachtrag (2026-10-21):** Der `converters`-Workflow wurde von Hand gestartet und ist grün: [Run 781](https://gitea.nehmer.net/torben/chemenu/actions/runs/781), Stack `55ddf652` gegen `chemenu-testfiles` `ba1eb95`. Ergebnis: `85 passed in 531.48s` unter Python 3.13 im CI-Container. Damit sind die Tests von `ingest-bench` zum ersten Mal in CI gelaufen; der Body nennt den Lauf in § Abschluss der Bauphase und unter Belege, Punkt 1.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#228