@tienne/gestalt 0.51.0 → 0.52.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 (67) hide show
  1. package/CLAUDE.md +7 -4
  2. package/dist/package.json +4 -3
  3. package/dist/plugin/role-agents/_shared/references/README.md +13 -0
  4. package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  5. package/dist/plugin/role-agents/_shared/references/style-guide.md +40 -0
  6. package/dist/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  7. package/dist/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  8. package/dist/plugin/role-agents/harness-architect/AGENT.md +1 -1
  9. package/dist/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  10. package/dist/plugin/role-agents/jira-writer/AGENT.md +11 -11
  11. package/dist/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  12. package/dist/plugin/skills/dispatch/SKILL.md +3 -3
  13. package/dist/plugin/skills/execute/SKILL.md +1 -1
  14. package/dist/plugin/skills/jira-create/SKILL.md +5 -5
  15. package/dist/plugin/skills/presentation/SKILL.md +6 -6
  16. package/dist/plugin/skills/review-reply/SKILL.md +3 -3
  17. package/dist/plugin/skills/slack-send/SKILL.md +2 -2
  18. package/dist/src/cli/commands/humanize-check.d.ts +8 -0
  19. package/dist/src/cli/commands/humanize-check.d.ts.map +1 -0
  20. package/dist/src/cli/commands/humanize-check.js +29 -0
  21. package/dist/src/cli/commands/humanize-check.js.map +1 -0
  22. package/dist/src/cli/index.d.ts.map +1 -1
  23. package/dist/src/cli/index.js +11 -0
  24. package/dist/src/cli/index.js.map +1 -1
  25. package/dist/src/code-graph/rrf.d.ts +4 -4
  26. package/dist/src/code-graph/rrf.js +4 -4
  27. package/dist/src/execute/parallel-groups.d.ts +1 -1
  28. package/dist/src/execute/parallel-groups.js +1 -1
  29. package/dist/src/gestalt/surface-labels.d.ts +3 -3
  30. package/dist/src/gestalt/surface-labels.js +1 -1
  31. package/dist/src/humanize/change-rate.d.ts +13 -0
  32. package/dist/src/humanize/change-rate.d.ts.map +1 -0
  33. package/dist/src/humanize/change-rate.js +86 -0
  34. package/dist/src/humanize/change-rate.js.map +1 -0
  35. package/dist/src/humanize/check.d.ts +39 -0
  36. package/dist/src/humanize/check.d.ts.map +1 -0
  37. package/dist/src/humanize/check.js +150 -0
  38. package/dist/src/humanize/check.js.map +1 -0
  39. package/dist/src/humanize/detectors.d.ts +28 -0
  40. package/dist/src/humanize/detectors.d.ts.map +1 -0
  41. package/dist/src/humanize/detectors.js +134 -0
  42. package/dist/src/humanize/detectors.js.map +1 -0
  43. package/dist/src/humanize/index.d.ts +5 -0
  44. package/dist/src/humanize/index.d.ts.map +1 -0
  45. package/dist/src/humanize/index.js +5 -0
  46. package/dist/src/humanize/index.js.map +1 -0
  47. package/dist/src/humanize/rules.d.ts +34 -0
  48. package/dist/src/humanize/rules.d.ts.map +1 -0
  49. package/dist/src/humanize/rules.js +95 -0
  50. package/dist/src/humanize/rules.js.map +1 -0
  51. package/package.json +4 -3
  52. package/plugin/.codex-plugin/plugin.json +1 -1
  53. package/plugin/role-agents/_shared/references/README.md +13 -0
  54. package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  55. package/plugin/role-agents/_shared/references/style-guide.md +40 -0
  56. package/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  57. package/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  58. package/plugin/role-agents/harness-architect/AGENT.md +1 -1
  59. package/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  60. package/plugin/role-agents/jira-writer/AGENT.md +11 -11
  61. package/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  62. package/plugin/skills/dispatch/SKILL.md +3 -3
  63. package/plugin/skills/execute/SKILL.md +1 -1
  64. package/plugin/skills/jira-create/SKILL.md +5 -5
  65. package/plugin/skills/presentation/SKILL.md +6 -6
  66. package/plugin/skills/review-reply/SKILL.md +3 -3
  67. package/plugin/skills/slack-send/SKILL.md +2 -2
