...or "")
    if len(text) <= max_chars:
        return text
    head = int(max_chars * head_ratio)
    tail = max_chars - head - 40
    tail = max(0, tail)
    return text[:head] + "\n...\n[TRUNCATED]\n...\n" + (text[-tail:] if tail else "")


def extract_block_id_from_filename(p: Path) -> str:
    # Beispiele:
    # CONV_0008_BLOCK_01.txt -> CONV_0008_BLOCK_01
    # CONV_0206_BLOCK_01__EXTRACT.txt -> ...