@tienne/gestalt 0.70.0 → 0.72.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 (55) hide show
  1. package/CLAUDE.md +1 -1
  2. package/README.ko.md +3 -3
  3. package/README.md +4 -4
  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 +13 -9
  7. package/dist/plugin/role-agents/_shared/references/author-voice.md +8 -8
  8. package/dist/plugin/role-agents/_shared/references/style-guide.md +13 -0
  9. package/dist/plugin/role-agents/humanize-monolith/AGENT.md +1 -1
  10. package/dist/plugin/skills/_shared/agent-delegation.md +1 -1
  11. package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
  12. package/dist/plugin/skills/local-pr/SKILL.md +1 -0
  13. package/dist/plugin/skills/pr/SKILL.md +2 -0
  14. package/dist/plugin/skills/review/SKILL.md +2 -0
  15. package/dist/plugin/skills/review-reply/SKILL.md +2 -0
  16. package/dist/plugin/skills/ship/SKILL.md +750 -0
  17. package/dist/src/cli/commands/humanize-check.d.ts.map +1 -1
  18. package/dist/src/cli/commands/humanize-check.js +5 -6
  19. package/dist/src/cli/commands/humanize-check.js.map +1 -1
  20. package/dist/src/cli/commands/humanize-scan.d.ts +4 -2
  21. package/dist/src/cli/commands/humanize-scan.d.ts.map +1 -1
  22. package/dist/src/cli/commands/humanize-scan.js +15 -9
  23. package/dist/src/cli/commands/humanize-scan.js.map +1 -1
  24. package/dist/src/core/types.d.ts +1 -1
  25. package/dist/src/humanize/detectors.d.ts +31 -2
  26. package/dist/src/humanize/detectors.d.ts.map +1 -1
  27. package/dist/src/humanize/detectors.js +192 -7
  28. package/dist/src/humanize/detectors.js.map +1 -1
  29. package/dist/src/humanize/index.d.ts +1 -1
  30. package/dist/src/humanize/index.d.ts.map +1 -1
  31. package/dist/src/humanize/index.js +1 -1
  32. package/dist/src/humanize/index.js.map +1 -1
  33. package/dist/src/humanize/read-input.d.ts +21 -0
  34. package/dist/src/humanize/read-input.d.ts.map +1 -0
  35. package/dist/src/humanize/read-input.js +51 -0
  36. package/dist/src/humanize/read-input.js.map +1 -0
  37. package/dist/src/humanize/scan.d.ts +13 -0
  38. package/dist/src/humanize/scan.d.ts.map +1 -1
  39. package/dist/src/humanize/scan.js +16 -5
  40. package/dist/src/humanize/scan.js.map +1 -1
  41. package/dist/src/mcp/schemas.js +1 -1
  42. package/package.json +1 -1
  43. package/plugin/.codex-plugin/plugin.json +2 -2
  44. package/plugin/role-agents/_shared/references/README.md +1 -1
  45. package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +13 -9
  46. package/plugin/role-agents/_shared/references/author-voice.md +8 -8
  47. package/plugin/role-agents/_shared/references/style-guide.md +13 -0
  48. package/plugin/role-agents/humanize-monolith/AGENT.md +1 -1
  49. package/plugin/skills/_shared/agent-delegation.md +1 -1
  50. package/plugin/skills/_shared/proactive-routing.md +1 -0
  51. package/plugin/skills/local-pr/SKILL.md +1 -0
  52. package/plugin/skills/pr/SKILL.md +2 -0
  53. package/plugin/skills/review/SKILL.md +2 -0
  54. package/plugin/skills/review-reply/SKILL.md +2 -0
  55. package/plugin/skills/ship/SKILL.md +750 -0
@@ -1,3 +1,14 @@
1
+ /**
2
+ * 윤문 전에 원문을 훑어 "이번에 볼 룰"만 추린다.
3
+ *
4
+ * 룰북은 예순 개를 넘겼다. 매번 전부 펼치면 모델이 나눠 쓰는 주의가 룰마다 얇아진다.
5
+ * 실제로 걸린 서너 개는 안 걸린 쉰 개에 묻힌다. 스캔은 그 반대로 간다 —
6
+ * 걸린 룰만 처방과 함께 내놓는다. 나머지는 아예 말하지 않는다.
7
+ *
8
+ * 탐지기가 없는 S1은 목록으로만 넘긴다. 코드가 못 가리는 자리를 가린다고 하면
9
+ * 그게 더 나쁜 거짓말이다.
10
+ */
11
+ import { type SpacingIssue } from './detectors.js';
1
12
  import { type Register, type RuleScanOptions } from './rules.js';
