hanlint 0.0.7 → 0.0.9

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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -9
  3. package/data/adjectiveStems.txt +118 -0
  4. package/data/baselineAnchors.txt +3 -0
  5. package/data/blindEvaluation.schema.json +26 -0
  6. package/data/bridgeOpeners.txt +10 -0
  7. package/data/candidateActionNouns.txt +39 -0
  8. package/data/candidateSplitEndings.txt +13 -0
  9. package/data/cliches.json +1 -1
  10. package/data/confusable.json +2 -2
  11. package/data/deixis.txt +10 -3
  12. package/data/draftHistory.txt +10 -0
  13. package/data/easyWords.json +0 -42
  14. package/data/enoughMarkers.txt +6 -0
  15. package/data/entailmentPredictions.schema.json +52 -0
  16. package/data/euiNouns.txt +3 -4
  17. package/data/evidenceEntailmentBenchmark.schema.json +126 -0
  18. package/data/exemplars.json +323 -0
  19. package/data/holeKinds.json +2 -14
  20. package/data/iVerbStems.txt +26 -0
  21. package/data/inNouns.txt +147 -0
  22. package/data/irregularStems.txt +64 -0
  23. package/data/nonNouns.txt +153 -0
  24. package/data/panelAssignmentReview.schema.json +117 -0
  25. package/data/panelJudgePredictions.schema.json +78 -0
  26. package/data/panelReviewBatch.schema.json +79 -0
  27. package/data/panelTrialSet.schema.json +44 -0
  28. package/data/patterns.json +103 -0
  29. package/data/platformApis.txt +3 -1
  30. package/data/profiles.json +1 -0
  31. package/data/readerCalls.txt +12 -7
  32. package/data/redundantPair.json +1 -1
  33. package/data/rieulStems.txt +30 -0
  34. package/data/ruleCategories.json +52 -0
  35. package/data/ruleDocs.json +27 -19
  36. package/data/ruleMechanisms.json +52 -0
  37. package/data/spacing.json +0 -12
  38. package/data/spelling.json +7 -25
  39. package/data/translationese.json +10 -0
  40. package/data/verbTails.txt +17 -0
  41. package/data/version.json +1 -1
  42. package/data/writingBrief.schema.json +64 -0
  43. package/data/writingBriefV2.schema.json +116 -0
  44. package/data/writingTrial.schema.json +36 -0
  45. package/koglType1.LICENSE.md +25 -0
  46. package/package.json +18 -6
  47. package/src/analysis/grammar/ending.js +336 -0
  48. package/src/analysis/grammar/hangul.js +94 -0
  49. package/src/analysis/grammar/index.js +5 -0
  50. package/src/analysis/grammar/josa.js +73 -0
  51. package/src/analysis/grammar/register.js +115 -0
  52. package/src/analysis/grammar/voice.js +43 -0
  53. package/src/analysis/index.js +4 -31
  54. package/src/analysis/josa.js +2 -0
  55. package/src/analysis/{surface/splitSentences.js → splitSentences.js} +1 -1
  56. package/src/analysis/{surface/tokenize.js → tokenize.js} +70 -13
  57. package/src/baseline/store.js +114 -0
  58. package/src/cli/main.js +508 -61
  59. package/src/cli/walk.js +30 -0
  60. package/src/cli/welcome.js +52 -0
  61. package/src/config/settings.js +111 -12
  62. package/src/data/exemplars.js +177 -0
  63. package/src/data/load.js +10 -0
  64. package/src/data/operations.js +278 -0
  65. package/src/data/patches.js +125 -0
  66. package/src/data/patterns.js +48 -0
  67. package/src/data/profiles.js +102 -0
  68. package/src/document/model.js +2 -0
  69. package/src/document/parseMarkdown.js +84 -11
  70. package/src/edit/applyFixes.js +0 -0
  71. package/src/fingerprint/build.js +60 -39
  72. package/src/{rules/shared → fingerprint}/codeBlocks.js +11 -11
  73. package/src/fingerprint/codeMarkers.js +73 -0
  74. package/src/fingerprint/markers.js +9 -0
  75. package/src/fingerprint/readerState.js +126 -0
  76. package/src/fingerprint/sourceSentence.js +37 -0
  77. package/src/fingerprint/topics.js +1 -1
  78. package/src/index.js +2 -16
  79. package/src/report/compactReport.js +6 -1
  80. package/src/report/fingerprintJson.js +8 -3
  81. package/src/report/jsonReport.js +50 -3
  82. package/src/report/operationMatch.js +31 -0
  83. package/src/report/patchMatch.js +44 -0
  84. package/src/report/registerMatch.js +40 -0
  85. package/src/report/textReport.js +41 -5
  86. package/src/rules/code/duplicateBlock.js +4 -3
  87. package/src/rules/code/firstResultDistance.js +1 -0
  88. package/src/rules/code/inputFileSource.js +23 -68
  89. package/src/rules/code/installImport.js +6 -5
  90. package/src/rules/code/platformApi.js +7 -6
  91. package/src/rules/document/countMismatch.js +22 -6
  92. package/src/rules/document/enoughOnce.js +25 -0
  93. package/src/rules/document/fieldEcho.js +38 -0
  94. package/src/rules/document/keywordHeading.js +32 -0
  95. package/src/rules/document/keywordMissing.js +1 -0
  96. package/src/rules/document/noQuestion.js +5 -1
  97. package/src/rules/document/promiseRecall.js +4 -2
  98. package/src/rules/document/tableOddCell.js +61 -0
  99. package/src/rules/finding.js +24 -2
  100. package/src/rules/orthography/confusable.js +1 -0
  101. package/src/rules/orthography/spacing.js +1 -0
  102. package/src/rules/orthography/spelling.js +1 -0
  103. package/src/rules/paragraph/factListParagraph.js +1 -0
  104. package/src/rules/paragraph/paraFragment.js +21 -11
  105. package/src/rules/registry.js +70 -9
  106. package/src/rules/sentence/cliche.js +1 -0
  107. package/src/rules/sentence/connectorRepeat.js +8 -7
  108. package/src/rules/sentence/danglingDeixis.js +23 -3
  109. package/src/rules/sentence/dash.js +2 -1
  110. package/src/rules/sentence/deixis.js +7 -3
  111. package/src/rules/sentence/doubleNegative.js +4 -1
  112. package/src/rules/sentence/doublePassive.js +38 -1
  113. package/src/rules/sentence/draftHistory.js +24 -0
  114. package/src/rules/sentence/endingRepeat.js +6 -2
  115. package/src/rules/sentence/euiChain.js +3 -2
  116. package/src/rules/sentence/fillerOpener.js +1 -0
  117. package/src/rules/sentence/hardWord.js +1 -0
  118. package/src/rules/sentence/imperativePeriod.js +2 -1
  119. package/src/rules/sentence/japaneseLoan.js +1 -0
  120. package/src/rules/sentence/longSentence.js +3 -1
  121. package/src/rules/sentence/negationRedefine.js +12 -2
  122. package/src/rules/sentence/nounPile.js +1 -0
  123. package/src/rules/sentence/numberOrphan.js +45 -0
  124. package/src/rules/sentence/outsideProfile.js +68 -0
  125. package/src/rules/sentence/redundantPair.js +1 -0
  126. package/src/rules/sentence/translationese.js +1 -0
  127. package/src/rules/shared/candidates.js +129 -0
  128. package/src/rules/shared/dictionaryRule.js +12 -2
  129. package/src/rules/shared/localAntecedent.js +12 -0
  130. package/src/rules/shared/repeat.js +48 -0
  131. package/src/rules/structure/blockUnread.js +33 -0
  132. package/src/rules/structure/bridgeRepeat.js +40 -0
  133. package/src/rules/structure/emojiBullet.js +1 -0
  134. package/src/rules/structure/headingSentence.js +9 -4
  135. package/src/rules/structure/headingSkip.js +1 -0
  136. package/src/rules/structure/headingUniform.js +12 -20
  137. package/src/rules/structure/introImage.js +19 -0
  138. package/src/rules/structure/introLong.js +4 -1
  139. package/src/rules/structure/loneSubheading.js +42 -0
  140. package/src/rules/structure/moreLater.js +48 -0
  141. package/src/rules/structure/sectionNoProse.js +1 -0
  142. package/src/text.js +19 -0
  143. package/data/coverageTypes.txt +0 -7
  144. package/src/rules/document/readerAbsent.js +0 -11
  145. package/src/rules/paragraph/topicBreak.js +0 -25
  146. package/src/rules/sentence/ellipsis.js +0 -18
  147. package/src/rules/shared/runs.js +0 -22
  148. package/src/rules/structure/sectionResult.js +0 -37
