Länge als dritte Größenachse beim Ingest: CHECK ab ~15 k Tokens, kapitelweise Units nach der Gliederung, Extrakt als Faktenliste #226

Closed
opened 2026-10-13 20:58:40 +00:00 by torben · 4 comments
Owner

Abgespalten aus #224 (Entscheidung E2 vom 2026-10-13). Zweites Glied der Kette „Große Dokumente“; baut auf der Gliederung mit Zeilennummern aus #225 auf.

Problem (behoben)

instructions/ingest-large-tree.md § When to run kannte zwei Achsen: Volumen (> ~20 Rohdateien, > ~15 raw_files:) und Breite (> ~20 Entities+Concepts). Ein einzelnes langes Dokument mit wenigen Themen löste keine davon aus und lief durch wiki-ingest, dessen Schritt 1 „Read the file completely“ verlangte – bei den IHF-Regeln 2025 ~60 k Tokens in einem Zug, auf jedem Modell.

Selbst im Workshop-Pfad für breite Quellen (§ „A broad source is not cut“) las Schritt 5a „every raw file in the unit, in full“: Bei einer Datei pro Unit las jede Unit wieder das ganze Dokument.

Dazu kommt die Grundlast: Ein Ingest lädt AGENTS.md, den Skill, kb/CONTRACT.md, kb/CONVENTIONS.md, die COLLECTION.md-Dateien, Teile von raw/CONTRACT.md usw. – zusammen gemessen ~180 KB, also grob 30–45 k Tokens, ohne Systemprompt und Tool-Definitionen des Harness.

