feat(citability): KB-v2-Verifikation der norm_ids einarbeiten (16/19 confirmed)

Feedback der Compliance/KB-Session (2026-07-01): die 19 verify_pending norm_ids
gegen KB-v2 (bp_compliance_kb_2026_1_build) geprüft — 16/19 bestätigt (alle
CRA+MaschVO-Artikel existieren). Die 3 fehlenden = Kapitel-Ebene
(EU-MaschVO-KapitelIV/V/VI): der KB-Compiler mintet Artikel+Annex, KEINE Kapitel.

- Artikel-norm_ids verify_pending -> article_confirmed (16 distinkt).
- Kapitel-norm_ids -> chapter_no_kb_unit (danglender Join-Key) + norm_id_note
  (Re-Anchor auf Konstituenten-Artikel = Enhancement, KB-v2 hat sie; NICHT geraten).
- 2 Kapitel-Obligations (notifizierte Stellen · Marktüberwachung/Schutzklausel,
  beide rein prozedural, obligation_id=None) citation_status norm_id_linked ->
  chapter_reanchor_pending. Joinbar bleiben 62 Obligations.
- Status gesamt: 53 annex_confirmed + 10 article_confirmed + 2 chapter_no_kb_unit.
- norm_id_manifest.json + Contract-Block um kb_v2_verification ergänzt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-07-01 12:31:35 +02:00
parent 808a7faea3
commit a4cb104258
10 changed files with 123 additions and 36 deletions
+5 -4
View File
@@ -540,7 +540,7 @@
"norm_ids": [ "norm_ids": [
"EU-CRA-Art31" "EU-CRA-Art31"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [ "guidance_basis": [
@@ -1311,7 +1311,7 @@
"EU-CRA-Art14", "EU-CRA-Art14",
"EU-CRA-Art16" "EU-CRA-Art16"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -1647,7 +1647,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+3 -2
View File
@@ -10487,7 +10487,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+3 -2
View File
@@ -91,7 +91,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+3 -2
View File
@@ -4766,7 +4766,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+15 -12
View File
@@ -3273,7 +3273,7 @@
"norm_ids": [ "norm_ids": [
"EU-MaschVO-Art25" "EU-MaschVO-Art25"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -3601,7 +3601,7 @@
"EU-MaschVO-Art21", "EU-MaschVO-Art21",
"EU-MaschVO-Art22" "EU-MaschVO-Art22"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -3707,7 +3707,7 @@
"EU-MaschVO-Art10", "EU-MaschVO-Art10",
"EU-MaschVO-Art11" "EU-MaschVO-Art11"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -4092,7 +4092,8 @@
"norm_ids": [ "norm_ids": [
"EU-MaschVO-KapitelIV" "EU-MaschVO-KapitelIV"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "chapter_no_kb_unit",
"norm_id_note": "Kapitel-Ebene nicht als KB-v2-Unit gemintet (Compiler = Artikel+Annex). Re-Anchor auf Konstituenten-Artikel = Enhancement (KB-v2 hat die Artikel); NICHT geraten."
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -4115,7 +4116,7 @@
"member_count": 11, "member_count": 11,
"relationships": [], "relationships": [],
"citation_anchor_ids": [], "citation_anchor_ids": [],
"citation_status": "norm_id_linked", "citation_status": "chapter_reanchor_pending",
"review_status": "draft", "review_status": "draft",
"provenance": { "provenance": {
"discovery_confidence": 0.8, "discovery_confidence": 0.8,
@@ -4148,7 +4149,8 @@
"EU-MaschVO-KapitelV", "EU-MaschVO-KapitelV",
"EU-MaschVO-KapitelVI" "EU-MaschVO-KapitelVI"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "chapter_no_kb_unit",
"norm_id_note": "Kapitel-Ebene nicht als KB-v2-Unit gemintet (Compiler = Artikel+Annex). Re-Anchor auf Konstituenten-Artikel = Enhancement (KB-v2 hat die Artikel); NICHT geraten."
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -4193,7 +4195,7 @@
"member_count": 30, "member_count": 30,
"relationships": [], "relationships": [],
"citation_anchor_ids": [], "citation_anchor_ids": [],
"citation_status": "norm_id_linked", "citation_status": "chapter_reanchor_pending",
"review_status": "draft", "review_status": "draft",
"provenance": { "provenance": {
"discovery_confidence": 0.8, "discovery_confidence": 0.8,
@@ -4225,7 +4227,7 @@
"norm_ids": [ "norm_ids": [
"EU-MaschVO-Art50" "EU-MaschVO-Art50"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -4291,7 +4293,7 @@
"EU-MaschVO-Art53", "EU-MaschVO-Art53",
"EU-MaschVO-Art54" "EU-MaschVO-Art54"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -4426,7 +4428,7 @@
"norm_ids": [ "norm_ids": [
"EU-MaschVO-Art18" "EU-MaschVO-Art18"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -5664,7 +5666,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+3 -2
View File
@@ -310,7 +310,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+3 -2
View File
@@ -1687,7 +1687,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+5 -4
View File
@@ -65,7 +65,7 @@
"norm_ids": [ "norm_ids": [
"EU-CRA-Art13" "EU-CRA-Art13"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [ "guidance_basis": [
@@ -701,7 +701,7 @@
"norm_ids": [ "norm_ids": [
"EU-CRA-Art13" "EU-CRA-Art13"
], ],
"norm_id_status": "verify_pending" "norm_id_status": "article_confirmed"
} }
], ],
"guidance_basis": [], "guidance_basis": [],
@@ -1849,7 +1849,8 @@
"convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build", "convention": "EU-<ACT>-Anhang<ROM> (Annex-Ebene) / EU-<ACT>-Art<N> (verify) — KB-v2 bp_compliance_kb_2026_1_build",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD", "granularity": "annex-grob — 'Annex I Part II (1)' -> EU-CRA-AnhangI; Part/Punkt = KB-Enhancement TBD",
"article_status": "EU-<ACT>-Art<N> in KB-v2 noch zu verifizieren; Annex-IDs confirmed", "article_status": "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed",
"source": "Board Compliance/KB-v2 2026-07-01" "source": "Board Compliance/KB-v2 2026-07-01",
"kb_v2_verification": "2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); 3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
} }
} }
+13 -6
View File
@@ -1,9 +1,15 @@
{ {
"contract": "norm_id logical citation join (Domäne 2 legal_basis -> KB-v2 units)", "contract": "norm_id logical citation join (Domäne 2 legal_basis -> KB-v2 units)",
"convention": "EU-<ACT>-Anhang<ROM> (annex, confirmed) / EU-<ACT>-Art<N> + EU-<ACT>-Kapitel<ROM> (verify_pending)", "convention": "EU-<ACT>-Anhang<ROM> (annex) / EU-<ACT>-Art<N> (article) — beide in KB-v2 confirmed; EU-<ACT>-Kapitel<ROM> NICHT gemintet",
"act_naming": "EU-MaschVO-* (NICHT MaschinenVO)", "act_naming": "EU-MaschVO-* (NICHT MaschinenVO)",
"granularity": "annex-grob", "granularity": "annex-grob",
"source": "KB-v2 bp_compliance_kb_2026_1_build (Board Compliance/KB-v2 2026-07-01)", "source": "KB-v2 bp_compliance_kb_2026_1_build",
"kb_v2_verification": {
"date": "2026-07-01",
"by": "Compliance/KB (RAG-Ingestion)-Session",
"result": "16/19 verify_pending bestätigt (alle Artikel existieren); 3 Kapitel-IDs fehlen (Compiler mintet Artikel+Annex, keine Kapitel)",
"resolution": "Kapitel re-anchoren auf Konstituenten-Artikel (KB-v2 hat alle) ODER Kapitel-Units als KB-Enhancement; hier als chapter_no_kb_unit markiert, NICHT geraten"
},
"annex_confirmed": { "annex_confirmed": {
"EU-CRA-AnhangI": 34, "EU-CRA-AnhangI": 34,
"EU-CRA-AnhangVII": 2, "EU-CRA-AnhangVII": 2,
@@ -11,7 +17,7 @@
"EU-MaschVO-AnhangIII": 14, "EU-MaschVO-AnhangIII": 14,
"EU-MaschVO-AnhangIV": 2 "EU-MaschVO-AnhangIV": 2
}, },
"verify_pending_KBv2": { "article_confirmed": {
"EU-CRA-Art13": 3, "EU-CRA-Art13": 3,
"EU-CRA-Art14": 1, "EU-CRA-Art14": 1,
"EU-CRA-Art16": 1, "EU-CRA-Art16": 1,
@@ -27,10 +33,11 @@
"EU-MaschVO-Art5": 1, "EU-MaschVO-Art5": 1,
"EU-MaschVO-Art50": 1, "EU-MaschVO-Art50": 1,
"EU-MaschVO-Art53": 1, "EU-MaschVO-Art53": 1,
"EU-MaschVO-Art54": 1, "EU-MaschVO-Art54": 1
},
"chapter_no_kb_unit": {
"EU-MaschVO-KapitelIV": 1, "EU-MaschVO-KapitelIV": 1,
"EU-MaschVO-KapitelV": 1, "EU-MaschVO-KapitelV": 1,
"EU-MaschVO-KapitelVI": 1 "EU-MaschVO-KapitelVI": 1
}, }
"note": "KB-v2 bitte prüfen ob die verify_pending Artikel-/Kapitel-norm_ids als Units gemintet sind; Annex-IDs gelten als confirmed."
} }
@@ -0,0 +1,70 @@
"""KB-v2-Verifikation der norm_ids einarbeiten (2026-07-01, Feedback Compliance/KB-Session).
KB-v2 hat die 19 verify_pending IDs geprüft: 16/19 ✓ (alle CRA+MaschVO-Artikel existieren),
3 fehlen = Kapitel-Ebene (`EU-MaschVO-KapitelIV/V/VI`) — der KB-Compiler mintet Artikel+Annex,
KEINE Kapitel. Konsequenz: Artikel-norm_ids `verify_pending→article_confirmed`; Kapitel-norm_ids
`chapter_no_kb_unit` (danglender Join-Key) + Re-Anchor-Hinweis (KB-v2 hat die Konstituenten-Artikel;
Re-Anchor = Enhancement, NICHT geraten). Deterministisch aus dem norm_id-Inhalt neu abgeleitet.
"""
from __future__ import annotations
import glob
import json
REANCHOR_NOTE = (
"Kapitel-Ebene nicht als KB-v2-Unit gemintet (Compiler = Artikel+Annex). "
"Re-Anchor auf Konstituenten-Artikel = Enhancement (KB-v2 hat die Artikel); NICHT geraten."
)
def status_for(norm_ids: list[str]) -> str:
has_annex = any("-Anhang" in n for n in norm_ids)
has_article = any("-Art" in n and "-Anhang" not in n for n in norm_ids)
has_chapter = any("-Kapitel" in n for n in norm_ids)
if has_annex:
return "annex_confirmed"
if has_article:
return "article_confirmed" # KB-v2 verified 16/16
if has_chapter:
return "chapter_no_kb_unit"
return "unparsed"
def main() -> None:
counts = {"annex_confirmed": 0, "article_confirmed": 0, "chapter_no_kb_unit": 0}
obl_linked = obl_chapter = 0
for f in sorted(glob.glob("obligations/cra*.json")):
d = json.load(open(f, encoding="utf-8"))
for o in d.get("obligations", []):
joinable = chapter_only = False
for b in o.get("legal_basis", []):
nids = b.get("norm_ids", [])
st = status_for(nids)
b["norm_id_status"] = st
counts[st] = counts.get(st, 0) + 1
if st == "chapter_no_kb_unit":
b["norm_id_note"] = REANCHOR_NOTE
chapter_only = True
elif st in ("annex_confirmed", "article_confirmed"):
joinable = True
if joinable:
o["citation_status"] = "norm_id_linked"
obl_linked += 1
elif chapter_only:
o["citation_status"] = "chapter_reanchor_pending"
obl_chapter += 1
# Contract-Block um den Verifikationsstand ergänzen
c = d.get("norm_id_contract")
if isinstance(c, dict):
c["kb_v2_verification"] = (
"2026-07-01: 16/19 verify_pending IDs in KB-v2 bestätigt (alle Artikel); "
"3 Kapitel-IDs = chapter_no_kb_unit (Compiler mintet keine Kapitel)."
)
c["article_status"] = "EU-<ACT>-Art<N> in KB-v2 BESTÄTIGT (16/16); Annex-IDs confirmed"
json.dump(d, open(f, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
print("legal_basis status:", counts)
print(f"citation_status: norm_id_linked {obl_linked} | chapter_reanchor_pending {obl_chapter}")
if __name__ == "__main__":
main()