From 5404343a1ad751bc5e9fa804e96501344399a5bd Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Thu, 30 Apr 2026 08:29:39 +0900 Subject: [PATCH] =?UTF-8?q?fix(study):=20HC-5=20block=20math=20spacing=20?= =?UTF-8?q?=E2=80=94=20KaTeX=20\$\$...\$\$=20=EC=95=9E=EB=92=A4=20?= =?UTF-8?q?=EB=B9=88=20=EC=A4=84=20=EB=B3=B4=EC=9E=A5=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제: 보기/해설 본문의 \$\$ ... \$\$ block math 가 앞뒤 빈 줄 없으면 마크다운 파서가 라벨/텍스트와 같은 단락에 묶어 KaTeX 렌더 실패 → raw 표시. 운영 결과 (21회분 = 2,100문항): - HC-5 detect 317건 모두 자동 fix 완료. 모든 회차 재검사 0건. - 추가 fix: q1579 (2023년 1회 q81) 바이메탈 ASCII 다이어그램 fence wrap. 알고리즘: - 자체 줄 \$\$...\$\$ (한 줄 안 시작·종료, 길이 4+) detect. - 앞·뒤 라인이 비어있지 않으면 빈 줄 삽입 — idempotent. - inline \$ ... \$ 영향 없음. - 의미 변경 0 (빈 줄 삽입만, 본문 텍스트/수식 보존). Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/audit_study_question_markdown.py | 41 +++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/scripts/audit_study_question_markdown.py b/scripts/audit_study_question_markdown.py index ee47669..c4ffe04 100644 --- a/scripts/audit_study_question_markdown.py +++ b/scripts/audit_study_question_markdown.py @@ -106,6 +106,40 @@ def hc4_strip_whitespace(text: str) -> str | None: return stripped if stripped != text else None +def hc5_block_math_spacing(text: str) -> str | None: + """HC-5: 자체 줄 block math (^$$...$$$ 단독 라인) 의 앞뒤로 빈 줄 보장. + + KaTeX block math 가 인라인 텍스트와 같은 단락에 묶여 렌더 실패하는 케이스 fix. + 빈 줄 삽입만 — 본문 내용 보존. + """ + if not text or "$$" not in text: + return None + lines = text.split("\n") + new_lines: list[str] = [] + changed = False + for i, line in enumerate(lines): + s = line.strip() + # 자체 줄 block math: ^$$...$$$ (한 줄 안 시작·종료, 내용 1자 이상) + is_block = ( + s.startswith("$$") and s.endswith("$$") and len(s) >= 4 and s != "$$" + ) + if is_block: + # 앞에 비어있지 않은 라인 있으면 빈 줄 추가 + if new_lines and new_lines[-1].strip(): + new_lines.append("") + changed = True + new_lines.append(line) + # 다음 라인이 비어있지 않으면 빈 줄 추가 + if i < len(lines) - 1 and lines[i + 1].strip(): + new_lines.append("") + changed = True + else: + new_lines.append(line) + if not changed: + return None + return "\n".join(new_lines) + + def apply_all_hc(text: str) -> tuple[str, list[str]]: """HC 룰 순서대로 적용. (최종 텍스트, 적용된 룰 라벨 리스트).""" new = text @@ -130,6 +164,11 @@ def apply_all_hc(text: str) -> tuple[str, list[str]]: if r is not None: new = r applied.append("HC-4") + # HC-5 block math spacing (마지막 — HC-1~4 가 변경한 결과에도 적용) + r = hc5_block_math_spacing(new) + if r is not None: + new = r + applied.append("HC-5") return new, applied @@ -290,7 +329,7 @@ async def run(topic_id: int, exam_round: str, apply: bool, abort_threshold: int) rule_counts[rl] = rule_counts.get(rl, 0) + 1 print("─── HC dry-run ───") - for rl in ["HC-1", "HC-2", "HC-3", "HC-4"]: + for rl in ["HC-1", "HC-2", "HC-3", "HC-4", "HC-5"]: print(f" {rl}: {rule_counts.get(rl, 0)}건") print(f" 총 변경 대상 field: {len(hc_changes)}건\n")