fix(founding-wizard): missing context vars (P_INFO etc) + italic regex no longer eats snake_case underscores
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 16s
CI / loc-budget (push) Successful in 19s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / detect-changes (push) Successful in 10s
CI / branch-name (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 41s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped

This commit is contained in:
Benjamin Admin
2026-05-20 18:37:12 +02:00
parent 28f9e13c1f
commit 93cedbecbd
2 changed files with 112 additions and 1 deletions
@@ -30,7 +30,12 @@ TABLE_ROW_RE = re.compile(r"^\|(.+)\|\s*$")
TABLE_SEP_RE = re.compile(r"^\|[\s\-:|]+\|\s*$")
INLINE_BOLD = re.compile(r"\*\*([^*]+)\*\*")
INLINE_ITALIC = re.compile(r"(?<!\*)\*(?!\*)([^*]+)\*(?!\*)|_([^_]+)_")
# Italic: nur _wort_ wenn von Whitespace/Satzzeichen umgeben — verhindert dass
# snake_case-Variablen wie ESKALATION_TAGE_INTERN als Italic interpretiert werden.
INLINE_ITALIC = re.compile(
r"(?<!\*)\*(?!\*)([^*\n]+)\*(?!\*)"
r"|(?<![A-Za-z0-9_])_([^_\n]+)_(?![A-Za-z0-9_])"
)
INLINE_CODE = re.compile(r"`([^`]+)`")
@@ -75,6 +75,17 @@ def _company_purpose_bullets(bullets: list[str]) -> str:
return "\n".join(bullets) if bullets else "a) Allgemeine geschäftliche Tätigkeit"
def _roles_description(gesellschafter: list[dict[str, Any]]) -> str:
"""Generiert Anlage-A Rollenbeschreibung pro Gesellschafter."""
lines = []
for idx, g in enumerate(gesellschafter):
name = g.get("name", "")
role = g.get("internal_role") or "Gesellschafter"
lines.append(f"({idx + 2}) **{role}{name}**")
lines.append(f"Verantwortlich für die operative Leitung im Bereich {role}.\n")
return "\n".join(lines)
def _einzahlungsaufstellung(gesellschafter: list[dict[str, Any]], quote_pct: int) -> str:
rows = []
for g in gesellschafter:
@@ -174,5 +185,100 @@ def base_context(state: dict[str, Any]) -> dict[str, Any]:
"HAS_HRB": False,
"HRB_NUMBER": "[wird vergeben]",
"IS_UG": basics.get("legal_form") == "UG",
# GO-GF dynamische §-Numerierung
"P_INFO": 5,
"P_GESELLSCHAFTER": 4 if num_gf == 1 else 4,
"P_AUSSER": 5,
"P_ENT": 6,
"P_FIN": 7,
"P_PERS": 8,
"P_IK": 9,
"P_NEB": 10,
"P_DOC": 10,
"P_DOC_NEXT": 2,
"P_DOC_NEXT_2": 3,
"P_END": 11,
"LAST_PARA_4": 4 if num_gf == 2 else 5,
# SHA dynamische §-Numerierung (mit/ohne Beirat)
"P_NONCOMPETE": 16 if sha.get("has_beirat") else 15,
"P_CONFIDENTIAL": 17 if sha.get("has_beirat") else 16,
"P_TERM": 18 if sha.get("has_beirat") else 17,
"P_FINAL": 19 if sha.get("has_beirat") else 18,
"P_IP_PARA_6": 6 if has_academic else 3,
"P_IP_PARA_7": 7 if has_academic else 4,
"P_IP_PARA_8": 8 if has_academic else 5,
"P_DEADLOCK_FINAL": 5,
"P_DEADLOCK_LAST": 6,
"LAST_ROLE_PARA": len(gesellschafter) + 2,
"LAST_ROLE_PARA_PLUS_1": len(gesellschafter) + 3,
# Satzung dynamische §-Numerierung
"P_EINZIEHUNG": 7,
"P_VORKAUF": 8,
"P_TAGALONG": 9,
"P_DRAGALONG": 10,
"P_VERSAMMLUNG": 11,
"P_JA": 12,
"P_ERGEBNIS": 13,
"P_AUFGRIFF": 14,
"P_ABTRETUNG": 15,
"P_ERBE": 16,
"P_AUFL": 17,
"P_SCHLUSS": 18,
# SHA Eskalation und sonstige Schwellenwerte
"ESKALATION_TAGE_INTERN": 5,
"ESKALATION_TAGE_GESELLSCHAFTER": 14,
"ERHEBLICH_EUR": "10.000",
"DEADLOCK_FRIST_TAGE": 30,
"MEDIATION_INIT_TAGE": 7,
"MEDIATOR_FRIST_TAGE": 5,
"MEDIATION_MAX_TAGE": 30,
"SHOOTOUT_FRIST_TAGE": 14,
"SHOOTOUT_ABWICKLUNG_TAGE": 60,
"ESKALATION_TAGE": 30,
"JURISDICTION_LOCATION": basics.get("company_seat", "[Sitz]"),
"PARA_181_DETAILS": "soweit Geschäftsführer von den Beschränkungen befreit",
"ARCHIV_VERANTWORTLICH": "Geschäftsführung",
"DOKUMENTATIONS_SYSTEM": "elektronischen Dokumentenmanagement",
"ARCHIVIERUNG_JAHRE": 10,
"REVIEW_VERANTWORTLICH": "Geschäftsführung",
"MEETING_OPERATIVE_FREQ": "wöchentliche",
"MEETING_STRATEGIE_FREQ": "monatliche",
"SCHWELLE_EINZEL_EUR": "10.000",
"SCHWELLE_EINZEL_EUR_PLUS_1": "10.001",
"SCHWELLE_GEMEINSAM_EUR": "50.000",
"SCHWELLE_GESELLSCHAFTER_EUR": "50.000",
"BUDGET_ABWEICHUNG_PCT": 10,
"VERTRAG_LAUFZEIT_MONATE": 24,
"VERTRAG_WERT_EUR": "50.000",
"LIQUIDITAET_MIN_MONATE": 3,
"FORECAST_HORIZON_MONTHS": 12,
"SCHLUESSELPERSON_GEHALT_EUR": "80.000",
"NEBENTAETIGKEIT_MAX_STUNDEN": 8,
# SHA-Spezifika
"VESTING_START_EVENT": "Eintragung der Gesellschaft im Handelsregister",
"VESTING_MONTHS": sha.get("vesting_months", 48),
"CLIFF_MONTHS": sha.get("cliff_months", 12),
"ACCELERATION_THRESHOLD_PCT": 50,
"ACCELERATION_PCT": 100,
"BAD_LEAVER_UNVESTED_PCT": 20,
"FMV_AGREEMENT_DAYS": 14,
"ABFINDUNG_RATEN_MAX": 24,
"NON_SOLICIT_MONTHS": 12,
"VORKAUFSRECHT_TAGE": 14,
"TAG_ALONG_THRESHOLD_PCT": sha.get("tag_along_threshold_pct", 20),
"TAG_ALONG_FRIST_TAGE": 14,
"DRAG_ALONG_THRESHOLD_PCT": sha.get("drag_along_threshold_pct", 75),
"RESERVED_MATTERS_MAJORITY_PCT": sha.get("reserved_matters_majority_pct", 75),
"ASSET_THRESHOLD_EUR": "50.000",
"ESOP_POOL_PCT": sha.get("esop_pool_pct", 0),
"INVESTOR_INFO_THRESHOLD_EUR": "50.000",
"ANNUAL_REPORT_MONTHS": 6,
"BEIRAT_MAX_MITGLIEDER": 5,
"BEIRAT_FREQ": "vierteljährlich",
"PASSIVE_INVEST_PCT": 5,
"POST_EXIT_GOOD_MONTHS": 12,
"POST_EXIT_BAD_MONTHS": 24,
"ROLES_DESCRIPTION": _roles_description(gesellschafter),
"SIGNATURE_DATE": notar.get("notarial_date", "[Datum]"),
}
return ctx