2
13
  export interface ScanHit {
3
14
  ruleId: string;
@@ -14,6 +25,8 @@ export interface ScanReport {
14
25
  hits: ScanHit[];
15
26
  /** 탐지기가 없어 모델이 직접 봐야 하는 S1 룰 ID */
16
27
  unverifiable: string[];
28
+ /** 어투가 아니라 맞춤법인 자리. s1Total 과 worthHumanizing 에는 안 섞는다 */
29
+ spacing: SpacingIssue[];
17
30
  /** 걸리는 게 없으면 윤문하지 않는다 */
18
31
  worthHumanizing: boolean;
19
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/humanize/scan.ts"],"names":[],"mappings":"AAWA,OAAO,EAAmC,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElG,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,mCAAmC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,yBAAyB;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC;AAE1C,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,UAAU,CAyB5E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAqCrD"}
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/humanize/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAmC,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElG,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,mCAAmC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,0DAA0D;IAC1D,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,yBAAyB;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC;AAE1C,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,UAAU,CA4B5E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAiDrD"}
@@ -1,21 +1,22 @@
1
1
  /**
2
2
  * 윤문 전에 원문을 훑어 "이번에 볼 룰"만 추린다.
3
3
  *
4
- * 룰북은 59개까지 자랐다. 매번 전부 펼치면 모델이 나눠 쓰는 주의가 룰마다 얇아진다.
4
+ * 룰북은 예순 개를 넘겼다. 매번 전부 펼치면 모델이 나눠 쓰는 주의가 룰마다 얇아진다.
5
5
  * 실제로 걸린 서너 개는 안 걸린 쉰 개에 묻힌다. 스캔은 그 반대로 간다 —
6
6
  * 걸린 룰만 처방과 함께 내놓는다. 나머지는 아예 말하지 않는다.
7
7
  *
8
8
  * 탐지기가 없는 S1은 목록으로만 넘긴다. 코드가 못 가리는 자리를 가린다고 하면
9
9
  * 그게 더 나쁜 거짓말이다.
10
10
  */
11
- import { detect, DETECTABLE_RULE_IDS } from './detectors.js';
11
+ import { scanProse, DETECTABLE_RULE_IDS } from './detectors.js';
12
12
  import { parseRuleBook, ruleLabel, s1Ids } from './rules.js';
13
13
  export function scan(text, options = {}) {
14
14
  const register = options.register ?? 'doc';
15
15
  const book = options.book ?? parseRuleBook();
16
16
  const targets = s1Ids(book, register);
17
17
  const detectable = new Set(DETECTABLE_RULE_IDS);
18
- const hits = detect(text, targets)
18
+ const { detections, spacing } = scanProse(text, targets);
19
+ const hits = detections
19
20
  .map((found) => ({
20
21
  ruleId: found.ruleId,
21
22
  label: ruleLabel(book, found.ruleId),
@@ -30,10 +31,17 @@ export function scan(text, options = {}) {
30
31
  s1Total,
31
32
  hits,
32
33
  unverifiable: targets.filter((id) => !detectable.has(id)),
34
+ spacing,
33
35
  worthHumanizing: s1Total > 0,
34
36
  };
35
37
  }
36
38
  export function formatScan(report) {
39
+ const spacing = report.spacing.flatMap((issue) => [
40
+ `- ${issue.label} ${issue.count}건`,
41
+ ...issue.samples.map((sample) => ` "${sample}"`),
42
+ ` 처방: ${issue.fix}`,
43
+ ]);
44
+ const spacingBlock = spacing.length > 0 ? ['', '맞춤법 (등급과 무관하게 그냥 고친다)', ...spacing] : [];
37
45
  if (!report.worthHumanizing) {
38
46
  // 직접 확인할 룰을 먼저 세운다. "윤문하지 않는다"를 앞에 두면 그 한 줄만 읽고
39
47
  // 비탐지 룰 확인을 건너뛰게 된다 — 탐지기가 0건이라고 글이 깨끗한 건 아니다.
@@ -42,8 +50,11 @@ export function formatScan(report) {
42
50
  '',
43
51
  '아래 룰은 탐지기가 못 가린다. 직접 읽어서 확인한다.',
44
52
  ` ${report.unverifiable.join(' ')}`,
53
+ ...spacingBlock,
45
54
  '',
46
- '여기서도 걸리는 게 없으면 윤문하지 않고 원문을 그대로 낸다.',
55
+ report.spacing.length > 0
56
+ ? '어투는 그대로 두고 위 맞춤법만 고쳐서 낸다.'
57
+ : '여기서도 걸리는 게 없으면 윤문하지 않고 원문을 그대로 낸다.',
47
58
  ].join('\n');
48
59
  }
49
60
  const lines = [
@@ -59,7 +70,7 @@ export function formatScan(report) {
59
70
  if (hit.prescription)
60
71
  lines.push(` 처방: ${hit.prescription}`);
61
72
  }
62
- lines.push('', '탐지기가 못 가리는 S1 (직접 확인)', ` ${report.unverifiable.join(' ')}`, '', '위 목록 밖의 룰은 이번 텍스트에서 안 걸렸다. 찾아 나서지 않는다.');
73
+ lines.push('', '탐지기가 못 가리는 S1 (직접 확인)', ` ${report.unverifiable.join(' ')}`, ...spacingBlock, '', '위 목록 밖의 룰은 이번 텍스트에서 안 걸렸다. 찾아 나서지 않는다.');
63
74
  return lines.join('\n');
64
75
  }
65
76
  //# sourceMappingURL=scan.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/humanize/scan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/humanize/scan.ts"],"names":[],"mappings":"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"}
@@ -431,7 +431,7 @@ export const executeInputSchema = z.object({
431
431
  prReviewer: z
432
432
  .string()
433
433
  .optional()
434
- .describe('review_publish가 남길 판정의 리뷰어 이름. 생략하면 GESTALT_ACTOR 환경변수, 그것도 없으면 gestalt:review를 쓴다. 개별 코멘트 작성자는 이 값이 아니라 각 지적의 reportedBy다.'),
434
+ .describe('review_publish가 남길 판정의 리뷰어 이름. 생략하면 GESTALT_ACTOR 환경변수, 그것도 없으면 gestalt:review를 쓴다. 개별 코멘트 작성자는 이 값이 아니라 각 의견의 reportedBy다.'),
435
435
  });
436
436
  export const executeToolSchema = executeInputSchema.shape;
437
437
  // ─── Create Agent Tool ──────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tienne/gestalt",
3
- "version": "0.70.0",
3
+ "version": "0.72.0",
4
4
  "description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gestalt",
3
- "version": "0.70.0",
3
+ "version": "0.72.0",
4
4
  "description": "Gestalt psychology-driven AI development harness. Transforms scattered requirements into structured, validated specifications through interactive interviews.",
5
5
  "author": {
6
6
  "name": "tienne"
@@ -22,7 +22,7 @@
22
22
  "interface": {
23
23
  "displayName": "Gestalt",
24
24
  "shortDescription": "Requirements-to-spec pipeline with review and PR workflows",
25
- "longDescription": "Gestalt turns vague ideas into validated specifications through Gestalt-principle interviews, then drives execution, code review, and PR authoring. Bundles 18 workflow skills and 27 role agents over 12 MCP tools.",
25
+ "longDescription": "Gestalt turns vague ideas into validated specifications through Gestalt-principle interviews, then drives execution, code review, and PR authoring. Bundles 19 workflow skills and 27 role agents over 12 MCP tools.",
26
26
  "developerName": "tienne",
27
27
  "category": "Developer Tools",
28
28
  "capabilities": [
@@ -31,7 +31,7 @@ pnpm verify:rules
31
31
  본문에 쓰면 산출물로 샌다. 금지어를 넣었으면 같은 문서를 grep한다.
32
32
  - 어투 규칙은 **S1으로 올려야 실제로 강제된다.** S2는 모델이 우선순위를 알아서 정하면서 새어나간다.
33
33
  - 심각도를 바꿀 때는 근거를 남긴다. A-2, I-1, C-8은 대조 코퍼스 측정으로 조정했고 그 근거가
34
- 룰북 §실측 근거에 있다. 감으로 올리고 내리면 다음 사람이 되돌린다.
34
+ [룰북 측정 근거](ai-tell-quick-rules.md#측정-근거)에 있다. 감으로 올리고 내리면 다음 사람이 되돌린다.
35
35
  - 경로를 참조하는 자리가 여러 곳이다. 파일을 옮기거나 이름을 바꾸면 `plugin/` 전체에서
36
36
  상대경로 참조를 다시 확인한다 (에이전트는 `../_shared/references/`, 에이전트의 `references/`
37
37
  하위 문서는 `../../_shared/references/`, 스킬은 `../../role-agents/_shared/references/`).
@@ -6,7 +6,7 @@
6
6
 
7
7
  **Do-NOT (탐지·윤문 모두 제외):** 고유명사, 제품명, 모델명, 기관명, 수치, 날짜, 단위, 큰따옴표 안 직접 인용, 법률 조문, 수학, 화학, 통계 표기, 영어 약어(LLM·GPU·MCP·API 등 업계 표준).
8
8
 
9
- **약어 면제는 업계 표준에만 준다:** 풀어 썼을 때 안 굳어진 음차가 되는 약어는 면제 대상이 아니다. `SSOT`나 `SoT`를 그대로 두면 "소스 오브 트루스"를 약어로 우회한 것과 같다 — B-3로 우리말로 푼다. 무엇을 가리키느냐에 따라 말이 달라지므로 대체어 표는 `style-guide.md` §single source of truth를 뭐라고 쓸까에 둔다. LLM, API처럼 풀어 쓸 일이 없는 표준 약어만 그대로 둔다.
9
+ **약어 면제는 업계 표준에만 준다:** 풀어 썼을 때 안 굳어진 음차가 되는 약어는 면제 대상이 아니다. `SSOT`나 `SoT`를 그대로 두면 "소스 오브 트루스"를 약어로 우회한 것과 같다 — B-3로 우리말로 푼다. 무엇을 가리키느냐에 따라 말이 달라지므로 대체어 표는 [style-guide.md single source of truth를 뭐라고 쓸까](style-guide.md#single-source-of-truth를-뭐라고-쓸까)에 둔다. LLM, API처럼 풀어 쓸 일이 없는 표준 약어만 그대로 둔다.
10
10
 
11
11
  **굳어진 음차 화이트리스트 (B-3 제외 — 그대로 둔다):** 컴포넌트·토큰·커밋·인터페이스·메서드·빌드·디플로이·캐시·렌더링·콜백·프레임워크·라이브러리·리팩터링·마이그레이션·아이콘·레이아웃·그리드·모달·토스트·타이포그래피·플레이스홀더·프로젝트·스프린트·이슈·리뷰·머지·브랜치·사이드 이펙트·보일러플레이트·트레이드오프·딥다이브·얼라인·온보딩·소스·롤백·파싱·레지스트리·불릿 등 업계 정착어. 이 목록 밖의 안 굳어진 음차(소스 오브 트루스·룩 앤 필·로우 행잉 프룻 등)만 B-3로 교정한다.
12
12
 
@@ -18,7 +18,7 @@
18
18
 
19
19
  **한자어를 피하는 게 목적이 아니다 (F-4·F-5 오적용 주의):** 겨냥하는 건 개념을 뭉친 **명사화**(-성/-적/-화)이지 한자어 동사가 아니다. "측정하다"를 "재다"로, "판단하다"를 "따지다"로 바꾸면 정확도만 잃는다. 그 자리의 정확한 말이 한자어면 한자어를 쓴다. 반대 방향 실수도 같다 — 한자어를 피하려고 비유 명사(축·증류)나 물리 동사(재다)로 도망가면 F-7에 걸린다. 셋 다 겪은 실례: `네 축을 따로 재고 판정한다` → `4가지 측면에서 각각 측정하고 판단한다`.
20
20
 
21
- **근거가 붙은 룰 (→ 아래 §실측 근거):** A-2, I-1, C-8은 대조 코퍼스 측정으로 심각도를 조정했고 B-4는 팀이 실제로 쓰는 말이라 예시에서 뺐다. 원어민이 오히려 더 쓰는 표현이나 팀에서 이미 굳은 말을 지우면 사람 글을 AI 글로 만든다.
21
+ **근거가 붙은 룰 (→ 아래 [측정 근거](#측정-근거)):** A-2, I-1, C-8은 대조 코퍼스 측정으로 심각도를 조정했고 B-4는 팀이 실제로 쓰는 말이라 예시에서 뺐다. 원어민이 오히려 더 쓰는 표현이나 팀에서 이미 굳은 말을 지우면 사람 글을 AI 글로 만든다.
22
22
 
23
23
  ---
24
24
 
@@ -48,9 +48,9 @@
48
48
  |---|---|---|---|
49
49
  | B-1 | 한글 + 괄호 영어 매번 ("~(Sovereign AI)" 처럼) | S2 | 첫 등장만 병기, 이후 한글만 |
50
50
  | B-2 | 영어 어휘 직역 가능한데 그대로 | S2 | 한국어로 옮기되 업계 표준은 유지 |
51
- | B-3 | 안 굳어진 영어 구·단어 음차 표기 ("소스 오브 트루스"), 그 음차를 약어로 우회한 표기(`SSOT`·`SoT`) | S1 | 한글 의역 + 첫 등장만 원어 괄호 병기("기준 문서(source of truth)", "단일 기준점(source of truth)" 등), 이후 한글만. 단 위 "굳어진 음차 화이트리스트"에 있는 정착어는 Do-NOT — of/and 등 기능어까지 통째 음차한 구(룩 앤 필·로우 행잉 프룻)가 최우선 대상. 무엇을 가리키는지 보고 고르는 표는 `style-guide.md` §single source of truth를 뭐라고 쓸까를 따른다 |
52
- | B-4 | 영어 개념을 어색하게 옮긴 조어("생산처" ← producer, "응답처") | S2 | 억지 신조어 대신 이미 쓰이는 말로. 코드 맥락이면 "호출부"·"사용처". **팀에서 이미 굳은 조어는 예외** — "소비처"는 팀 지라 티켓에서 라이브러리를 가져다 쓰는 쪽을 가리키는 말로 정착했으므로 교정 대상이 아니다 (→ 아래 §실측 근거) |
53
- | B-5 | 영어 추상 개념어를 사전 첫 뜻으로 옮겨 레지스터가 어긋난 말 (materialize → "물질화", semantics → "의미론", virtue → "미덕", durably → "내구성 있게") | S1 | 그 자리에서 실제로 무슨 일이 벌어지는지를 동사로 쓴다. 아래 §B-5 대체어 표 참조. 음차로 도망가지 않는다 — "머티리얼라이즈"로 바꾸면 B-3에 걸린다 |
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
+ | B-4 | 영어 개념을 어색하게 옮긴 조어("생산처" ← producer, "응답처") | S2 | 억지 신조어 대신 이미 쓰이는 말로. 코드 맥락이면 "호출부"·"사용처". **팀에서 이미 굳은 조어는 예외** — "소비처"는 팀 지라 티켓에서 라이브러리를 가져다 쓰는 쪽을 가리키는 말로 정착했으므로 교정 대상이 아니다 (→ 아래 [측정 근거](#측정-근거)) |
53
+ | B-5 | 영어 추상 개념어를 사전 첫 뜻으로 옮겨 레지스터가 어긋난 말 (materialize → "물질화", semantics → "의미론", virtue → "미덕", durably → "내구성 있게") | S1 | 그 자리에서 실제로 무슨 일이 벌어지는지를 동사로 쓴다. 아래 [B-5 대체어](#b-5-대체어) 표 참조. 음차로 도망가지 않는다 — "머티리얼라이즈"로 바꾸면 B-3에 걸린다 |
54
54
 
55
55
  ### B-5 대체어
56
56
 
@@ -91,7 +91,8 @@
91
91
  | D-5 | 의인화 추상 주어("기술이 묻는다·시대가 부른다") | S1 | 사람·기관 주어로 |
92
92
  | D-6 | 결말 공식 "~할 때다/~해야 한다/~지금이야말로" | S1 | 삭제하고 **원문에 이미 있는 가장 구체적인 문장으로 끝낸다.** 더 나은 마무리 문장으로 고쳐쓰지 말고, 리듬을 살리려 하지도 않는다. 닫는 느낌이 꼭 필요하면 원문 근거만으로 쓸 수 있는 평서 한 줄(다음 할 일 등)까지만 |
93
93
  | D-7 | 변환 공식 "X에서 Y로" 반복 | S2 | 한 번만, 나머지는 일반 서술 |
94
- | D-8 | 과잉 자책, 감정 과장 반응("제일 아팠습니다·뼈아픕니다·부끄럽습니다·뜨끔했습니다") | S1 | 짧은 수긍으로 환원한다("아 그렇네요", "이거 놓쳤네요"). 사실 서술은 그대로 두고 감정 수식만 뺀다. D-4(hype 어휘)의 뒷면이다 — 칭찬 쪽만 막으면 같은 충동이 자책 쪽으로 샌다. 지적들 사이에 "제일"로 순위를 매기는 것도 여기 해당한다 |
94
+ | D-8 | 과잉 자책, 감정 과장 반응("제일 아팠습니다·뼈아픕니다·부끄럽습니다·뜨끔했습니다") | S1 | 짧은 수긍으로 환원한다("아 그렇네요", "이거 놓쳤네요"). 사실 서술은 그대로 두고 감정 수식만 뺀다. D-4(hype 어휘)의 뒷면이다 — 칭찬 쪽만 막으면 같은 충동이 자책 쪽으로 샌다. 남긴 의견들 사이에 "제일"로 순위를 매기는 것도 여기 해당한다 |
95
+ | D-9 | 추상명사에 이동 동사("방향도 맞게 갔습니다", "결론이 그쪽으로 갔어요") | S2 / **대화·리뷰 S1** | 방향, 결론, 판단, 논의가 스스로 움직이게 두지 않는다. 사람이나 대상을 주어로 되돌린다("맞는 방향 같아요", "그렇게 결론 냈어요"). D-5 의인화 추상 주어의 사촌이다 |
95
96
 
96
97
  ## E. 리듬, 종결어미
97
98
 
@@ -109,6 +110,7 @@
109
110
  | F-5 | "~적 N" 추상 체인 ("전략적 함의", "실천적 기반") | S2 / **대화·리뷰 S1** | 명사+명사 또는 풀어쓰기("전략 함의", "실천의 기반") |
110
111
  | F-6 | 복합명사 압축 — 명사구를 조사·동사 없이 이어붙여 개념을 뭉침 ("시안 정합 버그픽스", "유지보수성 개선 작업", "권한 체크 로직") | S2 / **대화·리뷰 S1** | 동사·조사로 풀어 서술 ("디자인 시안과 다르게 렌더링되던 문제", "나중에 유지보수하기 편하게"). 사람은 압축 명사구 대신 무엇을 왜 했는지 풀어 말한다 |
111
112
  | F-7 | 기술·이공계 비유 명사를 일상 대화에 그대로 (증류·배선·결정화·평탄화·오케스트레이션·파이프라인화·축 등, 화학·전기·수학 어휘의 비유 차용) | S2 / **대화·리뷰 S1** | 일상 동사·명사로 환원 (증류 → "추려내다/뽑아내다", 배선 → "연결하다/걸어두다", 결정화 → "정리하다", 평탄화 → "밋밋하게 만들다", **축 → "측면"**·"기준"). 문법은 멀쩡해 룰 매칭이 안 되지만 사람은 대화에서 안 쓴다. "네 축을 잰다"가 아니라 "4가지 측면에서 측정한다". **예외는 그 프로젝트가 개념에 붙인 이름일 때만이고, 그 개념을 다루는 자리에서만이다** — 게슈탈트의 "스펙 결정화"는 `similarity-crystallizer` 에이전트 이름이자 인터뷰→Spec 변환의 정의라서 두지만, 같은 말을 지라 티켓 작성처럼 무관한 자리에 끌어다 쓰면 F-7이다. 코드의 "파이프라인" 자체, 그래프의 x축도 같은 기준. **테스트를 자물쇠에 빗댄 "잠그다/잠근다/잠긴"도 여기 해당한다** — "경계마다 관련 테스트가 있다"처럼 쓴다 |
113
+ | F-8 | 추상명사에 물리 측량 동사("근거를 재봤는데", "판단을 재보고 있다", "근거를 재본 결과", "의견을 달아봤는데") | S2 / **대화·리뷰 S1** | 저울에 올린 게 아니라 검토한 것이다. 사람이 하는 행위 동사로 되돌린다("근거를 확인해봤는데", "의견을 검토해봤는데"). F-7 물리 동사 도피의 사촌이라 목적어가 근거, 의견, 판단, 영향, 의미, 가치, 리스크인 자리만 본다 — "온도를 재봤는데"는 대상이 아니다 |
112
114
 
113
115
  ## G. Hedging
114
116
 
@@ -135,7 +137,9 @@
135
137
  | I-3 | "~다는 뜻이다/~다는 의미다" 결말 | S2 | 본문에 풀어 쓰기 |
136
138
  | I-4 | 권고형 결말 "~해야 한다·~합니다" 반복 | S2 | 평서·단언으로 |
137
139
  | I-5 | 사무투 분류사 "~ 건/해당 건/이번 건/그 건", 코드·문서 용어를 대화에 그대로("주석 건") | S2 / **대화·리뷰 S1** | 구체 명사로 풀기("Copilot이 짚은 주석 건" → "Copilot이 남긴 코멘트"). "건"은 공문서투 분류사라 대화에서 어색하다 |
138
- | I-6 | 측량·사무투 명사 "실측·계측·산출·오탐" 등으로 판정·근거를 명사 하나로 압축 | S2 / **대화·리뷰 S1** | 동사로 풀어 말하기("레포 실측으로 1444개 중" → "레포 뒤져보니 1444개 중", "이건 오탐이에요" → "이건 잘못 감지한 거예요"). "잘못 걸리다"처럼 안 붙는 동사로 도망가지 말고 원래 짝이 맞는 동사(감지하다·측정하다)에 "잘못"을 붙인다 |
140
+ | 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) 절이다 |
142
+ | I-8 | 형식명사 "수준"으로 정도 뭉개기("다듬는 수준", "확인만 하는 수준") | S2 / **대화·리뷰 S1** | "정도"를 쓰거나 형식명사를 빼고 동사로 푼다("가볍게 손보면 되는 것들"). "수준이 낮다"의 등급 어감이 딸려와 채점처럼 읽히기 때문이다. 남의 코드를 두고 쓰면 특히 그렇다. 등급을 실제로 말하는 자리("높은 수준의 격리")는 대상이 아니다 |
139
143
 
140
144
  ## J. 시각 장식
141
145
 
@@ -155,7 +159,7 @@
155
159
  2. **변경률**: 30% 이하인가 (50% 초과는 작업 중단)
156
160
  3. **장르 이탈 없음**: 칼럼이 에세이나 문학으로 변하지 않았는가, 리포트가 블로그체로 떨어지지 않았는가
157
161
  4. **말투 보존**: 원문 격식체면 결과도 격식체. 평어체로 떨어뜨리지 않는다
158
- 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, F-4, F-5, F-6, F-7, I-1, I-5, I-6도 S1로 포함)
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로 포함)
159
163
  6. **인공 표현 자제**: 원문에 없던 비유, 수사, 문학적 표현을 윤문 과정에서 임의로 추가하지 않았는가
160
164
  7. **삭제 처방 준수**: D-2, D-3, D-4, D-6, C-10을 재작성으로 처리하지 않았는가. 마무리 문장, 부제, 수식어를 지우는 대신 더 그럴듯한 것으로 갈아끼운 자리가 없는가
161
165
 
@@ -174,7 +178,7 @@ gestalt humanize-check --before before.md --after after.md --register chat
174
178
  변경률 2.8%인데 문장 3할이 갈려나간 사례가 있었다. **이 출력대로 판정하고 자기가 낸 값으로
175
179
  덮어쓰지 않는다.** 측면별 임계와 탐지 대상 룰은 `src/humanize/`에 있다.
176
180
 
177
- ## 실측 근거
181
+ ## 측정 근거
178
182
 
179
183
  감으로 올리고 내린 심각도는 다음 사람이 되돌린다. 바꿀 때는 근거를 남긴다.
180
184
 
@@ -175,7 +175,7 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
175
175
 
176
176
  **"수준"으로 정도를 말하지 말 것.** "다듬는 수준", "확인만 하는 수준"처럼 쓰면 정도를 말하려던 게
177
177
  채점처럼 읽힌다 — "수준이 낮다"의 등급 어감이 딸려오기 때문이다. 남의 코드를 두고 쓰면 특히 그렇다.
178
- 범위를 말할 때는 **"정도"** 를 쓰고 가능하면 형식명사를 빼고 동사로 푼다("가볍게 손보면 되는 것들").
178
+ 범위를 말할 때는 **"정도"** 를 쓰고 가능하면 형식명사를 빼고 동사로 푼다("가볍게 손보면 되는 것들") (ai-tell I-8).
179
179
 
180
180
  **목적어를 생략하지 말 것.** "한 가지만 작게 남겨요"처럼 무엇을 남기는지(코멘트·의견)를 빼고
181
181
  형식 수량사("한 가지")와 어색한 부사("작게")로 때우면 붕 뜬다. "코멘트 하나 남길게요",
@@ -184,14 +184,14 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
184
184
  **추상명사에 이동 동사를 붙이지 말 것.** "방향도 맞게 갔습니다", "결론이 그쪽으로 갔어요"처럼
185
185
  방향, 결론, 판단 같은 추상명사를 스스로 움직이게 만들면 붕 뜬다. 방향 자체가 가는 게 아니라
186
186
  무언가가 그 방향으로 가는 것이다. "맞는 방향 같아요", "그렇게 결론 냈어요"처럼 사람이나
187
- 대상을 주어로 되돌린다 (ai-tell D-5 의인화 추상 주어의 사촌).
187
+ 대상을 주어로 되돌린다 (ai-tell D-9, D-5 의인화 추상 주어의 사촌).
188
188
 
189
189
  **추상명사에 측량 동사를 붙이지 말 것.** "근거를 재봤는데", "의견을 달아봤는데"처럼 재다나
190
190
  달다처럼 물리적으로 계측하는 동사를 근거, 의견, 판단 같은 추상명사에 붙이면 붕 뜬다. 실제로
191
191
  저울에 올린 게 아니라 검토하거나 확인한 것이다. "근거를 확인해봤는데", "의견을 검토해봤는데"처럼
192
- 사람이 하는 행위 동사로 되돌린다 (ai-tell F-7 물리 동사 도피의 사촌). 정규식 탐지기는 "재다"의
193
- 멀쩡한 물리적 용법("온도를 재봤는데")까지 걸릴까 패턴을 일부러 빼뒀다 — 목적어가
194
- 추상명사인지 보고 사람이 판단한다.
192
+ 사람이 하는 행위 동사로 되돌린다 (ai-tell F-8, F-7 물리 동사 도피의 사촌). 목적어를 근거, 의견,
193
+ 판단 같은 추상명사로 한정해서 탐지기가 본다 — "온도를 재봤는데" 멀쩡한 물리적 용법은 목적어가
194
+ 달라서 걸린다.
195
195
 
196
196
  **얽힌 것에는 풀다, 막힌 것에는 해소하다.** "오해를 풀다", "갈등을 풀다"처럼 얽혀 있는
197
197
  대상에는 풀다가 맞는다. 그런데 "진입을 막고 있던 두 가지를 풉니다"처럼 막혀 있는 대상(문제,
@@ -201,7 +201,7 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
201
201
 
202
202
  ---
203
203
 
204
- ## 리뷰 코멘트를 "지적"이라고 부르지 않는다
204
+ ## 리뷰 코멘트를 "지적"이라고 부르지 않는다 (ai-tell I-7)
205
205
 
206
206
  산출물에서 리뷰 코멘트를 가리킬 때 "지적"을 쓰지 않는다. 상대를 잡아세우는 뉘앙스가 붙어서
207
207
  같은 내용이라도 제안형 어투와 어긋난다. 이 voice의 본질은 제안이지 판정이 아니다.
@@ -263,7 +263,7 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
263
263
  - **가운뎃점(·) 나열 남발** — 본문에서 "A·B·C" 압축은 기계 티. 쉼표나 "A랑 B하고 C"로 푼다 (ai-tell C-12)
264
264
  - **명사구 압축, 사무투 분류사** — "시안 정합 버그픽스", "주석 건" 같은 명사 뭉치는 동사로 풀고 "건"은 구체 명사로 (ai-tell F-6·I-5, 리뷰 코멘트에선 S1)
265
265
  - **기술 비유 명사** — "증류·배선·결정화·평탄화" 같은 화학, 전기 어휘 차용은 일상 동사로 (ai-tell F-7, 리뷰 코멘트에선 S1)
266
- - **"지적"** — 리뷰 코멘트를 가리키는 말로 쓰지 않는다. "남겼던 의견", "짚어주신 부분"으로 (위 "리뷰 코멘트를 '지적'이라고 부르지 않는다")
266
+ - **"지적"**(ai-tell I-7) — 리뷰 코멘트를 가리키는 말로 쓰지 않는다. "남겼던 의견", "짚어주신 부분"으로 (위 "리뷰 코멘트를 '지적'이라고 부르지 않는다")
267
267
  - **`c:`/`r:`/`a:` 접두어를 어투 시그니처처럼 흉내 내기, `[출처]` 대괄호 태깅, "…권장." 체언 종지** — Claude가 만든 가짜 시그니처. 단, 팀이 채택한 리뷰 강제성 라벨은 예외다
268
268
 
269
269
  ---
@@ -278,4 +278,4 @@ OO님 이거 타겟 브랜치를 변경해주셔야 할 것 같아요!
278
278
  6. 친근체, 물결, 이모지는 자연스럽게, 과하지 않게.
279
279
  7. `c:`/`r:`·`a:`를 어투처럼 흉내 내지 않는다. 팀이 채택한 리뷰 강제성 라벨은 예외다. `[출처]`·"권장." 은 쓰지 않는다 (Claude artifact).
280
280
  8. 개념을 명사로 뭉치지 말고 동사로 푼다("시안 정합 버그픽스" → "시안이랑 다르게 나오던 거"). "건" 같은 사무투 분류사와 생략된 목적어를 되살린다.
281
- 9. 리뷰 코멘트를 "지적"이라 부르지 않는다. 내 것은 "남겼던 의견 / 드렸던 의견", 상대 것은 "짚어주신 부분 / 남겨주신 의견".
281
+ 9. 리뷰 코멘트를 "지적"이라 부르지 않는다 (I-7). 내 것은 "남겼던 의견 / 드렸던 의견", 상대 것은 "짚어주신 부분 / 남겨주신 의견".
@@ -24,6 +24,19 @@
24
24
  - 🔴 Danger: data loss, security risk — never use Note for this
25
25
  - Descriptive link text — Don't: `[여기](url)` / Do: `[설치 가이드](url)`
26
26
 
27
+ ### 다른 문서의 절을 가리킬 때
28
+
29
+ 절 참조는 대상 제목이 바뀌면 조용히 낡는다. 그래서 표기를 기계가 검사할 수 있는 꼴로 고정한다 (`pnpm verify:rules` 8번).
30
+
31
+ - **마크다운 → 마크다운**: 앵커 링크. `[측정 근거](ai-tell-quick-rules.md#측정-근거)`, 같은 문서 안이면 `[측정 근거](#측정-근거)`
32
+ - **코드 주석 → 마크다운**: `파일명 §「제목 전문」`. 주석에서는 링크가 안 눌리므로 낫표로 제목의 끝을 막는다. `author-voice.md §「기계적 점검 (어투는 아니지만 자주 틀리는 것)」`
33
+ - 마크다운 본문에 `§`를 쓰지 않는다. 앵커로 쓸 수 있는 자리에 `§`를 쓰면 검사가 비켜간다
34
+ - 앵커와 낫표 안은 **제목 전문**을 그대로 옮긴다. 꼬리를 잘라 적으면 검사에 걸린다. 매번 적기 버거운 제목은 참조를 줄이지 말고 제목을 줄인다
35
+ - 링크 텍스트는 짧게 써도 된다 — 검사하는 건 앵커지 표시 문구가 아니다
36
+ - 제목이 아닌 자리(볼드 라벨, 표의 행)는 `§`로 가리키지 않는다. 검사할 수 없어서 낡는 걸 못 잡는다
37
+
38
+ 앵커 슬러그는 제목을 소문자로 내리고 문장부호를 지운 뒤 공백을 하이픈으로 바꾼 것이다. `### B-5 대체어` → `#b-5-대체어`.
39
+
27
40
  ### Content Principles
28
41
  - Lead with business value, follow with technical detail
29
42
  - Real-world examples before abstract definitions
@@ -81,7 +81,7 @@ S2
81
81
  gestalt humanize-scan --file <원문> --register <doc|chat|report>
82
82
  ```
83
83
 
84
- 종료 코드로도 답한다. 걸린 게 있으면 0, 탐지기가 가리는 범위에서 0건이면 10이다.
84
+ 종료 코드로도 답한다. 걸린 게 있으면 0, 어투는 깨끗한데 맞춤법만 걸리면 11, 탐지기가 가리는 범위에서 0건이면 10이다. 11이면 어투는 그대로 두고 맞춤법 절만 고쳐서 낸다.
85
85
  파일이 없으면 3이다. 셸에서 분기할 때 stdout 을 파싱하지 않아도 된다.
86
86
 
87
87
  스캔이 내놓는 것만 본다.
@@ -1,6 +1,6 @@
1
1
  # 에이전트를 서브에이전트로 위임하기 (공유 규칙)
2
2
 
3
- > **현재 적용: `review`, `pr`, `brief`, `presentation`, `review-reply`, `slack-send`, `jira-create`.** 에이전트를 불러 쓰는 스킬은 전부 위임한다. 새 스킬이 `ges_agent get`을 메인에서 하면 그건 예외가 아니라 빠뜨린 것이다.
3
+ > **현재 적용: `review`, `pr`, `brief`, `presentation`, `review-reply`, `slack-send`, `jira-create`, `ship`.** 에이전트를 불러 쓰는 스킬은 전부 위임한다. 새 스킬이 `ges_agent get`을 메인에서 하면 그건 예외가 아니라 빠뜨린 것이다.
4
4
 
5
5
  ## 왜 필요한가
6
6
 
@@ -38,6 +38,7 @@
38
38
  | 내 PR에 달린 리뷰 코멘트 답변 본문 작성 (반영·대안·보류·질문) | `code-review-responder` |
39
39
  | PR·브랜치·커밋 코드 리뷰 요청 | `/review` 스킬 사용 |
40
40
  | 받은 리뷰 반영·답글 게시 요청 ("리뷰 반영해줘", "리뷰 코멘트에 답해줘", "받은 리뷰 처리해줘") | `review-reply` 스킬 사용 (스레드 수집 → 유형 분류 승인 → 수정·커밋 → 답글 승인 → 게시) |
41
+ | 리뷰가 수렴할 때까지 돌려 GitHub까지 내보내는 요청 ("출하해줘", "리뷰 통과할 때까지", "코파일럿 리뷰까지 받아줘") | `ship` 스킬 사용 (로컬 PR → 리뷰 수렴 루프 → 승인 → draft PR → Copilot 수렴 루프 → ready). 리뷰 한 번만이면 `review` |
41
42
  | PR 작성·생성 요청 ("PR 만들어줘", "PR 작성해줘", "PR 올려줘") | `gestalt:pr` 스킬 사용 |
42
43
  | 실행 태스크를 외부 런타임 워커로 뿌리는 요청 ("orca로 실행", "codex로 실행", "워커 띄워서 실행") | `dispatch` 스킬 사용 (런타임 감지 → 같은 워크트리에 터미널 → worker_done 대기 → ready 재계산). 런타임 없으면 execute의 기본 병렬 경로 |
43
44
 
@@ -47,6 +47,7 @@ outputs:
47
47
  | 에이전트끼리 코드를 주고받는 자리 | **이 스킬** |
48
48
  | 이미 있는 변경을 검토받기 | `review` |
49
49
  | 받은 리뷰에 답하기 | `review-reply` |
50
+ | 리뷰가 수렴할 때까지 돌려 GitHub까지 내보내기 | `ship` |
50
51
 
51
52
  원격 PR은 사람이 읽고 판단하라고 올린다. 에이전트끼리 주고받는 데는 `gh`도 인증도 원격 왕복도 군더더기다. 워크트리 여럿이 `.gestalt/reviews.db` 하나를 공유하므로 어느 워크트리에서 쳐도 같은 목록을 본다.
52
53
 
@@ -39,6 +39,8 @@ outputs:
39
39
  /pr feature/auth # 특정 브랜치
40
40
  ```
41
41
 
42
+ PR을 만드는 것까지가 범위입니다. 올리기 전에 리뷰를 통과시키고 Copilot 리뷰까지 받으려면 `ship` 스킬을 씁니다 — 그쪽이 이 스킬의 0~4.5단계로 description을 짓고 `--draft`로 제출합니다.
43
+
42
44
  ## 전제 조건
43
45
 
44
46
  `repoRoot`가 주어지지 않으면 현재 작업 디렉토리를 절대 경로로 사용합니다.
@@ -63,6 +63,8 @@ execute 세션 없이 PR, 브랜치, 커밋의 변경사항을 직접 리뷰 파
63
63
  /review abc1234 # 특정 커밋
64
64
  ```
65
65
 
66
+ 리뷰 한 번이 이 스킬의 범위입니다. 이슈가 없어질 때까지 리뷰와 대응을 반복하고 GitHub PR까지 내보내려면 `ship` 스킬을 씁니다 — 그쪽이 라운드마다 이 스킬을 부릅니다.
67
+
66
68
  ## 전제 조건
67
69
 
68
70
  없습니다. git 저장소이기만 하면 바로 돌아갑니다 — 코드 그래프는 쓰지 않습니다.
@@ -60,6 +60,8 @@ outputs:
60
60
  /review-reply feature/auth # 해당 브랜치의 PR
61
61
  ```
62
62
 
63
+ 받은 코멘트에 한 번 답하는 게 이 스킬의 범위다. 코멘트가 안 나올 때까지 리뷰와 대응을 반복하려면 `ship` 스킬을 쓴다 — 그쪽이 라운드마다 이 스킬을 부른다.
64
+
63
65
  ## 불변 규칙 두 가지
64
66
 
65
67
  이 스킬은 외부에 나가는 문장을 쓰고 그 문장이 사실 주장이다. 아래 둘은 어떤 경우에도 건너뛰지 않는다.