Recherche (in #224 zusammengefasst): Bei Zusammenfassungen dominieren Auslassungen gegenüber Verfälschungen (ARC, EACL 2026: ~28 % fehlende vs. ~3 % falsch wiedergegebene Fakten ab 7B). Kleine Modelle verlieren mit wachsender Länge überproportional (NoLiMa, ICML 2025: deutliche Einbrüche schon zwischen 8 k und 32 k). Und eine mehrstufige Verdichtung (Kapitel zusammenfassen, dann die Zusammenfassungen zusammenfassen) verliert ihren Vorteil wieder (NAACL 2025). Kapitelweise also ja – aber als Faktenliste mit verlustarmer Zusammenführung, nicht als Zusammenfassung von Zusammenfassungen.

Entscheidungen (umgesetzt)

  • Länge ist die dritte Achse. Schwelle laut Betreiber ~15 k Tokens – lieber früh als spät, weil Harness und Skills schon viel Kontext belegen.
  • Gemessen in Zeichen, nicht in Tokens: Zeichen sind deterministisch und modellunabhängig; Tokens hängen vom Tokenizer ab. Umrechnung für Deutsch ~3,3 Zeichen/Token → 50.000 Zeichen; für englischen Text ~12,5 k Tokens, also auf der vorsichtigen Seite. Gezählt werden die Zeichen der geschriebenen .md, Kopf eingeschlossen – das, was eine Sitzung liest, dieselbe Größe wie wc -m. Am Original: IHF 204.713, BHV Teil I 101.453 → Zeile; BHV Teil II 9.884, Teil III 15.048 → keine.
  • Der Wert steht an einer Stelle: LONG_TEXT_CHARS = 50_000 in tools/chemenu/commands/raw/_common.py, gelesen von raw derive, raw fetch und raw pending. raw derive und raw fetch geben je Lauf eine CHECK-Zeile aus, die jede zu lange .md nennt („Longer than one ingest reads in one pass (50,000 characters): ( characters). Read it in parts - instructions/ingest-large-tree.md, the length axis.“); raw fetch auch für eine wie empfangen abgelegte text/plain-/text/markdown-Antwort. Die -h-Notizen setzen den Wert aus der Konstante ein, daher steht er auch in den generierten tools/CONTRACT.md und docs/reference/commands/raw-material-and-uploads.md; von Hand nur in der Konstante. ingest-large-tree.md und wiki-ingest routen auf die CHECK-Zeile und nennen den Wert nicht (Invariante 8).
  • Textdatei ohne Ableitung: raw pending zeigt eine einzelne .md/.txt über der Schwelle mit long: <n> characters an (JSON: length, sonst null). Es liest den Inhalt nur, wenn die Größe in Bytes über der Schwelle liegt (UTF-8 hat nie mehr Zeichen als Bytes), sonst bleibt es bei lstat. Für eine Textdatei außerhalb von incoming/ nennt wiki-ingest Schritt 1 wc -m mit Verweis auf den Wert in raw derive -h.
  • Route wie Breite, nicht wie Volumen: ein Raw-File, eine Source-Seite (raw/ bleibt ungeschnitten, ein Raw-File hat einen Eigentümer). Der Workshop dient dem Lesen in Teilen und dem Extrakt.
  • Units nach der Gliederung: je Unit ein Seitenbereich, geschnitten an der höchsten Gliederungsebene, deren Abschnitte unter der Schwelle bleiben; ein größerer Abschnitt (IHF „II. Erläuterungen“, S. 56–78) an der nächsten Ebene oder an Seitengrenzen. Ohne Gliederung: Seitenbereiche nach <!-- page N -->; ohne Seitenmarken (abgerufene Seite, Klartext) an den eigenen Überschriften, sonst nach Zeilennummern. plan.md hält je Unit Titel, Seiten und Zeilenbereich fest.
  • Schritt 5a liest nur den Zeilenbereich der Unit (den Kopf einmal, in der ersten Unit), nie die ganze Datei je Unit.
  • Schritt 5b auf dem Längen-Pfad: der Extrakt ist eine Faktenliste, je Eintrag mit Fundstelle (Seite, Regel-/Abschnittsnummer) und – wo vorhanden – Bedingung, Ausnahme, Frist/Zahl und Modalität (muss/soll/kann/darf nicht). Die Source-Seite entsteht aus den Faktenlisten aller Units, nicht aus Zusammenfassungen; Schritte 5d–5e laufen einmal, nach der letzten Unit.
  • Länge und Breite zusammen: derselbe Workshop; die Auswahl der seitenwürdigen Themen läuft über die gesammelten Extrakte.

Geänderte Dateien

  • Code: tools/chemenu/commands/raw/_common.py (Konstante, _long_text_check, _plain_text_length), derive.py, fetch.py, pending.py; Tests in tools/chemenu/tests/test_raw_derive.py (Grenze an der Konstante, Zeichen statt Bytes, Ordner und ZIP, raw pending) und test_raw_fetch.py (abgeleitete Seite, Klartext).
  • instructions/ingest-large-tree.md: § When to run (dritte Achse mit Begründung), § Tiers (Zeile „Long“), neuer Abschnitt „A long source is read in parts“, Schritte 3, 5a, 5b, 5d, ein Entscheidungspunkt, § Scope.
  • instructions/wiki-ingest/SKILL.md Schritt 1 („Check the size first, on all three axes“) und § Decision points.
  • types/source.guidance.md: ## Not Extracted ist auf jeder Achse Pflicht, auch auf dem Längen-Pfad.
  • raw/CONTRACT.md (§ raw derive: „A text too long for one pass is named.“), tools/CONTRACT.md und docs/reference/commands/raw-material-and-uploads.md (generiert), docs/how-to/ingest-a-source.md, docs/explanation/knowledge-and-commitment.md (Abschluss), CHANGES.md (Abschnitt „Lange Dokumente: Länge als dritte Größenachse“).

Akzeptanzkriterien

  • raw derive auf das IHF-PDF und auf BHV Teil I gibt die Längen-CHECK-Zeile aus; auf BHV Teil II und III nicht. Ein Test prüft die Grenze an der Konstante (knapp darunter: keine Zeile, knapp darüber: Zeile).
  • raw fetch gibt dieselbe Zeile für eine abgeleitete Seite über der Schwelle aus.
  • Der Zahlenwert der Schwelle steht genau einmal im Repo (der Konstante; die generierten Referenzen setzen ihn daraus ein); ingest-large-tree.md und wiki-ingest verweisen auf die CHECK-Zeile.
  • ingest-large-tree.md beschreibt drei Achsen; der Längen-Pfad schreibt vor, dass Schritt 5a nur den Zeilenbereich der Unit liest, und dass der Extrakt eine Faktenliste mit Fundstelle und Modalität ist.
  • Für eine Datei ohne Gliederung ist der Schnitt nach Seitenbereichen beschrieben.
  • pytest, docs verify, instructions verify grün (lokal 3080 passed, 4 skipped; CI-Lauf 729).

Versionsteil

MINOR. Drop-in: neue CHECK-Zeile, ein zusätzliches JSON-Feld length in raw pending --json und eine zusätzliche Route in den Anweisungen; keine Kopfzeile, kein Frontmatter-Feld, kein Befehl ändert sich inkompatibel, kb/ bleibt unberührt.

Ergebnis

Ausgeliefert in 10.1.0-beta.10, Commit eae4a42, verifiziert durch CI-Lauf 729, Converters-Lauf 730 (echte Dokumente des privaten Korpus) und release.yml-Lauf 731 (Kandidat, kein Release), alle grün. Beim Abschluss nachgezogen: docs/explanation/knowledge-and-commitment.md nennt auch die lange Quelle (Commit 4f5913a, nur docs/, kein Bump), CI-Lauf 732 grün.

Kette

Kette „Große Dokumente“

Abgespalten aus #224 (Entscheidung E2 vom 2026-10-13). Zweites Glied der Kette „Große Dokumente“; baut auf der Gliederung mit Zeilennummern aus #225 auf. ## Problem (behoben) `instructions/ingest-large-tree.md` § When to run kannte zwei Achsen: **Volumen** (> ~20 Rohdateien, > ~15 `raw_files:`) und **Breite** (> ~20 Entities+Concepts). Ein einzelnes langes Dokument mit wenigen Themen löste keine davon aus und lief durch `wiki-ingest`, dessen Schritt 1 „Read the file completely“ verlangte – bei den IHF-Regeln 2025 ~60 k Tokens in einem Zug, auf jedem Modell. Selbst im Workshop-Pfad für breite Quellen (§ „A broad source is not cut“) las Schritt 5a „every raw file in the unit, in full“: Bei einer Datei pro Unit las jede Unit wieder das ganze Dokument. Dazu kommt die Grundlast: Ein Ingest lädt `AGENTS.md`, den Skill, `kb/CONTRACT.md`, `kb/CONVENTIONS.md`, die `COLLECTION.md`-Dateien, Teile von `raw/CONTRACT.md` usw. – zusammen gemessen ~180 KB, also grob 30–45 k Tokens, ohne Systemprompt und Tool-Definitionen des Harness. Recherche (in #224 zusammengefasst): Bei Zusammenfassungen dominieren **Auslassungen** gegenüber Verfälschungen (ARC, EACL 2026: ~28 % fehlende vs. ~3 % falsch wiedergegebene Fakten ab 7B). Kleine Modelle verlieren mit wachsender Länge überproportional (NoLiMa, ICML 2025: deutliche Einbrüche schon zwischen 8 k und 32 k). Und eine **mehrstufige** Verdichtung (Kapitel zusammenfassen, dann die Zusammenfassungen zusammenfassen) verliert ihren Vorteil wieder (NAACL 2025). Kapitelweise also ja – aber als Faktenliste mit verlustarmer Zusammenführung, nicht als Zusammenfassung von Zusammenfassungen. ## Entscheidungen (umgesetzt) - **Länge ist die dritte Achse.** Schwelle laut Betreiber **~15 k Tokens** – lieber früh als spät, weil Harness und Skills schon viel Kontext belegen. - **Gemessen in Zeichen, nicht in Tokens:** Zeichen sind deterministisch und modellunabhängig; Tokens hängen vom Tokenizer ab. Umrechnung für Deutsch ~3,3 Zeichen/Token → **50.000 Zeichen**; für englischen Text ~12,5 k Tokens, also auf der vorsichtigen Seite. Gezählt werden die Zeichen der **geschriebenen `.md`, Kopf eingeschlossen** – das, was eine Sitzung liest, dieselbe Größe wie `wc -m`. Am Original: IHF 204.713, BHV Teil I 101.453 → Zeile; BHV Teil II 9.884, Teil III 15.048 → keine. - **Der Wert steht an einer Stelle:** `LONG_TEXT_CHARS = 50_000` in `tools/chemenu/commands/raw/_common.py`, gelesen von `raw derive`, `raw fetch` und `raw pending`. `raw derive` und `raw fetch` geben je Lauf eine `CHECK`-Zeile aus, die jede zu lange `.md` nennt („Longer than one ingest reads in one pass (50,000 characters): <Pfad> (<n> characters). Read it in parts - instructions/ingest-large-tree.md, the length axis.“); `raw fetch` auch für eine wie empfangen abgelegte `text/plain`-/`text/markdown`-Antwort. Die `-h`-Notizen setzen den Wert aus der Konstante ein, daher steht er auch in den **generierten** `tools/CONTRACT.md` und `docs/reference/commands/raw-material-and-uploads.md`; von Hand nur in der Konstante. `ingest-large-tree.md` und `wiki-ingest` routen auf die `CHECK`-Zeile und nennen den Wert nicht (Invariante 8). - **Textdatei ohne Ableitung:** `raw pending` zeigt eine einzelne `.md`/`.txt` über der Schwelle mit `long: <n> characters` an (JSON: `length`, sonst `null`). Es liest den Inhalt nur, wenn die Größe in Bytes über der Schwelle liegt (UTF-8 hat nie mehr Zeichen als Bytes), sonst bleibt es bei `lstat`. Für eine Textdatei außerhalb von `incoming/` nennt `wiki-ingest` Schritt 1 `wc -m` mit Verweis auf den Wert in `raw derive -h`. - **Route wie Breite, nicht wie Volumen:** ein Raw-File, eine Source-Seite (`raw/` bleibt ungeschnitten, ein Raw-File hat einen Eigentümer). Der Workshop dient dem Lesen in Teilen und dem Extrakt. - **Units nach der Gliederung:** je Unit ein Seitenbereich, geschnitten an der höchsten Gliederungsebene, deren Abschnitte unter der Schwelle bleiben; ein größerer Abschnitt (IHF „II. Erläuterungen“, S. 56–78) an der nächsten Ebene oder an Seitengrenzen. Ohne Gliederung: Seitenbereiche nach `<!-- page N -->`; ohne Seitenmarken (abgerufene Seite, Klartext) an den eigenen Überschriften, sonst nach Zeilennummern. `plan.md` hält je Unit Titel, Seiten und Zeilenbereich fest. - **Schritt 5a liest nur den Zeilenbereich der Unit** (den Kopf einmal, in der ersten Unit), nie die ganze Datei je Unit. - **Schritt 5b auf dem Längen-Pfad:** der Extrakt ist eine **Faktenliste**, je Eintrag mit Fundstelle (Seite, Regel-/Abschnittsnummer) und – wo vorhanden – Bedingung, Ausnahme, Frist/Zahl und Modalität (*muss/soll/kann/darf nicht*). Die Source-Seite entsteht aus den Faktenlisten aller Units, nicht aus Zusammenfassungen; Schritte 5d–5e laufen einmal, nach der letzten Unit. - **Länge und Breite zusammen:** derselbe Workshop; die Auswahl der seitenwürdigen Themen läuft über die gesammelten Extrakte. ## Geänderte Dateien - Code: `tools/chemenu/commands/raw/_common.py` (Konstante, `_long_text_check`, `_plain_text_length`), `derive.py`, `fetch.py`, `pending.py`; Tests in `tools/chemenu/tests/test_raw_derive.py` (Grenze an der Konstante, Zeichen statt Bytes, Ordner und ZIP, `raw pending`) und `test_raw_fetch.py` (abgeleitete Seite, Klartext). - `instructions/ingest-large-tree.md`: § When to run (dritte Achse mit Begründung), § Tiers (Zeile „Long“), neuer Abschnitt „A long source is read in parts“, Schritte 3, 5a, 5b, 5d, ein Entscheidungspunkt, § Scope. - `instructions/wiki-ingest/SKILL.md` Schritt 1 („Check the size first, on all three axes“) und § Decision points. - `types/source.guidance.md`: `## Not Extracted` ist auf jeder Achse Pflicht, auch auf dem Längen-Pfad. - `raw/CONTRACT.md` (§ raw derive: „A text too long for one pass is named.“), `tools/CONTRACT.md` und `docs/reference/commands/raw-material-and-uploads.md` (generiert), `docs/how-to/ingest-a-source.md`, `docs/explanation/knowledge-and-commitment.md` (Abschluss), `CHANGES.md` (Abschnitt „Lange Dokumente: Länge als dritte Größenachse“). ## Akzeptanzkriterien - [x] `raw derive` auf das IHF-PDF und auf BHV Teil I gibt die Längen-`CHECK`-Zeile aus; auf BHV Teil II und III nicht. Ein Test prüft die Grenze an der Konstante (knapp darunter: keine Zeile, knapp darüber: Zeile). - [x] `raw fetch` gibt dieselbe Zeile für eine abgeleitete Seite über der Schwelle aus. - [x] Der Zahlenwert der Schwelle steht genau einmal im Repo (der Konstante; die generierten Referenzen setzen ihn daraus ein); `ingest-large-tree.md` und `wiki-ingest` verweisen auf die `CHECK`-Zeile. - [x] `ingest-large-tree.md` beschreibt drei Achsen; der Längen-Pfad schreibt vor, dass Schritt 5a nur den Zeilenbereich der Unit liest, und dass der Extrakt eine Faktenliste mit Fundstelle und Modalität ist. - [x] Für eine Datei ohne Gliederung ist der Schnitt nach Seitenbereichen beschrieben. - [x] `pytest`, `docs verify`, `instructions verify` grün (lokal 3080 passed, 4 skipped; CI-Lauf 729). ## Versionsteil MINOR. Drop-in: neue `CHECK`-Zeile, ein zusätzliches JSON-Feld `length` in `raw pending --json` und eine zusätzliche Route in den Anweisungen; keine Kopfzeile, kein Frontmatter-Feld, kein Befehl ändert sich inkompatibel, `kb/` bleibt unberührt. ## Ergebnis Ausgeliefert in **10.1.0-beta.10**, Commit `eae4a42`, verifiziert durch CI-Lauf [729](https://gitea.nehmer.net/torben/chemenu/actions/runs/729), Converters-Lauf [730](https://gitea.nehmer.net/torben/chemenu/actions/runs/730) (echte Dokumente des privaten Korpus) und `release.yml`-Lauf [731](https://gitea.nehmer.net/torben/chemenu/actions/runs/731) (Kandidat, kein Release), alle grün. Beim Abschluss nachgezogen: `docs/explanation/knowledge-and-commitment.md` nennt auch die lange Quelle (Commit `4f5913a`, nur `docs/`, kein Bump), CI-Lauf [732](https://gitea.nehmer.net/torben/chemenu/actions/runs/732) grün. ## Kette Kette „Große Dokumente“ - Vorgänger: #225 - Nachfolger: #227
torben added the prio/plannedsize/Marea/kbkind/build labels 2026-10-13 20:58:40 +00:00
torben added the status/blocked label 2026-10-13 20:59:27 +00:00
torben removed the status/blocked label 2026-10-14 04:52:01 +00:00
Author
Owner

status/blocked abgenommen: #225 (einziger offener Blocker, die Gliederung mit Zeilennummern) ist geschlossen und veröffentlicht als 10.1.0-beta.1. Hinweis aus dem Abschluss: Die Prüfung der Gliederung und der Kennzeichnungen an den echten PDFs (IHF, BHV Teil I) steht in #225 unter „Prüfung am Original“ noch von Hand aus – der Bau hier leitet das IHF-PDF ohnehin ab und kann sie miterledigen.

`status/blocked` abgenommen: #225 (einziger offener Blocker, die Gliederung mit Zeilennummern) ist geschlossen und veröffentlicht als 10.1.0-beta.1. Hinweis aus dem Abschluss: Die Prüfung der Gliederung und der Kennzeichnungen an den echten PDFs (IHF, BHV Teil I) steht in #225 unter „Prüfung am Original“ noch von Hand aus – der Bau hier leitet das IHF-PDF ohnehin ab und kann sie miterledigen.
Author
Owner

Nachtrag: Die Prüfung am Original aus #225 ist erledigt (Ergebnis dort im Body), dieser Bau muss sie nicht mehr mitnehmen. Für die Längenschwelle: Die Kennzeichnungen vergrößern den abgeleiteten Text. derived.md mit Kopf hat jetzt IHF 224.537 Bytes, BHV Teil I 104.193, Teil II 15.103, Teil III 15.780. Die Einteilung über/unter 50.000 Zeichen bleibt dieselbe. BHV Teil I hat zwei Gliederungsebenen, nicht drei.

Nachtrag: Die Prüfung am Original aus #225 ist erledigt (Ergebnis dort im Body), dieser Bau muss sie nicht mehr mitnehmen. Für die Längenschwelle: Die Kennzeichnungen vergrößern den abgeleiteten Text. `derived.md` mit Kopf hat jetzt IHF 224.537 Bytes, BHV Teil I 104.193, Teil II 15.103, Teil III 15.780. Die Einteilung über/unter 50.000 Zeichen bleibt dieselbe. BHV Teil I hat zwei Gliederungsebenen, nicht drei.
Author
Owner

Gebaut und veröffentlicht als 10.1.0-beta.10 (eae4a42); CI 729, Converters 730 und Release 731 grün.

  • LONG_TEXT_CHARS = 50_000 in tools/chemenu/commands/raw/_common.py; raw derive und raw fetch geben eine CHECK-Zeile für jede geschriebene .md darüber aus (auch für abgelegte text/plain/text/markdown), raw pending markiert eine einzelne lange .md/.txt mit long: / JSON length.
  • Gezählt: Zeichen der .md wie geschrieben, Kopf eingeschlossen. Am Original: IHF 204.713, BHV I 101.453 → Zeile; BHV II 9.884, III 15.048 → keine.
  • ingest-large-tree.md: dritte Achse, Tier „Long“, Abschnitt „A long source is read in parts“, Schnitt nach Gliederung → Seitenmarken → Überschriften → Zeilen, 5a nur Zeilenbereich, 5b Faktenliste mit Fundstelle und Modalität. wiki-ingest Schritt 1 und Entscheidungspunkt, source.guidance.md, raw/CONTRACT.md, How-to und Changelog-Abschnitt nachgezogen.
  • Abweichungen vom ursprünglichen Body sind dort als „beim Bau präzisiert/ergänzt“ markiert.
Gebaut und veröffentlicht als 10.1.0-beta.10 (`eae4a42`); CI 729, Converters 730 und Release 731 grün. - `LONG_TEXT_CHARS = 50_000` in `tools/chemenu/commands/raw/_common.py`; `raw derive` und `raw fetch` geben eine `CHECK`-Zeile für jede geschriebene `.md` darüber aus (auch für abgelegte `text/plain`/`text/markdown`), `raw pending` markiert eine einzelne lange `.md`/`.txt` mit `long:` / JSON `length`. - Gezählt: Zeichen der `.md` wie geschrieben, Kopf eingeschlossen. Am Original: IHF 204.713, BHV I 101.453 → Zeile; BHV II 9.884, III 15.048 → keine. - `ingest-large-tree.md`: dritte Achse, Tier „Long“, Abschnitt „A long source is read in parts“, Schnitt nach Gliederung → Seitenmarken → Überschriften → Zeilen, 5a nur Zeilenbereich, 5b Faktenliste mit Fundstelle und Modalität. `wiki-ingest` Schritt 1 und Entscheidungspunkt, `source.guidance.md`, `raw/CONTRACT.md`, How-to und Changelog-Abschnitt nachgezogen. - Abweichungen vom ursprünglichen Body sind dort als „beim Bau präzisiert/ergänzt“ markiert.
Author
Owner

Abgeschlossen: Länge ist die dritte Größenachse beim Ingest (10.1.0-beta.10, eae4a42, CI 729/730/731 grün); beim Abschluss docs/explanation/knowledge-and-commitment.md nachgezogen (4f5913a, CI 732 grün). Body im Endzustand.

Abgeschlossen: Länge ist die dritte Größenachse beim Ingest (10.1.0-beta.10, `eae4a42`, CI 729/730/731 grün); beim Abschluss `docs/explanation/knowledge-and-commitment.md` nachgezogen (`4f5913a`, CI 732 grün). Body im Endzustand.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#226