@tienne/gestalt 0.72.1 → 0.72.3

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 (48) hide show
  1. package/CLAUDE.md +22 -0
  2. package/README.ko.md +33 -7
  3. package/README.md +33 -6
  4. package/dist/package.json +1 -1
  5. package/dist/plugin/role-agents/_shared/references/README.md +1 -1
  6. package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +24 -14
  7. package/dist/plugin/role-agents/_shared/references/author-voice.md +35 -9
  8. package/dist/plugin/role-agents/code-review-responder/AGENT.md +2 -2
  9. package/dist/plugin/role-agents/code-review-writer/AGENT.md +7 -4
  10. package/dist/plugin/role-agents/humanize-monolith/AGENT.md +1 -1
  11. package/dist/plugin/role-agents/jira-writer/AGENT.md +1 -1
  12. package/dist/plugin/role-agents/presentation-writer/references/content-playbook.md +1 -1
  13. package/dist/plugin/skills/local-pr/SKILL.md +5 -5
  14. package/dist/plugin/skills/review/SKILL.md +1 -1
  15. package/dist/plugin/skills/review-reply/SKILL.md +9 -9
  16. package/dist/plugin/skills/ship/SKILL.md +10 -10
  17. package/dist/src/cli/commands/pr.js +2 -2
  18. package/dist/src/cli/commands/pr.js.map +1 -1
  19. package/dist/src/cli/index.js +4 -4
  20. package/dist/src/cli/index.js.map +1 -1
  21. package/dist/src/humanize/detectors.d.ts +3 -3
  22. package/dist/src/humanize/detectors.d.ts.map +1 -1
  23. package/dist/src/humanize/detectors.js +12 -5
  24. package/dist/src/humanize/detectors.js.map +1 -1
  25. package/dist/src/local-pr/engine.d.ts +1 -1
  26. package/dist/src/local-pr/engine.d.ts.map +1 -1
  27. package/dist/src/local-pr/engine.js +1 -1
  28. package/dist/src/local-pr/engine.js.map +1 -1
  29. package/dist/src/local-pr/repository.js +1 -1
  30. package/dist/src/local-pr/repository.js.map +1 -1
  31. package/dist/src/mcp/schemas.js +2 -2
  32. package/dist/src/mcp/tools/review-passthrough.js +2 -2
  33. package/package.json +1 -1
  34. package/plugin/.codex-plugin/plugin.json +1 -1
  35. package/plugin/.mcp.json +1 -1
  36. package/plugin/mcp.json +1 -1
  37. package/plugin/role-agents/_shared/references/README.md +1 -1
  38. package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +24 -14
  39. package/plugin/role-agents/_shared/references/author-voice.md +35 -9
  40. package/plugin/role-agents/code-review-responder/AGENT.md +2 -2
  41. package/plugin/role-agents/code-review-writer/AGENT.md +7 -4
  42. package/plugin/role-agents/humanize-monolith/AGENT.md +1 -1
  43. package/plugin/role-agents/jira-writer/AGENT.md +1 -1
  44. package/plugin/role-agents/presentation-writer/references/content-playbook.md +1 -1
  45. package/plugin/skills/local-pr/SKILL.md +5 -5
  46. package/plugin/skills/review/SKILL.md +1 -1
  47. package/plugin/skills/review-reply/SKILL.md +9 -9
  48. package/plugin/skills/ship/SKILL.md +10 -10
package/CLAUDE.md CHANGED
@@ -115,6 +115,28 @@ plugin/.mcp.json Grok MCP (plugin/mcp.json과 동일)
115
115
  - `plugin/skills/review/SKILL.md`가 `../../role-agents/`를 참조한다. 스킬과 에이전트를 함께 옮겨야 이 상대 깊이가 유지된다.
116
116
  - 자산 디렉토리 기본값은 `src/core/config.ts`에 `skillsDir`, `agentsDir`, `roleAgentsDir`, `reviewAgentsDir`, `personasDir` 다섯 개로 있다. 경로를 바꾸면 전부 함께 고친다.
117
117
 
118
+ ### MCP 기동 경로
119
+
120
+ 클라이언트마다 서버를 띄우는 방식이 다르다.
121
+
122
+ ```
123
+ .mcp.json Claude — sh로 scripts/mcp-serve.sh를 찾아 실행
124
+ .claude-plugin/.mcp.json .mcp.json과 내용 동일 (해석 기준 디렉토리가 모호해 양쪽에 둔다)
125
+ plugin/mcp.json Codex — npx, 버전 핀
126
+ plugin/.mcp.json Grok(배포) — plugin/mcp.json과 동일
127
+ .grok/config.toml Grok(이 레포 개발용) — scripts/grok-mcp-serve.sh
128
+ ```
129
+
130
+ - `npx`는 버전을 박아도 기동할 때마다 레지스트리를 조회한다. 캐시가 비면 20초, 레지스트리에 못 닿으면 70초를 매달린다. Claude Code의 기동 제한은 30초라 둘 다 `Connection closed`로 끊긴다.
131
+ - `startup_timeout_sec`와 `tool_timeout_sec`는 Codex 키다. Claude Code는 안 읽고 `MCP_TIMEOUT` 환경변수만 본다. Claude 매니페스트에 넣어봐야 무시된다.
132
+ - `scripts/mcp-serve.sh`가 그 셋을 처리한다. nvm, fnm, Volta, Homebrew에서 Node >= 20을 찾는다 (GUI 세션은 PATH에 버전 매니저가 없다). 전역 `gestalt`가 있으면 그걸 쓰고 없으면 `npx --offline`으로 캐시에서 해석한다.
133
+ - 그 스크립트는 npx로 서버를 띄우지 않고 bin 경로만 받아와 직접 exec한다. npx가 cwd의 로컬 패키지를 먼저 보기 때문에, node_modules 없는 gestalt 체크아웃 안에서는 `gestalt: command not found`로 죽는다. 그래서 해석은 `cd /`에서 한다.
134
+ - 전역 `gestalt`가 깔려 있으면 핀보다 그게 이긴다. 누가 `npm i -g`를 했다는 건 이 체크아웃이 번들한 것보다 구체적인 선택이라서다. 대신 어느 쪽을 썼는지 stderr에 적어 버전이 어긋났을 때 로그에서 보이게 한다.
135
+ - 매니페스트의 `sh -c`는 `${CLAUDE_PLUGIN_ROOT}`를 먼저 본다. 거기서 스크립트를 찾으면 `GESTALT_LAUNCHER`는 아예 안 본다. 플러그인으로 설치된 상태에서는 그 변수가 안 걸린다는 뜻이다. 플러그인 없이 이 레포만 연 경우에만 차례가 온다. 그때도 **절대 경로만** 받는다 — 상대 경로를 허용하면 남의 레포를 열었을 때 거기 있는 동명 실행 파일이 서버 대신 도는 자리가 된다.
136
+ - 그 `sh -c`의 최후 폴백도 버전이 핀되어 있다. 거기까지 왔으면 스크립트를 못 찾은 것이다. 스크립트가 없으면 `package.json`도 없어 런타임에 버전을 못 읽는다. 그래서 그 자리만은 `sync-version.ts`가 문자열에 직접 박는다.
137
+ - 네 매니페스트의 버전 핀을 `scripts/sync-version.ts`가 릴리즈마다 함께 갱신한다. `plugin/*`는 인자 하나가 통째로 스펙이고 Claude 쪽은 `sh` 문자열 안에 박혀 있는데, 같은 정규식으로 둘 다 친다.
138
+ - `command: "sh"`라서 Windows 호스트에서는 안 뜬다. 그쪽은 전역 설치 후 `command: "gestalt"`로 안내한다.
139
+
118
140
  ## Conventions
119
141
  - MCP 서버에서 `console.log` 금지 → `log()` stderr 유틸 사용
120
142
  - `noUncheckedIndexedAccess` 환경 → 배열 인덱스·regex 캡처그룹에 `!` 단언 필수
package/README.ko.md CHANGED
@@ -161,14 +161,18 @@ claude plugin install gestalt@gestalt
161
161
 
162
162
  ### 옵션 2: Claude Code Desktop
163
163
 
164
- Claude Code Desktop 설정에서 `settings.json` (또는 `claude_desktop_config.json`)에 추가하세요:
164
+ 먼저 전역 설치한 다음, 설정이 바이너리를 가리키게 하세요:
165
+
166
+ ```bash
167
+ npm install -g @tienne/gestalt
168
+ ```
165
169
 
166
170
  ```json
167
171
  {
168
172
  "mcpServers": {
169
173
  "gestalt": {
170
- "command": "npx",
171
- "args": ["-y", "@tienne/gestalt"]
174
+ "command": "gestalt",
175
+ "args": ["serve"]
172
176
  }
173
177
  }
174
178
  }
@@ -176,13 +180,15 @@ Claude Code Desktop 설정에서 `settings.json` (또는 `claude_desktop_config.
176
180
 
