@ihabdevteam/core 0.135.0 → 0.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dist/components.cjs.js +177 -177
  3. package/dist/components.esm.css +3 -3
  4. package/dist/hooks.cjs.js +1 -1
  5. package/dist/i18n.cjs.js +3 -3
  6. package/dist/ihabdevteam-core.cjs.js +181 -181
  7. package/dist/ihabdevteam-core.d.ts +38 -7
  8. package/dist/packages/core/src/components/Alert.js +1 -1
  9. package/dist/packages/core/src/components/Breadcrumb.js +1 -0
  10. package/dist/packages/core/src/components/Button.css +5 -0
  11. package/dist/packages/core/src/components/Button.js +3 -3
  12. package/dist/packages/core/src/components/Checkbox.js +10 -2
  13. package/dist/packages/core/src/components/CodeBox.js +2 -1
  14. package/dist/packages/core/src/components/Effect/EffectPartyPopper.js +5 -2
  15. package/dist/packages/core/src/components/Icon.js +4 -1
  16. package/dist/packages/core/src/components/IconGridMenu.js +25 -22
  17. package/dist/packages/core/src/components/LandingHeader.d.ts +1 -1
  18. package/dist/packages/core/src/components/LandingHeader.js +5 -1
  19. package/dist/packages/core/src/components/PageTitle.js +1 -0
  20. package/dist/packages/core/src/components/Pagination.js +1 -1
  21. package/dist/packages/core/src/components/Panel.css +3 -0
  22. package/dist/packages/core/src/components/Panel.d.ts +11 -1
  23. package/dist/packages/core/src/components/Panel.js +3 -3
  24. package/dist/packages/core/src/components/PanelRow.js +8 -1
  25. package/dist/packages/core/src/components/PassCard/PassCardBgIHAB.js +1 -0
  26. package/dist/packages/core/src/components/PassCard/PassCardBgLeftColorGrid.js +1 -0
  27. package/dist/packages/core/src/components/PassCard/PassCardBgSoundMove.js +1 -0
  28. package/dist/packages/core/src/components/PassCard/PassCardBgSoundMoveV1.js +1 -0
  29. package/dist/packages/core/src/components/PassCard/PassCardBgTalk.js +1 -0
  30. package/dist/packages/core/src/components/PassCard/PassCardBgTalkV1.js +1 -0
  31. package/dist/packages/core/src/components/PassCard/PassCardBgTwoCircle.js +1 -0
  32. package/dist/packages/core/src/components/Popup/DeviceSideTable.js +8 -1
  33. package/dist/packages/core/src/components/Popup/ListPopup.js +3 -1
  34. package/dist/packages/core/src/components/Popup/LoadTablePopup.js +6 -5
  35. package/dist/packages/core/src/components/Popup/Popup.css +19 -0
  36. package/dist/packages/core/src/components/Popup/Popup.d.ts +14 -1
  37. package/dist/packages/core/src/components/Popup/Popup.js +6 -5
  38. package/dist/packages/core/src/components/Popup/TrainingResultPopup.js +6 -1
  39. package/dist/packages/core/src/components/Popup/customerDetailUtils.js +5 -3
  40. package/dist/packages/core/src/components/ProgressBar.js +5 -2
  41. package/dist/packages/core/src/components/ProgressIndicator.js +7 -1
  42. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgDark.js +1 -0
  43. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgDeep.js +1 -0
  44. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgDiagonal.js +1 -0
  45. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgDots.js +1 -0
  46. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgInstagram.js +1 -0
  47. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgMain.js +1 -0
  48. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgNaver.js +1 -0
  49. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgOutline.js +1 -0
  50. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgRadial.js +1 -0
  51. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgSoft.js +1 -0
  52. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgSoftSub.js +1 -0
  53. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgSub.js +1 -0
  54. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgSuccess.js +1 -0
  55. package/dist/packages/core/src/components/PromoBannerBg/PromoBannerBgWarm.js +1 -0
  56. package/dist/packages/core/src/components/Rating.js +3 -1
  57. package/dist/packages/core/src/components/SideNav.js +6 -3
  58. package/dist/packages/core/src/components/SplashLogo.js +1 -2
  59. package/dist/packages/core/src/components/StatChart.js +1 -1
  60. package/dist/packages/core/src/components/TextField.js +3 -1
  61. package/dist/packages/core/src/components/Tooltip/DescriptionTooltip.js +1 -0
  62. package/dist/packages/core/src/components/Tooltip/TrainingTooltip.js +6 -5
  63. package/dist/packages/core/src/components/Training/TrainingBlockButton.css +57 -0
  64. package/dist/packages/core/src/components/Training/TrainingBlockButton.js +15 -7
  65. package/dist/packages/core/src/components/Training/TrainingCardGroup.js +1 -0
  66. package/dist/packages/core/src/components/Training/TrainingPagePopupTitle.js +2 -1
  67. package/dist/packages/core/src/components/Training/TrainingStepAudioPlayer.js +28 -1
  68. package/dist/packages/core/src/components/Training/TrainingStepCard.js +10 -3
  69. package/dist/packages/core/src/components/Training/TrainingStepCardOrder.js +36 -26
  70. package/dist/packages/core/src/components/Training/TrainingStepOrderList.d.ts +0 -1
  71. package/dist/packages/core/src/components/Training/TrainingStepOrderList.js +16 -1
  72. package/dist/packages/core/src/components/Training/TrainingStepTextBox.js +7 -4
  73. package/dist/packages/core/src/components/Training/TrainingStepTitle.js +4 -1
  74. package/dist/packages/core/src/components/Training/TrainingWordCard.js +21 -4
  75. package/dist/packages/core/src/components/Training/WordTablePopup.js +9 -3
  76. package/dist/packages/core/src/components/Training/currentSound.d.ts +5 -0
  77. package/dist/packages/core/src/components/Training/currentSound.js +13 -0
  78. package/dist/packages/core/src/components/Training/trainingBlockButtonTypes.d.ts +3 -1
  79. package/dist/packages/core/src/components/Training/trainingMissStats.js +9 -2
  80. package/dist/packages/core/src/components/Training/trainingPopupUtils.js +12 -1
  81. package/dist/packages/core/src/components/Training/useNoiseFade.js +4 -0
  82. package/dist/packages/core/src/components/Training/useTTSPlayback.js +5 -1
  83. package/dist/packages/core/src/components/Word/WordTableBlock.js +5 -2
  84. package/dist/packages/core/src/components/Word/WordTableButton.js +3 -0
  85. package/dist/packages/core/src/components/Word/useWordTableDisplaySettings.js +5 -1
  86. package/dist/packages/core/src/components/Word/wordScoreStats.js +7 -2
  87. package/dist/packages/core/src/components/Word/wordTablePrint.js +15 -2
  88. package/dist/packages/core/src/components/WordTable.js +19 -5
  89. package/dist/packages/core/src/components/buttonTypes.d.ts +6 -0
  90. package/dist/packages/core/src/components/useCalendarMonth.js +15 -17
  91. package/dist/packages/core/src/components/useToastLifecycle.js +7 -2
  92. package/dist/packages/core/src/context/I18nProvider.js +12 -3
  93. package/dist/packages/core/src/hooks/useFontScale.js +13 -4
  94. package/dist/packages/core/src/hooks/useIcon.js +3 -0
  95. package/dist/packages/core/src/hooks/useLucideIcon.js +3 -0
  96. package/dist/packages/core/src/hooks/useMediaQuery.d.ts +2 -1
  97. package/dist/packages/core/src/hooks/useMediaQuery.js +37 -8
  98. package/dist/packages/core/src/hooks/usePagedList.js +1 -0
  99. package/dist/packages/core/src/hooks/useSoundCompassExam.js +13 -2
  100. package/dist/packages/core/src/hooks/useTrainingTypeLabels.js +1 -0
  101. package/dist/packages/core/src/hooks/useVisitHistory.js +1 -0
  102. package/dist/packages/core/src/hooks/useWordTrainingDataGeneration.js +18 -3
  103. package/dist/packages/core/src/i18n/locales/en.json +42 -4
  104. package/dist/packages/core/src/i18n/locales/ko.json +42 -4
  105. package/dist/packages/core/src/utils/date.js +26 -5
  106. package/dist/packages/core/src/utils/errorMessage.js +7 -1
  107. package/dist/packages/core/src/utils/speak.js +23 -3
  108. package/dist/packages/core/src/utils/textSort.js +12 -1
  109. package/dist/packages/core/src/utils/ttsConfig.js +10 -8
  110. package/dist/packages/core/src/version.d.ts +1 -1
  111. package/dist/packages/core/src/version.js +1 -1
  112. package/dist/utils.cjs.js +2 -2
  113. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,134 @@ All notable changes to this project will be documented in this file.
