)]}'
{
  "log": [
    {
      "commit": "ffc553b4d2ad5b1f4c1a4dec0ad9c19d96556378",
      "tree": "1b04665246208c9e149a5efc26e67497db5001a9",
      "parents": [
        "2b1841e17533543d1cb15220ca86a2a37c853daf"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sat Aug 15 12:18:32 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sat Aug 15 12:18:32 2026 +0200"
      },
      "message": "Die Beschlussempfehlung liefert die beschlossene Fassung\n\nBisher wurde eine Beschlussempfehlung erkannt und mit Begründung übergangen:\nIhre maßgebliche Fassung steht in der zweispaltigen Zusammenstellung, deren\nrechte Spalte für sich unlesbar ist. Sie druckt Unverändertes nicht ab,\nsondern vermerkt bloß „unverändert“ — und zwar nicht nur je\nGliederungspunkt, sondern auch zeilenweise innerhalb zitierter Blöcke,\nweshalb ihre Anführungszeichen nicht aufgehen. Eine Auflösung über die\nGliederungspfade scheitert daran nachweislich (45 statt 117 Befehlen).\n\nMaßgeblich ist die Grundlinie: Beide Spalten sind zeilensynchron gesetzt,\njeder Vermerk steht auf der Höhe der Entwurfszeile, die er meint. Der neue\n`ZusammenstellungsLeser` führt sie über Seite und Grundlinie in eine\ngemeinsame Lesereihenfolge zusammen und entscheidet dann Zeile für Zeile:\n„unverändert“ holt den Wortlaut aus der Entwurfsspalte, „entfällt“ streicht\nihn, sonst gilt die Ausschussspalte. Das Vokabular der rechten Spalte ist\nausgezählt genau zweiteilig — 166-mal „unverändert“, 17-mal „entfällt“.\n\nDabei meint „unverändert“ den Wortlaut, nicht die Zählung: Streicht der\nAusschuss einen Punkt, rücken die folgenden auf, und sein „5. unverändert“\nsteht der Entwurfsnummer 6 gegenüber. Die Marke kommt deshalb von rechts,\nder Wortlaut von links.\n\nVoraussetzung dafür war, die Geometrie aus dem `FontgroessenFilter`\nherauszuführen. Sonst verließ ihn nur das End-X der Zeile; jetzt trägt jede\nZeile Seite, Grundlinie und End-X (`FontgroessenFilter.Zeile`). Die\nMetadaten reisen weiterhin im Textstrom mit, statt nebenher gesammelt zu\nwerden: Nur so ist ihre Zuordnung zu den Zeilen gesichert, denn PDFBox\nschreibt Zeilentrenner an mehreren Stellen. Der Schritt ist reine\nUmstrukturierung, sämtliche gepinnten Zahlen bleiben unverändert.\n\nDrei Fehler standen im Weg, alle in der Spaltentrennung:\n\n* Der Steg wurde einschließlich der Leerzeichen-Glyphen gemessen, die im\n  Textstrom fast bis an die nächste Spalte reichen. Ein 7-pt-Steg schrumpfte\n  so auf 4,7 pt und galt als durchlaufender Text, was in BT-Drs. 20/7619 die\n  gesperrte Marke des Punktes 14 mitten entzweiriss. Gemessen wird jetzt an\n  den sichtbaren Zeichen; die Schwelle sinkt von 12 auf 6 pt und liegt damit\n  belegt zwischen dem schmalsten echten Steg (6,9 pt) und dem breitesten\n  Wortzwischenraum einer ganzseitenbreiten Zeile (5,4 pt) — in beiden\n  Belegdokumenten übereinstimmend.\n\n* Gedrehter Text hat Koordinaten in seinem eigenen Bezugssystem. Der\n  Randvermerk „Vorabfassung – wird durch die lektorierte Fassung ersetzt“\n  lief mit seiner vermeintlichen Grundlinie quer durch beide Spalten und\n  zerschnitt deren Zeilenfolge. Beim Spaltenauszug bleibt er nun draußen;\n  beim ungeteilten entfernt ihn wie bisher der TextBereiniger.\n\n* Die Zeilenenden müssen je Spalte klassifiziert werden, bevor die Spalten\n  zusammenkommen: Ihre Satzspiegelränder liegen verschieden, in der\n  gemischten Fassung fände keine ihren eigenen Ausrichtungs-Cluster wieder\n  und die Silbentrennung bliebe ungeheilt („An- gabe“).\n\nDie Quellenzeile weist die verwendete Spalte als „[Beschlussempfehlung …,\nAusschussfassung]“ aus. Lässt sich die Zusammenstellung nicht auflösen,\nwird die Datei nach wie vor mit Begründung übergangen — eine halb\naufgelöste Fassung auszugeben wäre schlimmer als keine.\n\nZwei Belegfälle: BT-Drs. 20/7619 (GEG) mit 67 angewandten Befehlen, wobei\ndie Ausschussfassung mehr Befehle trägt als der Regierungsentwurf daneben —\nder Ausschuss hat zwei Artikel ergänzt —, und BT-Drs. 19/24334 (Drittes\nBevölkerungsschutzgesetz) mit 47. Der große manuelle Rest hat denselben\nGrund wie beim Entwurf: Das Beispiel-XML ist die Urfassung des GEG von 2020,\ngeändert wird eine Fassung von 2023. Die verbliebenen zwei unerkannten\nBefehle gehen auf Setzfehler der amtlichen Drucksache zurück (fehlender\nSchlusspunkt, überzähliges Anführungszeichen) und sind zeichengenau so\nübernommen.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: Id5db19cb8f27a51af0c23cfd4a9969dd4120f569\n"
    },
    {
      "commit": "2b1841e17533543d1cb15220ca86a2a37c853daf",
      "tree": "01b940cb06c5abc36704d2d4853343ee7b38ce02",
      "parents": [
        "5700bbcb89186e432c5c7dd232b61c052de8e784"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sat Aug 15 10:51:11 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sat Aug 15 10:51:11 2026 +0200"
      },
      "message": "Die Web-App rechnet im Browser statt auf dem Server\n\nBisher lief die Weboberfläche auf einem JDK-HttpServer: Uploads landeten als\ntemporäre Dateien auf dem Server, die Synopse entstand dort. Das kostete\nBetrieb (systemd, Reverse Proxy, Rate-Limiting, Timeouts) und verlangte ein\nDatenschutzversprechen, das nur zusicherbar, nicht nachprüfbar war — gerade\nEntwurfstexte verließen den Rechner der Nutzer:innen.\n\nNeu übersetzt `./mvnw -Pwasm package` dieselbe Pipeline mit GraalVM Web Image\n(`native-image --tool:svm-wasm`) nach WebAssembly, PDFBox eingeschlossen.\nAusgeliefert werden nur noch statische Dateien; gerechnet wird im Browser.\nDie erzeugte Synopse ist byteweise identisch mit der der Befehlszeile\n(SHA-256 verglichen für IfSG 48/27/21 und BayJG 151/3/54).\n\nDie Befehlszeile bleibt unberührt: `./mvnw package` erzeugt unverändert das\nJAR, alle Optionen und Meldungstexte sind gleich, das Wasm-Profil ist rein\nadditiv und verlangt Oracle GraalVM 25.1+ (die CE hat kein Web Image).\n\nPortabilitätsschnitt (nützt beiden Fassungen):\n\n* `Quelle` (Name + Bytes) ersetzt `Path` in der Pipeline; nur die\n  Befehlszeile kennt noch ein Dateisystem. Der Name trägt genau den\n  bisherigen `getFileName()`-Text, damit Warnungen und Quellenzeile\n  wortgleich bleiben.\n\n* `DateiTyp` erkennt PDF/XML/Klartext an den Signaturbytes. Tika entfällt —\n  eine schwergewichtige Abhängigkeit samt ServiceLoader- und\n  XML-Konfiguration weniger, was der Wasm-Übersetzung unmittelbar zugutekommt.\n\nVier Eigenheiten von Web Image, die der Quelltext jeweils an Ort und Stelle\nvermerkt:\n\n* `java.util.zip.Inflater` ist nicht angebunden (GR-65205), ohne Inflate ist\n  kein PDF lesbar. `InflaterErsatz` substituiert ihn durch jzlib.\n\n* Typisierte JS-Felder lassen sich nicht nach `byte[]` umsetzen\n  („byteArrayHub is not defined“); der Dateiinhalt wandert als Base64.\n\n* JULs Standardformatter ruft `StackWalker`, den es dort nicht gibt.\n\n* Im Worker fehlt `document.currentScript`, worauf die Laufzeit das\n  Wasm-Modul neben `worker.js` sucht; die VM wird deshalb mit ausdrücklichem\n  Pfad ein zweites Mal gestartet.\n\nDie Reachability-Metadaten stammen aus einem Lauf des Tracing-Agents über die\nPipeline; die PDFBox- und FontBox-Ressourcen sind als Globs ergänzt, sonst\nscheitern PDFs an „Could not find referenced cmap stream Identity-H“.\n\nEntfallen: WebMain, UploadHandler, StaticHandler, Multipart und die\nsystemd-Unit. Die nginx-Vorlage liefert jetzt statische Dateien aus, und die\nDatenschutzseite sagt, was nun stimmt: Die Dateien verlassen den Rechner\nnicht.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: I38faf2ac0f764d601f080d4276babe4747773683\n"
    },
    {
      "commit": "7235b34eeb6ff331c152116cbe4df846d7476110",
      "tree": "febb373089f624511a484316642bad31519ed5ca",
      "parents": [
        "7b455cd43149834ccd2163b4e5d197809bd34a37"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Fri Aug 14 18:58:25 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Fri Aug 14 18:58:25 2026 +0200"
      },
      "message": "Quellformate jenseits des verkündeten Gesetzes\n\nBisher nahm ÄndGgner nur verkündete Artikelgesetze und Gesetzentwürfe an, ohne\nden Unterschied zu kennen. Dokumente, die einen Entwurf ändern statt ein\nGesetz, lieferten still null Befehle.\n\nNeu:\n\n* Dokumentart-Erkennung aus dem Rohtext (DokumentErkenner, DokumentArt,\n  DokumentKopf) — vor der Bereinigung, weil gerade die Drucksachenköpfe als\n  Kolumnentitel wegfallen. Erkannt wird nie am Dateinamen: Die Beispieldaten\n  enthalten eine Datei namens Beschlussempfehlung, die in Wahrheit ein\n  Entschließungsantrag ist. Dokumente ohne Befehle erzeugen jetzt eine\n  benannte Warnung statt stiller Leere.\n\n* Änderungsanträge (AenderungsantragParser, EntwurfsPatcher): Der Antrag wird\n  auf den Entwurfstext angewandt, der geänderte Entwurf danach wie gewohnt auf\n  das Stammgesetz — eine komponierte Synopse. Drucksachen- und Gesetzesstellen\n  bleiben getrennte Typen; die Zuordnung Antrag→Entwurf läuft über die\n  Drucksachennummer, nicht über die Argumentreihenfolge. Der 1910 Zeilen große\n  BefehlAnwender bleibt unberührt.\n\n* Beschlussempfehlungen werden erkannt und mit Begründung übergangen, die den\n  brauchbaren Entwurf beim Namen nennt. Die Spaltentrennung der\n  Zusammenstellung ist gebaut (FontgroessenFilter.Spalte, koordinatenbasiert\n  am Steg) und belegt: Die linke Spalte ergibt Befehl für Befehl den\n  Regierungsentwurf. Die rechte Spalte bleibt bewusst offen — sie vermerkt\n  „unverändert“ auch zeilenweise innerhalb zitierter Blöcke, ihre\n  Anführungszeichen gehen daher nicht auf; nötig ist die zeilenweise Zuordnung\n  beider Spalten über die gemeinsame Grundlinie.\n\nDie Synopse kennzeichnet eine Entwurfsfassung als solche.\n\n296 Tests grün (vorher 269); alle gepinnten Akzeptanzzahlen unverändert.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: I0001d25fcbd9969fc06eea675edc4326ce2e02f9\n"
    },
    {
      "commit": "7b455cd43149834ccd2163b4e5d197809bd34a37",
      "tree": "5194dad78446c9631da454a523f122f9de46057c",
      "parents": [
        "5b2e6ef635026a62e23fe5ea6df2c85d839ff78c"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 09 08:33:37 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 09 08:33:37 2026 +0200"
      },
      "message": "Add a public web front end alongside the CLI\n\nExtracts the CLI pipeline into a reusable Pipeline class and exposes it\nvia a dependency-free JDK HttpServer (upload form, bounded worker pool\nwith 503 on overload, per-request size/time limits, no persisted\nuploads), plus nginx/systemd deploy templates and Impressum/Datenschutz\nplaceholders for public operation.\n\nChange-Id: I6e8e7afa3c4b1082cdf9e82da0fae0b5b49470ad\n"
    },
    {
      "commit": "5b2e6ef635026a62e23fe5ea6df2c85d839ff78c",
      "tree": "6c7af175312d929ea698a6567ba8f2fd3367abc4",
      "parents": [
        "a201e83e59562e0e662196a616ff746cdaddd74e"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 02 20:01:37 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 02 20:01:37 2026 +0200"
      },
      "message": "Add Hesse as an extraction and recognition case\n\nThe Hesse GVBl issue 5/2026 amends the ordinance on traffic-law\ncompetences. All 21 commands of its article 1 are now recognised.\n\nThe blocked letterspacing that was expected to be the hard part turns\nout to affect only the signature block, not a single command. What did\nneed work was three other things: the running GVBl footer and the\nmasthead remainder are now stripped as page furniture, and so is the\nheading\u0027s asterisk footnote (\"* Ändert FFN 61-60\"), which sits at the\nfoot of a page between two enumeration items and stuck to the command\nabove it.\n\nTwo command forms are new, both general rather than Hessian: \"am Ende\"\nmay be absent from a punctuation replacement — the definite article then\nrequires the unit to carry exactly one such mark, which the applier\nchecks — and the object after \"durch\" may be elided in the form without\na location, as it already could in the form with one. Where a\npunctuation replacement follows a renumbering in the same sentence it\nbinds to the renumbered unit: unlike a word operation it has no\ndistinguishing target text, so resolving it norm-wide would be useless.\n\nA full acceptance test stays out of reach: hessenrecht.hessen.de is the\nsame login-only juris application as the Schleswig-Holstein and Berlin\nportals. Checking landesrecht-bw.de too, that now covers all four\nportals that could have supplied an annex-bearing statute, so the\nLandesRechtTextParser\u0027s missing annex headings will need a stem from\nrecht.nrw.de instead.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: Ief04164ee25653345a011f3ffbbfaa6df1f5c64b\n"
    },
    {
      "commit": "a201e83e59562e0e662196a616ff746cdaddd74e",
      "tree": "bebd570c3098f8793d9d6f3442bbb50433374917",
      "parents": [
        "bac648b8fc06dfffaf67cf283f73fa2572e67575"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 02 19:45:34 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Aug 02 19:45:34 2026 +0200"
      },
      "message": "Close the NRW issue: 17. RÄStV-AusfG as a fourth acceptance case\n\nArticle 4 of the 22nd Broadcasting Amendment Act recasts § 1 of the act\nimplementing the 17th Broadcasting Amendment Treaty. Both the pre- and\nthe post-amendment consolidated version are served by recht.nrw.de, so\nthis closes the last open article of GV. NRW. 7/2026.\n\nNo production code needed changing: the article carries its single\ncommand without an enumeration item, and the recast quote contains\nnested quotation marks — both are already handled. The result matches\nthe official version of 1 April 2026 character for character, including\nits editorial placeholders.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: If63606d113f2801f0c9e82350215443da8e8be8b\n"
    },
    {
      "commit": "bac648b8fc06dfffaf67cf283f73fa2572e67575",
      "tree": "e2e4387451deabb37b5f80ed42e06bd17b3127d9",
      "parents": [
        "5f30f566873c313b554f087c0f7e132efa54d64a"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Tue Jul 28 07:51:09 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Tue Jul 28 07:51:09 2026 +0200"
      },
      "message": "Run the NRW mass test: WDR-Gesetz and LMG NRW\n\nThe 22nd Rundfunkänderungsgesetz amends five laws in one gazette issue.\nArticle 3 (TMZ-Gesetz) was already an acceptance case; this adds the two\nbig ones — Article 1 (WDR-Gesetz, 101 commands across 31 norms) and\nArticle 2 (LMG NRW, 18 commands). Both stem versions come from\nrecht.nrw.de, whose URLs address a version by its date of entry into\nforce, so the results could be checked norm by norm against the official\n1 April 2026 consolidations.\n\nApplying them turned up work at every layer:\n\nOrder of application. Renumbering always refers to the original count,\nnot to the state after the preceding items, so a cascade („Absatz 3 wird\nAbsatz 4“, „Absatz 4 wird Absatz 5“, …) applied in document order leaves\nthe law carrying two units of the same name. BefehlAnwender now derives,\nfor each command, which designations it vacates and which it newly\noccupies, and pulls a vacating command ahead of the first one it\ncollides with. That single rule subsumes the previous §-only special\ncase, orders a cascade descending, and — inside a Sammelbefehl too —\nkeeps a range renumbering from colliding with itself. Bayern\u0027s Art. 29a\nsequence now resolves as well (5 manual residues down to 3).\n\nRenumbering an enumeration item. Unlike an Absatz, a Nummer carries its\ndesignation as a marker in the text; the applier silently reported\nsuccess without touching it. It now rewrites the marker and lets a\nstruck placeholder with the target designation give way.\n\nSentence splitting. Gazette citations („(BGBl. I S. 1982)“) and\nline-initial enumeration markers were splitting sentences, so Satz\nlocators pointed into the wrong place; a sentence may also open with §.\n\nCommand language: „wie folgt neu gefasst“ and the missing „wird“, a\nsplit location („In Absatz 2 wird Satz 1 wie folgt gefasst“), an\ninsertion behind a location prefix, the standalone „Der Punkt am Ende\nwird durch … ersetzt“, „Dem Wortlaut des Absatzes 3 …“, the verb frame\n„Es werden ersetzt:“ whose items carry only the location, coordination\nat „sowie“ and before a punctuation clause, and a stray closing quote at\nthe end of a sentence.\n\nStem format: LandesRechtTextParser reads an „Inhaltsübersicht“ line as\nthe norm of that name (which is what the Angabe commands address) and\nrecognises keyword-less Roman section headings.\n\nEverything the two acceptance tests do not apply is named: one command\nin the WDR-Gesetz whose „Punkt am Ende des Satzes“ is not unambiguous in\na two-sentence Nummer. The remaining differences from the official\nconsolidations are places where the official text itself departs from\nthe command wording; SOURCES lists them.\n\nChange-Id: I261cf89cd5820f7597bc5db734f322d94b84828e\n"
    },
    {
      "commit": "5f30f566873c313b554f087c0f7e132efa54d64a",
      "tree": "4f6c33a0a1e9a6b2b1ad29bffef4defd0990fef2",
      "parents": [
        "79b88e0a8cb4dfc9c33fe219045f3da7f64256c4"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Tue Jul 28 06:00:16 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Tue Jul 28 06:00:16 2026 +0200"
      },
      "message": "Recognise word-anchored insertions; close quotes at the next item\n\nThe documented next step was the word-anchored structural insertion\n(\"Vor den Wörtern „Aus dem Bereich Verkehr:“ wird folgender Absatz 5\neingefügt\", Berlin Artikel 1 Nr. 2 b) bb)). StrukturEinfuegung now\ncarries an optional WortAnker, the recogniser has a pattern for the form\n— placed before STRUKTUR_EINFUEGUNG, which bails out of recognition\nentirely when the StellenParser cannot read \"den Wörtern «0»\" — and the\napplier positions the new unit at the anchor line instead of a structural\nboundary.\n\nTwo blockers turned up next to it, both measured on the corpus rather\nthan assumed:\n\nThe command was not cleanly recognisable at all. Its closing quotation\nmark is missing in the official text, so the quote swallowed items cc)\nand c); an anchor alone would have made the command look applicable with\na huge foreign quote as its payload. The docs called a boundary at\nenumeration markers impossible, and that holds for the unguarded form: a\nquoted amendment provision carries command language itself. Guarded by\nfour conditions together — the article\u0027s quotation marks demonstrably do\nnot balance, the next line\u0027s marker is at the same or a shallower level\nthan the one the quote opened on, that line carries command language, and\nclosing here leaves the rest of the article balanced — it fires exactly\ntwice in the whole sample corpus, both times where the missing mark\nbelongs: Berlin before cc), and GV. NRW. Artikel 2 before 12. Without the\nguards it also fires inside quoted amendment provisions in the BayJG and\nGModG documents; the balance gate rules those out.\n\nThe GV.-NRW. gazette encodes part of its umlauts decomposed (u + U+0308,\n79 places, dozens of them \"eingefügt:\"/\"angefügt:\"). Invisible in the\ntext, but a different word to every command pattern, so those commands\ncould never match. TextBereiniger now normalises to NFC first — not\nNFKC, which would flatten the official sentence numbers ¹²³ and take\nSatzTeiler and Superskript their basis. Every other sample document,\nevery gii-XML stem and every hand-kept plain-text stem is already NFC, so\nthe pinned figures stay bit-identical.\n\nBerlin Artikel 1 is thereby fully recognised (6 of 6 commands, none\nunknown). One pinned statement changed for a stated reason: the NRW\nacceptance test asserted the article-heading warning, which is now\npreempted by the item boundary inside Artikel 2 — Nr. 12 survives\ninstead of being swallowed. 241 tests green.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: Ic579bec6fecc2495a61b3dcf87c9ad71b42f34ae\n"
    },
    {
      "commit": "2cfea0076b43001569565c2f625afa42901282cd",
      "tree": "f2dfc99525473ea5af1c02b20521fa9680ae5265",
      "parents": [
        "81777013dfa582053489efea874e84379f1f0805"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Jul 26 13:32:26 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Jul 26 13:32:26 2026 +0200"
      },
      "message": "Bring the documentation up to the current state\n\nThe README still described state law as Bavaria-only, six Länder later.\nThe sample-data overview grew a section on how to obtain the pre-\namendment stems per portal — which of the three routes works, and that\nthe juris state portals are a dead end — and a short prioritised \"where\nto continue\", so the next session does not have to re-derive it.\n\nCorrected while writing it: the regression figures are not all pinned\nthe same way. UWG, AGG and ProdHaftG pin \"nothing left manual\", BayJG\npins 154 commands and names its five renumbering residues, and the state\ncases pin full application. Saying \"UWG 19/0, GEG 66/53, …\" would have\ndescribed observations, not what the tests actually assert.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: Ie247e9626e789e628d537bede735923d5b67d14b\n"
    },
    {
      "commit": "65eff08b32a0f00ff0f5e4bda3fe5793f631ed64",
      "tree": "1d101859b51c80bc117ec72a871933575ed8b2f3",
      "parents": [
        "f20828ffd8ea9d554566636a9c53a3abd57507c5"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sat Jul 18 12:24:32 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Jul 19 09:00:01 2026 +0200"
      },
      "message": "Support Bavarian state law (BayJG) with Art./§ inversion and superscripts\n\nExtend ÄndGgner from federal-only to Bavarian state law. Bavarian base\nlaws are structured in Artikel while their amending acts are structured\nin Paragraphen (inverted from the Bund); official sentence numbers and\nfootnote markers are carried as Unicode superscripts (¹²³, ⁶)).\n\n- Generalise Stelle.Paragraph to carry a sigil (\"§\" or \"Art.\") and route\n  it through recogniser, applier and resolver (bit-identical Bund output).\n- Superscript pipeline: geometric detection in FontgroessenFilter\n  (SuperskriptModus BEHALTEN), Superskript util, exact sentence splitting\n  in SatzTeiler, label-based sentence resolution.\n- BayRechtLoader/BayRechtTextParser for gesetze-bayern.de PDF/plaintext.\n- §-structured amending acts, GVBl/Landtag column titles, non-breaking\n  spaces, the GVBl continuation quote; Bavarian command forms (footnote\n  aufhebung, Satznummerierung streichung, Wortlaut forms, Halbsatz,\n  gapping chains).\n\nAcceptance (EndToEndTest.bayJgGvblAcceptance): the pre-2026 BayJG\nfassung (BayJG-alt.txt, reconstructed from Wayback single-article\nsnapshots) with GVBl 6/2026 §§ 1-2 applied — 154 commands, 0 unknown,\n149 applied automatically, 5 pinned residuals (follow-up edits inside\ntwo multi-step renumbering sequences in Art. 29a and Art. 56).\n\nApplication-side fixes surfaced by the acceptance run (all Bund-safe):\nsentence-start superscript before §; sentence boundaries \u003d {0} ∪ {each\nnumber ≥ 2}; gapping scope inheritance for bare word operations;\nfootnote definition lines hidden from word operations; absatz aufhebung\nmarks \"(weggefallen)\" keeping its number, and absatz renumbering\noverwrites an empty placeholder (weggefallen/gegenstandslos) target.\n\n211 tests green (mvnw verify); federal reference numbers unchanged.\n\nCo-Authored-By: Claude Opus 4.8 \u003cnoreply@anthropic.com\u003e\nChange-Id: Iebae4c17ca90755c5fd36251362042f3d5796fd0\n"
    },
    {
      "commit": "b7e9f0f4756bf87ef98500d5fd0ce87d2916c3c4",
      "tree": "82c7f38b566d2ded6989cdd05ea628dcf4ba6de2",
      "parents": [
        "ebd5a7bcfb13c1a74a5ad65de772e171d98ad156"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Thu Jul 16 21:12:08 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Thu Jul 16 21:12:08 2026 +0200"
      },
      "message": "Support Anhang/Anlage targets, Inhaltsübersicht Angabe commands, and Gliederungs-Überschriften insertion/replacement\n\nFourth enablement wave: Anhänge/Anlagen resolve as ordinary norm targets with\nnested Nummer/Buchstabe block resolution, InhaltsuebersichtAnwender applies\nAngabe commands automatically, GliederungsUeberschriften handles inserting and\nreplacing structural headings, the law\u0027s own heading can be recast, and\nFontgroessenFilter now determines body text per page instead of document-wide.\nSample data (UWG/AGG/ProdHaftG) now applies with 0 manual cases.\n\nCo-Authored-By: Claude Sonnet 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: I1a76750afbecfa1aae734bcdabc91470a28420ca\n"
    },
    {
      "commit": "ebd5a7bcfb13c1a74a5ad65de772e171d98ad156",
      "tree": "d43c01a878323bd14999ca5f6167ecf0cc5bae82",
      "parents": [
        "73c5dbae7a487db2b9ea29cd050eac94644974bb"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Wed Jul 15 20:54:27 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Wed Jul 15 20:54:27 2026 +0200"
      },
      "message": "Support range structure replacement, struct renumbering, and multi-paragraph blocks\n\nAdds bisStelle to StrukturErsetzung for coordinated target ranges, recognizes\ndeletion/renumbering of whole structural units (paragraphs and Gliederung\nentries), and handles insertion/replacement of multi-paragraph blocks split on\n§-headings. Updates FASSUNGEN.txt accordingly.\n\nCo-Authored-By: Claude Sonnet 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: I637cc5effbe32c094e62c070b63c470149a77c85\n"
    },
    {
      "commit": "58e19982f25ae6433d7837454bb54b8edc37589c",
      "tree": "ba5f4f8712150e0a9aae195e59290393831845a4",
      "parents": [
        "d1e2facd01c88dbd4758fbc2a64bf9e01abca4e7"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Mon Jul 13 07:09:19 2026 +0200"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Mon Jul 13 07:09:19 2026 +0200"
      },
      "message": "Add tests, usage documentation, and .claude/ to .gitignore.\n\nUnit tests for the gii-norm loader, text cleanup, quote extraction,\ncommand recognition (literal sentences from the sample amendment act),\nsentence splitting, and command application on a synthetic mini law;\nan HTML renderer test including escaping; and an end-to-end smoke test\non the IfSG sample data that skips itself when the (untracked) sample\nfiles are absent.  The README gains a German usage section.\n\nCo-Authored-By: Claude Fable 5 \u003cnoreply@anthropic.com\u003e\nChange-Id: I7f02ff349f9c3bd34fa90a2a84678b9e6fad697d\n"
    },
    {
      "commit": "c7f1136da4b0acf11e784397e4c46278706dc84f",
      "tree": "5957fae9c9da5d1a558845720c4c8ebae69f6bf9",
      "parents": [
        "d9f32a8a04152f9028a436be1deabe8f908b5ca4"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Nov 22 15:01:07 2020 +0100"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Mon Nov 23 06:36:04 2020 +0100"
      },
      "message": "Modularize, avoid shade plugin by default.\n\nChange-Id: I704d78b7553f057f73e1387078623d8fe5d0b154\n"
    },
    {
      "commit": "b291c363badec283553d8e013c5fa912a930e764",
      "tree": "bfc5a298b720c72901a650e28929c61ae4e7e1d7",
      "parents": [
        "4562aed1971ca9cd401cd649d23333a84a20658e"
      ],
      "author": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Nov 22 10:22:27 2020 +0100"
      },
      "committer": {
        "name": "Matthias Andreas Benkard",
        "email": "code@mail.matthias.benkard.de",
        "time": "Sun Nov 22 14:36:08 2020 +0100"
      },
      "message": "Project skeleton\n\nChange-Id: I5609adfca13ffad643a3db93e848fc01636b066a\n"
    }
  ]
}