177
181
  Claude Code Desktop을 재시작하면 MCP 도구가 즉시 사용 가능해요. 슬래시 커맨드는 플러그인 설치 또는 별도 스킬 설정이 필요해요.
178
182
 
183
+ `npx -y @tienne/gestalt`도 되긴 하는데, 그 전에 [기동 타임아웃](#기동-타임아웃)을 읽어보세요. 데스크톱 앱이 이 문제에 제일 잘 걸립니다.
184
+
179
185
  ---
180
186
 
181
187
  ### 옵션 3: Claude Code CLI
182
188
 
183
189
  ```bash
184
- # claude CLI로 추가
185
- claude mcp add gestalt -- npx -y @tienne/gestalt
190
+ npm install -g @tienne/gestalt
191
+ claude mcp add gestalt -- gestalt serve
186
192
  ```
187
193
 
188
194
  또는 `~/.claude/settings.json`을 직접 편집하세요:
@@ -191,8 +197,8 @@ claude mcp add gestalt -- npx -y @tienne/gestalt
191
197
  {
192
198
  "mcpServers": {
193
199
  "gestalt": {
194
- "command": "npx",
195
- "args": ["-y", "@tienne/gestalt"]
200
+ "command": "gestalt",
201
+ "args": ["serve"]
196
202
  }
197
203
  }
198
204
  }
@@ -200,6 +206,26 @@ claude mcp add gestalt -- npx -y @tienne/gestalt
200
206
 
201
207
  ---
202
208
 
209
+ ### 기동 타임아웃
210
+
211
+ 서버가 붙을 때는 붙고 어떨 때는 `Connection closed`로 끊긴다면, 원인은 대개 Gestalt가 아니라 `npx`입니다. 알아둘 게 셋입니다.
212
+
213
+ **npx는 기동할 때마다 레지스트리를 조회합니다.** 버전을 정확히 박아도 마찬가지예요. npm 상대로 재봤더니 캐시가 데워졌을 때 1.9초, 비었을 때 20초, 레지스트리에 못 닿으면 70초를 매달린 뒤 실패했습니다. Claude Code는 stdio 서버에 `initialize` 응답까지 30초를 주므로 콜드 상태와 오프라인 상태가 둘 다 끊긴 연결로 나타납니다. 전역 설치해서 `gestalt serve`를 직접 부르면 이 과정이 통째로 사라집니다.
214
+
215
+ **GUI로 띄운 세션은 PATH가 다릅니다.** 터미널 밖에서 시작한 것들 — 데스크톱 앱, 런처, launchd — 은 버전 매니저가 빠진 PATH를 물려받아서 `npx`를 아예 못 찾고 즉시 죽습니다. `command`에 절대 경로를 주거나 서버 항목에 `env.PATH`를 지정하세요.
216
+
217
+ **Claude Code에서 `startup_timeout_sec`는 아무 일도 안 합니다.** 그건 Codex 키예요. Claude Code는 `MCP_TIMEOUT` 환경변수(밀리초)를 읽으므로 `settings.json`에 넣어야 Claude Code 프로세스까지 전달됩니다:
218
+
219
+ ```json
220
+ {
221
+ "env": { "MCP_TIMEOUT": "180000" }
222
+ }
223
+ ```
224
+
225
+ 플러그인 설치(옵션 1)는 앞의 둘을 `scripts/mcp-serve.sh`가 알아서 처리해요. Node는 nvm, fnm, Volta, Homebrew 밑에서 찾고요. 전역 설치된 `gestalt`가 있으면 그걸 씁니다. 없으면 핀된 버전을 npm 캐시에서 바로 해석하고요.
226
+
227
+ ---
228
+
203
229
  ### 옵션 4: OpenAI Codex 플러그인
204
230
 
205
231
  Claude Code 플러그인과 똑같이 MCP 서버랑 워크플로 스킬 19개를 한 번에 받아요.
package/README.md CHANGED
@@ -132,14 +132,18 @@ What you get:
132
132
 
133
133
  ### Option 2: Claude Code Desktop
134
134
 
135
- Add this to your `settings.json` (or `claude_desktop_config.json`) and restart:
135
+ Install once, then point the config at the installed binary:
136
+
137
+ ```bash
138
+ npm install -g @tienne/gestalt
139
+ ```
136
140
 
137
141
  ```json
138
142
  {
139
143
  "mcpServers": {
140
144
  "gestalt": {
141
- "command": "npx",
142
- "args": ["-y", "@tienne/gestalt"]
145
+ "command": "gestalt",
146
+ "args": ["serve"]
143
147
  }
144
148
  }
145
149
  }
@@ -147,12 +151,15 @@ Add this to your `settings.json` (or `claude_desktop_config.json`) and restart:
147
151
 
148
152
  MCP tools are available immediately after restart. Slash commands require the plugin or manual skills setup.
149
153
 
154
+ `npx -y @tienne/gestalt` works too, but read [Startup timeouts](#startup-timeouts) first — the desktop app is the setup most likely to hit them.
155
+
150
156
  ---
151
157
 
152
158
  ### Option 3: Claude Code CLI
153
159
 
154
160
  ```bash
155
- claude mcp add gestalt -- npx -y @tienne/gestalt
161
+ npm install -g @tienne/gestalt
162
+ claude mcp add gestalt -- gestalt serve
156
163
  ```
157
164
 
158
165
  Or add directly to `~/.claude/settings.json`:
@@ -161,8 +168,8 @@ Or add directly to `~/.claude/settings.json`:
161
168
  {
162
169
  "mcpServers": {
163
170
  "gestalt": {
164
- "command": "npx",
165
- "args": ["-y", "@tienne/gestalt"]
171
+ "command": "gestalt",
172
+ "args": ["serve"]
166
173
  }
167
174
  }
168
175
  }
@@ -170,6 +177,26 @@ Or add directly to `~/.claude/settings.json`:
170
177
 
171
178
  ---
172
179
 
180
+ ### Startup timeouts
181
+
182
+ If the server connects sometimes and reports `Connection closed` other times, the cause is almost always `npx`, not Gestalt. Three things are worth knowing.
183
+
184
+ **npx reaches the registry on every start.** Pinning an exact version does not change that. Measured against npm: 1.9s on a warm cache, 20s on a cold one, and a 70s hang before failing when the registry is unreachable. Claude Code gives a stdio server 30s to answer `initialize`, so the cold and offline cases both surface as a closed connection. Installing the package globally and calling `gestalt serve` skips all of it.
185
+
186
+ **GUI-launched sessions have a different PATH.** Anything started outside a terminal — the desktop app, a launcher, launchd — inherits a PATH with no version manager on it, so `npx` is not found and the server dies instantly. Give `command` an absolute path, or set `env.PATH` on the server entry.
187
+
188
+ **`startup_timeout_sec` does nothing in Claude Code.** That key belongs to Codex. Claude Code reads the `MCP_TIMEOUT` environment variable (milliseconds) instead, so it goes in `settings.json`, where it lands in the Claude Code process:
189
+
190
+ ```json
191
+ {
192
+ "env": { "MCP_TIMEOUT": "180000" }
193
+ }
194
+ ```
195
+
196
+ The plugin install (Option 1) already handles the first two through `scripts/mcp-serve.sh`: it finds Node under nvm, fnm, Volta, or Homebrew, prefers a globally installed `gestalt`, and otherwise resolves the pinned version from the npm cache, falling back to the network only when the cache misses.
197
+
198
+ ---
199
+
173
200
  ### Option 4: OpenAI Codex Plugin
174
201
 
175
202
  Bundles the MCP server and all 19 workflow skills, the same way the Claude Code plugin does.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tienne/gestalt",
3
- "version": "0.72.1",
3
+ "version": "0.72.3",
4
4
  "description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -29,7 +29,7 @@ pnpm verify:rules
29
29
 
30
30
  - **룰을 추가하면 그 문서가 스스로 그 룰을 지키는지 먼저 확인한다.** 룰 문서가 금지 어휘를
31
31
  본문에 쓰면 산출물로 샌다. 금지어를 넣었으면 같은 문서를 grep한다.
32
- - 어투 규칙은 **S1으로 올려야 실제로 강제된다.** S2는 모델이 우선순위를 알아서 정하면서 새어나간다.
32
+ - 어투 규칙은 **S1으로 올려야 실제로 강제된다.** S2는 모델이 우선순위를 알아서 정하면서 빠져나간다.
33
33
  - 심각도를 바꿀 때는 근거를 남긴다. A-2, I-1, C-8은 대조 코퍼스 측정으로 조정했고 그 근거가
34
34
  [룰북 측정 근거](ai-tell-quick-rules.md#측정-근거)에 있다. 감으로 올리고 내리면 다음 사람이 되돌린다.
35
35
  - 경로를 참조하는 자리가 여러 곳이다. 파일을 옮기거나 이름을 바꾸면 `plugin/` 전체에서
@@ -14,7 +14,7 @@
14
14
 
15
15
  **삭제 처방은 삭제다 (중요):** 처방에 "삭제"가 있는 항목은 **더 나은 표현으로 바꾸지 않는다.** 지우고 그 자리를 원문에 이미 있는 가장 구체적인 문장으로 대신한다. 모델은 D-2, D-3, D-4, D-6, C-10처럼 "삭제"라고 적힌 항목에서 리듬을 살리려고 새 마무리 문장이나 새 부제를 만들어 넣는 경향이 강한데, 그건 원문에 없던 수사를 추가하는 것이라 자체검증 6번에 걸린다. 지울 자리에 쓸 문장이 원문에 없으면 그냥 앞 문장에서 끝낸다.
16
16
 
17
- **말투 감도 (중요):** 같은 명사화, 번역투라도 **대화나 리뷰 코멘트에서는 문서보다 훨씬 튄다.** 문서(칼럼·리포트) 기준 S2인 A-2, A-5, F-4, F-5, F-6, F-7, I-1, I-5 계열은 대화, 리뷰 코멘트에서 **S1로 격상**해 교정한다. 사람은 대화에서 개념을 명사 덩어리로 뭉치지 않고 동사로 풀어 말하기 때문이다. 심각도 칸에 `S2 / **대화·리뷰 S1**`이라고 적힌 룰이 여기 해당한다.
17
+ **말투 감도 (중요):** 같은 명사화, 번역투라도 **대화나 리뷰 코멘트에서는 문서보다 훨씬 튄다.** 문서(칼럼·리포트) 기준 S2인 상당수가 대화, 리뷰 코멘트에서 **S1로 격상**된다. 사람은 대화에서 개념을 명사 덩어리로 뭉치지 않고 동사로 풀어 말하기 때문이다. 어느 룰이 격상되는지는 심각도 칸에 `S2 / **대화·리뷰 S1**`이라고 적힌 표기로 판단한다. 전체 목록이 필요하면 자체검증 5번을 본다 — **사본은 그 한 자리로 정한다.** 여기 또 적으면 세 자리가 갈라진다.
18
18
 
19
19
  **한자어를 피하는 게 목적이 아니다 (F-4·F-5 오적용 주의):** 겨냥하는 건 개념을 뭉친 **명사화**(-성/-적/-화)이지 한자어 동사가 아니다. "측정하다"를 "재다"로, "판단하다"를 "따지다"로 바꾸면 정확도만 잃는다. 그 자리의 정확한 말이 한자어면 한자어를 쓴다. 반대 방향 실수도 같다 — 한자어를 피하려고 비유 명사(축·증류)나 물리 동사(재다)로 도망가면 F-7에 걸린다. 셋 다 겪은 실례: `네 축을 따로 재고 판정한다` → `4가지 측면에서 각각 측정하고 판단한다`.
20
20
 
@@ -50,11 +50,11 @@
50
50
  | B-2 | 영어 어휘 직역 가능한데 그대로 | S2 | 한국어로 옮기되 업계 표준은 유지 |
51
51
  | B-3 | 안 굳어진 영어 구·단어 음차 표기 ("소스 오브 트루스"), 그 음차를 약어로 우회한 표기(`SSOT`·`SoT`) | S1 | 한글 의역 + 첫 등장만 원어 괄호 병기("기준 문서(source of truth)", "단일 기준점(source of truth)" 등), 이후 한글만. 단 위 "굳어진 음차 화이트리스트"에 있는 정착어는 Do-NOT — of/and 등 기능어까지 통째 음차한 구(룩 앤 필·로우 행잉 프룻)가 최우선 대상. 무엇을 가리키는지 보고 고르는 표는 [style-guide.md의 single source of truth를 뭐라고 쓸까](style-guide.md#single-source-of-truth를-뭐라고-쓸까)를 따른다 |
52
52
  | B-4 | 영어 개념을 어색하게 옮긴 조어("생산처" ← producer, "응답처") | S2 | 억지 신조어 대신 이미 쓰이는 말로. 코드 맥락이면 "호출부"·"사용처". **팀에서 이미 굳은 조어는 예외** — "소비처"는 팀 지라 티켓에서 라이브러리를 가져다 쓰는 쪽을 가리키는 말로 정착했으므로 교정 대상이 아니다 (→ 아래 [측정 근거](#측정-근거)) |
53
- | B-5 | 영어 추상 개념어를 사전 뜻으로 옮겨 레지스터가 어긋난 말 (materialize → "물질화", semantics → "의미론", virtue → "미덕", durably → "내구성 있게") | S1 | 그 자리에서 실제로 무슨 일이 벌어지는지를 동사로 쓴다. 아래 [B-5 대체어](#b-5-대체어) 표 참조. 음차로 도망가지 않는다 — "머티리얼라이즈"로 바꾸면 B-3에 걸린다 |
53
+ | B-5 | 영어 개념어나 다의어 동사를 한국어 단어로 몰아 옮겨 레지스터가 어긋난 말 (materialize → "물질화", semantics → "의미론", close → "닫다") | S1 | 그 자리에서 실제로 무슨 일이 벌어지는지를 동사로 쓴다. 아래 [B-5 대체어](#b-5-대체어) 표 참조. 음차로 도망가지 않는다 — "머티리얼라이즈"로 바꾸면 B-3에 걸린다 |
54
54
 
55
55
  ### B-5 대체어
56
56
 
57
- 영어 원문을 옮길 때 반복해서 새는 자리다. 사전 첫 뜻이 한국어에서 다른 영역의 말이라 그 자리만 톤이 튄다.
57
+ 영어 원문을 옮길 때 반복해서 틀리는 자리다. 사전 첫 뜻이 한국어에서 다른 영역의 말이라 그 자리만 톤이 튄다.
58
58
 
59
59
  | 원어 | 쓰지 말 것 | 이렇게 |
60
60
  |---|---|---|
@@ -64,9 +64,17 @@
64
64
  | durably persist | 내구성 있게 저장한다 | 유실 없이 기록한다 / 영속 저장소에 남긴다 |
65
65
  | opaque (system) | 불투명한 시스템으로 전락한다 | 아무도 들여다볼 수 없게 된다 |
66
66
  | deliberately (not) | 의도적으로 결정했다 | 일부러 안 했다 / 이번엔 빼기로 했다 |
67
+ | close (a comment, a talk) | 질문으로 닫는다 | 질문으로 끝낸다 / 마지막에 둔다 |
68
+ | close (an issue, PR, thread) | 이슈를 닫는다 | 이슈를 종료한다 / 스레드를 종료한다 |
69
+ | close (a connection, a repo) | 저장소를 닫는다 | 저장소 연결을 끊는다 |
70
+ | leak (자주 나온다는 뜻으로) | 자주 새는 룰 | 자주 걸리는 룰 / 반복해서 틀리는 자리 |
67
71
 
68
72
  "의미론적 검색"처럼 형용사로 굳은 자리(`의미론적`)는 대상이 아니다. 명사로 홀로 서서 시스템의 동작 규칙을 가리킬 때만 걸린다.
69
73
 
74
+ **한 동사에 여러 뜻을 몰지 않는다.** `close`는 한국어에서 자리마다 다른 동사로 갈린다 — 코멘트나 발표는 끝내고 이슈나 스레드는 종료하고 연결은 끊는다. 이걸 "닫다" 하나로 몰면 그 자리마다 조금씩 어긋난다. 코드 안의 `close()` 호출 그 자체를 가리킬 때만 "닫는다"를 둔다. 산문으로 동작을 설명하는 자리는 무엇을 어떻게 하는지 적는다 — "저장소 연결을 끊는다"처럼. 글이나 말을 "닫는다"고 쓰지 않는다. "맺는다"는 원래 한국어 연어라 그대로 쓸 수 있다. 다만 발표나 코멘트를 두고는 "끝낸다"가 더 흔하다. 자리마다 맞는 동사를 고른다. **상태를 가리키는 "닫힌 PR"은 대상이 아니다** — `CLOSED` 상태값을 옮긴 말이라 동사 교정과 결이 다르다.
75
+
76
+ **"새다"는 누출일 때만 쓴다.** 금지어가 산출물에 흘러나가는 자리에는 맞다. 검사를 빠져나가는 자리("어디까지 새는지")나 자주 나온다는 뜻("자주 새는 룰")에는 안 맞는다. 앞은 "놓친다", "빠져나간다"이고 뒤는 "자주 걸린다", "반복해서 틀린다"다.
77
+
70
78
  ## C. 구조적 AI 패턴
71
79
 
72
80
  | ID | 패턴 | 심각도 | 처방 |
@@ -79,6 +87,7 @@
79
87
  | C-11 | 연결어미 뒤 쉼표 (-고/-며/-지만/-며서/-아서/-어서 직후 쉼표) | S1 | 쉼표 제거. 6+회=강한 신호. KatFish 4.84배 분리도 |
80
88
  | C-12 | 가운뎃점(·) 나열 남발 — 본문 산문에서 "A·B·C"로 항목 압축 | S1 | 쉼표나 구어 연결로 풀기("A, B, C" / "A랑 B하고 C"). 사람은 산문에서 가운뎃점을 거의 안 쓴다. 단 표 안 압축, 용어 목록, 굳어진 합성어("입출력")는 예외 |
81
89
  | C-13 | 같은 문단에서 같은 수치를 다른 단위로 반복 표기("3%" 다음 "3할") — 참조 표현의 숫자만 바꿔 재사용하며 단위를 못 맞춘 경우 | S2 | 단위를 하나로 통일한다. 빌려 쓴 수치 예시는 값과 단위를 통째로 새로 쓴다("3%인데 3할이" → "3%인데 3%가") |
90
+ | C-14 | 수량 예고 — "두 가지", "세 가지 이유"처럼 할 말의 개수를 앞세워 문단을 엶 | S2 / **대화·리뷰 S1** | **문단 첫머리가 개수로 열리는 꼴만 본다.** 개수를 뒤로 보내 서술 안에 넣거나 뺀다("두 가지 짚을 것" → "확인이 필요한 게 2건 있습니다"). 개수가 문장 안에 서술의 일부로 들어간 꼴은 대상이 아니다 — 사람도 결과를 세어 말한다. 겨냥하는 건 먼저 선언하고 시작하는 꼴이다. **개수가 대상의 고정 속성이면 대상이 아니다** — 게슈탈트 원리가 실제로 다섯 개라서 "다섯 가지 원리"는 사실 서술이다. 다만 **필자가 나눈 분류의 개수는 고정 속성이 아니다** — "세 가지로 갈린다. 첫째는…"처럼 문단을 열고 뒤에 올 항목을 예고하면 위치 기준에 걸린다. C-9 숫자 인덱싱의 사촌인데 C-9는 표기만 보고 예고 자체는 안 본다. 이 경계는 뜻이라 탐지기가 없다. E-8·G-4와 겹치면 셋을 다 적용한 꼴이 최종형이다("제가 봤을 때는 확인이 필요한 게 2건 있습니다") |
82
91
 
83
92
  ## D. AI 특유의 관용구 (Signature Phrases)
84
93
 
@@ -89,9 +98,9 @@
89
98
  | D-3 | "본질적으로/핵심적으로" | S1 | 삭제. 다른 부사로 갈아끼우지 말고 그냥 뺀다 |
90
99
  | D-4 | hype 어휘(파격적·압도적·강력한·획기적·치명적) 3회+ | S1 | 원문에 수치·사실이 있으면 그걸로 환원, **없으면 수치를 만들지 말고 수식어만 삭제** |
91
100
  | D-5 | 의인화 추상 주어("기술이 묻는다·시대가 부른다") | S1 | 사람·기관 주어로 |
92
- | D-6 | 결말 공식 "~할 때다/~해야 한다/~지금이야말로" | S1 | 삭제하고 **원문에 이미 있는 가장 구체적인 문장으로 끝낸다.** 더 나은 마무리 문장으로 고쳐쓰지 말고, 리듬을 살리려 하지도 않는다. 닫는 느낌이 꼭 필요하면 원문 근거만으로 쓸 수 있는 평서 한 줄(다음 할 일 등)까지만 |
101
+ | D-6 | 결말 공식 "~할 때다/~해야 한다/~지금이야말로" | S1 | 삭제하고 **원문에 이미 있는 가장 구체적인 문장으로 끝낸다.** 더 나은 마무리 문장으로 고쳐쓰지 말고, 리듬을 살리려 하지도 않는다. 맺는 느낌이 꼭 필요하면 원문 근거만으로 쓸 수 있는 평서 한 줄(다음 할 일 등)까지만 |
93
102
  | D-7 | 변환 공식 "X에서 Y로" 반복 | S2 | 한 번만, 나머지는 일반 서술 |
94
- | D-8 | 과잉 자책, 감정 과장 반응("제일 아팠습니다·뼈아픕니다·부끄럽습니다·뜨끔했습니다") | S1 | 짧은 수긍으로 환원한다("아 그렇네요", "이거 놓쳤네요"). 사실 서술은 그대로 두고 감정 수식만 뺀다. D-4(hype 어휘)의 뒷면이다 — 칭찬 쪽만 막으면 같은 충동이 자책 쪽으로 샌다. 남긴 의견들 사이에 "제일"로 순위를 매기는 것도 여기 해당한다 |
103
+ | D-8 | 과잉 자책, 감정 과장 반응("제일 아팠습니다·뼈아픕니다·부끄럽습니다·뜨끔했습니다") | S1 | 짧은 수긍으로 환원한다("아 그렇네요", "이거 놓쳤네요"). 사실 서술은 그대로 두고 감정 수식만 뺀다. D-4(hype 어휘)의 뒷면이다 — 칭찬 쪽만 막으면 같은 충동이 자책 쪽으로 옮겨간다. 남긴 의견들 사이에 "제일"로 순위를 매기는 것도 여기 해당한다 |
95
104
  | D-9 | 추상명사에 이동 동사("방향도 맞게 갔습니다", "결론이 그쪽으로 갔어요") | S2 / **대화·리뷰 S1** | 방향, 결론, 판단, 논의가 스스로 움직이게 두지 않는다. 사람이나 대상을 주어로 되돌린다("맞는 방향 같아요", "그렇게 결론 냈어요"). D-5 의인화 추상 주어의 사촌이다 |
96
105
 
97
106
  ## E. 리듬, 종결어미
@@ -101,6 +110,7 @@
101
110
  | E-1 | 문장 길이 균일(stdev 8 미만) | S2 | 단문 1~2개 / 장문 1개를 각 문단에 의도적 삽입 |
102
111
  | E-2 | 동일 종결어미 "~다" 4문장 연속 + 진행형 "~고 있다" 자동 매핑 | S2 | "~었다·~ㄴ다·~는다·~기 마련이다·~ㄹ 것이다" 등 다양화. "~고 있다" 단순 시제 환원 가능 시 환원("읽고 있다" → "읽는다") |
103
112
  | E-7 | 청자 경어법 4단계(해라/하게/하오/해요/합쇼) 일관성 손실 (대화·구어 한정) | S2 | 한 단락 내 혼용 금지, 격식 일관 (김혜영 2019, 추정) |
113
+ | E-8 | 관형형 + 의존명사 종결 — 서술어 없이 "짚을 것", "고려할 점", "주의 사항"으로 문장을 끊음 | S2 / **대화·리뷰 S1** | 서술어를 붙여 문장을 끝낸다("두 가지 짚을 것" → "짚어볼 게 있습니다"). 목차 항목처럼 끊으면 사람이 한 말로 안 읽힌다. **헤딩, 표 셀, 체크리스트 항목, 문단을 여는 볼드 도입구는 대상이 아니다** — 거기서는 명사구 종결이 정상 문법이다. **볼드 예외는 규범, 참조 문서에서 문단 안 소제목 역할을 하는 자리에만 준다** — 리뷰 코멘트와 대화에서는 볼드를 씌워도 본문 산문으로 본다. 서식으로만 예외를 주면 "두 가지 짚을 것"을 볼드 처리해 그대로 통과시키게 된다. 본문 산문과 대화만 본다. 예외가 전부 문맥이라 줄 단위 정규식으로는 못 가르고, 그래서 탐지기가 없다. G-4와 겹치면 서술어를 붙이되 판단이면 화자도 함께 남긴다 |
104
114
 
105
115
  ## F. 과도한 수식, 중복
106
116
 
@@ -119,6 +129,7 @@
119
129
  | G-1 | "~것이다/~할 것이다" 미래 단정 남발 | S2 | 현재형·확정형으로 |
120
130
  | G-2 | "~로 보인다/~인 듯하다" 추정 남발 | S2 | 단언 가능한 곳은 단언 |
121
131
  | G-3 | 안전 균형 표현 "양쪽 모두/두 가지 모두/장점도 있지만/신중하게/균형" | S2 | 4회 초과 시 1~2건 화자 입장으로 치환 |
132
+ | G-4 | 화자 소거 — 의견인데 "확인이 필요합니다"처럼 화자가 없어 사실 선언으로 읽힘 | S2 / **대화·리뷰 S1** | 누가 하는 말인지 살린다("확인이 필요합니다" → "제가 봤을 때는 확인이 필요합니다"). **G-2와 방향이 반대라 경계를 지킨다** — 사실 서술에 붙은 추정 어미("~로 보인다")는 G-2로 빼고 판단이나 제안에서 빠진 화자는 여기서 넣는다. **규범, 절차, 명세 문서의 지시문은 대상이 아니다** — 룰북과 스킬 문서는 화자 없이 규칙을 적는 게 표준이다. 화자가 개인 판단으로 말하는 자리(리뷰 코멘트, 대화, 제안)만 본다. **코드를 읽고 확인한 결함은 화자를 붙이지 않고 그대로 단정한다** — 화자는 판단과 제안에만 붙인다. 부재를 봐야 해서 탐지기가 없다 |
122
133
 
123
134
  ## H. 접속사 남발
124
135
 
@@ -136,9 +147,9 @@
136
147
  | I-2 | "X은 ~라는 점에 있다" | S2 | "X는 ~다" 직설로 |
137
148
  | I-3 | "~다는 뜻이다/~다는 의미다" 결말 | S2 | 본문에 풀어 쓰기 |
138
149
  | I-4 | 권고형 결말 "~해야 한다·~합니다" 반복 | S2 | 평서·단언으로 |
139
- | I-5 | 사무투 분류사 "~ 건/해당 건/이번 건/그 건", 코드·문서 용어를 대화에 그대로("주석 건") | S2 / **대화·리뷰 S1** | 구체 명사로 풀기("Copilot이 짚은 주석 건" → "Copilot이 남긴 코멘트"). "건"은 공문서투 분류사라 대화에서 어색하다 |
150
+ | I-5 | 사무투 분류사 "~ 건/해당 건/이번 건/그 건", 코드·문서 용어를 대화에 그대로("주석 건") | S2 / **대화·리뷰 S1** | 구체 명사로 풀기("Copilot이 짚은 주석 건" → "Copilot이 남긴 코멘트"). "건"은 공문서투 분류사라 대화에서 어색하다. **수량 자리는 사물 명사가 바로 앞에 붙은 꼴만 본다** — "버그 8건", "코멘트 9건", "티켓 8건"을 "8개", "9개"로 고친다. 세는 사물이 안 적힌 자리("확인이 필요한 게 2건 있습니다")는 **대상이 아니다** — 무엇을 세는지 문장에 없으면 판정할 근거도 없고, 명사를 지웠다 살렸다로 답이 뒤집히는 기준은 쓸 수 없다. **이 규칙은 산출물 문장에만 적용된다** — 룰 문서나 스킬 문서가 자기 데이터를 집계해 적는 자리("인라인 리뷰 1,321건", "표본 282건")는 대상이 아니다. I-7이 같은 예외를 갖는 것과 같은 이유다. **탐지기는 한글 한 글자 + 공백 + "건" + 조사(은/이/을/에/도) 꼴을 전부 건다** — 수량인지 사무투 분류사인지, 준말 "것은"인지 못 가르므로 걸린 자리는 사람이 위 기준으로 다시 본다. 아라비아 숫자 꼴("8건 고쳤어요")은 정규식이 안 닿아 사람만 본다 |
140
151
  | I-6 | 측량·사무투 명사 "실측·계측·산출·오탐" 등으로 판정·근거를 명사 하나로 압축 (피동 "산출된다"도 같다. 파생어 예외는 "산출"에만 있다 — "산출물", "산출 근거", "산출도구"는 빠지고 "계측기", "실측값"은 걸린다. 서술격 "산출이에요"와 관형격 "산출의"는 탐지기가 못 본다) | S2 / **대화·리뷰 S1** | 동사로 풀어 말하기("레포 실측으로 1444개 중" → "레포 뒤져보니 1444개 중", "이건 오탐이에요" → "이건 잘못 감지한 거예요"). "잘못 걸리다"처럼 안 붙는 동사로 도망가지 말고 원래 짝이 맞는 동사(감지하다·측정하다)에 "잘못"을 붙인다 |
141
- | I-7 | 리뷰 코멘트를 "지적"이라 부르기 ("지적 사항", "지적 N건", "지적했던 부분"처럼 뒤에 명사가 붙은 꼴도 같다. 코멘트가 아닌 일반 동사 용법 "원칙 위반을 지적하고", "논문이 지적한 점"은 예외. 탐지기가 어디까지 보고 어디서 새는지는 `src/humanize/detectors.ts` 의 I-7 주석과 코퍼스가 갖는다) | S2 / **대화·리뷰 S1** | 내가 남긴 건 "남겼던 의견"이나 "드렸던 의견", 상대가 남긴 건 "짚어주신 부분"이나 "남겨주신 의견"으로. "지적"은 상대를 잡아세우는 뉘앙스가 붙어 코멘트를 판정으로 만든다. 룰 원문은 [리뷰 코멘트를 "지적"이라고 부르지 않는다](author-voice.md#리뷰-코멘트를-지적이라고-부르지-않는다-ai-tell-i-7) 절이다 |
152
+ | I-7 | 리뷰 코멘트를 "지적"이라 부르기 ("지적 사항", "지적 N건", "지적했던 부분"처럼 뒤에 명사가 붙은 꼴도 같다. 코멘트가 아닌 일반 동사 용법 "원칙 위반을 지적하고", "논문이 지적한 점"은 예외. 탐지기가 어디까지 보고 어디서 놓치는지는 `src/humanize/detectors.ts` 의 I-7 주석과 코퍼스가 갖는다) | S2 / **대화·리뷰 S1** | 내가 남긴 건 "남겼던 의견"이나 "드렸던 의견", 상대가 남긴 건 "짚어주신 부분"이나 "남겨주신 의견"으로. "지적"은 상대를 잡아세우는 뉘앙스가 붙어 코멘트를 판정으로 만든다. 룰 원문은 [리뷰 코멘트를 "지적"이라고 부르지 않는다](author-voice.md#리뷰-코멘트를-지적이라고-부르지-않는다-ai-tell-i-7) 절이다 |
142
153
  | I-8 | 형식명사 "수준"으로 정도 뭉개기("다듬는 수준", "확인만 하는 수준") | S2 / **대화·리뷰 S1** | "정도"를 쓰거나 형식명사를 빼고 동사로 푼다("가볍게 손보면 되는 것들"). "수준이 낮다"의 등급 어감이 딸려와 채점처럼 읽히기 때문이다. 남의 코드를 두고 쓰면 특히 그렇다. 등급을 실제로 말하는 자리("높은 수준의 격리")는 대상이 아니다 |
143
154
 
144
155
  ## J. 시각 장식
@@ -159,11 +170,11 @@
159
170
  2. **변경률**: 30% 이하인가 (50% 초과는 작업 중단)
160
171
  3. **장르 이탈 없음**: 칼럼이 에세이나 문학으로 변하지 않았는가, 리포트가 블로그체로 떨어지지 않았는가
161
172
  4. **말투 보존**: 원문 격식체면 결과도 격식체. 평어체로 떨어뜨리지 않는다
162
- 5. **잔존 S1 패턴 0건**: A-1, A-3, A-7, A-8, A-16, B-3, B-5, C-5, C-8, C-10, C-11, C-12, D-1~D-6, D-8, H-1, H-3, J-2가 남아있지 않은가 (대화·리뷰 말투면 A-2, A-5, D-9, F-4, F-5, F-6, F-7, F-8, I-1, I-5, I-6, I-7, I-8도 S1로 포함)
173
+ 5. **잔존 S1 패턴 0건** (탐지기 수치는 각 룰의 대상 기준으로 걸러 센다 — 룰이 예외로 둔 자리는 잔존 건수에 안 넣는다): A-1, A-3, A-7, A-8, A-16, B-3, B-5, C-5, C-8, C-10, C-11, C-12, D-1~D-6, D-8, H-1, H-3, J-2가 남아있지 않은가 (대화·리뷰 말투면 A-2, A-5, C-14, D-9, E-8, F-4, F-5, F-6, F-7, F-8, G-4, I-1, I-5, I-6, I-7, I-8도 S1로 포함)
163
174
  6. **인공 표현 자제**: 원문에 없던 비유, 수사, 문학적 표현을 윤문 과정에서 임의로 추가하지 않았는가
164
175
  7. **삭제 처방 준수**: D-2, D-3, D-4, D-6, C-10을 재작성으로 처리하지 않았는가. 마무리 문장, 부제, 수식어를 지우는 대신 더 그럴듯한 것으로 갈아끼운 자리가 없는가
165
176
 
166
- 위반 시: edit 롤백 → 다시 윤문 → 재점검. 자체 루프 최대 1회. 이상 미해결이면 결과를 그대로 출력하되 `summary.md`에 "자가검증 미통과 항목 N" 표기.
177
+ 위반 시: edit 롤백 → 다시 윤문 → 재점검. 자체 루프 최대 1회. 이상 미해결이면 결과를 그대로 출력하되 `summary.md`에 "자가검증 미통과 항목 N" 표기.
167
178
 
168
179
  ## 코드 검사 (자가 채점보다 위)
169
180
 
@@ -193,10 +204,9 @@ AI 생성 산문 60편(모델 3종)과 2022년 이전 발행이 확인된 한국
193
204
  | I-1 "~한 것이다" | AI 20.4 vs 인간 43.0 (G²=6.2) — 인간이 2배 더 씀. 단락 말 위치·연속 반복도 AI가 더 적음 | S1 → S2(연속 3회+), 대화·리뷰만 S1 |
194
205
  | C-8 부정 대구 | AI 5.8 vs 인간 0.6 (9.2배, G²=41.7) — 개인 글 대비로는 18배. 모델 3종 공통 | S2 → S1 |
195
206
 
196
- 읽을 때 두 가지를 같이 봐야 한다. 인간 코퍼스가 **편집된 출판 산문**이라 "인간 일반"이 아니라
207
+ 읽을 때 같이 봐야 게 있다. 인간 코퍼스가 **편집된 출판 산문**이라 "인간 일반"이 아니라
197
208
  "잘 쓴 글"과의 대조다. 그리고 이 측정은 **문서 산문**을 잰 것이라 대화, 리뷰 코멘트에는 그대로
198
209
  적용되지 않는다 — A-2와 I-1이 대화에서 S1로 남는 이유가 이것이다.
199
- 출처: [`epoko77-ai/im-not-ai`](https://github.com/epoko77-ai/im-not-ai)의 `empirical-validation.md`.
200
210
 
201
211
  ### 팀 실제 사용 (B-4)
202
212
 
@@ -204,10 +214,10 @@ AI 생성 산문 60편(모델 3종)과 2022년 이전 발행이 확인된 한국
204
214
 
205
215
  | 룰 | 확인한 것 | 조정 |
206
216
  |---|---|---|
207
- | B-4 "소비처" | 팀 지라 티켓 3건에서 섹션 헤딩과 본문으로 일관되게 쓴다. 작성자 본인 어휘다 | 교정 예시에서 제외 |
217
+ | B-4 "소비처" | 팀 지라 티켓 3개에서 섹션 헤딩과 본문으로 일관되게 쓴다. 작성자 본인 어휘다 | 교정 예시에서 제외 |
208
218
 
209
219
  **교정어를 정하기 전에 팀이 실제로 뭐라고 쓰는지 먼저 본다.** 지라, PR, 슬랙을 검색하면 답이 있다.
210
- "인수조건"도 같은 방법으로 걷어냈다 — 팀 지라 전체에 5건뿐이고 그중 넷이 2025년 9월 한 묶음,
220
+ "인수조건"도 같은 방법으로 걷어냈다 — 팀 지라 전체에 5개뿐이고 그중 넷이 2025년 9월 한 묶음,
211
221
  나머지 하나는 이 에이전트가 직접 넣은 것이었다. 팀이 쓰는 말이 아니라 템플릿이 심은 말이었다.
212
222
 
213
223
  ## 등급 기준 (자가 채점)
@@ -217,4 +227,4 @@ AI 생성 산문 60편(모델 3종)과 2022년 이전 발행이 확인된 한국
217
227
  - **C**: S1 잔존 1~2 또는 자체검증 5항 이하 통과 — 사용자에게 strict 모드 권고
218
228
  - **D**: S1 잔존 3+ 또는 변경률 50% 초과 — 작업 중단 권고
219
229
 
220
- > v2.0 신규/보강은 A-7, A-15, A-16, A-18, A-19, E-2, E-7, F-4 **8 (A-17 보류)**. 학술 인용 전문은 `references/scholarship.md`. post-editese 3축 지표는 본 룰북 미반영(metric only 트랙). A-17 무정물, 추상명사 '-들'은 학술 근거(전영철 2007·곽은주·진실로 2011) 강하나 외부 회차(2026-05-07 위키 6편)에서 양성 0 — NMT 원본 출력 회차 후 v2.1에서 동일 ID로 재평가.
230
+ > v2.0 신규/보강은 A-7, A-15, A-16, A-18, A-19, E-2, E-7, F-4 **8 (A-17 보류)**. 학술 인용 전문은 `references/scholarship.md`. post-editese 3축 지표는 본 룰북 미반영(metric only 트랙). A-17 무정물, 추상명사 '-들'은 학술 근거(전영철 2007·곽은주·진실로 2011) 강하나 외부 회차(2026-05-07 위키 6편)에서 양성 0 — NMT 원본 출력 회차 후 v2.1에서 동일 ID로 재평가.
@@ -149,7 +149,7 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
149
149
  주 참조 구간이고 협업 한마디는 말투 B를 빌린다. 반영은 커밋 링크 + 한 줄로 짧게, 이견은
150
150
  근거 하나 대고 상대에게 판단을 넘긴다. **리뷰이는 강제성을 매기는 자리가 아니라 `r:`/`c:`/`a:`
151
151
  접두어를 붙이지 않는다** — 접두어는 리뷰어 쪽 도구다. 과잉 사과와 장문 변명이 이 장르에서
152
- 가장 자주 새는 AI-tell이다.
152
+ 가장 자주 걸리는 AI-tell이다.
153
153
  - **PR 설명, 변경 컨텍스트(change-context-writer)**: 본문은 "무엇을 왜 바꿨는지"를 서술하는
154
154
  성격이라 제안형보다 **담백한 서술체**가 맞다. 단 "~한 것 같습니다"의 부드러움과 온기는 유지하고
155
155
  딱딱한 단언, 결산 피벗으로 평탄화하지 않는다. 협업 한마디(요청·배려)는 말투 B를 빌린다.
@@ -157,11 +157,11 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
157
157
 
158
158
  ---
159
159
 
160
- ## 명사로 뭉치지 말고 풀어 말하기 (자주 새는 사각지대)
160
+ ## 명사로 뭉치지 말고 풀어 말하기 (자주 놓치는 사각지대)
161
161
 
162
162
  가장 티 나는 AI 흔적은 번역투나 헤징이 아니라 **개념을 명사 덩어리로 압축하는 습관**이다.
163
163
  사람은 대화, 리뷰 코멘트에서 "무엇을 왜 했는지"를 동사로 풀어 말하지, 명사구를 이어붙여 뭉치지 않는다.
164
- 아래 쌍은 실제 리뷰 코멘트에서 나온 교정 사례다. 패턴만 참고하고 문장은 복붙하지 않는다.
164
+ 아래 표는 실제 리뷰 코멘트에서 나온 교정 사례다. 패턴만 참고하고 문장은 복붙하지 않는다.
165
165
 
166
166
  | AI가 쓴 것 (before) | 사람이 쓸 것 (after) | 원인 |
167
167
  |---|---|---|
@@ -171,7 +171,26 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
171
171
  | 규칙을 전 소비자에게 배선했습니다 | 규칙을 소비자 전부에 연결해뒀어요 | 기술 비유 명사 "배선"(F-7) |
172
172
  | 코멘트에서 지식을 증류해 반영했어요 | 코멘트에서 쓸 만한 걸 추려서 반영했어요 | 기술 비유 명사 "증류"(F-7) |
173
173
  | 강등 방향도 맞게 갔습니다 | 심각도 내린 것도 맞는 방향 같아요 | 한자어 명사 "강등"(→ 동사로) + 추상명사에 이동 동사 |
174
- | c: 여섯 건은 매끄럽게 다듬는 수준이고 | c: 여섯 개는 가볍게 손보면 되는 것들이에요 | 형식명사 "수준"으로 정도 뭉개기 + 세는 단위 ""(I-5) |
174
+ | c: 코멘트 여섯 건은 매끄럽게 다듬는 수준이고 | c: 코멘트 여섯 개는 가볍게 손보면 되는 것들이에요 | 형식명사 "수준"으로 정도 뭉개기 + 사물을 세니 ""(I-5) |
175
+ | 두 가지 짚을 것 | 제가 봤을 때는 확인이 필요한 게 2건 있습니다 | 수량 예고(C-14) + 명사구 종결(E-8) + 화자 소거(G-4) |
176
+
177
+ **문장을 명사구로 끝내지 말 것.** "두 가지 짚을 것", "확인할 것", "고려할 점"처럼 서술어 없이
178
+ 관형형과 의존명사로 끊으면 목차 항목처럼 읽힌다. 사람은 말할 때 문장을 명사구로 안 끝낸다.
179
+ "짚어볼 게 있습니다"처럼 서술어를 붙인다. 판단을 말하는 자리면 화자까지 남겨
180
+ "제가 봤을 때는 확인이 필요합니다"로 간다 — G-4와 겹치는 자리다. 헤딩이나 체크리스트 항목,
181
+ 규범 문서에서 소제목 역할을 하는 볼드 도입구는 명사구 종결이 정상 문법이라 대상이 아니다
182
+ (ai-tell E-8).
183
+
184
+ **개수를 앞세워 예고하지 말 것.** "두 가지 짚을 것", "세 가지 이유가 있습니다"처럼 할 말의 개수를
185
+ 먼저 세어 선언하고 시작하면 발표문이 된다. 사람은 말하다 보니 몇 개가 되는 것이지 미리 세지 않는다.
186
+ 개수를 뒤로 보내 결과로 붙인다 — "확인이 필요한 게 2건 있습니다". 다만 개수가 대상의 고정 속성일
187
+ 때는 그냥 사실이다. 게슈탈트 원리가 실제로 다섯 개라 "다섯 가지 원리"는 고칠 자리가 아니다
188
+ (ai-tell C-14).
189
+
190
+ **의견에는 화자를 남길 것.** "확인이 필요합니다"는 사실 선언처럼 읽히지만 실제로는 내 판단이다.
191
+ "제가 봤을 때는", "제 생각엔"을 붙여 누가 하는 말인지 밝힌다. 이 voice의 본질이 제안이지 판정이
192
+ 아니라서, 화자가 지워지면 같은 내용이라도 통보가 된다. 헤징을 걷어내라는 규칙과 방향이 반대라
193
+ 경계를 지킨다 — 사실 서술에 붙은 "~로 보인다"는 빼고 판단에서 빠진 화자는 넣는다 (ai-tell G-4).
175
194
 
176
195
  **"수준"으로 정도를 말하지 말 것.** "다듬는 수준", "확인만 하는 수준"처럼 쓰면 정도를 말하려던 게
177
196
  채점처럼 읽힌다 — "수준이 낮다"의 등급 어감이 딸려오기 때문이다. 남의 코드를 두고 쓰면 특히 그렇다.
@@ -215,17 +234,24 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
215
234
 
216
235
  - 내가 남긴 것을 가리킬 때: **"남겼던 의견", "드렸던 의견", "남긴 코멘트"**
217
236
  - 상대가 남긴 것을 가리킬 때: **"짚어주신 부분", "남겨주신 의견"** — 받는 쪽에서도 같은 결로 간다
218
- - 셀 있게 말할 때는 "8"보다 **"8개"** "여덟 개" (사무투 분류사 회피, ai-tell I-5)
237
+ - 사물을 때는 **"개"** 쓴다. "코멘트 8", "버그 3개", "티켓 8개" (ai-tell I-5)
219
238
 
220
- > **"건"을 글자로 매칭하면 안 된다.** 같은 글자가 층위가 다르게 쓰인다.
239
+ > **"건"을 글자로 매칭하면 안 된다.** 같은 글자가 층위마다 다르게 쓰인다.
221
240
  >
222
241
  > | 고칠 것 | 그대로 둘 것 |
223
242
  > |---|---|
224
- > | "c: 여섯 **건**은 다듬는 정도예요" — 세는 단위 | "안 돌려본 **건** PR에 적어두셔서" — "것은"의 준말 |
225
- > | "지적해주신 **건**은 확인했습니다" — 사무투 분류사 | "제가 놓친 **건** 맞아요" — "것은"의 준말 |
243
+ > | "지적해주신 **건**은 확인했습니다" — 사무투 분류사 | "안 돌려본 **건** PR에 적어두셔서" — "것은"의 준말 |
244
+ > | "코멘트 여섯 **건**은 다듬는 정도예요" — 사물을 센다 | "제가 놓친 **건** 맞아요" — "것은"의 준말 |
245
+ > | "버그 8**건** 고쳤어요" — 사물을 센다 | "안 돌려본 **건** 확인했어요" — "것은"의 준말 |
226
246
  >
227
247
  > 준말 "건"은 구어에서 자연스러운 표현이라 늘려 쓰면("안 돌려본 것은") 오히려 딱딱해진다.
228
- > 규칙을 적용하기 전에 자리가 **수량을 세는 자리인지** 확인한다.
248
+ > 수량 자리는 **세는 사물이 바로 앞에 적혀 있을 때만** 본다. 적혀 있으면 "개"로 간다
249
+ > ("코멘트 여섯 개", "버그 8개"). 무엇을 세는지 문장에 없으면("확인이 필요한 게 2건 있습니다")
250
+ > 판정할 근거가 없으니 그대로 둔다.
251
+ >
252
+ > **이 표는 산출물 문장에만 적용된다.** 이 문서나 룰 문서가 자기 데이터를 세어 적는
253
+ > 자리("인라인 리뷰 1,321건", "표본 282건")는 대상이 아니다 — I-7이 같은 예외를 갖는 것과
254
+ > 같은 이유다.
229
255
 
230
256
  이 규칙은 산출물 문장에만 적용된다. 룰 문서나 스킬 문서가 개념을 설명할 때는 "리뷰 코멘트",
231
257
  "코멘트"라는 중립어를 쓴다 — 룰 문서가 금지 어휘를 본문에서 쓰면 산출물로 새기 때문이다.
@@ -69,7 +69,7 @@ key는 넣었는데 index 대신 id를 썼어요. 목록 순서가 바뀌는 케
69
69
  요건 이번 PR 범위를 넘어서는 것 같아서 별도 티켓으로 뺄까 싶은데 괜찮을까요?
70
70
  ```
71
71
 
72
- - 반드시 상대에게 판단을 넘기는 한 문장으로 닫는다 ("어떻게 생각하세요?", "괜찮을까요?").
72
+ - 반드시 상대에게 판단을 넘기는 한 문장을 마지막에 둔다 ("어떻게 생각하세요?", "괜찮을까요?").
73
73
  - 이견은 근거 하나만 대고 짧게 끝낸다. 방어적으로 길게 쓰면 톤이 세진다.
74
74
 
75
75
  ### 4. 질문 (clarify) — 코멘트 의도를 못 잡았다
@@ -101,7 +101,7 @@ key는 넣었는데 index 대신 id를 썼어요. 목록 순서가 바뀌는 케
101
101
 
102
102
  ### Humanize 처리
103
103
 
104
- 초안을 쓴 뒤 AI-tell을 점검한다. 기준은 [`../_shared/references/ai-tell-quick-rules.md`](../_shared/references/ai-tell-quick-rules.md)이고 답글엔 특히 아래가 자주 샌다.
104
+ 초안을 쓴 뒤 AI-tell을 점검한다. 기준은 [`../_shared/references/ai-tell-quick-rules.md`](../_shared/references/ai-tell-quick-rules.md)이고 답글엔 특히 아래가 자주 걸린다.
105
105
 
106
106
  | 패턴 | 예시 | 교정 |
107
107
  |------|------|------|
@@ -31,7 +31,7 @@ PR diff를 리뷰하고 머지 가능 여부를 판단할 수 있는 구체적
31
31
 
32
32
  ## Review Focus
33
33
 
34
- 변경 diff 리뷰할 때 세 가지 축으로 검토한다.
34
+ 변경 diff 아래 축으로 검토한다.
35
35
 
36
36
  1. **Bug** — 논리 오류, 경계값(off-by-one, empty/overflow) 처리 누락, null/undefined 역참조, 예외 미처리, race condition, 잘못된 조건 분기
37
37
  2. **Performance** — N+1 쿼리, 루프 내 불필요한 반복 연산, 중복 호출, 불필요한 메모리 할당, 캐시 미적용, 큰 객체 복사
@@ -100,6 +100,9 @@ voice 모델을 따른다. 초안 작성 후 반드시 [`../_shared/references/a
100
100
  | 음차(B-3) | "소스 오브 트루스", "룩 앤 필" 등 안 굳어진 음차 | 한글 의역 + 첫 등장만 원어 병기 |
101
101
  | 가운뎃점 나열(C-12) | "버그·성능·품질을 봅니다" | 쉼표나 구어로 풀기("버그, 성능, 품질") — 표·용어목록·합성어(입출력)는 예외 |
102
102
  | 측량·사무투 명사(I-6) | "레포 실측으로 1444개 중", "이건 오탐이에요" | 동사로 풀기("레포 뒤져보니 1444개 중", "이건 잘못 감지한 거예요") |
103
+ | 수량 예고(C-14) | "두 가지 짚을 것", "세 가지만 남길게요" | 개수를 뒤로 보내기("제가 봤을 때는 확인이 필요한 게 2건 있어요") — 개수가 대상의 고정 속성이면 그대로 |
104
+ | 명사구 종결(E-8) | "두 가지 짚을 것", "확인할 점" | 서술어를 붙여 끝내기("짚어볼 게 있어요") — 헤딩과 체크리스트는 예외 — 코멘트에서는 볼드를 씌워도 본문으로 본다 |
105
+ | 화자 소거(G-4) | "확인이 필요합니다" | 누구 판단인지 밝히기("제가 봤을 때는 확인이 필요해요") — 코드를 읽고 확인한 결함은 그대로 단정한다 |
103
106
 
104
107
  **근거를 제시하는 자리의 어휘.** 수치를 들이밀 때 "실측", "계측", "산출", "오탐" 같은 측량투
105
108
  명사를 쓰지 않는다 — 일상 대화에서 안 쓰는 말이라 그 자리만 문서 톤으로 튄다.
@@ -171,11 +174,11 @@ voice 모델을 따른다. 초안 작성 후 반드시 [`../_shared/references/a
171
174
  같은 리듬으로 나온 사례가 있다.
172
175
 
173
176
  - 한 코멘트에 "~것 같" 계열은 **1회까지**. 문제 진술과 제안에 각각 붙여 두 번 쓰지 않는다.
174
- - 리뷰 한 건에서 "~것 같"으로 닫는 코멘트는 **절반 이하**. 나머지는 "~는 건 어떨까요?",
177
+ - 리뷰 한 번에서 "~것 같"으로 끝내는 코멘트는 **절반 이하**. 나머지는 "~는 건 어떨까요?",
175
178
  "좋아보입니다", "~네요", 단정형으로 흩는다.
176
179
  - **코드를 읽고 확인한 결함은 단정한다.** 전부 헤지하면 확신도 신호가 사라져서 리뷰이가
177
180
  "이건 확실한 버그, 저건 그냥 의심"을 구분하지 못한다.
178
- - 확신이 없으면 헤지를 겹치지 말고 **질문으로 닫는다**("이 경로도 타나요?").
181
+ - 확신이 없으면 헤지를 겹치지 말고 **질문으로 끝낸다**("이 경로도 타나요?").
179
182
 
180
183
  | 헤지 몰림 | 이렇게 |
181
184
  |-----------|--------|
@@ -239,7 +242,7 @@ GitHub 마크다운은 **한 줄 개행(`\n`)을 무시하고 같은 문단으
239
242
  내놓기 전에 아래를 센다. 걸리면 초안을 그대로 내지 말고 고쳐서 낸다.
240
243
 
241
244
  1. "~것 같" 계열이 **한 코멘트에 2회 이상**인 곳 → 1회로 줄인다
242
- 2. "~것 같"으로 닫는 코멘트가 **전체의 절반을 넘는지** → 다른 종결로 분산한다
245
+ 2. "~것 같"으로 끝내는 코멘트가 **전체의 절반을 넘는지** → 다른 종결로 분산한다
243
246
  3. 코드로 확인한 결함을 헤지로 진술한 곳 → 단정으로 바꾼다
244
247
  4. 모든 코멘트가 **같은 3단 구조에 같은 분량**인지 → 사소한 건 한 줄로 줄인다
245
248
  5. 사소한 코멘트가 섞여 있는데 `a:`가 하나도 없는지 → severity를 다시 매긴다
@@ -90,7 +90,7 @@ gestalt humanize-scan --file <원문> --register <doc|chat|report>
90
90
  - **탐지기가 못 가리는 S1**: ID 목록만 나온다. 이건 직접 읽어서 판단한다
91
91
  - **그 밖의 룰**: 이번 텍스트에서 안 걸렸다. 찾아 나서지 않는다
92
92
 
93
- 룰북은 59개까지 자랐다. 매번 전부 펼치면 실제로 걸린 서너 개가 안 걸린 개에 묻힌다.
93
+ 룰북은 예순 개가 넘는다. 매번 전부 펼치면 실제로 걸린 서너 개가 안 걸린 나머지에 묻힌다.
94
94
  스캔은 이번에 볼 목록을 좁히는 장치다. 목록 밖의 룰을 굳이 뒤지면 그 자리에서 과윤문이 시작된다.
95
95
 
96
96
  **S1 0건이면 윤문하지 않는다.** 탐지기가 가리는 범위에서 걸리는 게 없고 직접 확인할 룰도
@@ -108,7 +108,7 @@ You are the Jira Writer role agent.
108
108
 
109
109
  ### 4단계 — AI-tell 제거 + 말투 통일
110
110
 
111
- 본문을 다 쓴 뒤 `ai-tell-quick-rules.md`의 S1 패턴을 기준으로 훑어 걷어낸다. 티켓 맥락에서 특히 자주 새는 것:
111
+ 본문을 다 쓴 뒤 `ai-tell-quick-rules.md`의 S1 패턴을 기준으로 훑어 걷어낸다. 티켓 맥락에서 특히 자주 걸리는 것:
112
112
 
113
113
  | 제거할 패턴 | 룰북 ID | 교정 |
114
114
  |-------------|---------|------|
@@ -128,7 +128,7 @@ Before/After나 대안을 나란히 놓아 차이를 보게 한다.
128
128
 
129
129
  ## 9. 마무리 (closing)
130
130
 
131
- 발표를 다음 행동으로 닫는다. 보고가 아니라 요청으로 끝낸다.
131
+ 발표의 마지막은 다음 행동이다. 보고가 아니라 요청으로 끝낸다.
132
132
 
133
133
  ```
134
134
  - 마무리 메시지: [청중이 가져갈 마지막 한 문장]
@@ -146,7 +146,7 @@ GESTALT_ACTOR=agent:reviewer gestalt pr edit <id> --title "고친 제목"
146
146
 
147
147
  `edit`은 `update`와 다르다. head를 안 옮기고 리뷰 판정도 라운드도 안 건드린다. 본문 오타를 고쳤다고 리뷰어가 내린 `request_changes`가 풀리면 안 되기 때문이다. 안 준 항목은 그대로 두고 빈 파일을 주면 본문을 비운다.
148
148
 
149
- ## 5단계: 머지와 닫기
149
+ ## 5단계: 머지와 종료
150
150
 
151
151
  ```bash
152
152
  gestalt pr merge <id>
@@ -162,7 +162,7 @@ gestalt pr update <id> --head "$(git rev-parse HEAD)"
162
162
  gestalt pr merge <id>
163
163
  ```
164
164
 
165
- 닫힌 PR도 head ref를 그대로 붙잡는다. 나중에 `pr diff`와 `pr checkout`이 동작한다.
165
+ 종료된 PR도 head ref를 그대로 붙잡는다. 나중에 `pr diff`와 `pr checkout`이 동작한다.
166
166
 
167
167
  ## 6단계: ref 정리
168
168
 
@@ -177,8 +177,8 @@ gestalt pr prune --checkouts # 체크아웃 자국까지
177
177
  기준은 하나다. **놓아도 커밋이 안 사라지는가.**
178
178
 
179
179
  - 머지된 PR의 base와 head를 놓는다. 놓기 전에 head가 정말 base 이력에 있는지 확인한다. 아니면 안 놓고 이유를 돌려준다.
180
- - 닫힌 PR은 아무것도 안 놓는다.
181
- - 체크아웃 자국은 기본으로 안 놓는다. 어느 이력에도 없는 커밋이라 놓으면 영영 사라진다. `--checkouts`로 뜻을 밝혀야 하고 그 PR이 이미 머지되거나 닫혔을 때만 놓는다.
180
+ - 종료된 PR은 아무것도 안 놓는다.
181
+ - 체크아웃 자국은 기본으로 안 놓는다. 어느 이력에도 없는 커밋이라 놓으면 영영 사라진다. `--checkouts`로 뜻을 밝혀야 하고 그 PR이 이미 머지되거나 종료됐을 때만 놓는다.
182
182
 
183
183
  `prune`은 CLI에만 있다. 되돌릴 수 없게 놓는 자리라 MCP 도구로는 안 뒀다.
184
184
 
@@ -197,6 +197,6 @@ gestalt pr prune --checkouts # 체크아웃 자국까지
197
197
  | --- | --- |
198
198
  | `prId` | PR id (8자 16진수) |
199
199
  | `prStatus` | `open`, `merged`, `closed` |
200
- | `unresolvedCount` | 안 닫힌 스레드 수 |
200
+ | `unresolvedCount` | 안 끝난 스레드 수 |
201
201
 
202
202
  로컬 PR에는 URL이 없다. `prUrl`을 안 돌려준다.
@@ -123,7 +123,7 @@ id를 직접 주면 아래 1번의 첫 수단이 브랜치를 안 따지고 잡
123
123
  2. **GitHub 지정** — `target`이 PR 번호나 GitHub URL이면 → `github`입니다. 사용자가 원격을 짚었으므로 아래 3번을 건너뜁니다.
124
124
  3. **안 끝난 로컬 PR** — 현재 브랜치에 안 끝난 로컬 PR이 있으면 → `local`입니다. 1번이 이미 조회했으면 그 결과를 그대로 씁니다. 1번을 안 거쳤으면 여기서 처음 조회합니다.
125
125
 
126
- 로컬 PR이 안 끝났다는 건 그 코드가 아직 안 정해졌다는 뜻입니다. 그 상태로 원격에 리뷰를 게시하면 두 자리에 서로 다른 판정이 남습니다. 로컬을 먼저 닫고 원격을 봅니다.
126
+ 로컬 PR이 안 끝났다는 건 그 코드가 아직 안 정해졌다는 뜻입니다. 그 상태로 원격에 리뷰를 게시하면 두 자리에 서로 다른 판정이 남습니다. 로컬을 먼저 종료하고 원격을 봅니다.
127
127
 
128
128
  이 갈래로 왔으면 사용자에게 한 줄 알립니다: "현재 브랜치에 안 끝난 로컬 PR {id}가 있어서 그쪽을 먼저 봐요. 원격이면 PR 번호나 URL을 주세요."
129
129
  4. `gh auth status`가 실패하거나(인증 안 됨) `git remote -v`가 비어 있으면(원격 없음) → GitHub 경로가 막혀 있습니다. → `none`입니다.