7
7
  > 적은 글이라, 지금 이름으로 고쳐 놓으면 그 시절에 그 이름으로 받은 사람이
8
8
  > 제 이야기를 못 찾는다.
9
9
 
10
+ ## 0.137.0
11
+
12
+ 6차 검수 판이다 — 이번에는 가로지르는 검수 넷(서버 렌더 안전·StrictMode 부작용·언마운트 뒤 남는 것·영어 화면의 한국어)과
13
+ 훅·기본 컴포넌트 2차 검수에서 **재현된** 결함을 고쳤다. 항목마다 시험을 붙이고 고친 줄을 되돌리면 붉어지는 것을 확인했다.
14
+ 말귀 훈련 계획 창이 덮어쓰던 규칙을 prop 으로 더 가져왔다. 걷은 prop·타입·열쇠는 없다. 사전 열쇠를 더했다
15
+ (`wordTable.info.*`·`wordTable.pos.*`·`common.networkError`·`training.audioStatus.*`·`device.type.*`·`header.menuClose`).
16
+
17
+ ### 소비자에게 먼저
18
+
19
+ - **Popup `height`**: 인라인 `height` 대신 CSS 변수 `--popup-height` + `.popup-panel--has-height` 로 건다 — 앱의
20
+ `.x .popup-panel { height }` 미디어 규칙이 이긴다. 패널 `style.height` 를 읽는 시험은 `style.getPropertyValue('--popup-height')` 로.
21
+ - **useMediaQuery**(React 18+): 서버 렌더 HTML 을 붙일 때 첫 렌더는 `false`(서버와 같게), 붙인 뒤 곧바로 실제 값. 서버 렌더가
22
+ 아닌 첫 렌더는 전과 같이 실제 값이다. React 16/17 은 예전 그대로.
23
+ - **'use client'**: 훅을 쓰는 모듈 30곳에 지시문을 달았다(Icon·PageTitle·Breadcrumb·ProgressIndicator·DescriptionTooltip·
24
+ TrainingCardGroup·PassCardBg*·PromoBannerBg*·usePagedList·useTrainingTypeLabels·useVisitHistory). 빠뜨림을 잡는 시험을 둔다.
25
+ - **영어 화면**: 훈련 블록 유형·카테고리, 팝업 아이콘 툴팁, 낱말 정보 툴팁, 네트워크 오류 안내(`toUserErrorMessage` —
26
+ `NETWORK_ERROR_MESSAGE` 상수는 그대로), 오디오 불러오기 상태, 기기 종류 배지, LandingHeader 기본 메뉴 이름이 사전을 거친다.
27
+ 한국어 화면의 글자는 그대로다.
28
+ - **Pagination** `totalPages=0`: `"1 / 1"`(전에는 `"1 / 0"`).
29
+ - **Icon**: `label` 이 요소면 `img alt=""`(전에는 `"[object Object]"`).
30
+
31
+ ### 더함 (말귀 요청)
32
+
33
+ - **Popup `fillBody`**: 본문은 굴리지 않고 안쪽이 세로 flex·높이 100% — 안의 한 칸만 굴린다.
34
+ - **Panel `scrollbarGutter`**: `'auto'`(기본) | `'stable'`.
35
+ - **Panel `compactRows`**: 행 최소 높이 46px·위아래 3px — `size="small"` 행 하나짜리 패널이 테두리까지 48px.
36
+
37
+ ### 바뀜 — 훈련
38
+
39
+ - **TrainingStepOrderList**: `context` 를 안 주면 렌더가 끝없이 돌았다(CPU 100%). 끌기 첫 프레임 전에 끝내거나 떠나면 rAF 루프가
40
+ 영영 돌았다. StrictMode 에서 처음 배치 알림이 두 번(첫 알림은 화면에 안 뜬 배치).
41
+ - **useNoiseFade**(StrictMode·`<Activity>`): 소음 요소를 다시 만들면 파일이 안 물려, 소음이 켜진 채 마운트된 단계에서 소음이 안 났다.
42
+ - **TrainingWordCard·TrainingStepCard**: 음성 합성으로 듣는 중·합성 주소를 기다리는 중·'모두 듣기' 중에 떠나면 소리가 계속 났다 —
43
+ 떠날 때 제가 쥔 소리만 끊는다.
44
+ - **TrainingStepAudioPlayer**: 불러오는 중 떠나면 늦게 온 소리로 blob 주소를 남기고 떼어진 `<audio>` 를 불러왔다.
45
+ - **useTTSPlayback**: 마운트만 한 단계가 떠날 때 다른 곳의 음성 합성을 끊었다.
46
+ - **TrainingResultPopup** 폭죽 신호 · **EffectPartyPopper** 움직임 줄이기 `onComplete`: StrictMode 에서 두 번.
47
+ - **useWordTrainingDataGeneration**: `types` 가 늦게 오면 끝까지 안 만들었고, 언어를 바꿔도 단추 제목이 옛 언어였다.
48
+
49
+ ### 바뀜 — 훅·기본 컴포넌트
50
+
51
+ - **useFontScale**: `storageKey` 가 바뀌면 앞 값으로 새 열쇠의 저장값을 덮었다. 저장소를 못 읽으면 범위를 안 조였다.
52
+ - **Icon·useIcon**: 다른 SVG 로 바꾸는 동안 앞 아이콘이 그려졌다. 그림 파일 경로를 lucide 이름으로 찾아 개발 경고를 냈다.
53
+ - **TextField**: 서버 렌더(React 18)에서 `useLayoutEffect` 경고.
54
+
55
+ ### 고치지 않은 것 — 결정·확인이 필요하다
56
+
57
+ - i18n 이 불러오는 순간 저장된 언어로 시작해, 서버 렌더 앱에서 저장 언어가 en 이면 hydration 이 어긋난다(말귀 SPA 에는 장점).
58
+ - Calendar·BarChart·useRelativeDay 가 렌더 중 '지금' 을 읽는다 — 서버·브라우저 날짜가 다르면 어긋난다.
59
+ - `/images/brand/check.svg` 같은 파일 경로가 lucide `check` 로 그려진다. PanelRowDevice·HearingDeviceInfo 좌·우 단추 이름이 같다.
60
+ - `reviewTableName` "N차 복습"·`duplicateTable` "(복사)" 가 저장 이름에 한국어로 붙는다. 한국어 원본 상수(POS_LABEL 등)를 계속 공개할지.
61
+ - 앞 판에 적은 결정(저장 실패 반환·오프셋 없는 시각·Board 빈 문구·Rating 조작 소수·ConfirmPopup 거절)은 그대로.
62
+
63
+ ## 0.136.0
64
+
65
+ 5차 검수 판이다 — 이번에는 아직 깊이 안 본 곳(context·i18n·유틸, 입력·표시 컴포넌트, 팝업·툴팁·단어표 도구, 훈련 단계)을
66
+ 훑어 **재현된** 결함만 고쳤다. 항목마다 시험을 붙이고 고친 줄을 되돌리면 붉어지는 것을 확인했다. 말귀가 앱에서 덮어쓰던
67
+ 규칙을 코어 prop 으로 가져왔다. 걷은 prop·타입·열쇠는 없다. 사전 열쇠 `training.selectInOrder` 를 더했다.
68
+
69
+ ### 소비자에게 먼저
70
+
71
+ - **칸순**(ListPopup 정렬): 글자 안의 숫자도 수로 견준다 — `'회차 9'` 가 `'회차 10'` 앞에 선다(전에는 뒤). 숫자 칸과
72
+ 숫자로 시작하는 글자 칸이 섞이면 차례가 돌아(`'9'<'10'`·`'10'<'10분'`·`'10분'<'9'`) 들어온 차례에 따라 결과가 달랐다.
73
+ - **ProgressBar** `max=0`: 라벨 `"0 / 0"`·`aria-valuemax=0`(전에는 `"0 / 1"`).
74
+ - **ProgressIndicator** `announce`: 알림 자리 안에 눈에 안 보이는 글자로 단계를 적고 aria-label 은 달지 않는다.
75
+ - **StatChart** 누르는 카드 이름에 증감이 붙는다(`"오늘 방문 7 +3"`).
76
+ - **formatDuration**: 초로 반올림한다(`90.5` → `"1분 31초"`, 0.5초 미만은 `'-'`).
77
+ - **tableTrends**: 매긴 칸이 하나도 없는 기록은 흐름에서 뺀다(모두 비면 그 표는 결과에 없다).
78
+ - **날짜 형식 함수**(`formatDateKo`·`formatDateLongKo`·`formatDatetimeKo`·`formatDateLocale`·`formatDateLongLocale`): 못 읽는 값이면
79
+ `"Invalid Date"` 대신 빈 글자.
80
+ - **IconGridMenu** 제어 모드: prop 을 그대로 그린다 — 누르면 onSelect 만 부르고, 부모가 값을 안 바꾸면 화면도 그대로다.
81
+
82
+ ### 더함 (말귀 요청)
83
+
84
+ - **Popup `layer`**: `'modal'`(기본) | `'belowPagePopup'` — 훈련 페이지 팝업 바로 아래 층(`--z-page-popup` - 1).
85
+ - **Popup `size`**: `'xlarge'`(1320px, 폭 화면 - 80px) · `'fit'`(내용 폭, 최소 min(480px, 화면-40px)·최대 min(1140px, 화면-40px)).
86
+ - **TrainingBlockButton `size="row"`**: 전체 너비 가로 행 [아이콘][유형·제목][문항수], 미리 듣기 없음 — 좁은 화면 목록용.
87
+ - **Button `tooltipOnly`**: 툴팁만 보여 주는 칩 — 커서만 기본 화살표(모양·포커스·툴팁 그대로, `disabled` 와 다름).
88
+
89
+ ### 바뀜 — 입력·표시
90
+
91
+ - **Checkbox**: `indeterminate` 가 누르는 순간 풀려(브라우저가 DOM 속성을 끔) prop 이 그대로 true 여도 빈 칸으로 남았다.
92
+ - **IconGridMenu**: 비제어에서 카테고리가 늦게 오면 첫 항목이 안 골라졌고, StrictMode 에서 첫 알림이 두 번.
93
+ - **SplashLogo**: `onDone` 이 나중에 들어오면 타이머가 끝내 안 걸려 스플래시가 남았다.
94
+ - **Rating**: 소수 값이 모두 반 별로 그려져 4.1 과 4.9 가 같았다 — 값만큼 채운다.
95
+ - **CodeBox**: `language` 가 'sh' 를 품기만 해도(csharp) 셸로 읽었다.
96
+ - **Alert**: `message=""` 면 children 이 가려 빈 칸.
97
+ - **useCalendarMonth**: 한 핸들러에서 `prevMonth` 를 두 번 부르면 (2026, -1).
98
+ - **Toast**: 마우스·포커스로 멈춘 채 문구가 바뀌면 읽는 알림이 손 밑에서 사라졌다.
99
+ - **SideNav**: `appMode` 를 안 주면 여기만 매니저로 봐 Header·BottomNav 와 반대 방향 전환 단추를 띄웠다.
100
+ - **ListPopup**: 고른 행 표시가 열 className(맞춤·폭)을 덮었다.
101
+ - **Button**: `onDisabledClick` 을 준 막힌 단추에 `aria-disabled` 가 안 붙었다.
102
+
103
+ ### 바뀜 — 훈련
104
+
105
+ - **useSoundCompassExam**: 수가 같은 다른 배치로 바꾸면 다시 시작하지 않아 무엇을 골라도 오답이었다. 한 대기에서 고르기가
106
+ 두 번 불리면 점수 +2.
107
+ - **TrainingStepCard**: 따로 쓴 단계에서 '모두 듣기' 가 소리 없이 끝났다.
108
+ - **TrainingStepCardOrder**: StrictMode 에서 onChange·onDone 두 번, 풀 때 onChange 없음, 낱말에 '|' 가 있으면 못 끝냄, 기본
109
+ 제목 한국어 고정.
110
+ - **TrainingStepTitle**: 키보드로 누른 '모두 듣기' 가 재생 중 막히며 초점이 body 로 빠졌다.
111
+ - **TrainingStepTextBox**: 펼쳐 둔 상자에서 다음 문제로 넘어가면 한 틱 동안 새 문장(정답)이 드러났다.
112
+ - **TrainingPagePopupTitle**: title 이 비고 depth 가 없으면 subtitle 이 두 줄.
113
+ - **TrainingTooltip**: 영어에서도 훈련 유형 머리글이 한국어.
114
+ - **summarizeMisses**: A→B→A 로 풀면 복습이 가장 최근 세트 대신 옛 세트로 짜였다.
115
+ - **WordTablePopup `autoPrint`**: StrictMode·100ms 안 인쇄 설정 변경에서 한 번도 안 떴다.
116
+ - **EffectPartyPopper**: 첫 틀이 조각 지연보다 이르면 한 조각도 안 나고 곧바로 끝났다.
117
+
118
+ ### 바뀜 — 단어표·팝업·유틸
119
+
120
+ - **LoadTablePopup**: 저장소의 표 하나가 `savedAt`·`words` 가 없으면 팝업 전체가 렌더 중에 터졌다. 영어에서도 "N개".
121
+ - **WordTableButton**: 카드 안 '더보기'·게시자 단추에서 Enter/Space 가 카드를 열었다.
122
+ - **WordTableBlock·useWordTableDisplaySettings**: 페이지당 개수 '전체' 를 고른 뒤 항목이 늘면 선택지에 없는 값이 남았다.
123
+ - **printWordTableElements**: iframe 인쇄 뒤 탭 제목이 표 이름으로 남을 수 있었고, 다음 인쇄가 그것을 원래 제목으로 잡았다.
124
+ - **checkAudioExists**: 서버 오류(5xx)를 '음성 없음' 으로 영구 캐시했다. 비운 뒤 늦게 실패한 옛 요청이 새 확인을 지웠다.
125
+ - **speak·stopSpeaking**: 목소리 목록이 비었을 때 부른 말이 줄을 서고 멈추지 않았고, 목록이 끝내 안 오면 onEnd 가 안 불렸다.
126
+ - **I18nProvider**: `locale="en-US"` 이면 한국어로 떨어지고 context 는 `'en-US'` 로 남았다.
127
+
128
+ ### 고치지 않은 것 — 결정·확인이 필요하다
129
+
130
+ - `saveTable`·`updateSavedTable`·`duplicateTable` 은 저장소 쓰기가 실패해도 성공처럼 돌려준다 — 반환 타입을 바꿔야 한다.
131
+ - 오프셋 없는 시각 문자열(`normalizeDate`·`formatYmd`)이 기기 시간대를 따른다.
132
+ - `reviewTableName`: '수업 3차' 의 첫 복습과 '수업' 의 3차 복습이 같은 이름이다(이름만으로는 가를 수 없다).
133
+ - `weakItems`: 동형어가 저장 labels 에 번호가 없어 합쳐진다.
134
+ - Board 의 빈 목록 기본 문구가 한국어 고정(서버 렌더 호환이라 hook 을 안 쓴다).
135
+ - Rating 조작 모드에 소수 `value` 를 주면 화살표가 3.5 를 낸다.
136
+ - ConfirmPopup: onConfirm 거절이 처리되지 않은 거절로 올라간다(삼키면 오류 추적에서 사라진다).
137
+
10
138
  ## 0.135.0
11
139
 
12
140
  3차·4차 검수 판이다 — 훈련 단계 UI·차트·리포트·팝업·방문 훅을 훑어 **재현된** 결함만 고쳤다. 항목마다 시험을 붙이고 고친 줄을