@@ -0,0 +1,153 @@
1
+ # 명사 연속을 끊는 어절. 조사도 어미도 안 붙어서 표층 판정이 명사로 오인하지만 명사 쌓기의 재료가 아닌 것들.
2
+ # 의존명사, 관형사, 부사, 그리고 굳은 꼴이다. nounPile 만 이 목록을 읽는다.
3
+ # 실측: 005-python-history 에서 nounPile 세 건이 전부 이 부류 때문이었다 (토론 4번).
4
+ # `아니라 1970년대 BBC 코미디 Monty` (아니라), `도는지 직접 눌러 볼 수` (직접, 수),
5
+ # `최근 몇 년 동안 파이썬` (몇, 년, 동안).
6
+ # 이 목록은 연속을 끊기만 하므로 잘못 넣으면 놓치는 쪽으로 틀린다. 잡는 쪽으로는 틀리지 않는다.
7
+
8
+ # 의존명사
9
+ 수
10
+ 것
11
+ 때
12
+ 곳
13
+ 중
14
+ 뿐
15
+ 등
16
+ 바
17
+ 데
18
+ 편
19
+ 셈
20
+ 터
21
+ 채
22
+ 김
23
+ 분
24
+ 쪽
25
+ 줄
26
+ 지경
27
+
28
+ # 시간과 단위의 의존명사
29
+ 년
30
+ 월
31
+ 일
32
+ 시
33
+ 초
34
+ 동안
35
+ 무렵
36
+ 즈음
37
+ 가량
38
+ 남짓
39
+
40
+ # 관형사
41
+ 몇
42
+ 여러
43
+ 각
44
+ 어느
45
+ 무슨
46
+ 온갖
47
+ 아무
48
+ 딴
49
+
50
+ # 부사
51
+ 직접
52
+ 크게
53
+ 다시
54
+ 매우
55
+ 아주
56
+ 잘
57
+ 더
58
+ 덜
59
+ 함께
60
+ 각각
61
+ 먼저
62
+ 바로
63
+ 특히
64
+ 이미
65
+ 아직
66
+ 늘
67
+ 항상
68
+ 자주
69
+ 가끔
70
+ 서로
71
+ 모두
72
+ 전부
73
+ 거의
74
+ 조금
75
+ 훨씬
76
+ 그냥
77
+ 오히려
78
+ 결국
79
+ 실제로
80
+ 곧
81
+ 잠깐
82
+ 따로
83
+ 그대로
84
+ 반드시
85
+ 너
86
+ 왜
87
+ 얼마
88
+ 아니
89
+ 문득
90
+ 또
91
+ 어찌
92
+
93
+ # 접속부사와 계사 꼴. 실측: 형태소 분석기와 말뭉치 390편을 견주자 표층만 잡은 nounPile 129건의 대부분이
94
+ # `A 및 B` 의 및 과 `사용 중인 X` 의 중인 을 명사로 센 것이었다 (2026-08-29).
95
+ 및
96
+ 중인
97
+ # 부사와 관형사 둘째 묶음. 후, 이후, 직후 같은 시간 의존명사는 넣지 않는다. 원사례 `가상환경 생성 후 패키지 설치 확인 절차` 가
98
+ # 후 를 건너 하나의 나열이다. 실측: 형태소 분석기와 말뭉치 390편을 견주자 표층만 명사 다섯으로 본 63문장에서
99
+ # `못 들어`, `가장 추운`, `지난 30일`, `다른 방법`, `오늘 새벽`, `총 약 1억`, `브랜치 간`, `7분 경` 이 명사로 세어졌다 (2026-08-29).
100
+ 못
101
+ 안
102
+ 좀
103
+ 너무
104
+ 몹시
105
+ 꽤
106
+ 역시
107
+ 가장
108
+ 총
109
+ 약
110
+ 현
111
+ 첫
112
+ 한
113
+ 올
114
+ 지난
115
+ 새
116
+ 옛
117
+ 다른
118
+ 어떤
119
+ 이런
120
+ 그런
121
+ 저런
122
+ 오늘
123
+ 어제
124
+ 내일
125
+ 지금
126
+ 현재
127
+ 당시
128
+ 내
129
+ 간
130
+ 경
131
+ 별로
132
+ 아마
133
+ 물론
134
+ 이
135
+ 그
136
+ 저
137
+ 우리
138
+ 아무리
139
+ 딱
140
+ 점점
141
+ 만일
142
+ 처음
143
+ 소위
144
+ 과거
145
+ # 굳은 꼴
146
+ 아니라
147
+ 대신
148
+ 위해
149
+ 통해
150
+ 비해
151
+ 관해
152
+ 대해
153
+ 의해
@@ -0,0 +1,117 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://hanlint.dev/schemas/panelAssignmentReview.schema.json",
4
+ "title": "hanlint writing arena assigned human review",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["version", "kind", "assignmentSha256", "evaluator", "reviews"],
8
+ "properties": {
9
+ "version": { "const": 1 },
10
+ "kind": { "const": "hanlint.panelAssignmentReview" },
11
+ "assignmentSha256": { "$ref": "#/$defs/sha256" },
12
+ "evaluator": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "required": ["id", "group", "protocolRevision"],
16
+ "properties": {
17
+ "id": {
18
+ "type": "string",
19
+ "minLength": 1,
20
+ "pattern": "^\\S(?:.*\\S)?$",
21
+ "not": { "const": "<required>" }
22
+ },
23
+ "group": {
24
+ "enum": ["targetReader", "professionalEditor", "koreanExpert", "generalReader"]
25
+ },
26
+ "protocolRevision": { "const": "hanlint.writingArena.panel.v1" }
27
+ }
28
+ },
29
+ "reviews": {
30
+ "type": "array",
31
+ "minItems": 1,
32
+ "items": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["caseId", "assignmentCaseSha256", "contentChecks", "preferences", "reasons"],
36
+ "properties": {
37
+ "caseId": { "type": "string", "minLength": 1 },
38
+ "assignmentCaseSha256": { "$ref": "#/$defs/sha256" },
39
+ "contentChecks": { "$ref": "#/$defs/contentChecks" },
40
+ "preferences": { "$ref": "#/$defs/preferences" },
41
+ "reasons": { "$ref": "#/$defs/reasons" }
42
+ },
43
+ "allOf": [
44
+ {
45
+ "if": {
46
+ "not": {
47
+ "properties": {
48
+ "contentChecks": {
49
+ "properties": {
50
+ "left": { "const": "pass" },
51
+ "right": { "const": "pass" }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ },
57
+ "then": {
58
+ "properties": {
59
+ "preferences": {
60
+ "properties": {
61
+ "naturalness": { "const": "cannotJudge" },
62
+ "clarity": { "const": "cannotJudge" },
63
+ "taskUtility": { "const": "cannotJudge" },
64
+ "voice": { "const": "cannotJudge" }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ]
71
+ }
72
+ }
73
+ },
74
+ "$defs": {
75
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
76
+ "contentChoice": { "enum": ["pass", "fail", "cannotJudge"] },
77
+ "preferenceChoice": { "enum": ["left", "right", "tie", "cannotJudge"] },
78
+ "contentChecks": {
79
+ "type": "object",
80
+ "additionalProperties": false,
81
+ "required": ["left", "right"],
82
+ "properties": {
83
+ "left": { "$ref": "#/$defs/contentChoice" },
84
+ "right": { "$ref": "#/$defs/contentChoice" }
85
+ }
86
+ },
87
+ "preferences": {
88
+ "type": "object",
89
+ "additionalProperties": false,
90
+ "required": ["naturalness", "clarity", "taskUtility", "voice"],
91
+ "properties": {
92
+ "naturalness": { "$ref": "#/$defs/preferenceChoice" },
93
+ "clarity": { "$ref": "#/$defs/preferenceChoice" },
94
+ "taskUtility": { "$ref": "#/$defs/preferenceChoice" },
95
+ "voice": { "$ref": "#/$defs/preferenceChoice" }
96
+ }
97
+ },
98
+ "reason": {
99
+ "type": "string",
100
+ "minLength": 1,
101
+ "pattern": "\\S",
102
+ "not": { "const": "<required>" }
103
+ },
104
+ "reasons": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": ["content", "naturalness", "clarity", "taskUtility", "voice"],
108
+ "properties": {
109
+ "content": { "$ref": "#/$defs/reason" },
110
+ "naturalness": { "$ref": "#/$defs/reason" },
111
+ "clarity": { "$ref": "#/$defs/reason" },
112
+ "taskUtility": { "$ref": "#/$defs/reason" },
113
+ "voice": { "$ref": "#/$defs/reason" }
114
+ }
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://hanlint.dev/schemas/panelJudgePredictions.schema.json",
4
+ "title": "hanlint writing arena automatic judge predictions",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "version",
9
+ "kind",
10
+ "judgeCasesSha256",
11
+ "evaluatorId",
12
+ "evaluatorRevision",
13
+ "promptSha256",
14
+ "predictions"
15
+ ],
16
+ "properties": {
17
+ "version": { "const": 1 },
18
+ "kind": { "const": "hanlint.panelJudgePredictions" },
19
+ "judgeCasesSha256": { "$ref": "#/$defs/sha256" },
20
+ "evaluatorId": { "type": "string", "minLength": 1 },
21
+ "evaluatorRevision": { "$ref": "#/$defs/sha256" },
22
+ "promptSha256": { "$ref": "#/$defs/sha256" },
23
+ "predictions": {
24
+ "type": "array",
25
+ "items": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["presentationId", "presentationSha256", "contentChecks", "preferences"],
29
+ "properties": {
30
+ "presentationId": { "type": "string", "minLength": 1 },
31
+ "presentationSha256": { "$ref": "#/$defs/sha256" },
32
+ "contentChecks": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["left", "right"],
36
+ "properties": {
37
+ "left": { "$ref": "#/$defs/contentDecision" },
38
+ "right": { "$ref": "#/$defs/contentDecision" }
39
+ }
40
+ },
41
+ "preferences": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["naturalness", "clarity", "taskUtility", "voice"],
45
+ "properties": {
46
+ "naturalness": { "$ref": "#/$defs/preferenceDecision" },
47
+ "clarity": { "$ref": "#/$defs/preferenceDecision" },
48
+ "taskUtility": { "$ref": "#/$defs/preferenceDecision" },
49
+ "voice": { "$ref": "#/$defs/preferenceDecision" }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "$defs": {
57
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
58
+ "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
59
+ "contentDecision": {
60
+ "type": "object",
61
+ "additionalProperties": false,
62
+ "required": ["choice", "confidence"],
63
+ "properties": {
64
+ "choice": { "enum": ["pass", "fail", "abstain"] },
65
+ "confidence": { "$ref": "#/$defs/confidence" }
66
+ }
67
+ },
68
+ "preferenceDecision": {
69
+ "type": "object",
70
+ "additionalProperties": false,
71
+ "required": ["choice", "confidence"],
72
+ "properties": {
73
+ "choice": { "enum": ["left", "right", "tie", "abstain"] },
74
+ "confidence": { "$ref": "#/$defs/confidence" }
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://hanlint.dev/schemas/panelReviewBatch.schema.json",
4
+ "title": "hanlint writing arena human review batch",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["version", "kind", "suiteSha256", "rubricSha256", "evaluator", "reviews"],
8
+ "properties": {
9
+ "version": { "const": 1 },
10
+ "kind": { "const": "hanlint.panelReviewBatch" },
11
+ "suiteSha256": { "$ref": "#/$defs/sha256" },
12
+ "rubricSha256": { "$ref": "#/$defs/sha256" },
13
+ "evaluator": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "required": ["id", "group", "protocolRevision"],
17
+ "properties": {
18
+ "id": { "type": "string", "minLength": 1 },
19
+ "group": {
20
+ "enum": ["targetReader", "professionalEditor", "koreanExpert", "generalReader"]
21
+ },
22
+ "protocolRevision": { "const": "hanlint.writingArena.panel.v1" }
23
+ }
24
+ },
25
+ "reviews": {
26
+ "type": "array",
27
+ "minItems": 1,
28
+ "items": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["caseId", "caseSha256", "contentChecks", "preferences", "reasons"],
32
+ "properties": {
33
+ "caseId": { "type": "string", "minLength": 1 },
34
+ "caseSha256": { "$ref": "#/$defs/sha256" },
35
+ "contentChecks": { "$ref": "#/$defs/contentChecks" },
36
+ "preferences": { "$ref": "#/$defs/preferences" },
37
+ "reasons": { "$ref": "#/$defs/reasons" }
38
+ }
39
+ }
40
+ }
41
+ },
42
+ "$defs": {
43
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
44
+ "contentChoice": { "enum": ["pass", "fail", "cannotJudge"] },
45
+ "preferenceChoice": { "enum": ["left", "right", "tie", "cannotJudge"] },
46
+ "contentChecks": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": ["left", "right"],
50
+ "properties": {
51
+ "left": { "$ref": "#/$defs/contentChoice" },
52
+ "right": { "$ref": "#/$defs/contentChoice" }
53
+ }
54
+ },
55
+ "preferences": {
56
+ "type": "object",
57
+ "additionalProperties": false,
58
+ "required": ["naturalness", "clarity", "taskUtility", "voice"],
59
+ "properties": {
60
+ "naturalness": { "$ref": "#/$defs/preferenceChoice" },
61
+ "clarity": { "$ref": "#/$defs/preferenceChoice" },
62
+ "taskUtility": { "$ref": "#/$defs/preferenceChoice" },
63
+ "voice": { "$ref": "#/$defs/preferenceChoice" }
64
+ }
65
+ },
66
+ "reasons": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["content", "naturalness", "clarity", "taskUtility", "voice"],
70
+ "properties": {
71
+ "content": { "type": "string", "minLength": 1 },
72
+ "naturalness": { "type": "string", "minLength": 1 },
73
+ "clarity": { "type": "string", "minLength": 1 },
74
+ "taskUtility": { "type": "string", "minLength": 1 },
75
+ "voice": { "type": "string", "minLength": 1 }
76
+ }
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://hanlint.dev/schemas/panelTrialSet.schema.json",
4
+ "title": "hanlint writing arena panel trial set",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "version",
9
+ "kind",
10
+ "studyId",
11
+ "candidateStrategyId",
12
+ "provenance",
13
+ "trials",
14
+ "claimBoundary",
15
+ "trialSetSha256"
16
+ ],
17
+ "properties": {
18
+ "version": { "const": 1 },
19
+ "kind": { "const": "hanlint.panelTrialSet" },
20
+ "studyId": { "type": "string", "minLength": 1 },
21
+ "candidateStrategyId": { "type": "string", "minLength": 1 },
22
+ "provenance": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "required": ["origin", "license", "containsExternalReferenceText", "qualityLabels"],
26
+ "properties": {
27
+ "origin": { "type": "string", "minLength": 1 },
28
+ "license": { "type": "string", "minLength": 1 },
29
+ "containsExternalReferenceText": { "type": "boolean" },
30
+ "qualityLabels": { "const": false }
31
+ }
32
+ },
33
+ "trials": {
34
+ "type": "array",
35
+ "minItems": 1,
36
+ "items": { "$ref": "writingTrial.schema.json" }
37
+ },
38
+ "claimBoundary": { "type": "string", "minLength": 1 },
39
+ "trialSetSha256": { "$ref": "#/$defs/sha256" }
40
+ },
41
+ "$defs": {
42
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
43
+ }
44
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "entry": [
3
+ {
4
+ "name": "행동과 결과",
5
+ "form": "{대상}을 {행동}하면 {결과}가 {어디}에 {생깁니다}",
6
+ "when": "독자에게 무엇을 시킬 때. 가능성만 말하지 않고 손이 할 일과 눈에 보일 것을 한 문장에 담는다",
7
+ "example": "`저장` 버튼을 누르면 `report.csv` 가 그 폴더에 만들어집니다.",
8
+ "instead": "이 기능을 통해 파일 생성이 가능합니다.",
9
+ "avoids": [
10
+ "translationese"
11
+ ],
12
+ "source": "글쓰기 스킬의 쉬운 말로 바로 쓰기. 배상복 문장기술의 주어와 서술어를 붙여 쓰기"
13
+ },
14
+ {
15
+ "name": "확인",
16
+ "form": "{무엇}이 {어떤지} 확인합니다. {그 값}이 보이면 된 것입니다",
17
+ "when": "절을 닫을 때. 독자가 자기 화면에서 결과를 확인할 자리를 만든다",
18
+ "example": "폴더에 `link.png` 가 생겼는지 확인합니다. 파일이 보이면 된 것입니다.",
19
+ "instead": "결과가 저장되어집니다.",
20
+ "avoids": [
21
+ "doublePassive"
22
+ ],
23
+ "source": "글쓰기 스킬의 한 절을 다 읽으면 결과 하나가 남는다"
24
+ },
25
+ {
26
+ "name": "인과 잇기",
27
+ "form": "{앞 사실}입니다. 그래서 {뒤 사실}입니다",
28
+ "when": "사실이 둘 이상 나란히 놓일 때. 관계를 독자가 세우게 두지 않는다",
29
+ "example": "병합 셀은 첫 칸에만 값이 들어 있습니다. 그래서 그대로 정렬하면 빈 칸이 값과 떨어져 순서가 깨집니다.",
30
+ "instead": "값이 있습니다. 칸은 빕니다. 순서가 깨집니다.",
31
+ "avoids": [
32
+ "factListParagraph"
33
+ ],
34
+ "source": "글쓰기 스킬의 설명을 풀어 쓰기. 이수열의 문장은 이어져야 한다"
35
+ },
36
+ {
37
+ "name": "이름으로 이어받기",
38
+ "form": "{앞에서 만든 것}은 {상태}입니다. {아직 못 하는 일}입니다",
39
+ "when": "새 문단이나 새 절을 열 때. 지시어 대신 앞에서 만든 것의 이름을 부른다",
40
+ "example": "`link.png` 는 33픽셀입니다. 명함에 넣기에는 너무 작습니다.",
41
+ "instead": "터미널을 엽니다. 이것을 실행합니다.",
42
+ "avoids": [
43
+ "danglingDeixis"
44
+ ],
45
+ "source": "글쓰기 스킬의 절은 앞 절이 못 한 일에서 시작한다. 김정선의 것을 이름으로"
46
+ },
47
+ {
48
+ "name": "독자에게 묻기",
49
+ "form": "그럼 {무엇}은 {어디}에 {있을까요}? {답}",
50
+ "when": "독자가 품을 의문이 생기는 자리. 대신 묻고 다음 문장에서 답한다",
51
+ "example": "## 절\n\n파일을 만듭니다.\n\n## 다음 절\n\n그럼 파일은 어디에 생겼을까요? 방금 명령을 실행한 그 폴더에 있습니다.\n",
52
+ "instead": "## 절\n\n파일을 만듭니다.\n\n## 다음 절\n\n파일이 만들어집니다.\n",
53
+ "avoids": [
54
+ "noQuestion"
55
+ ],
56
+ "source": "글쓰기 스킬의 사실과 목소리"
57
+ },
58
+ {
59
+ "name": "값 소개",
60
+ "form": "{값}은 {무엇}입니다. {왜 그 값인지}. {지금 무엇을 하면 되는지}",
61
+ "when": "새 숫자나 옵션이 처음 나올 때. 셋 중 하나라도 못 적으면 그 값을 아직 넣을 때가 아니다",
62
+ "example": "`border` 는 그림 바깥에 남기는 빈 칸의 수입니다. 빈 자리가 없으면 카메라가 그림의 끝을 못 찾습니다. 그래서 기본값 4 를 그대로 둡니다.",
63
+ "instead": "메모리 최대치는 453MB에서 700MB로 올라갔습니다.",
64
+ "avoids": [
65
+ "numberOrphan"
66
+ ],
67
+ "source": "글쓰기 스킬의 새로 나온 값과 옵션은 세 가지를 그 자리에서 준다"
68
+ },
69
+ {
70
+ "name": "동사로 되돌리기",
71
+ "form": "{무엇}을 {한 뒤} {무엇}이 {어떤지} {확인합니다}",
72
+ "when": "명사가 셋 이상 이어질 때. 조사를 되살려 무엇이 무엇의 목적어인지 보인다",
73
+ "example": "가상환경을 만든 뒤 패키지가 깔렸는지 확인합니다.",
74
+ "instead": "가상환경 생성 후 패키지 설치 확인 절차를 따릅니다.",
75
+ "avoids": [
76
+ "nounPile"
77
+ ],
78
+ "source": "이오덕 우리글 바로쓰기의 명사문을 동사문으로. 글쓰기 스킬의 명사를 쌓지 말고 동사로 되돌린다"
79
+ },
80
+ {
81
+ "name": "결핍 도입",
82
+ "form": "{독자가 지금 하려는 일}입니다. {왜 지금 방법으로는 안 되는지}. 끝까지 읽으면 {손에 남는 것}이 남습니다",
83
+ "when": "글의 첫 문단. 정의로 시작하지 않고 독자가 막힌 자리로 시작한다",
84
+ "example": "거래 기록을 CSV로 내려받았더니 5백만 줄입니다. 엑셀로 열면 1,048,576줄에서 잘립니다. 끝까지 읽으면 그 표를 여는 코드가 손에 남습니다.",
85
+ "instead": "핵심은 속도입니다.",
86
+ "avoids": [
87
+ "cliche"
88
+ ],
89
+ "source": "글쓰기 스킬의 도입은 결핍부터. 이태준 문장강화의 첫머리"
90
+ },
91
+ {
92
+ "name": "미룬 것 회수",
93
+ "form": "앞에서 미룬 {이름}을 이제 봅니다",
94
+ "when": "뒤에서 다루겠다고 해 둔 것을 실제로 다루는 자리. 미뤘다는 사실을 밝히고 그 이름을 다시 부른다",
95
+ "example": "앞에서 미룬 `usecols` 를 이제 봅니다.",
96
+ "instead": "다음으로 크기를 바꿉니다.",
97
+ "avoids": [
98
+ "fillerOpener"
99
+ ],
100
+ "source": "글쓰기 스킬의 미룬 것은 같은 글 안에서 회수한다"
101
+ }
102
+ ]
103
+ }
@@ -6,7 +6,9 @@ os\.startfile\( 윈도우 subprocess.run(["open", 경로]) 나 xdg-open
6
6
  \bmsvcrt\b 윈도우 termios 나 다른 입력 방법
7
7
  \bwin32(?:api|con|gui|com)\b 윈도우 pywin32 는 윈도우 전용이다
8
8
  \bosascript\b 맥 다른 운영체제에는 AppleScript 가 없다
9
- /proc/ 리눅스 psutil 같은 이식 가능한 API
9
+ # /proc/ 는 뺐다. 코드에 박히는 API 호출이 아니라 셸 명령의 경로이고, 컨테이너 안에서는
10
+ # 리눅스가 기본 실행 환경이다. 실측: 기준 말뭉치의 지적 여덟 건이 전부 이 한 줄이었고 전부
11
+ # 쿠버네티스 안내서의 kubectl exec 와 컨테이너 안 셸 기록이라 독자가 멈추지 않는다 (2026-08-31).
10
12
  \bfcntl\b 리눅스와 맥 윈도우에는 fcntl 이 없다
11
13
  resource\.getrusage\( 리눅스와 맥 윈도우에는 resource 모듈이 없다
12
14
  [A-Za-z]:\\\\ 윈도우 절대 경로 대신 상대 경로나 pathlib