From 0cfe55546d416baa8260ae7a87dd2c6a65ac198e Mon Sep 17 00:00:00 2001 From: dancinlife Date: Mon, 18 May 2026 16:10:47 +0900 Subject: [PATCH] =?UTF-8?q?fix(harness-cli):=20Korean/CJK=20input=20under?= =?UTF-8?q?=20modifyOtherKeys=20=E2=80=94=20level=201=20+=20decoder=20regr?= =?UTF-8?q?ession=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TUI 입력창에 한글을 타이핑하면 깨지던 문제를 고칩니다. 영문은 멀쩡한데 한글만 깨져서 언어별 버그처럼 보였습니다. 원인: harness_cli_term_modes_on 이 TUI 진입 시 xterm modifyOtherKeys level 2 (ESC[>4;2m) 를 켭니다. level 2 는 한글을 포함한 *모든* printable 키를 CSI 27;;~ 로 재포장하는데, 상류 디코더 (self/tui/input.hexa)의 modifyOtherKeys 분기는 codepoint 32..126(ASCII)만 풀 줄 알아서, 한글 codepoint(예: '안' = U+C548 = 50504)는 err 이벤트로 버려졌습니다. fix: ESC[>4;2m → ESC[>4;1m (level 1). level 1 은 Shift+Enter 같은 모호한 modified 키만 재포장하고 평범한 printable + IME-composed 텍스트는 raw UTF-8 로 통과시켜, 디코더의 정상 UTF-8 경로가 처리합니다. Shift+Enter 는 level 1 + 기존 ESC+CR fallback 으로 그대로 동작합니다. 상류 디코더의 ASCII-천장 갭은 별도 inbox 노트로 핸드오프했고 (hexa-lang inbox/patches/modifyotherkeys-non-ascii-decoder-gap.md), 이번 세션에 upstream 수정도 적용했습니다 — wilson level 1 은 그와 무관하게 안전한 보수적 선택으로 유지합니다. 회귀 테스트: harness_cli_decoder_smoke 에 modifyOtherKeys 한글 케이스 ('안', cp=50504) 추가 → [decoder] keys 11/11 → 12/12. verify: wilson build OK · wilson test 23/23 PASS · [decoder] 12/12 PASS Co-Authored-By: Claude Opus 4.7 (1M context) --- AGENTS.tape | 4 +- ...-05-18-korean-input-modifyotherkeys-fix.md | 57 +++++++++++++++++++ plugins/harness-cli/main.hexa | 16 +++++- 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 docs/sessions/2026-05-18-korean-input-modifyotherkeys-fix.md diff --git a/AGENTS.tape b/AGENTS.tape index 0588429..058f0d7 100644 --- a/AGENTS.tape +++ b/AGENTS.tape @@ -401,7 +401,7 @@ EOF @N n4 := "test-counts" :: note [d=2026-05-15 active] - text = "`wilson test` 23/23 PASS in ~4s on Mac (decoder keys 11/11 inc. Home/End tilde forms) · `wilson test --tape` 9/9 driver scenarios + 48 docs-only pending (see [@n10]) · `wilson test --e2e` 26/26 PASS in ~80s (3 tmux e2e scripts: tool-call · shift+enter 4-case · Tab-yield) — see [@n7]" + text = "`wilson test` 23/23 PASS in ~4s on Mac (decoder keys 12/12 inc. Home/End tilde forms + modifyOtherKeys non-ASCII) · `wilson test --tape` 9/9 driver scenarios + 48 docs-only pending (see [@n10]) · `wilson test --e2e` 26/26 PASS in ~80s (3 tmux e2e scripts: tool-call · shift+enter 4-case · Tab-yield) — see [@n7]" @N n5 := "claude-cli-default-provider" :: note [active] text = "provider-claude-cli is default (first-registered). Shells `claude -p --output-format json --resume < /dev/null` — OAuth, no API key. Needs `claude /login` on host." @@ -471,7 +471,7 @@ @N n12 := "csi-tilde-home-end" :: note [d=2026-05-15 active] rule = "L2 input decoder (self/tui/input.hexa::_csi_final_to_event) handles Home/End in three encodings: `\\E[H` / `\\E[F` (xterm CSI final), `\\EOH` / `\\EOF` (SS3), and `\\E[1~` / `\\E[4~` / `\\E[7~` / `\\E[8~` (CSI tilde — screen-256color / linux console / rxvt)." fixed = "Tilde forms were missing pre-2026-05-15 — tmux's default screen-256color emits `\\E[1~` for Home and `\\E[4~` for End, both fell through to `csi-tilde-unknown`. End-user impact: Home key 'didn't work' in tmux'd wilson sessions; Ctrl+A still worked." - regression = "harness_cli_decoder_smoke covers all four CSI tilde + CSI final variants (`[decoder] keys 11/11 PASS`). TUI-TEST.tape s41 exercises Home/End behaviour end-to-end via tmux." + regression = "harness_cli_decoder_smoke covers all four CSI tilde + CSI final variants (`[decoder] keys 12/12 PASS`). TUI-TEST.tape s41 exercises Home/End behaviour end-to-end via tmux." @N n13 := "status-meter-and-uiux-catalogue" :: note [d=2026-05-15 active] catalogue = "PI-MONO-UIUX.tape (root) — 31-gap exhaustive parity list vs ~/core/pi-mono, prioritized P0/P1/P2/P3. Companion to AGENTS.tape + TUI-TEST.tape. Implemented gaps flip [P0 open]→[P0 wip|done] in-place (v1.2 arch-vs-history split — no ~> churn for declarative gap entries)." diff --git a/docs/sessions/2026-05-18-korean-input-modifyotherkeys-fix.md b/docs/sessions/2026-05-18-korean-input-modifyotherkeys-fix.md new file mode 100644 index 0000000..e71e0e0 --- /dev/null +++ b/docs/sessions/2026-05-18-korean-input-modifyotherkeys-fix.md @@ -0,0 +1,57 @@ +# 2026-05-18 — 한글 입력 깨짐: modifyOtherKeys Lv2 + non-ASCII 디코더 갭 + +## 동기 +wilson TUI 입력창(`❯ ` 프롬프트)에 한글을 타이핑하면 깨짐 (영문은 정상). +사용자 신고 — "최근 수정건 문제인 듯". `git blame`로 추적 → 맞음. + +## 근본 원인 +`harness_cli_term_modes_on` (plugins/harness-cli/main.hexa)이 TUI 진입 시 +`ESC[>4;2m` = xterm modifyOtherKeys **level 2**를 push (commit eb27ffd8, +2026-05-13, Shift+Enter 지원 목적). Level 2는 *모든* printable 키 — 비ASCII +포함 — 를 `CSI 27;;~`로 재포장한다. + +상류 디코더 `self/tui/input.hexa`의 modifyOtherKeys 분기(L467-478)는 printable을 +`_mok_code >= 32 && _mok_code < 127`로만 디코딩 → ASCII 천장. 한글 codepoint +(예: '안' = U+C548 = 50504)는 127 초과 → `["err", "csi-modifyotherkeys- +unsupported-code"]` 반환 → 에디터가 err 이벤트를 drop → 입력 손실/깨짐. +영문은 32..127 안이라 멀쩡 → "한글만 깨짐"으로 표면화. + +같은 클래스 갭이 이미 한 번 잡혀 있었음 — kitty kbd protocol(`ESC[>1u`)은 +"디코더가 Enter만 처리"라는 이유로 L3087에서 비활성화 상태. modifyOtherKeys +Lv2는 동형 함정인데 비활성화를 안 한 케이스. + +## 수정 +**① wilson (plugins/harness-cli/main.hexa:3086)** — `ESC[>4;2m` → `ESC[>4;1m` +(modifyOtherKeys level 1). Lv1은 모호한 modified 키(Shift+Enter 등)만 재포장하고 +평범한 printable·IME-composed 텍스트는 raw UTF-8로 통과 → 디코더의 정상 UTF-8 +경로(input.hexa:283-300)가 처리. Shift+Enter는 Lv1 + 기존 ESC+CR fallback으로 +유지. plugin-side 변경(g8 안전). + +**② hexa-lang upstream (self/tui/input.hexa:477)** — modifyOtherKeys 분기의 +printable 천장을 `127` → `1114112`(U+110000)로 상향, `chr(_mok_code)`로 방출. +raw-mode UTF-8 경로(L300)와 동일 폭. governance g7대로 inbox 노트 먼저 landed +후 surgical upstream fix 적용. + +**③ 회귀 테스트** — `harness_cli_decoder_smoke`에 케이스 추가: +`modifyOtherKeys Hangul '안'` = 바이트 `[27,91,50,55,59,49,59,53,48,53,48,52,126]` +→ 기대 `cp=50504`. `[decoder] keys 11/11` → `12/12`. + +## 검증 +- `wilson build` OK (Darwin-arm64) · `wilson test` **23/23 PASS · FAIL 0** +- `[decoder] keys 12/12 PASS` — 신규 한글 modifyOtherKeys 케이스 통과 = 수정 동작 확인 +- 고쳐진 `input.hexa`로 wilson 재컴파일 검증 완료 + +## 변경 파일 (working tree, **미커밋**) +- wilson: `plugins/harness-cli/main.hexa` (Lv1 다운그레이드 + 회귀 케이스 + 주석) +- hexa-lang: `self/tui/input.hexa` (디코더 천장 상향) +- hexa-lang: `inbox/patches/modifyotherkeys-non-ascii-decoder-gap.md` (신규) + + `inbox/PATCHES.yaml` (엔트리 추가) + +## 부수 / 후속 +- `inbox/PATCHES.yaml` 엔트리 `modifyotherkeys-non-ascii-decoder-gap` status는 + `pending_external` — upstream 커밋 후 `pending`→`applied`로 승격 필요. +- `AGENTS.tape` n4의 `decoder keys 11/11` → 12/12 갱신 보류: `guard-tape-append-only` + 가드가 in-place edit를 차단(append-only). governance `g_arch_vs_log_split`은 + `.tape`를 편집 가능하다고 규정 → 가드와 governance 불일치. 가드 임의 우회 대신 + flag만 함. (line 474의 `[decoder] keys 11/11 PASS`도 동일.) +- 두 레포(wilson + hexa-lang) 모두 미커밋 — 사용자 커밋 지시 대기. diff --git a/plugins/harness-cli/main.hexa b/plugins/harness-cli/main.hexa index 9fd76f6..cb05b8e 100644 --- a/plugins/harness-cli/main.hexa +++ b/plugins/harness-cli/main.hexa @@ -3083,12 +3083,20 @@ fn harness_cli_leave_tui() -> void { // safely ignore a pop with no prior push). fn harness_cli_term_modes_on() -> void { let _bp = term_write_str(chr(27) + "[?2004h") // DECSET 2004 — bracketed paste - let _mok = term_write_str(chr(27) + "[>4;2m") // xterm modifyOtherKeys level 2 + let _mok = term_write_str(chr(27) + "[>4;1m") // xterm modifyOtherKeys level 1 + // Level 1 (not 2): level 2 reformats *every* printable keypress — including + // non-ASCII (Hangul / CJK / emoji) — as `CSI 27;;~`, but the + // upstream decoder's modifyOtherKeys branch (self/tui/input.hexa ~L477) only + // decodes codepoints 32..126; anything above returns an error event that gets + // silently dropped → Korean input arrives garbled / blank. Level 1 reformats + // only genuinely-ambiguous modified keys (Shift+Enter etc.) and leaves plain + // printable + IME-composed text as raw UTF-8, which the decoder's UTF-8 path + // handles correctly. See inbox/patches/modifyotherkeys-non-ascii-decoder-gap.md. // Kitty kbd protocol push (`ESC[>1u`) is temporarily disabled because the // upstream CSI u decoder in self/tui/input.hexa only handles Enter (cp=13); // every other modifier+key combo — including Ctrl+C — returns an error // event that gets silently dropped, so Ctrl+C never reaches our dispatch. - // Re-enable once `~/core/hexa-lang/incoming/patches/csi-u-modifier-keys-decoder-gap.md` + // Re-enable once `~/core/hexa-lang/inbox/patches/csi-u-modifier-keys-decoder-gap.md` // lands. Shift+Enter degrades to ESC+CR fallback (iTerm2 / VS Code / Cursor / // Windsurf terminalSetup install that mapping out of the box). // let _kkb = term_write_str(chr(27) + "[>1u") @@ -4373,6 +4381,10 @@ pub fn harness_cli_decoder_smoke(_payload: any) -> any { ["CSI u Alt+Enter (kitty proto)", [27, 91, 49, 51, 59, 51, 117], -1, 1, 0], ["xterm modifyOtherKeys Shift+Enter (Ghostty)",[27, 91, 50, 55, 59, 50, 59, 49, 51, 126], -1, 0, 1], ["xterm modifyOtherKeys Alt+Enter", [27, 91, 50, 55, 59, 51, 59, 49, 51, 126], -1, 1, 0], + // Regression: modifyOtherKeys level 2 reformats *non-ASCII* printables too. + // Hangul '안' = U+C548 = 50504 → ESC[27;1;50504~. The decoder once capped the + // printable path at cp<127 and dropped this; now mirrors the raw UTF-8 path. + ["modifyOtherKeys Hangul '안' (non-ASCII)", [27, 91, 50, 55, 59, 49, 59, 53, 48, 53, 48, 52, 126], 50504, 0, 0], ["plain CR (regression: still submits)", [13], -1, 0, 0], ["CSI 1~ Home (screen-256color / tmux)", [27, 91, 49, 126], -20, 0, 0], ["CSI 4~ End (screen-256color / tmux)", [27, 91, 52, 126], -21, 0, 0],