@@ -0,0 +1,134 @@
1
+ /**
2
+ * 룰 ID별 결정적 탐지기.
3
+ *
4
+ * 여기 있는 건 정규식만으로 오탐 없이 셀 수 있는 룰뿐이다. D-5 의인화 주어처럼
5
+ * 뜻을 봐야 판단되는 룰은 일부러 뺐다 — 검사가 오탐으로 멈추면 아무도 안 쓴다.
6
+ * 탐지기가 없는 룰은 모델이 자체검증으로 본다.
7
+ */
8
+ const SAMPLE_CAP = 3;
9
+ /** 표 안 압축과 코드는 룰 적용 대상이 아니라서 센 뒤 빼야 한다 */
10
+ function proseOnly(text) {
11
+ return text
12
+ .replace(/```[\s\S]*?```/g, '\n')
13
+ .replace(/`[^`\n]+`/g, ' ')
14
+ .split('\n')
15
+ .filter((line) => !line.trimStart().startsWith('|'))
16
+ .join('\n');
17
+ }
18
+ function matcher(ruleId, re, onProse = true) {
19
+ return {
20
+ ruleId,
21
+ run: (text) => {
22
+ const target = onProse ? proseOnly(text) : text;
23
+ return [...target.matchAll(re)].map((m) => m[0].trim());
24
+ },
25
+ };
26
+ }
27
+ /** 문장 첫머리 접속사는 문장을 갈라서 봐야 한다 */
28
+ function sentenceInitial(ruleId, words) {
29
+ const re = new RegExp(`^(?:${words.join('|')})[\\s,]`);
30
+ return {
31
+ ruleId,
32
+ run: (text) => {
33
+ const hits = [];
34
+ for (const chunk of splitSentences(proseOnly(text))) {
35
+ const stripped = chunk.replace(/^[\s>*\-#\d.)]+/, '');
36
+ const match = stripped.match(re);
37
+ if (match)
38
+ hits.push(match[0].trim());
39
+ }
40
+ return hits;
41
+ },
42
+ };
43
+ }
44
+ export function splitSentences(text) {
45
+ return text
46
+ .split(/(?<=[.!?…])\s+|\n+/)
47
+ .map((s) => s.trim())
48
+ .filter(Boolean);
49
+ }
50
+ // 한글 뒤에는 \b가 성립하지 않는다(자모가 \w가 아님). 어미 끝은 후행 부정 탐색으로 막는다.
51
+ const NOT_HANGUL = '(?![가-힣])';
52
+ const JOSA = '(?:는|도|만|요)?';
53
+ const DETECTORS = [
54
+ matcher('A-1', new RegExp(`[가-힣)\\]]\\s*에\\s*대(?:해서|하여|해|한)${JOSA}${NOT_HANGUL}`, 'g')),
55
+ matcher('A-2', new RegExp(`[가-힣)\\]]\\s*(?:를|을)?\\s*통(?:해서|하여|해)${JOSA}${NOT_HANGUL}`, 'g')),
56
+ matcher('A-3', new RegExp(`[가-힣)\\]]\\s*에\\s*있어(?:서)?${JOSA}${NOT_HANGUL}`, 'g')),
57
+ matcher('A-5', new RegExp(`(?:와|과)\\s*관련(?:하여|해서|해|된|한)${NOT_HANGUL}`, 'g')),
58
+ matcher('A-7', /가지고\s*있(?:다|습니다|는|었|지)/g),
59
+ // 되어진다는 지+ㄴ이 결합해 "진"으로 적히므로 자모 분리 형태로는 안 잡힌다
60
+ matcher('A-8', /되어\s*(?:진|지[다고며])|지게\s*(?:된|되[다었어고])|되어\s*졌/g),
61
+ matcher('A-9', new RegExp(`[가-힣)\\]]\\s*에\\s*의(?:해서|하여|해)${NOT_HANGUL}`, 'g')),
62
+ matcher('A-19', new RegExp(`[가-힣]\\s*(?:에서의|에로의|으로의|로의|에의|으로부터의)${NOT_HANGUL}`, 'g')),
63
+ matcher('C-11', /[가-힣](?:하고|하며|되고|되며|고|며|지만|면서|아서|어서),/g),
64
+ matcher('C-12', /[가-힣A-Za-z0-9]·[가-힣A-Za-z0-9]/g),
65
+ matcher('D-1', /(?:결론적으로|요약하자면|요약하면|정리하자면|정리하면|종합하면|이를\s*통해)/g),
66
+ matcher('D-2', /(?:시사하는\s*바가\s*크|주목할\s*만하)/g),
67
+ matcher('D-3', /(?:본질적으로|핵심적으로)/g),
68
+ matcher('D-4', /(?:파격적|압도적|획기적|혁신적|전례\s*없|폭발적)/g),
69
+ matcher('D-6', /(?:할\s*때다|할\s*때입니다|할\s*시점|지금이야말로|할\s*순간)/g),
70
+ matcher('F-7', /(?:증류|배선|결정화|평탄화|오케스트레이션|파이프라인화)/g),
71
+ matcher('G-2', /(?:로\s*보인다|인\s*듯하다|로\s*판단된다|라고\s*여겨진다|로\s*여겨진다)/g),
72
+ matcher('I-1', /(?:인\s*것이다|한\s*것이다|는\s*것이다|일\s*것이다)/g),
73
+ matcher('I-3', /(?:다는\s*뜻이다|다는\s*의미다|다는\s*것이다)/g),
74
+ matcher('I-5', new RegExp(`(?:해당|이번|그)\\s*건${NOT_HANGUL}|[가-힣]\\s건(?:은|이|을|에|도)${NOT_HANGUL}`, 'g')),
75
+ sentenceInitial('H-1', ['또한', '따라서', '즉', '나아가', '아울러', '게다가', '더욱이']),
76
+ sentenceInitial('H-3', ['이는', '이\\s*점에서', '이\\s*관점에서', '이\\s*말은']),
77
+ ];
78
+ export const DETECTABLE_RULE_IDS = DETECTORS.map((d) => d.ruleId);
79
+ export function detect(text, ruleIds) {
80
+ const wanted = ruleIds ? new Set(ruleIds) : null;
81
+ const results = [];
82
+ for (const detector of DETECTORS) {
83
+ if (wanted && !wanted.has(detector.ruleId))
84
+ continue;
85
+ const hits = detector.run(text);
86
+ if (hits.length === 0)
87
+ continue;
88
+ results.push({
89
+ ruleId: detector.ruleId,
90
+ count: hits.length,
91
+ samples: [...new Set(hits)].slice(0, SAMPLE_CAP),
92
+ });
93
+ }
94
+ return results;
95
+ }
96
+ export function countByRule(text, ruleIds) {
97
+ return new Map(detect(text, ruleIds).map((d) => [d.ruleId, d.count]));
98
+ }
99
+ // --- 보존해야 하는 토큰 ---------------------------------------------------
100
+ const PROTECTED_PATTERNS = [
101
+ /```[\s\S]*?```/g,
102
+ /`[^`\n]+`/g,
103
+ /https?:\/\/[^\s)\]]+/g,
104
+ /"[^"\n]{2,}"|“[^”\n]{2,}”/g,
105
+ /\d[\d,]*(?:\.\d+)?%?/g,
106
+ /\b[A-Z][A-Za-z0-9]*(?:[A-Z][A-Za-z0-9]*)+\b/g,
107
+ /\b[A-Z]{2,}\b/g,
108
+ ];
109
+ /** 원문에서 한 글자도 바뀌면 안 되는 토큰을 뽑는다 */
110
+ export function protectedTokens(text) {
111
+ const tokens = new Set();
112
+ for (const re of PROTECTED_PATTERNS) {
113
+ for (const match of text.matchAll(re)) {
114
+ const token = match[0].trim();
115
+ if (token.length >= 2)
116
+ tokens.add(token);
117
+ }
118
+ }
119
+ return [...tokens];
120
+ }
121
+ export function missingProtectedTokens(before, after) {
122
+ return protectedTokens(before).filter((token) => !after.includes(token));
123
+ }
124
+ export function structureStats(text) {
125
+ const lines = text.split('\n');
126
+ return {
127
+ sentences: splitSentences(proseOnly(text)).length,
128
+ headings: lines.filter((line) => /^#{1,6}\s/.test(line.trim())).length,
129
+ bullets: lines.filter((line) => /^[-*+]\s|^\d+\.\s/.test(line.trim())).length,
130
+ codeFences: (text.match(/```/g) ?? []).length,
131
+ links: (text.match(/\[[^\]]+\]\([^)]+\)/g) ?? []).length,
132
+ };
133
+ }
134
+ //# sourceMappingURL=detectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectors.js","sourceRoot":"","sources":["../../../src/humanize/detectors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { parseRuleBook, s1Ids, citedRuleIds, expandIdRanges, QUICK_RULES_PATH, type Register, type Rule, type RuleBook, type Severity, } from './rules.js';
2
+ export { detect, countByRule, protectedTokens, missingProtectedTokens, structureStats, splitSentences, DETECTABLE_RULE_IDS, type Detection, type StructureStats, } from './detectors.js';
3
+ export { changeRate, type ChangeRateOptions } from './change-rate.js';
4
+ export { runCheck, formatReport, EXIT_CODE, THRESHOLD, type CheckReport, type AxisResult, type Verdict, } from './check.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/humanize/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { parseRuleBook, s1Ids, citedRuleIds, expandIdRanges, QUICK_RULES_PATH, } from './rules.js';
2
+ export { detect, countByRule, protectedTokens, missingProtectedTokens, structureStats, splitSentences, DETECTABLE_RULE_IDS, } from './detectors.js';
3
+ export { changeRate } from './change-rate.js';
4
+ export { runCheck, formatReport, EXIT_CODE, THRESHOLD, } from './check.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/humanize/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,GAKjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,mBAAmB,GAGpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAA0B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,GAIV,MAAM,YAAY,CAAC"}
@@ -0,0 +1,34 @@
1
+ export type Severity = 'S1' | 'S2' | 'S3';
2
+ /** 산문(칼럼·리포트·문서) 기준과 대화·리뷰 코멘트 기준을 나눠 본다 */
3
+ export type Register = 'doc' | 'chat';
4
+ export interface Rule {
5
+ id: string;
6
+ category: string;
7
+ categoryTitle: string;
8
+ pattern: string;
9
+ /** 문서 기준 심각도 */
10
+ severity: Severity;
11
+ /** 대화·리뷰에서 격상되는 룰은 여기가 S1이 된다 */
12
+ chatSeverity: Severity;
13
+ prescription: string;
14
+ }
15
+ export interface RuleBook {
16
+ path: string;
17
+ rules: Map<string, Rule>;
18
+ /** 자체검증 5번이 열거한 잔존 금지 S1 목록 */
19
+ selfCheckS1: string[];
20
+ /** 자체검증 5번의 대화·리뷰 추가분 */
21
+ selfCheckChatS1: string[];
22
+ }
23
+ export declare const QUICK_RULES_PATH: string;
24
+ /**
25
+ * "D-1~D-7" 같은 범위 표기를 개별 ID로 편다.
26
+ * 룰북이 사람 읽기 좋게 범위로 적어둔 자리를 코드가 그대로 이해하게 만든다.
27
+ */
28
+ export declare function expandIdRanges(text: string): string[];
29
+ /** 마크다운 본문에서 인용된 모든 룰 ID를 뽑는다 (범위 표기 포함) */
30
+ export declare function citedRuleIds(markdown: string): string[];
31
+ export declare function parseRuleBook(path?: string): RuleBook;
32
+ /** 해당 말투 기준으로 S1인 룰 ID */
33
+ export declare function s1Ids(book: RuleBook, register: Register): string[];
34
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/humanize/rules.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtC,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iCAAiC;IACjC,YAAY,EAAE,QAAQ,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,yBAAyB;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAID,eAAO,MAAM,gBAAgB,QAG5B,CAAC;AAeF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBrD;AAED,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAyB,GAAG,QAAQ,CA6CvE;AAED,0BAA0B;AAC1B,wBAAgB,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAKlE"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * 룰 기준 문서인 ai-tell-quick-rules.md를 읽어 룰 목록으로 만든다.
3
+ *
4
+ * 룰은 사람이 읽는 마크다운이 기준이고, 코드는 그걸 읽기만 한다.
5
+ * 반대로 코드에 룰을 복사해 두면 룰북과 코드가 조용히 갈라진다.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ import { dirname, resolve } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ export const QUICK_RULES_PATH = resolve(__dirname, '../../plugin/role-agents/_shared/references/ai-tell-quick-rules.md');
12
+ const CATEGORY_HEADING = /^##\s+([A-J])\.\s+(.+?)\s*$/;
13
+ const TABLE_ROW = /^\|\s*([A-J]-\d{1,2})\s*\|(.+)$/;
14
+ const RULE_ID = /\b([A-J]-\d{1,2})\b/g;
15
+ const ID_RANGE = /\b([A-J])-(\d{1,2})\s*~\s*(?:[A-J]-)?(\d{1,2})\b/g;
16
+ function parseSeverity(cell) {
17
+ const found = cell.match(/\bS[123]\b/g) ?? [];
18
+ const base = (found[0] ?? 'S2');
19
+ // "S2 / **대화·리뷰 S1**" 처럼 두 개가 적힌 칸은 뒤쪽이 대화 기준이다
20
+ const chat = (found[1] ?? base);
21
+ return { severity: base, chatSeverity: chat };
22
+ }
23
+ /**
24
+ * "D-1~D-7" 같은 범위 표기를 개별 ID로 편다.
25
+ * 룰북이 사람 읽기 좋게 범위로 적어둔 자리를 코드가 그대로 이해하게 만든다.
26
+ */
27
+ export function expandIdRanges(text) {
28
+ const ids = new Set();
29
+ let remaining = text;
30
+ for (const match of text.matchAll(ID_RANGE)) {
31
+ const letter = match[1];
32
+ const from = Number(match[2]);
33
+ const to = Number(match[3]);
34
+ for (let n = Math.min(from, to); n <= Math.max(from, to); n += 1) {
35
+ ids.add(`${letter}-${n}`);
36
+ }
37
+ remaining = remaining.replace(match[0], ' ');
38
+ }
39
+ for (const match of remaining.matchAll(RULE_ID)) {
40
+ ids.add(match[1]);
41
+ }
42
+ return [...ids];
43
+ }
44
+ /** 마크다운 본문에서 인용된 모든 룰 ID를 뽑는다 (범위 표기 포함) */
45
+ export function citedRuleIds(markdown) {
46
+ return expandIdRanges(markdown);
47
+ }
48
+ export function parseRuleBook(path = QUICK_RULES_PATH) {
49
+ const raw = readFileSync(path, 'utf-8');
50
+ const lines = raw.split('\n');
51
+ const rules = new Map();
52
+ let category = '';
53
+ let categoryTitle = '';
54
+ for (const line of lines) {
55
+ const heading = line.match(CATEGORY_HEADING);
56
+ if (heading) {
57
+ category = heading[1];
58
+ categoryTitle = heading[2];
59
+ continue;
60
+ }
61
+ const row = line.match(TABLE_ROW);
62
+ if (!row)
63
+ continue;
64
+ const id = row[1];
65
+ const cells = row[2].split('|').map((cell) => cell.trim());
66
+ const { severity, chatSeverity } = parseSeverity(cells[1] ?? '');
67
+ rules.set(id, {
68
+ id,
69
+ category,
70
+ categoryTitle,
71
+ pattern: cells[0] ?? '',
72
+ severity,
73
+ chatSeverity,
74
+ prescription: cells[2] ?? '',
75
+ });
76
+ }
77
+ const selfCheckLine = lines.find((line) => line.includes('잔존 S1 패턴 0건')) ?? '';
78
+ const chatSplit = selfCheckLine.indexOf('대화·리뷰 말투면');
79
+ const docPart = chatSplit >= 0 ? selfCheckLine.slice(0, chatSplit) : selfCheckLine;
80
+ const chatPart = chatSplit >= 0 ? selfCheckLine.slice(chatSplit) : '';
81
+ return {
82
+ path,
83
+ rules,
84
+ selfCheckS1: expandIdRanges(docPart),
85
+ selfCheckChatS1: expandIdRanges(chatPart),
86
+ };
87
+ }
88
+ /** 해당 말투 기준으로 S1인 룰 ID */
89
+ export function s1Ids(book, register) {
90
+ return [...book.rules.values()]
91
+ .filter((rule) => (register === 'chat' ? rule.chatSeverity : rule.severity) === 'S1')
92
+ .map((rule) => rule.id)
93
+ .sort();
94
+ }
95
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/humanize/rules.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tienne/gestalt",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -20,7 +20,7 @@
20
20
  "scripts": {
21
21
  "dev": "tsx bin/gestalt.ts",
22
22
  "build": "tsc",
23
- "postbuild": "rm -rf dist/plugin && mkdir -p dist/plugin && cp -r plugin/agents plugin/role-agents plugin/review-agents plugin/personas plugin/skills dist/plugin/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js && pnpm run verify:plugin",
23
+ "postbuild": "rm -rf dist/plugin && mkdir -p dist/plugin && cp -r plugin/agents plugin/role-agents plugin/review-agents plugin/personas plugin/skills dist/plugin/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js && pnpm run verify:plugin && pnpm run verify:rules",
24
24
  "verify:plugin": "tsx scripts/verify-plugin-assets.ts",
25
25
  "prepublishOnly": "pnpm build",
26
26
  "test": "vitest run",
@@ -33,7 +33,8 @@
33
33
  "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
34
34
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
35
35
  "version:sync": "tsx scripts/sync-version.ts",
36
- "postversion": "pnpm run version:sync"
36
+ "postversion": "pnpm run version:sync",
37
+ "verify:rules": "tsx scripts/verify-rule-refs.ts"
37
38
  },
38
39
  "dependencies": {
39
40
  "@anthropic-ai/sdk": "^0.39.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gestalt",
3
- "version": "0.51.0",
3
+ "version": "0.52.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",
@@ -12,9 +12,22 @@
12
12
 
13
13
  ## 고칠 때
14
14
 
15
+ 룰 ID와 심각도는 `ai-tell-quick-rules.md`가 기준이다. 고친 뒤에는 반드시 돌린다.
16
+
17
+ ```bash
18
+ pnpm verify:rules
19
+ ```
20
+
21
+ 에이전트 문서 14곳이 룰 ID와 금지 어휘를 손으로 옮겨 적고 있어서, 룰북에서 ID를 지우거나
22
+ 심각도를 바꾸면 그 사본들이 조용히 어긋난다. 이 검사가 네 가지를 본다 — 없는 ID를 인용하는
23
+ 문서, 자체검증 목록에서 빠진 S1, 표와 목록의 심각도 불일치, 룰 문서 본문의 금지어 사용.
24
+ `pnpm test`와 `pnpm build`에도 걸려 있다.
25
+
15
26
  - **룰을 추가하면 그 문서가 스스로 그 룰을 지키는지 먼저 확인한다.** 룰 문서가 금지 어휘를
16
27
  본문에 쓰면 산출물로 샌다. 금지어를 넣었으면 같은 문서를 grep한다.
17
28
  - 어투 규칙은 **S1으로 올려야 실제로 강제된다.** S2는 모델이 우선순위를 알아서 정하면서 새어나간다.
29
+ - 심각도를 바꿀 때는 근거를 남긴다. A-2, I-1, C-8은 대조 코퍼스 측정으로 조정했고 그 근거가
30
+ 룰북 §실측 근거에 있다. 감으로 올리고 내리면 다음 사람이 되돌린다.
18
31
  - 경로를 참조하는 자리가 여러 곳이다. 파일을 옮기거나 이름을 바꾸면 `plugin/` 전체에서
19
32
  상대경로 참조를 다시 확인한다 (에이전트는 `../_shared/references/`, 에이전트의 `references/`
20
33
  하위 문서는 `../../_shared/references/`, 스킬은 `../../role-agents/_shared/references/`).
@@ -1,18 +1,24 @@
1
1
  # Quick Rules — Monolith Fast Path 전용 (v2.0)
2
2
 
3
- `humanize-monolith` 에이전트가 한 콜에서 탐지·윤문·자체검증을 끝내기 위해 사용하는 슬림 룰북. 본진 `ai-tell-taxonomy.md`(590줄)에서 S1·S2 핵심 패턴만 추려 처방과 함께 한 줄로 압축했다.
3
+ `humanize-monolith` 에이전트가 한 콜에서 탐지·윤문·자체검증을 끝내기 위해 사용하는 슬림 룰북. 기준 문서 `ai-tell-taxonomy.md`(590줄)에서 S1·S2 핵심 패턴만 추려 처방과 함께 한 줄로 압축했다.
4
4
 
5
- **원칙:** 정의 1줄 + 처방 1줄. 예문 생략. 본진 ID와 1:1 매칭.
5
+ **원칙:** 정의 1줄 + 처방 1줄. 예문 생략. 기준 문서 ID와 1:1 매칭.
6
6
 
7
7
  **Do-NOT (탐지·윤문 모두 제외):** 고유명사·제품명·모델명·기관명, 수치·날짜·단위, 큰따옴표 안 직접 인용, 법률 조문, 수학·화학·통계 표기, 영어 약어(LLM·GPU·MCP·API 등 업계 표준).
8
8
 
9
- **굳어진 음차 화이트리스트 (B-3 제외 그대로 둔다):** 컴포넌트·토큰·커밋·인터페이스·메서드·빌드·디플로이·캐시·렌더링·콜백·프레임워크·라이브러리·리팩터링·마이그레이션·아이콘·레이아웃·그리드·모달·토스트·타이포그래피·플레이스홀더·프로젝트·스프린트·이슈·리뷰·머지·브랜치·사이드 이펙트·보일러플레이트·트레이드오프·딥다이브·얼라인·온보딩 업계 정착어. 목록 밖의 굳어진 음차(소스 오브 트루스·룩 필·로우 행잉 프룻 등)만 B-3로 교정한다.
9
+ **약어 면제는 업계 표준에만 준다:** 풀어 썼을 굳어진 음차가 되는 약어는 면제 대상이 아니다. `SSOT`나 `SoT`를 그대로 두면 "소스 오브 트루스"를 약어로 우회한 것과 같다 B-3로 우리말로 푼다. 무엇을 가리키느냐에 따라 말이 달라지므로 대체어 표는 `style-guide.md` §single source of truth를 뭐라고 쓸까에 둔다. LLM·API처럼 풀어 쓸 일이 없는 표준 약어만 그대로 둔다.
10
+
11
+ **굳어진 음차 화이트리스트 (B-3 제외 — 그대로 둔다):** 컴포넌트·토큰·커밋·인터페이스·메서드·빌드·디플로이·캐시·렌더링·콜백·프레임워크·라이브러리·리팩터링·마이그레이션·아이콘·레이아웃·그리드·모달·토스트·타이포그래피·플레이스홀더·프로젝트·스프린트·이슈·리뷰·머지·브랜치·사이드 이펙트·보일러플레이트·트레이드오프·딥다이브·얼라인·온보딩·소스·롤백·파싱·레지스트리·불릿 등 업계 정착어. 이 목록 밖의 안 굳어진 음차(소스 오브 트루스·룩 앤 필·로우 행잉 프룻 등)만 B-3로 교정한다.
10
12
 
11
13
  **과윤문 가드:** 변경률 30% 초과 = 경고, 50% 초과 = 강제 중단·롤백.
12
14
 
13
15
  **삭제 처방은 삭제다 (중요):** 처방에 "삭제"가 있는 항목은 **더 나은 표현으로 바꾸지 않는다.** 지우고, 그 자리를 원문에 이미 있는 가장 구체적인 문장으로 대신한다. 모델은 D-2·D-3·D-4·D-6·C-10처럼 "삭제"라고 적힌 항목에서 리듬을 살리려고 새 마무리 문장이나 새 부제를 만들어 넣는 경향이 강한데, 그건 원문에 없던 수사를 추가하는 것이라 자체검증 6번에 걸린다. 지울 자리에 쓸 문장이 원문에 없으면 그냥 앞 문장에서 끝낸다.
14
16
 
15
- **말투 감도 (중요):** 같은 명사화·번역투라도 **대화나 리뷰 코멘트에서는 문서보다 훨씬 튄다.** 문서(칼럼·리포트) 기준 S2인 F-4·F-5·F-6·F-7·I-5·A-5 계열은 대화·리뷰 코멘트에서 **S1로 격상**해 교정한다. 사람은 대화에서 개념을 명사 덩어리로 뭉치지 않고 동사로 풀어 말하기 때문이다.
17
+ **말투 감도 (중요):** 같은 명사화·번역투라도 **대화나 리뷰 코멘트에서는 문서보다 훨씬 튄다.** 문서(칼럼·리포트) 기준 S2인 A-2, A-5, F-4, F-5, F-6, F-7, I-1, I-5 계열은 대화·리뷰 코멘트에서 **S1로 격상**해 교정한다. 사람은 대화에서 개념을 명사 덩어리로 뭉치지 않고 동사로 풀어 말하기 때문이다. 심각도 칸에 `S2 / **대화·리뷰 S1**`이라고 적힌 룰이 여기 해당한다.
18
+
19
+ **한자어를 피하는 게 목적이 아니다 (F-4·F-5 오적용 주의):** 겨냥하는 건 개념을 뭉친 **명사화**(-성/-적/-화)이지 한자어 동사가 아니다. "측정하다"를 "재다"로, "판단하다"를 "따지다"로 바꾸면 정확도만 잃는다. 그 자리의 정확한 말이 한자어면 한자어를 쓴다. 반대 방향 실수도 같다 — 한자어를 피하려고 비유 명사(축·증류)나 물리 동사(재다)로 도망가면 F-7에 걸린다. 셋 다 겪은 실례: `네 축을 따로 재고 판정한다` → `4가지 측면에서 각각 측정하고 판단한다`.
20
+
21
+ **근거가 붙은 룰 (→ 아래 §실측 근거):** A-2, I-1, C-8은 대조 코퍼스 측정으로 심각도를 조정했고, B-4는 팀이 실제로 쓰는 말이라 예시에서 뺐다. 원어민이 오히려 더 쓰는 표현이나 팀에서 이미 굳은 말을 지우면 사람 글을 AI 글로 만든다.
16
22
 
17
23
  ---
18
24
 
@@ -21,10 +27,10 @@
21
27
  | ID | 패턴 | 심각도 | 처방 |
22
28
  |---|---|---|---|
23
29
  | A-1 | "~에 대해(서)" | S1 | 목적격 조사로 직결("X에 대해 논의" → "X를 논의") |
24
- | A-2 | "~를 통해/통하여" 남발 | S1 | "~로", "~해서", "~함으로써"로 분산 |
30
+ | A-2 | "~를 통해/통하여" **한 글에 3회+ 반복** | S2 / **대화·리뷰 S1** | 반복분만 "~로", "~해서", "~함으로써"로 분산하고 1~2회는 남긴다. 문서 산문에서 원어민이 번역문보다 2배 더 쓰는 표현이라 전부 지우면 오히려 어색해진다 (최희경 2016). 대화·리뷰 코멘트에서는 1회부터 교정 |
25
31
  | A-3 | "~에 있어(서)" | S1 | "~에서", "~을 볼 때" |
26
32
  | A-4 | "~라는 점에서" 3회+ | S2 | "~서", "~라는 이유로" |
27
- | A-5 | "~와 관련하여/관련된" | S2 | "~에", "~의" |
33
+ | A-5 | "~와 관련하여/관련된" | S2 / **대화·리뷰 S1** | "~에", "~의" |
28
34
  | A-6 | "~에 기반하여/바탕으로" 남발 | S2 | "~로", "~을 보고" |
29
35
  | A-7 | "가지고 있다" / have·make·take·give + N 직역 | S1 | 형용사·동사 환원 또는 이중주어("회의를 가지다" → "회의를 했다", "강한 경쟁력을 가지고 있다" → "경쟁력이 강하다") |
30
36
  | A-8 | 이중 피동 "~되어진다" | S1 | 능동 또는 단일 피동 ("판단되어진다" → "판단된다") |
@@ -42,8 +48,8 @@
42
48
  |---|---|---|---|
43
49
  | B-1 | 한글 + 괄호 영어 매번 ("~(Sovereign AI)" 처럼) | S2 | 첫 등장만 병기, 이후 한글만 |
44
50
  | B-2 | 영어 어휘 직역 가능한데 그대로 | S2 | 한국어로 옮기되 업계 표준은 유지 |
45
- | B-3 | 안 굳어진 영어 구·단어 음차 표기 ("소스 오브 트루스") | S1 | 한글 의역 + 첫 등장만 원어 괄호 병기("진실의 원천(source of truth)"), 이후 한글만. 단 위 "굳어진 음차 화이트리스트"에 있는 정착어는 Do-NOT — of/and 등 기능어까지 통째 음차한 구(룩 앤 필·로우 행잉 프룻)가 최우선 대상 |
46
- | B-4 | 영어 개념을 어색하게 옮긴 조어("소비처" ← consumer, "생산처") | S2 | 정착한 우리말로("소비처" "사용처", 코드 맥락이면 "호출부"). 억지 신조어 대신 이미 쓰이는 |
51
+ | B-3 | 안 굳어진 영어 구·단어 음차 표기 ("소스 오브 트루스"), 그 음차를 약어로 우회한 표기(`SSOT`·`SoT`) | S1 | 한글 의역 + 첫 등장만 원어 괄호 병기("진실의 원천(source of truth)"), 이후 한글만. 단 위 "굳어진 음차 화이트리스트"에 있는 정착어는 Do-NOT — of/and 등 기능어까지 통째 음차한 구(룩 앤 필·로우 행잉 프룻)가 최우선 대상 |
52
+ | B-4 | 영어 개념을 어색하게 옮긴 조어("생산처" ← producer, "응답처") | S2 | 억지 신조어 대신 이미 쓰이는 말로. 코드 맥락이면 "호출부"·"사용처". **팀에서 이미 굳은 조어는 예외** "소비처"는 WDS 티켓에서 라이브러리를 가져다 쓰는 쪽을 가리키는 말로 정착했으므로 교정 대상이 아니다 (→ 아래 §실측 근거) |
47
53
 
48
54
  ## C. 구조적 AI 패턴
49
55
 
@@ -51,7 +57,7 @@
51
57
  |---|---|---|---|
52
58
  | C-5 | 이모지 남발 | S1 | 장르 칼럼·리포트면 전부 삭제 |
53
59
  | C-7 | "먼저·반면·결국" 3단 공식 | S2 | 접속사 1~2개로 줄이거나 본문에 녹여 제거 |
54
- | C-8 | "A인가·B인가" 대구 반복 | S2 | 한 번만 살리고 나머지는 평서문으로 |
60
+ | C-8 | "A인가, B인가" / "A가 아니라 B" 대구 반복 | S1 | 한 번만 살리고 나머지는 비대칭 평서문·직접 단언으로. 대조 코퍼스에서 인간 대비 9.2배(개인 글 기준 18배)로 나온 최강 신호이고 모델 계열을 안 가린다 |
55
61
  | C-9 | 숫자 괄호 인덱싱 "(1)·(2)·(3)" | S2 | 본문에 녹이거나 단순 줄바꿈 |
56
62
  | C-10 | 콜론 부제 헤딩 "X: Y" 반복 | S1 | 콜론 뒤를 버리고 앞부분만 남긴다. **더 좋은 부제로 바꾸지 않는다** — 부제를 갈아끼우면 패턴이 그대로 남는다. 앞부분만으로 뜻이 안 서면 평서 헤딩 한 문장으로 |
57
63
  | C-11 | 연결어미 뒤 쉼표 (-고/-며/-지만/-며서/-아서/-어서 직후 쉼표) | S1 | 쉼표 제거. 6+회=강한 신호. KatFish 4.84배 분리도 |
@@ -81,10 +87,10 @@
81
87
 
82
88
  | ID | 패턴 | 심각도 | 처방 |
83
89
  |---|---|---|---|
84
- | F-4 | 한자어 명사화 -성/-적/-화 + 영어 명사화 -tion/-ment/-ness/-ity 누적 (한 글 12회+) | S2 | 동사·형용사 어근으로 환원("the implementation of the policy" → "정책 시행" 또는 "정책을 시행하기") |
85
- | F-5 | "~적 N" 추상 체인 ("전략적 함의·실천적 기반") | S2 | 명사+명사 또는 풀어쓰기("전략 함의·실천의 기반") |
90
+ | F-4 | 한자어 명사화 -성/-적/-화 + 영어 명사화 -tion/-ment/-ness/-ity 누적 (한 글 12회+) | S2 / **대화·리뷰 S1** | 동사·형용사 어근으로 환원("the implementation of the policy" → "정책 시행" 또는 "정책을 시행하기") |
91
+ | F-5 | "~적 N" 추상 체인 ("전략적 함의", "실천적 기반") | S2 / **대화·리뷰 S1** | 명사+명사 또는 풀어쓰기("전략 함의", "실천의 기반") |
86
92
  | F-6 | 복합명사 압축 — 명사구를 조사·동사 없이 이어붙여 개념을 뭉침 ("시안 정합 버그픽스", "유지보수성 개선 작업", "권한 체크 로직") | S2 / **대화·리뷰 S1** | 동사·조사로 풀어 서술 ("디자인 시안과 다르게 렌더링되던 문제", "나중에 유지보수하기 편하게"). 사람은 압축 명사구 대신 무엇을 왜 했는지 풀어 말한다 |
87
- | F-7 | 기술·이공계 비유 명사를 일상 대화에 그대로 (증류·배선·결정화·평탄화·오케스트레이션·파이프라인화 등, 화학·전기·수학 어휘의 비유 차용) | S2 / **대화·리뷰 S1** | 일상 동사로 환원 (증류 → "추려내다/뽑아내다", 배선 → "연결하다/걸어두다", 결정화 → "정리하다", 평탄화 → "밋밋하게 만들다"). 문법은 멀쩡해 룰 매칭이 안 되지만 사람은 대화에서 안 쓴다. 도메인 정식 용어(코드의 "파이프라인" 자체 등)는 예외 |
93
+ | F-7 | 기술·이공계 비유 명사를 일상 대화에 그대로 (증류·배선·결정화·평탄화·오케스트레이션·파이프라인화·축 등, 화학·전기·수학 어휘의 비유 차용) | S2 / **대화·리뷰 S1** | 일상 동사·명사로 환원 (증류 → "추려내다/뽑아내다", 배선 → "연결하다/걸어두다", 결정화 → "정리하다", 평탄화 → "밋밋하게 만들다", **축 → "측면"**·"기준"). 문법은 멀쩡해 룰 매칭이 안 되지만 사람은 대화에서 안 쓴다. "네 축을 잰다"가 아니라 "4가지 측면에서 측정한다". **예외는 그 프로젝트가 개념에 붙인 이름일 때만이고, 그 개념을 다루는 자리에서만이다** — 게슈탈트의 "스펙 결정화"는 `similarity-crystallizer` 에이전트 이름이자 인터뷰→Spec 변환의 정의라서 두지만, 같은 말을 지라 티켓 작성처럼 무관한 자리에 끌어다 쓰면 F-7이다. 코드의 "파이프라인" 자체, 그래프의 x축도 같은 기준 |
88
94
 
89
95
  ## G. Hedging
90
96
 
@@ -106,7 +112,7 @@
106
112
 
107
113
  | ID | 패턴 | 심각도 | 처방 |
108
114
  |---|---|---|---|
109
- | I-1 | "~인 것이다/~한 것이다" 결말 | S1 | 평서형으로 |
115
+ | I-1 | "~인 것이다/~한 것이다" 결말 **연속 3회+** | S2 / **대화·리뷰 S1** | 반복분만 평서형으로. 문서 산문에서는 인간이 AI보다 2배 더 쓰는 표현이라 한두 번은 그대로 둔다. 대화·리뷰 코멘트에서는 1회부터 교정 |
110
116
  | I-2 | "X은 ~라는 점에 있다" | S2 | "X는 ~다" 직설로 |
111
117
  | I-3 | "~다는 뜻이다/~다는 의미다" 결말 | S2 | 본문에 풀어 쓰기 |
112
118
  | I-4 | 권고형 결말 "~해야 한다·~합니다" 반복 | S2 | 평서·단언으로 |
@@ -118,7 +124,7 @@
118
124
  |---|---|---|---|
119
125
  | J-1 | 헤딩 마크다운 ** 강조 남발 | S2 | 칼럼·리포트면 거의 다 제거 |
120
126
  | J-2 | 따옴표 강조 5회+ | S1 | 핵심 한두 개만 살리고 평어로 |
121
- | J-3 | 불릿 리스트 (장르가 칼럼·리포트일 때) | S2 | 문단 산문으로 통합 |
127
+ | J-3 | 불릿 목록 (장르가 칼럼·리포트일 때) | S2 | 문단 산문으로 통합 |
122
128
 
123
129
  ---
124
130
 
@@ -130,12 +136,57 @@
130
136
  2. **변경률**: 30% 이하인가 (50% 초과는 작업 중단)
131
137
  3. **장르 이탈 없음**: 칼럼이 에세이·문학으로 변하지 않았는가, 리포트가 블로그체로 떨어지지 않았는가
132
138
  4. **말투 보존**: 원문 격식체면 결과도 격식체. 평어체로 떨어뜨리지 않는다
133
- 5. **잔존 S1 패턴 0건**: D-1~D-7, A-7, A-8, A-16, B-3, C-5, C-10, C-11, C-12, H-1, I-1, J-2 핵심 S1이 남아있지 않은가 (대화·리뷰 말투면 F-6·F-7·I-5·F-4·F-5·A-5도 S1로 포함)
139
+ 5. **잔존 S1 패턴 0건**: A-1, A-3, A-7, A-8, A-16, B-3, C-5, C-8, C-10, C-11, C-12, D-1~D-6, H-1, H-3, J-2 남아있지 않은가 (대화·리뷰 말투면 A-2, A-5, F-4, F-5, F-6, F-7, I-1, I-5도 S1로 포함)
134
140
  6. **인공 표현 자제**: 원문에 없던 비유·수사·문학적 표현을 윤문 과정에서 임의로 추가하지 않았는가
135
141
  7. **삭제 처방 준수**: D-2·D-3·D-4·D-6·C-10을 재작성으로 처리하지 않았는가. 마무리 문장·부제·수식어를 지우는 대신 더 그럴듯한 것으로 갈아끼운 자리가 없는가
136
142
 
137
143
  위반 시: edit 롤백 → 다시 윤문 → 재점검. 자체 루프 최대 1회. 이상 미해결이면 결과를 그대로 출력하되 `summary.md`에 "자가검증 미통과 항목 N건" 표기.
138
144
 
145
+ ## 코드 검사 (자가 채점보다 위)
146
+
147
+ 아래 등급은 모델이 스스로 매기는 참고값이다. 실제 판단은 코드가 한다.
148
+
149
+ ```bash
150
+ gestalt humanize-check --before before.md --after after.md --register chat
151
+ ```
152
+
153
+ 변경률, S1 잔존, 보호 토큰 생존, 구조 보존 4가지 측면에서 각각 측정하고 exit code로 답한다
154
+ (0 통과 / 1 경고 / 2 채택 금지 / 3 판정 불가). 변경률 하나만 보면 구조 편집이 안 보인다 —
155
+ 변경률 2.8%인데 문장 3할이 갈려나간 사례가 있었다. **이 출력대로 판정하고, 자기가 낸 값으로
156
+ 덮어쓰지 않는다.** 측면별 임계와 탐지 대상 룰은 `src/humanize/`에 있다.
157
+
158
+ ## 실측 근거
159
+
160
+ 감으로 올리고 내린 심각도는 다음 사람이 되돌린다. 바꿀 때는 근거를 남긴다.
161
+
162
+ ### 대조 코퍼스 (A-2, I-1, C-8)
163
+
164
+ AI 생성 산문 60편(모델 3종)과 2022년 이전 발행이 확인된 한국어 산문 60편을 로그우도비 G²로
165
+ 비교한 결과다.
166
+
167
+ | 룰 | 측정 | 조정 |
168
+ |---|---|---|
169
+ | A-2 "~를 통해" | 비번역 한국어 84.4 vs 번역문 42.1 — 원어민이 2배 더 쓴다 (최희경 2016). AI 코퍼스에는 거의 안 나옴 | S1 → S2, 대화·리뷰만 S1 |
170
+ | I-1 "~한 것이다" | AI 20.4 vs 인간 43.0 (G²=6.2) — 인간이 2배 더 씀. 단락 말 위치·연속 반복도 AI가 더 적음 | S1 → S2(연속 3회+), 대화·리뷰만 S1 |
171
+ | C-8 부정 대구 | AI 5.8 vs 인간 0.6 (9.2배, G²=41.7) — 개인 글 대비로는 18배. 모델 3종 공통 | S2 → S1 |
172
+
173
+ 읽을 때 두 가지를 같이 봐야 한다. 인간 코퍼스가 **편집된 출판 산문**이라 "인간 일반"이 아니라
174
+ "잘 쓴 글"과의 대조다. 그리고 이 측정은 **문서 산문**을 잰 것이라 대화·리뷰 코멘트에는 그대로
175
+ 적용되지 않는다 — A-2와 I-1이 대화에서 S1로 남는 이유가 이것이다.
176
+ 출처: [`epoko77-ai/im-not-ai`](https://github.com/epoko77-ai/im-not-ai)의 `empirical-validation.md`.
177
+
178
+ ### 팀 실제 사용 (B-4)
179
+
180
+ 룰이 팀에서 이미 굳은 말을 금지하고 있으면 룰이 틀린 것이다. 산출물을 어색하게 만든다.
181
+
182
+ | 룰 | 확인한 것 | 조정 |
183
+ |---|---|---|
184
+ | B-4 "소비처" | WDS 티켓 894, 919, 921에서 섹션 헤딩과 본문으로 일관되게 쓴다. 작성자 본인 어휘다 | 교정 예시에서 제외 |
185
+
186
+ **교정어를 정하기 전에 팀이 실제로 뭐라고 쓰는지 먼저 본다.** 지라·PR·슬랙을 검색하면 답이 있다.
187
+ "인수조건"도 같은 방법으로 걷어냈다 — WDS 전체에 5건뿐이고 그중 넷이 2025년 9월 한 묶음,
188
+ 나머지 하나는 이 에이전트가 직접 넣은 것이었다. 팀이 쓰는 말이 아니라 템플릿이 심은 말이었다.
189
+
139
190
  ## 등급 기준 (자가 채점)
140
191
 
141
192
  - **A**: S1 잔존 0, S2 잔존 2 이하, 변경률 10~25%, 자체검증 7항 모두 통과
@@ -50,6 +50,46 @@
50
50
  | 한국어 + 영어 병기 | 첫 등장 전문 용어 | 이벤트 소싱(Event Sourcing) |
51
51
  | 한국어만 | 자연스러운 표현 존재 | 버전 관리 (버저닝 ❌), 배포 (디플로이먼트 ❌) |
52
52
 
53
+ ### single source of truth를 뭐라고 쓸까
54
+
55
+ `SSOT`, `SoT`는 쓰지 않는다. "소스 오브 트루스"를 약어로 우회한 것이라 `ai-tell-quick-rules.md` B-3에 걸린다.
56
+ 한 단어로 정해두면 안 맞는 자리에 억지로 들어가니, **무엇을 가리키는지 보고 고른다.**
57
+
58
+ | 가리키는 것 | 쓰는 말 |
59
+ |---|---|
60
+ | 규칙·정의가 적힌 문서 | 기준 문서 |
61
+ | 비교 대상이 되는 수치 | 기준값 (목표 대비, 전기 대비 등 — impact-writer 용법) |
62
+ | 여러 사본 중 원본 하나 | 정본 |
63
+ | 조회·대조용 참조 자료 | 참조 기준 |
64
+ | 데이터가 처음 만들어지는 곳 | 원천 데이터 |
65
+ | 값을 담고 있는 데이터 자체 | 기준 데이터 |
66
+ | 회계·정산·과금 기록 | 기록 원장 |
67
+ | 조직이 인정한 발표처 | 공식 출처 |
68
+ | 기록을 관장하는 시스템 | 공식 기록 시스템 |
69
+ | 개념 자체를 풀어 말할 때 | 단일 기준점 |
70
+
71
+ **첫 번째 선택지는 단어를 안 붙이는 것이다.** 문맥이 이미 분명하면 파일 이름이나 대상만 쓴다.
72
+ "룰북과 에이전트 문서가 갈라졌는지 본다"가 "룰북 기준 문서와…"보다 낫다.
73
+ 명사를 고르기 전에 동사로 풀 수 있는지 먼저 본다 — "A가 기준이다", "A를 기준으로 삼는다".
74
+
75
+ ### 음차를 옮길 때 — 한 단어로 정하지 않는다
76
+
77
+ 같은 영어 단어라도 가리키는 게 다르면 다른 말이 된다. 대체어 하나를 정해놓고 전부 치환하면
78
+ 안 맞는 자리가 반드시 생긴다.
79
+
80
+ | 음차 | 가리키는 것 | 쓰는 말 |
81
+ |---|---|---|
82
+ | gate | 사람이 확인하고 넘어가는 지점 | 승인 단계 |
83
+ | gate | 코드가 통과·차단을 정하는 검사 | 검사 |
84
+ | layer | 쌓여 올라가는 구조, 중첩 깊이 | 계층 |
85
+ | layer | 동시에 처리되는 한 덩어리 | 묶음 |
86
+ | layer | 순서대로 밟는 구간 | 단계 |
87
+ | layer | 책임이 갈리는 구분 | 역할 |
88
+
89
+ **일괄 치환은 조사를 깨뜨린다.** 받침 유무가 바뀌면 뒤따르는 조사도 바뀐다.
90
+ `레이어라면` → `계층이라면`, `레이어(…)는` → `계층(…)은`. 실제로 이 자리에서 두 번 깨졌다.
91
+ 찾아 바꾸기로 밀지 말고 문장을 하나씩 읽는다.
92
+
53
93
  ---
54
94
 
55
95
  ## English Documentation Style
@@ -99,7 +99,7 @@ key는 넣었는데 index 대신 id를 썼어요. 목록 순서가 바뀌는 케
99
99
 
100
100
  ### Humanize 처리
101
101
 
102
- 초안을 쓴 뒤 AI-tell을 점검한다. SoT는 [`../_shared/references/ai-tell-quick-rules.md`](../_shared/references/ai-tell-quick-rules.md)이고, 답글엔 특히 아래가 자주 샌다.
102
+ 초안을 쓴 뒤 AI-tell을 점검한다. 기준은 [`../_shared/references/ai-tell-quick-rules.md`](../_shared/references/ai-tell-quick-rules.md)이고, 답글엔 특히 아래가 자주 샌다.
103
103
 
104
104
  | 패턴 | 예시 | 교정 |
105
105
  |------|------|------|
@@ -82,7 +82,7 @@ voice 모델을 따른다. 초안 작성 후 반드시 [`../_shared/references/a
82
82
 
83
83
  ### Humanize 처리 — AI-tell 제거 + 음차 교정
84
84
 
85
- 코멘트 초안을 작성한 뒤 AI-tell을 점검·교정한다. 교정 규칙의 SoT는
85
+ 코멘트 초안을 작성한 뒤 AI-tell을 점검·교정한다. 교정 규칙의 기준은
86
86
  [`../_shared/references/ai-tell-quick-rules.md`](../_shared/references/ai-tell-quick-rules.md)이며,
87
87
  인라인 코멘트엔 특히 다음을 적용한다.
88
88
 
@@ -187,7 +187,7 @@ $ARGUMENTS
187
187
 
188
188
  1. **목적 명확화**: 이 하네스가 어떤 문제를 해결하는가? 입력과 출력은 무엇인가?
189
189
  2. **철칙 도출**: 절대 위반하면 안 되는 조건이 무엇인가? (의미 보존, 품질 기준 등)
190
- 3. **에이전트 분해**: 전체 작업을 단일 책임 단위로 분해. 탐지/실행/검증 레이어 구분.
190
+ 3. **에이전트 분해**: 전체 작업을 단일 책임 단위로 분해. 탐지/실행/검증 역할 구분.
191
191
  4. **Fast/Full 선택**: 입력 크기, 검증 독립성, 반응 속도 요구에 따라 결정.
192
192
  5. **파이프라인 조립**: 단계 순서, 병렬 처리 가능 구간, 재시도 루프, 에스컬레이션 조건.
193
193
  6. **파일 작성**: CLAUDE.md → AGENT.md들 → SKILL.md → Command 파일 순서로 작성.