Skip to content

Task #576: 수식 토크나이저 times/sim 키워드 prefix-split 정정 (closes #576)#578

Closed
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:pr-task576
Closed

Task #576: 수식 토크나이저 times/sim 키워드 prefix-split 정정 (closes #576)#578
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:pr-task576

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

Summary

  • 본질: `tokenizer.rs::read_command` (L104) 의 prefix-split 키워드 list 가 폰트 스타일 모디파이어 3 개 (`bold/it/rm`) 만 처리. `times` / `sim` 등 연산자 키워드가 변수와 인접 시 단일 식별자로 토큰화 (예: `"a timesm"` → 단일 "timesm" 토큰).
  • 정정: 광범위 sweep (158 fixture / 563 unique 수식 scripts) 결과 결함 발현 키워드 4 개 (`times/sim/TIMES/SIM`) 만 list 에 추가. alpha/over/sqrt 등 다른 keyword 는 항상 공백 구분되어 prefix-split 불필요 — 그리스 문자 prefix 충돌 ("alphabet" → "alpha"+"bet") 회귀 위험 0.

핵심 정정 결과 (exam_science.hwp page 4 pi=128 20번 응답)

Script Before After
`{b} over {a timesm}` 분모 "a timesm" italic 식별자 "a × m" (× = U+00D7) ✓
`rm X simZ` "X simZ" italic 식별자 "X ∼ Z" (∼ = U+223C) ✓

영향 범위 (광범위 sweep 결과)

  • exam_science.hwp 한정 — 다른 fixture (exam_eng/exam_kor/exam_math/atop-equation-01/equation-lim/eq-01/biz_plan) byte-identical
  • 영향 paragraph:
    • page 3 pi=79 (15번 본문): `rm W simY/Z`, `rmX/W simZ` 등 다수
    • page 3 pi=82/68 (15/13번 보기): `rmA SIMC` 등
    • page 4 pi=126 (20번 본문): `1TIMES10^-14` → `1 × 10⁻¹⁴`
    • page 4 pi=128 (20번 응답): `{b} over {a timesm}`, `rm X simZ`

Test plan

  • `cargo test --lib` — 1125 → 1131 passed (+6 신규 tokenizer tests, 회귀 0)
  • `cargo test --test svg_snapshot` — 6/6 passed
  • `cargo clippy --release --lib` — 본 변경 신규 경고 0 (사전 결함 2건 변경 전후 동일)
  • 광범위 fixture sweep — 8 fixture 60+ 페이지, exam_science 외 byte-identical
  • exam_science page 1/2 byte-identical, page 3/4 의도된 정정만
  • 작업지시자 시각 판정 (`output/svg/exam_science_task576/*.svg`)
  • rhwp-studio web Canvas 시각 판정 (WASM)

신규 회귀 차단 unit tests (6 개)

```rust
test_task576_times_lowercase_prefix_split "a timesm" → ["a", "times", "m"]
test_task576_sim_lowercase_prefix_split "rm X simZ" → ["rm", "X", "sim", "Z"]
test_task576_times_uppercase_prefix_split "1TIMES10" → ["1", "TIMES", "10"]
test_task576_sim_uppercase_prefix_split "rmA SIMC" → ["rm", "A", "SIM", "C"]
test_task576_alpha_no_split "alpha"/"alphabet" 분리 안 됨 (회귀 차단)
test_task576_times_followed_by_space "a times b" 공백 구분 보존
```

메모리 정합

  • ✓ `feedback_essential_fix_regression_risk`: 광범위 sweep + tokenizer tests + svg_snapshot
  • ✓ `feedback_rule_not_heuristic`: 명시적 키워드 list (룰), 휴리스틱 미도입
  • ✓ `feedback_pdf_not_authoritative`: Unicode 코드포인트 검증, PDF 미사용

