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
@@ -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()