@ihabdevteam/core 0.327.0 → 0.329.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,155 @@ All notable changes to this project will be documented in this file.
7
7
  > 적은 글이라, 지금 이름으로 고쳐 놓으면 그 시절에 그 이름으로 받은 사람이
8
8
  > 제 이야기를 못 찾는다.
9
9
 
10
+ ## 0.329.0 — 못 일곱을 고쳐 **셈을 바로잡는다** (연장·관문)
11
+
12
+ 사장님이 꼽아 주신 일곱을 차례대로 고쳤다. 몸통은 하나다 — **못이 셈을 잘못 하거나,
13
+ 아예 아무것도 안 세고 있었다.** 자리를 고치기 전에 **옛 못으로 같은 것을 깨 보고** 초록이
14
+ 나는지를 먼저 쟀다.
15
+
16
+ ### ① 블록 끝을 중괄호로 센다
17
+
18
+ `test/tabletH3Size.test.ts` 가 `css.slice(0, css.indexOf('@media'))` 로 루트 블록을 잘랐다 —
19
+ 파일 **앞쪽에** `@media` 가 하나 더 생기는 날 고친 것이 없는데 운다. 같은 가정을
20
+ `wordTableBlockActionsLeftExtra` 에서 실제로 밟았다. 같은 파일이 이미 들고 있던
21
+ `blockOf`(중괄호를 센다)로 바꾸고, **루트 블록을 제대로 집었는지** 세는 못을 더했다.
22
+
23
+ ### ② 이름을 글자로 박은 못에 **닻**을 박는다
24
+
25
+ "재생기에 `padTimerRef` 가 없다" 처럼 **없음만** 세면, 그 이름이 바뀌거나 사라지는 날 못은
26
+ **울지 않고 초록**이 된다. 재어 보니 `usePlaybackSequencer` 시험의 못 일곱이 이미 그 꼴로
27
+ 죽어 있었다 — 다섯은 **한글 이름을 금한 뒤** 다시 생길 수 없는 이름이었고(`뜸Ref` 따위),
28
+ 둘은 `src` 에 한 건도 없었다(`padRef`·`jumpTokenRef`).
29
+
30
+ 고친 길 둘 — ㉮ 이름 대신 **생김새**로 센다(제 손으로 세는 벌 · 제 손으로 쓰는 자리),
31
+ ㉯ 생김새로 못 적는 이름은 남기되 **있어야 할 자리에 있는지** 함께 센다.
32
+
33
+ > 여덟 중 **셋은 안 고쳤다.** `EXIT_ANIM_MS`·`PHONE_REGEX`·`compareCell` 은 **같은 파일이
34
+ > 들여온다** — 이름이 바뀌면 컴파일이 울어 그게 맞는 신호다. `ANNOUNCED_STATUSES`·
35
+ > `STATUS_MESSAGES` 도 글자로 집는 그 파일이 함께 들여오고 있었다. 셈이 아니라 **헤아림**이
36
+ > 틀렸던 것이고, 그 셋을 흔드는 것은 일만 늘린다.
37
+
38
+ ### ③ 이름 못이 **안 훑은 자리**를 센다
39
+
40
+ `walked > 1100` 은 "많이 훑었다" 만 말한다. **무엇을 못 훑었는지는 안 말한다.** 이 문이
41
+ 내내 초록이던 까닭이 그것이었다 — `scripts/` 를 한 번도 안 보면서 숫자는 늘 넉넉했다.
42
+ 이제 **git 이 아는 코드 파일**을 census 로 삼아 맞춰 본다. 같은 `readdirSync` 로 두 번 세면
43
+ 같이 틀리므로 딴 데서 센다. `.mts`·`.cts` 가 하나 들어오는 날도 그 파일 이름을 대고 운다.
44
+
45
+ ### ④ 달 열쇠의 꼴을 아는 자리가 **하나**다
46
+
47
+ `"2026년 10월"` 이 **열 자리에 흩어져** 있었다 — 짓는 데 다섯, 정규식으로 뜯는 데 다섯.
48
+ 하나를 고치고 아홉을 놓치면 열쇠가 안 맞아 **달이 통째로 빈 칸**이 된다(0.325.0 이 그
49
+ 결함이었다). `src/components/barChartMonthKey.ts` 하나로 모았다 —
50
+ `monthKeyOf` · `monthKeyOfDate` · `parseMonthKey` · `weekValueOf`.
51
+
52
+ > **꼴은 안 바꿨다.** 로케일에 안 매인 `"2026-10"` 이 옳지만, 소비자 시험이 이 꼴을 열
53
+ > 군데서 못 박고 있다. 꼴을 바꾸는 일은 소비자와 **함께** 해야 하므로 따로 한다. 그 약속을
54
+ > 코어 안에 적어 두고 못으로 세운다(`test/monthKeyOneDecision.test.ts`).
55
+
56
+ ### ⑤ `scripts/` 에 타입 검사를 켠다 — `npm run typecheck:scripts`
57
+
58
+ `tsconfig.json`(src)·`tsconfig.test.json`(test+src) **어느 쪽에도 없었다.** 관문을 돌리는
59
+ 연장 서른둘이 한 번도 안 보였다. 켠 날 181건이었고 **0 으로 만들었다.** 암묵 any 는 안 센다
60
+ (195건이 늘지만 아무 결함도 안 가린다) — 켜 둔 것은 **없는 것을 부르는 자리**다. 그쪽이
61
+ 진짜 터지는 길이고, 실제로 설정을 못 읽을 때 날 스택을 뱉는 자리 넷과 `dist-freshness` 의
62
+ null 자리 일곱을 그날 찾았다.
63
+
64
+ ### ⑥ 맨손으로 부르면 **무엇이 없는지** 말한다
65
+
66
+ 연장 일곱이 `readFileSync(undefined)` 의 날 스택을 뱉었다. 스택은 **무엇을 줘야 하는지
67
+ 안 가리킨다** — 쓰는 사람이 소스를 열어 `process.argv[2]` 를 찾아 읽어야 했다.
68
+ `scripts/usage.mjs` 로 모으고 끝값을 갈랐다 — **2 는 "부르는 법이 틀렸다", 1 은 "재 보니
69
+ 걸렸다"** 다. 꾸러미를 못 열었을 때와 JSON 이 아닐 때도 따로 말한다.
70
+
71
+ ### ⑦ 관문을 113초 → **75초**로
72
+
73
+ 재고 고쳤다. 몸통 둘이었다. **75초는 끝에서 끝까지 쟀고**, 줄인 38초는 토막으로 쟀다
74
+ (빌드 14초 + 시험 둘째 바퀴 24초) — 그래서 옛 관문은 ≈113초다.
75
+
76
+ - **빌드를 두 번 했다**(14초 + 15초). `npm pack` 이 `prepare` 를 돌리고 `prepare` 는
77
+ `npm run build` 다 — 바로 위에서 돈 그 빌드였다. `--ignore-scripts` 로 넘기고, **그 가정을
78
+ 세어 둔다**(`prepare` 가 다른 일을 하게 되면 관문이 멈추고 말한다).
79
+ - **시험을 통째로 두 번 돌았다**(29초 × 2). 두 번째 바퀴는 표준시를 바꿔 재는 것인데, 다시
80
+ 재는 것 대부분이 때를 아예 안 쓴다. 이제 **때를 쓰는 95개만** 돈다(5초). 고르개는
81
+ `scripts/tz-sensitive-tests.cjs` 한 자리에 있다.
82
+
83
+ > 고르개는 **참임을 증명하지 못한다** — 겉으로 때를 안 쓰면서 안에서 쓸 수 있다. 그래서
84
+ > `test/tzSubsetCovers.test.ts` 가 **다른 길로** 센다(때 연장을 들여온 시험을 빠뜨렸나).
85
+ > 그 못이 만든 날 바로 구멍 넷을 잡았다 — `yearMonthLabelIntl` 처럼 **로케일을 재는 시험이
86
+ > 로케일 바퀴에서 빠져** 있었다. 의심스러운 날은 `npm run test:tz:all` 로 통째로 돈다.
87
+ > 가린 549 파일을 `TZ=UTC` 로 통째로 돌려 초록임을 쟀다(3,874 시험).
88
+
89
+ ### 곁다리 — 주석은 쓰임이 아니다
90
+
91
+ `test/hookHome.test.ts` 가 날 글자를 짚어, 내력을 적은 주석에 훅 이름이 한 번 나오면 그
92
+ 파일을 "쓰는 쪽" 으로 셌다. `barChartMonthKey.ts` 가 "이름표는 `useBarChartControl` 이
93
+ 덮어쓴다" 고 적자 **고친 것이 없는데 울었다.** 이 저장소가 같은 자리를 세 번 밟았다
94
+ (앞엔 `jumpTokenRef` · `await a.play()`).
95
+
96
+ ## 0.328.0 — 사장님이 정하신 UI·UX 넷 ((302)(303)(304)(306))
97
+
98
+ ### (302) 채점 표시 획 2 → 3.5
99
+
100
+ 폰에서 그림이 5.5px 가 되면 획이 **0.46px** 이라 뭉개져 ○ 와 △ 가 **모양으로 안 갈린다**
101
+ (색으로만). 2026-10-01 에 말귀가 재어 두고 *"미루는 것"* 으로 적어 둔 자리인데, 사장님이
102
+ 그 미룸을 거두셨다. **다시 재지 않았다** — CSS 에 적힌 넷 가운데 고르는 셈이 그대로 답이다.
103
+
104
+ 거는 자리는 `--on` 만이 아니라 **칸의 그림 전부**다. 고른 것만 굵히면 얹었을 때 함께 서는
105
+ 셋 중 하나만 두꺼워 **굵기가 "매긴 것" 을 말해 버린다** — 그 일은 색과 `--on` 이 한다.
106
+
107
+ > 접은 길 둘(크기 바닥 · 속 채우기)은 못이 **기록을 들고** 지킨다 — 속을 채우면 `✕` 가
108
+ > 죽는다(선 둘이라 채울 속이 없다). **다시 제안하지 않는다.**
109
+
110
+ ### (303) 결과 줄마다 **다시 듣기**
111
+
112
+ 들려줄 것은 정답 낱말이 아니라 **문제로 나왔던 그 소리**다. 이 창은 줄 자료를 여러 이름으로
113
+ 더듬어 받으므로(`question`·`q`·`sentence`…) 소리도 같은 결로 받는다
114
+ (`questionSound`·`soundSrc`·`audioSrc`·`sound`·`audio`·`src`).
115
+
116
+ - **안 넘기면 아무것도 안 그린다** — 쓰는 쪽은 지금과 똑같다.
117
+ - **글자이기만 한 것은 안 받는다** — 더듬개는 아무 글이나 돌려주므로, 소리 자리에 제목이 든
118
+ 꼴을 틀려 하면 **조용히 아무 일도 안 난다.**
119
+ - **울리는 것은 하나다** — 다른 줄을 누르면 앞 소리가 멈추고, 창이 닫힐 때도 멈춘다
120
+ (`new Audio()` 는 DOM 에 없어 화면이 사라져도 혼자 운다).
121
+ - 이름표에 **줄 번호**가 든다 — 줄마다 같은 단추라 낭독기 목록에서 못 가린다.
122
+
123
+ ### (304) 겨눌 수 없을 만큼 작아지면 속 단추를 감춘다
124
+
125
+ 375px 에서 배율 0.446 이면 40px 단추가 **9×9px** 이 된다 — 겨눌 수 없고 **빗나간 손가락이
126
+ 칸에 닿으면 점수가 바뀐다**(채점 표는 칸을 눌러 매긴다). 키우는 길은 사장님이 막아 두셨다.
127
+
128
+ 문턱은 **WCAG 2.5.8 Target Size (Minimum) 의 24×24 CSS px** — `scripts/target-size.browser.js`
129
+ 가 이미 그 자로 쓸고 있다. 지어낸 수가 아니다. **그려진 크기**(`buttonSize * scale`)로 잰다.
130
+
131
+ > **지우지 않고 감춘다.** `wordTablePrint` 가 이 칸을 복제해 `data-play-state`·`data-audio-src`
132
+ > 로 **종이 문서의 재생 단추**를 짓는다 — 안 그리면 **작은 화면에서 뽑은 종이에만** 재생이
133
+ > 없고, 그 차이는 종이를 받아 든 사람에게만 보인다. 화면 쪽 CSS 가 감추고 인쇄가 되돌린다.
134
+
135
+ ### (306) `ListPopup.resizeStorageKey`
136
+
137
+ `ListPopup` 은 `resizable` 을 못 박아 넘기는데 저장 열쇠를 안 줬다. 그런데 `Table` 은
138
+ **자동맞춤까지 저장 열쇠에 묶어** 두어, 이 창으로 선 표는 **자동맞춤이 하나도 안 걸렸다** —
139
+ 긴 글자가 든 칸이 눌려도 안 펴진다. 폭이 따라다니는 것과 스스로 펴지는 것은 **다른 일인데
140
+ 한 손잡이에 달려 있었다.**
141
+
142
+ 묶음을 통째로 푸는 길도 있었지만 **열쇠 없는 표 전부**가 따라 움직인다. 칸 하나로 열고
143
+ 고르는 것은 부르는 쪽에 둔다 — **안 주면 지금과 똑같다.**
144
+
145
+ ### 짓다가 못 다섯이 나를 잡았다
146
+
147
+ - **또 같은 치환 함정** — `replace(…, 1)` 이 **먼저 나온 옛 `다시하기` 단추**를 바꿨다.
148
+ 오늘 아침 기억에 적어 둔 그 꼴을 그대로 밟았다. 이번엔 `count` 로 세어 고쳤다.
149
+ - `training.result.replay` 는 **이미 "다시하기"** 였다 — `assert` 가 이름 충돌을 막았다.
150
+ 소리 쪽은 `replaySound` 로 갈랐다.
151
+ - **템플릿 글자열 안에 백틱**을 넣어 문자열을 끊었다(`tsc` 가 잡았다).
152
+ - `scopePrefixNoDeadRules` — 속성으로 시작하는 고르개는 스코프 프리픽스가 *조상 꼴* 로
153
+ 읽는다. **클래스로** 바꿨다.
154
+ - `cssClassIntegrity` — `.trp-row__replay` 를 **CSS 없이** 붙였다.
155
+
156
+ > 소비자 할 일: (303) 은 줄 자료에 소리를 담아 넘기면 선다. (306) 은 열쇠를 주고 싶은 창에만
157
+ > 준다. 나머지 둘은 없다.
158
+
10
159
  ## 0.327.0 — 달 보기 이름표가 **열쇠 글자로** 떴다 (0.325.0 회귀)
11
160
 
12
161
  ### 세 자리 중 하나를 빠뜨렸다