산출 문서

  • 수행계획: `mydocs/plans/task_m100_576.md`
  • Stage 1 진단 (코드 무수정): `mydocs/working/task_m100_576_stage1.md`
  • Stage 2 구현계획: `mydocs/plans/task_m100_576_impl.md`
  • Stage 3 구현+검증: `mydocs/working/task_m100_576_stage3.md`
  • 최종 보고서: `mydocs/report/task_m100_576_report.md`

선행 task

별개 결함 — equation 토크나이저 (Tasks #565/#568/#573 의 layout 결함과 무관).

closes #576

🤖 Generated with Claude Code

@edwardkim

Copy link
Copy Markdown
Owner

@planet6897 님, @oksure 님 — 두 PR (#578 + #579) 이 동일 이슈 #576 의 다른 접근으로 동시 등록되어 있습니다. 메인테이너 검토 결과 양쪽 통합 이 가장 정합한 방향으로 판단됩니다. 두 분의 협업 PR 을 부탁드리는 첫 시도로 본 안내를 드립니다.

두 PR 의 정합한 영역 비교

PR 본질 정합 메모리 룰
#578 (@planet6897) 광범위 sweep (158 fixture / 563 unique 수식 scripts) + 명시적 4 키워드 (times/sim/TIMES/SIM) list 추가 feedback_essential_fix_regression_risk / feedback_hancom_compat_specific_over_general
#579 (@oksure) 일반적 인프라 (is_known_command(), longest_keyword_prefix_len() 헬퍼 + 모든 알려진 키워드 통합 조회) feedback_rule_not_heuristic

통합 시 본질

두 영역 모두 가치 있고 본질적으로 보완:

  1. PR fix: 수식 토크나이저 keyword prefix-split 구현 (#576) #579 의 인프라symbols.rs::is_known_command() + longest_keyword_prefix_len() 헬퍼는 향후 키워드 추가 시 자동 인식되는 확장성 있는 본질. 모든 알려진 키워드 (OPERATORS / GREEK / FUNCTIONS / FONT_STYLES / DECORATIONS / 구조명령어) 를 통합 조회하여 단일 룰 적용
  2. PR Task #576: 수식 토크나이저 times/sim 키워드 prefix-split 정정 (closes #576) #578 의 sweep + case-specific — 158 fixture / 563 scripts 광범위 검증으로 발견한 4 영향 키워드 (times/sim/TIMES/SIM) — 회귀 위험 정밀 식별

일반화 알고리즘 (PR #579) 의 잠재 회귀:

PR #579longest_keyword_prefix_len() 이 모든 알려진 키워드를 prefix 로 분리할 수 있어 다음과 같은 case 에 회귀 위험:

  • alphabetalpha + bet (그리스 문자 prefix 충돌)
  • sqrtestsqrt + est

PR #578 의 광범위 sweep 결과로 이런 회귀가 실제 fixture 에서 발현되는지 검증되어 4 키워드만 영향이 있다는 것이 확정됨.

통합 PR 제안

다음 통합 영역 권장:

  1. PR fix: 수식 토크나이저 keyword prefix-split 구현 (#576) #579 의 인프라 (symbols.rs 헬퍼 + tokenizer.rs::read_command 정정) 채택
  2. PR Task #576: 수식 토크나이저 times/sim 키워드 prefix-split 정정 (closes #576) #578 의 광범위 sweep 결과로 회귀 검증 — 158 fixture / 563 scripts 에서 일반화 알고리즘 적용 시 byte-identical 또는 의도된 정정만 발현되는지 점검
  3. PR Task #576: 수식 토크나이저 times/sim 키워드 prefix-split 정정 (closes #576) #578 의 6 신규 unit tests 보존 (회귀 차단 가드)
  4. 회귀 발견 시: case-specific 분기 (예: alphabet 같은 알려진 충돌은 명시적 차단) 추가 또는 일반화 영역의 키워드 list 좁힘

협업 PR 자원 요청

본 안내는 두 컨트리뷰터의 커뮤니케이션 통한 PR 처리 시도 의 첫 사례입니다. 둘 중 한 분이 통합 PR 을 자원해주시거나, 함께 작업하실 방식 (예: PR #579 base 위에 PR #578 의 sweep 검증 영역 추가) 알려주시면 그에 따라 진행하겠습니다.

PR #578 / #579 의 OPEN 상태는 통합 PR 결정까지 유지합니다 (close 안 함).

본 사이클의 매우 활발한 컨트리뷰션 (3 컨트리뷰터, 10+ PR 처리 중) 의 진보 사례로 두 분의 협업을 부탁드립니다.

oksure added a commit to oksure/rhwp that referenced this pull request May 4, 2026
Copilot 리뷰 + 메인테이너 피드백 반영:
- `alphabet` → `alpha`+`bet` 회귀 방지
- `sinx` → `sin`+`x` 분할 방지

is_splittable_keyword()를 도입하여 prefix-split 대상을
OPERATORS, BIG_OPERATORS, SPECIAL_SYMBOLS, FONT_STYLES로 한정.
그리스 문자, 함수, 장식, 구조 명령어는 변수명 충돌 위험으로 제외.

PR edwardkim#578 (@planet6897) sweep 결과와 일치: 실제 영향 키워드는
times/sim/TIMES/SIM 4개 (모두 OPERATORS).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@planet6897

Copy link
Copy Markdown
Contributor Author

@oksure 님, @edwardkim 님 감사합니다.
issue 처리시에 조금 더 주의해서 진행하겠습니다.

@planet6897 planet6897 closed this May 4, 2026
@planet6897 planet6897 reopened this May 6, 2026
planet6897 added 5 commits May 6, 2026 10:20
작업지시자 시각 보고 — exam_science.hwp 4페이지 20번 응답 inline 수식
'{b} over {a timesm}' / 'rm X simZ' 가 'a × m' / 'X ~ Z' 로 렌더되어야
하나 italic 식별자 'a timesm' / 'X simZ' 그대로 표시.

본질 결함: tokenizer.rs::read_command (L101) 가 prefix-split 을
'rm/it/bold' 3 개만 처리. times/sim/over/sqrt/alpha/beta 등 수십 개
keyword 가 변수와 결합 시 단일 식별자로 토큰화.

3 정정 안 (Stage 2 에서 비교):
A — 키워드 목록 확장 (정적)
B — longest-prefix match against lookup_symbol set
C — 휴리스틱 (rule-not-heuristic 위반 가능)

위험 요소:
- 짧은 keyword (alpha/pi/mu) 가 다른 식별자 prefix 일 가능성
- 토크나이저 성능 저하 (모든 keyword 매번 비교)

Stage 1 진입 승인 요청 (정밀 진단 + 광범위 영향 범위 측정).
광범위 sweep 결과 (158 fixture / 563 unique 수식 script):
- 결함 발현: 10 unique scripts, 모두 exam_science.hwp 한정
- 결함 키워드: times/sim/TIMES/SIM 4 개 (대소문자)
- 다른 fixture (exam_eng/exam_kor/exam_math/atop-equation 등 558 scripts)
  결함 미발현
- alpha/beta 등 그리스 문자 prefix 충돌 케이스 미발현 (회귀 위험 낮음)

발현 영향 paragraph (작업지시자 보고 + sweep 매칭):
- pi=128 (20번 응답): {b} over {a timesm} + rm X simZ
- pi=79 (15번 본문): rm W simY, rmX simZ, rmW simZ 등 다수
- 기타 13/16/19번 등

3 정정 안 비교:
- 안 A 정적 키워드 list 확장 — 변경 면적 최소 (1줄), 회귀 위험 0
- 안 B longest-prefix match against lookup_symbol — 단일 source 이나 alpha
  등 prefix 충돌 위험
- 안 C 휴리스틱 — feedback_rule_not_heuristic 위반 회피

권고: 안 A (sweep 발견 4 키워드만 추가).

Stage 2 진입 승인 요청.
read_command (tokenizer.rs L104) 의 prefix-split list 를 sweep 발견
times/sim/TIMES/SIM 4 키워드 추가:

  for kw in ["bold", "it", "rm",
             "times", "sim", "TIMES", "SIM"] { ... }

추정 변경 +5/-1 LOC. 회귀 위험 0 (alpha/over/sqrt 등 다른 keyword 는 sweep
에서 결함 미발현).

회귀 차단 unit tests 6 개 추가:
- timesm/simZ/TIMES10/SIMC prefix-split 검증
- alpha/alphabet 분리 안 됨 (회귀 차단)
- 'a times b' 공백 구분 보존

Stage 3 진입 승인 요청.
본질 정정 — read_command (tokenizer.rs L104) 의 prefix-split 키워드 list 를
'bold/it/rm' 3 개 → 'bold/it/rm/times/sim/TIMES/SIM' 7 개로 확장.

광범위 sweep (Stage 1) 결과 발현 키워드 4 개만 추가하여 회귀 위험 최소화.
alpha/over/sqrt 등 다른 keyword 는 sweep 에서 결함 미발현 — prefix 충돌
('alphabet' → 'alpha'+'bet') 회귀 위험 0 보장.

검증:
- cargo test --lib 1131 통과 (+6 신규 tokenizer tests, 회귀 0)
- svg_snapshot 6/6 통과
- clippy 신규 경고 0 (사전 결함 2건 변경 전후 동일)
- 광범위 sweep 8 fixture 60+ 페이지 — exam_science 외 byte-identical
- exam_science page 1/2 byte-identical, page 3/4 의도된 정정만

핵심 정정 (pi=128 page 4 20번 응답):
- ctrl[0] '{b} over {a timesm}' 분모: 'a timesm' → 'a × m' (× U+00D7)
- ctrl[1] 'rm X simZ': 'X simZ' → 'X ∼ Z' (∼ U+223C)

영향 paragraph (sweep + 작업지시자 보고):
- page 3 pi=79 (15번 본문) sim 다수
- page 3 pi=82/68 (15/13번 보기) SIM 다수
- page 4 pi=126 (20번 본문) TIMES
- page 4 pi=128 (20번 응답) times/sim

변경 LOC: src/renderer/equation/tokenizer.rs +50/-1 (코드 +1, 주석 +5,
신규 unit tests +44).

Stage 4 진입 승인 요청.
본 task 산출물:
- mydocs/report/task_m100_576_report.md (최종 보고서)
- mydocs/orders/20260504.md (Issue edwardkim#568/edwardkim#572/edwardkim#573/edwardkim#574/edwardkim#576 행 추가)

검증 요약:
- pi=128 ctrl[0] 'a timesm' → 'a × m' (× U+00D7)
- pi=128 ctrl[1] 'X simZ' → 'X ∼ Z' (∼ U+223C)
- cargo test --lib 1131 (+6 신규 tokenizer tests, 회귀 0)
- svg_snapshot 6/6 / clippy 신규 0
- 광범위 sweep 8 fixture 60+ 페이지: exam_science 외 byte-identical
- exam_science page 1/2 byte-identical, page 3/4 의도된 정정

작업지시자 시각 판정 + close + local/devel merge 승인 요청.
edwardkim added a commit that referenced this pull request May 6, 2026
PR #578 (Task #576, @planet6897 / Jaeook Ryu) 1차 검토:
- 본질 결함: tokenizer.rs::read_command (L104) prefix-split list 가
  bold/it/rm 만 처리 → times/sim/TIMES/SIM 결합 식별자 단일 토큰화
  (예: "a timesm" → "timesm" italic)
- 본질 정정: list 확장 bold/it/rm → bold/it/rm/times/sim/TIMES/SIM
  (광범위 sweep 158 fixture / 563 scripts 결과 4 키워드만 발현)
- 회귀 위험 0 — alpha/over/sqrt 등 다른 keyword 는 공백 구분 보존
- 단일 파일 본질 (tokenizer.rs +53 LOC + 6 신규 unit tests)

PR #579 영역: 5/4 협업 PR 권유 후 @oksure self-close →
PR #578 단독 처리 정합, @planet6897 답신 학습 의지 표명.

본 환경 임시 검증:
- cherry-pick 충돌 0
- cargo test --lib --release 1140 passed (회귀 0)
- task576 unit tests 6/6 passed (alpha 회귀 차단 가드 포함)
- svg_snapshot 6/6 / clippy 0건

권장 처리: 옵션 A — 핀셋 cherry-pick + 결정적 검증 + 광범위 sweep +
작업지시자 시각 판정 (exam_science page 3/4).
edwardkim added a commit that referenced this pull request May 6, 2026
…ixture 1,614 페이지 회귀 0 + exam_science page 3/4 의도된 정정
edwardkim added a commit that referenced this pull request May 6, 2026
…키워드 prefix-split — @planet6897 / Jaeook Ryu 1 commit + 시각 판정 ★ 통과)

PR #578 (Task #576, @planet6897 PR / Jaeook Ryu commit author):
- 본질 결함: tokenizer.rs::read_command (L104) prefix-split list 가
  bold/it/rm 만 처리 → times/sim/TIMES/SIM 결합 식별자 단일 토큰화
  (예: "a timesm" → "timesm" italic)
- 본질 정정: list 확장 bold/it/rm → bold/it/rm/times/sim/TIMES/SIM
- 광범위 sweep (158 fixture / 563 scripts) 결과 4 키워드만 발현 →
  alpha/over/sqrt 등 회귀 위험 0
- 단일 파일 본질 (tokenizer.rs +53 LOC + 6 신규 unit tests)

PR #579 영역: 5/4 협업 PR 권유 후 @oksure self-close →
PR #578 단독 처리 정합.

검증:
- cargo test --lib --release 1140 passed (회귀 0)
- task576 unit tests 6/6 passed (alpha 회귀 차단 가드 포함)
- svg_snapshot 6/6 / clippy 0 / build --release
- WASM 4,583,156 bytes (v0.7.10 baseline +1,691 bytes — tokenizer.rs +53 LOC 정합)
- 광범위 페이지네이션 회귀 sweep: 164 fixture (158 hwp + 6 hwpx) /
  1,614 페이지 / 페이지 수 회귀 0
- exam_science byte 차이: page 3/4 만 의도된 정정 (page 1/2 byte-identical)

작업지시자 웹 시각 판정 ★ 통과.

closes #576.
@edwardkim

Copy link
Copy Markdown
Owner

@planet6897 @jangster77 님,

본 PR 의 본질 commit (`6f3d94aa`) 핀셋 cherry-pick 후 devel merge 완료되었습니다 (`72cd9fd`).

처리 결과

본질 cherry-pick

  • `6f3d94aa` Stage 3 본질 정정 (`src/renderer/equation/tokenizer.rs` +53 LOC)
  • 충돌 0건
  • author Jaeook Ryu (@jangster77) 보존

결정적 검증

  • `cargo test --lib --release` 1140 passed (회귀 0)
  • task576 unit tests 6/6 passed (`test_task576_alpha_no_split` 회귀 차단 가드 포함)
  • `cargo test --test svg_snapshot` 6/6 passed
  • `cargo clippy --release --lib` 0건
  • Docker WASM 4,583,156 bytes (v0.7.10 baseline +1,691 bytes — tokenizer.rs +53 LOC + 6 unit tests 정합)

광범위 페이지네이션 회귀 sweep (본 환경 자동)

통계 결과
총 fixture 164 (158 hwp + 6 hwpx — `samples/` 폴더 전체)
총 페이지 1,614
fixture 별 페이지 수 차이 0

exam_science byte 차이 (PR 본문 100% 재현)

페이지 byte 차이
page 1 identical ✅
page 2 identical ✅
page 3 differ ✅ (15번 본문/보기, `rm W simY/Z` 등)
page 4 differ ✅ (20번 본문/응답, `{b} over {a timesm}`, `1TIMES10^-14`, `rm X simZ`)

→ PR 본문 명시 정정 영역 (page 3/4) 정확 정합 + page 1/2 byte-identical (회귀 0).

시각 판정 (★ 게이트)

작업지시자 시각 검증 결과:

웹 시각판정 통과입니다.

`times`/`TIMES` → × (U+00D7) + `sim`/`SIM` → ∼ (U+223C) 정합 회복 + alpha/over/sqrt 회귀 0 확인.

본 PR 의 본질 — 광범위 sweep + 명시 list 정합

158 fixture / 563 unique 수식 scripts 광범위 sweep 으로 4 키워드 (`times/sim/TIMES/SIM`) 만 prefix-split 회귀 영역으로 식별 + 명시 list 추가 (휴리스틱 미도입).

회귀 차단 가드 (6 신규 unit tests):

  • `test_task576_alpha_no_split` — alpha/alphabet 분리 차단 (그리스 문자 prefix 충돌 회피)
  • `test_task576_times_followed_by_space` — 공백 구분 보존

메모리 룰 정합:

  • `feedback_essential_fix_regression_risk` — 광범위 sweep + tokenizer tests + svg_snapshot
  • `feedback_hancom_compat_specific_over_general` — 명시 4 키워드 list (case-specific)
  • `feedback_rule_not_heuristic` — 명시적 키워드 list (휴리스틱 미도입)

PR #579 영역 (5/4 협업 PR 권유 시도)

5/4 협업 PR 권유 댓글 후 PR #579 (@oksure) self-close → PR #578 단독으로 영역 정합. @planet6897 의 답신 (5/4 22:23) "issue 처리시에 조금 더 주의해서 진행하겠습니다" 의 학습 의지 영역 인지 — 본 사이클의 협업 PR 시도 학습 사례.

처리 보고서: `mydocs/pr/archives/pr_578_report.md` (작성 후 push 됩니다).

본 PR 도 두 분의 협업 흐름의 우수한 사례입니다. 광범위 sweep + 명시 list + 6 신규 unit tests 의 정밀한 회귀 차단 패턴이 메인테이너 cherry-pick 의 본질만 깨끗하게 추출 + 본 환경 결정적 검증 통과로 이어졌습니다. 감사합니다.

@edwardkim edwardkim closed this May 6, 2026
edwardkim added a commit that referenced this pull request May 6, 2026
- mydocs/pr/archives/pr_578_report.md 신규 (처리 보고서)
- mydocs/pr/pr_578_review.md → mydocs/pr/archives/pr_578_review.md 이동
- mydocs/orders/20260506.md 신규 (5/6 사이클 첫 작성: v0.7.10 릴리즈 + PR #578)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request May 6, 2026
- 9.5.5 시각 판정 자료 안내 (output/svg/pr578_before vs pr578_after, page 3/4 차이)
- 9.5.6 작업지시자 시각 판정 ★ 통과 명시
- 9.5.7 후속 처리 완료 표 (devel merge 72cd9fd / PR close / orders 갱신)
- 처리 결정 갱신 (검토 중 → 처리 완료)
- WASM 산출물 4,583,156 bytes 정합 명시

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request May 6, 2026
- Task #628 nested cell inline_shape_positions 키 충돌 정정 검토
- 본질 commit 04ce0d2 src 7 파일 (+62/-28) 단독 cherry-pick 가능
- 본 환경 검증: cargo test 1140 passed / clippy 0 / svg_snapshot 6/6
- 정량 측정: BEFORE 3 → AFTER 4 images (page 4), 위치 PR 본문 명세 100% 일치
- 광범위 sweep: 164 fixture / 1,684 페이지 / 차이 0
- WASM: 4,590,307 bytes (PR #578 baseline +7,151)
- 옵션 A (핀셋 cherry-pick) 권장, 작업지시자 시각 판정 + 결정 대기

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants