genetics-mcp 2.25.0 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NATIVE-CODEX-SESSION.md +182 -0
- package/bin/aarch64-apple-darwin/gcell +0 -0
- package/bin/aarch64-unknown-linux-musl/gcell +0 -0
- package/bin/manifest.json +5 -5
- package/bin/x86_64-apple-darwin/gcell +0 -0
- package/bin/x86_64-pc-windows-gnu/gcell.exe +0 -0
- package/bin/x86_64-unknown-linux-musl/gcell +0 -0
- package/codex-session-cli.mjs +82 -0
- package/codex-session.mjs +353 -0
- package/genetics.mjs +350 -49
- package/package.json +5 -2
- package/skills/gazette-report/scripts/tone.mjs +15 -6
- package/skills/gazette-report/scripts/tone.test.mjs +39 -0
- package/skills/genetics-report/SKILL.md +2 -2
- package/skills/genetics-report/assets/render.py +1 -4
- package/skills/genetics-report/references/content-pipeline.md +3 -4
- package/skills/genetics-report/references/lim-portal-format.md +29 -18
- package/skills/genetics-report/references/process.md +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genetics-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.26.0",
|
|
4
4
|
"description": "문서 포털 발행·세션 이식·사례 기억 MCP — 데이터를 주면 규격 문서가 나온다 (짝인 스킬 동봉)",
|
|
5
5
|
"author": "주식회사 LIM (LIM Inc.)",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"genetics.mjs",
|
|
13
|
+
"codex-session.mjs",
|
|
14
|
+
"codex-session-cli.mjs",
|
|
15
|
+
"NATIVE-CODEX-SESSION.md",
|
|
13
16
|
"LICENSE",
|
|
14
17
|
"skills",
|
|
15
18
|
"bin"
|
|
@@ -18,7 +21,7 @@
|
|
|
18
21
|
"node": ">=18"
|
|
19
22
|
},
|
|
20
23
|
"scripts": {
|
|
21
|
-
"test": "node smoke.mjs && node append.test.mjs && node task-results-stdio.test.mjs && node notify.test.mjs && node schedule.test.mjs && node windows.test.mjs && bash ../cell/tests/cellcycle.sh && python3 ../tests/report-patch.test.py",
|
|
24
|
+
"test": "node smoke.mjs && node append.test.mjs && node codex-session.test.mjs && node task-results-stdio.test.mjs && node notify.test.mjs && node schedule.test.mjs && node windows.test.mjs && bash ../cell/tests/native-codex-mail.sh && bash ../cell/tests/cellcycle.sh && python3 ../tests/report-patch.test.py",
|
|
22
25
|
"test:task-results": "node task-results.test.mjs && node task-results-stdio.test.mjs",
|
|
23
26
|
"prepack": "find skills -name __pycache__ -type d -prune -exec rm -rf {} + 2>/dev/null; bash ../cell/build-all.sh",
|
|
24
27
|
"prepublishOnly": "npm test",
|
|
@@ -53,15 +53,24 @@ export function analyze(raw0) {
|
|
|
53
53
|
// 떨어지지 않으려고 「회신 주시면 됨」 같은 하대로 돌아간다 — 2026-09-03 에 그렇게 반려됐다.
|
|
54
54
|
// ⑵ 「」 안은 원문 인용이다(SKILL 11 — 인용은 원문 문구 그대로). 앱 문구 「다시 입력해 주세요」를 인용한
|
|
55
55
|
// 표가 경어체로 잡히면 인용을 비틀게 된다. 요청 자리 밖(문단·표·요약)의 우리 문장은 그대로 센다.
|
|
56
|
-
// 2026-09-26 — ⑴ 과 같은 까닭으로 나머지 요청 자리도 뺀다: 머리 강조문(`aside.urgent` = cta), PART I 간지(`section.pt
|
|
56
|
+
// 2026-09-26 — ⑴ 과 같은 까닭으로 나머지 요청 자리도 뺀다: 머리 강조문(`aside.urgent` = cta), PART I 간지(첫 `section.pt`),
|
|
57
57
|
// 판권지 회신 안내(`p.colophon__note`). 요청 자리는 사실 문장까지 하십시오체다(genetics-report SKILL 5·5a) — 여기서 세면
|
|
58
58
|
// 본보기가 그 자리를 개조식으로 남겨 두게 되고, 에이전트는 그 본보기를 따른다(2026-09-26 A/B 에서 판단 항목 10/14 문장이 명사형).
|
|
59
|
-
// PART I 간지는 그 PART 가 요청·결정 PART 일 때(PART
|
|
59
|
+
// PART I 간지는 그 PART 가 요청·결정 PART 일 때(PART I 의 절 안에 요청 절 `ol.asks` 가 있을 때)만 요청 자리다 — 태그를 지우기 전에 뺀다.
|
|
60
60
|
// 배우는 문서·정황 공유 문서의 PART I(원리·경과)은 요청 자리가 아니므로 센다.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
// PART I 은 **문서 순서로** 가린다(2026-09-29, 서버 report_tone.php 와 같은 자) — 렌더러는 PART 마다 「간지 → 그 PART 의
|
|
62
|
+
// 절」 순서로 세우므로(gazette.py Doc.build()) 첫 간지부터 다음 간지 전까지가 PART I 이다. no 로 가리면 no 가 「1」이
|
|
63
|
+
// 아닌 문서(「I」)를 놓치고, 두 PART 가 같은 no 를 가지면(렌더러는 뒤 PART 가 절을 가져간다) 엉뚱한 간지를 뺀다.
|
|
64
|
+
// 단 첫 PART 에 제목도 절도 없으면 렌더러가 그 간지를 안 세운다 — 그때 첫 간지는 PART II 의 것이다. 차례는 PART 를
|
|
65
|
+
// 빠짐없이 순서대로 싣으므로(`li.toc__part`) 첫 간지의 no 가 차례 첫 PART 의 no 와 같을 때만 PART I 로 본다(차례가 없는 조각은 자리로).
|
|
66
|
+
const pts = [...raw.matchAll(/<section class="pt"[^>]*data-part-no="([^"]*)"[^>]*>/g)];
|
|
67
|
+
const toc1 = (raw.match(/<li class="toc__part" data-part-no="([^"]*)"/) || [])[1];
|
|
68
|
+
let rawReq = raw;
|
|
69
|
+
if (pts.length && (toc1 === undefined || pts[0][1] === toc1)
|
|
70
|
+
&& /class="asks"/.test(raw.slice(pts[0].index, pts.length > 1 ? pts[1].index : raw.length))) {
|
|
71
|
+
const end = raw.indexOf('</section>', pts[0].index);
|
|
72
|
+
if (end > 0) rawReq = raw.slice(0, pts[0].index) + ' ' + raw.slice(end + '</section>'.length);
|
|
73
|
+
}
|
|
65
74
|
const politeTxt = rawReq
|
|
66
75
|
.replace(/<p class="ask__body"[^>]*>[\s\S]*?<\/p>/g, ' ')
|
|
67
76
|
.replace(/<aside class="urgent"[^>]*>[\s\S]*?<\/aside>/g, ' ')
|
|
@@ -163,6 +163,45 @@ test('경어체 — 요청 PART 의 간지·강조문·판권지 회신 안내
|
|
|
163
163
|
assert.equal(pos(analyze(learn).polite.length), 1);
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
test('경어체 — PART I 은 문서 순서로 첫 간지다, no 가 「1」이 아니어도(2026-09-29 · 서버 report_tone.php 와 같은 자)', () => {
|
|
167
|
+
// no 가 「I」인 요청 PART — 전에는 data-part-no="1" 만 보아 이 간지를 요청 자리로 못 알아보고 셌다.
|
|
168
|
+
// 요청 PART 안이어도 여백 주석은 기록 자리다 — 간지만 빼고 절까지 들어내면(뮤테이션) 여기서 0 이 되어 죽는다.
|
|
169
|
+
const reqI = '<section class="pt" id="pt-I" data-part-no="I"><p class="pt__lede">확인을 부탁드리는 사항입니다.</p></section>'
|
|
170
|
+
+ '<section class="part" id="sec-1" data-chapter="01" data-part-no="I">'
|
|
171
|
+
+ '<aside class="marg"><p class="marg__t">10월 2일까지 회신 부탁드립니다.</p></aside>'
|
|
172
|
+
+ '<ol class="asks"><li class="ask"><p class="ask__body">회신 부탁드립니다.</p></li></ol></section>'
|
|
173
|
+
+ '<section class="pt" id="pt-II" data-part-no="II"><p class="pt__lede">경과를 적음.</p></section>'
|
|
174
|
+
+ '<section class="part" id="sec-2" data-chapter="02" data-part-no="II"><p>경과 하나를 다룸.</p></section>';
|
|
175
|
+
const r = analyze(reqI);
|
|
176
|
+
assert.equal(pos(r.polite.length), 1, r.polite.join(' | '));
|
|
177
|
+
assert.equal(r.polite[0].includes('10월 2일까지'), true, r.polite.join(' | '));
|
|
178
|
+
// 대조군 — 요청 절이 둘째 PART 에 있으면 첫 간지는 기록 자리다 → 센다. 뮤테이션: 요청 목록이 어느 PART 에 있든 첫 간지를 빼면 여기서 죽는다.
|
|
179
|
+
// 요청 절이 둘째 PART 에 있으면 첫 간지도, 요청 PART 인 둘째 간지도 센다 — 요청 자리는 PART I 간지뿐이다.
|
|
180
|
+
// 뮤테이션: 「요청 목록 앞의 간지」를 빼면 둘째 간지가 빠져 1 이 되어 죽는다.
|
|
181
|
+
const askInII = '<section class="pt" id="pt-I" data-part-no="I"><p class="pt__lede">원리를 먼저 설명합니다.</p></section>'
|
|
182
|
+
+ '<section class="part" id="sec-1" data-chapter="01" data-part-no="I"><p>원리 하나를 다룸.</p></section>'
|
|
183
|
+
+ '<section class="pt" id="pt-II" data-part-no="II"><p class="pt__lede">아래 항목에 회신 부탁드립니다.</p></section>'
|
|
184
|
+
+ '<section class="part" id="sec-2" data-chapter="02" data-part-no="II">'
|
|
185
|
+
+ '<ol class="asks"><li class="ask"><p class="ask__body">회신 부탁드립니다.</p></li></ol></section>';
|
|
186
|
+
assert.equal(pos(analyze(askInII).polite.length), 2);
|
|
187
|
+
// 첫 PART 에 제목도 절도 없으면 렌더러가 그 간지를 안 세운다 — 첫 간지는 PART II 의 것이라 요청 자리가 아니다 → 센다.
|
|
188
|
+
// 차례(`li.toc__part`)는 PART 를 빠짐없이 싣는다. 뮤테이션: 차례 대조 없이 첫 간지를 빼면 0 이 되어 죽는다.
|
|
189
|
+
const noPt1 = '<ol class="toc"><li class="toc__part" data-part-no="1"></li><li class="toc__part" data-part-no="2"></li></ol>'
|
|
190
|
+
+ '<section class="pt" id="pt-2" data-part-no="2"><p class="pt__lede">아래 항목에 회신 부탁드립니다.</p></section>'
|
|
191
|
+
+ '<section class="part" id="sec-1" data-chapter="01" data-part-no="2">'
|
|
192
|
+
+ '<ol class="asks"><li class="ask"><p class="ask__body">회신 부탁드립니다.</p></li></ol></section>';
|
|
193
|
+
assert.equal(pos(analyze(noPt1).polite.length), 1);
|
|
194
|
+
// 두 PART 가 같은 no 를 가지면 렌더러는 뒤 PART 가 절을 가져간다 — 요청 목록은 셋째 간지 밑에 서고 첫 간지는 기록 자리다 → 센다.
|
|
195
|
+
// 뮤테이션: no 로 가리면(data-part-no="1" 이 둘) 첫 간지를 빼서 여기서 죽는다.
|
|
196
|
+
const dupNo = '<section class="pt" id="pt-a" data-part-no="1"><p class="pt__lede">원리를 먼저 설명합니다.</p></section>'
|
|
197
|
+
+ '<section class="pt" id="pt-b" data-part-no="2"><p class="pt__lede">경과를 적음.</p></section>'
|
|
198
|
+
+ '<section class="part" id="sec-1" data-chapter="01" data-part-no="2"><p>경과 하나를 다룸.</p></section>'
|
|
199
|
+
+ '<section class="pt" id="pt-c" data-part-no="1"><p class="pt__lede">요청 두 항목.</p></section>'
|
|
200
|
+
+ '<section class="part" id="sec-2" data-chapter="02" data-part-no="1">'
|
|
201
|
+
+ '<ol class="asks"><li class="ask"><p class="ask__body">회신 부탁드립니다.</p></li></ol></section>';
|
|
202
|
+
assert.equal(pos(analyze(dupNo).polite.length), 1);
|
|
203
|
+
});
|
|
204
|
+
|
|
166
205
|
test('양성 표본 수 — 0표본 통과 방지', () => {
|
|
167
206
|
console.log(` 양성 표본 ${positives}건 (0 이면 이 시험은 아무것도 안 잰 것)`);
|
|
168
207
|
assert.equal(positives >= 28, true, String(positives));
|
|
@@ -103,8 +103,8 @@ version: "4.0.0"
|
|
|
103
103
|
`~하여 주시기 바랍니다 / ~부탁드립니다 / ~하겠습니다` 로 맺는다. 자세한 것은 아래 5·5a.
|
|
104
104
|
경어체 `습니다|십시오|합니다|입니다|됩니다|주세요` 0건은 **요청 자리 밖에만** 거는 기준이다.
|
|
105
105
|
- ⚠ **톤 게이트는 경고이지 거절이 아니다.** `report_tone.php report_tone_warnings()` 가 `dry_run` 경고로 셀 뿐 발행을 막지 않는다.
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
서버와 로컬 `tone.mjs` 는 같은 요청 자리 넷(판단 항목 본문·`cta`·판권지 회신 안내·요청 PART 의 PART I 간지 도입문·물음)과 「」 인용을 빼고 센다(2026-09-29 — 요청 절 여백 주석·PART 제목은 센다).
|
|
107
|
+
읽는 법(`guide`)의 요청 한 줄만 자리로 못 가려 두 경로 모두 센다 — 그 한 줄의 경어체 경고는 **의도이므로 고치지 않는다.** 간지에서 나면 요청 PART I 이 아닌 간지이니 개조식으로 고친다.
|
|
108
108
|
이 경고를 하드 규칙으로 오인해 종결을 비튼 것이 **거듭된 반려의 원인**이다(경위: `references/history.md` §5).
|
|
109
109
|
- `tenant` 는 키가 가리키는 고객사와 일치해야 한다(오발행 방지 가드). 값은 소속처 slug 우선·이름 폴백 — 8단계의 `slug` 는 **보고서** slug 라 다른 것이다.
|
|
110
110
|
- `sections[].kind` 는 `summary|status|cases|asks|note` 다섯 가지뿐 — 그 밖의 값은 절이 통째로 사라지므로 서버가 거절한다.
|
|
@@ -164,10 +164,7 @@ def templates_from_server(repo: pathlib.Path) -> dict:
|
|
|
164
164
|
_TEXT_SKIP = {'head', 'script', 'style', 'template', 'noscript', 'title', 'desc'}
|
|
165
165
|
# 머리띠 이동줄·진행 막대·측면 색인·「본문 바로가기」는 차례와 절 이름을 한 번 더 늘어놓는 화면 장치라 인쇄본도
|
|
166
166
|
# 지운다(gazette.css @media print 「화면 전용 크롬」). 그 목록의 현황 줄(notice)은 요약면 본문이라 남긴다.
|
|
167
|
-
_TEXT_CHROME = {'topbar', 'progress', 'rail', 'skip'
|
|
168
|
-
# 접기(<details>) 요약 줄 — 도판 번호·캡션과 「원인 · 조치 · 확인 방법」을 한 번 더 늘어놓는 화면 장치다.
|
|
169
|
-
# 인쇄본도 지운다(gazette.css 13-1b). 글은 접힌 칸 안에 그대로 있다(2026-09-30).
|
|
170
|
-
'fold__sum'}
|
|
167
|
+
_TEXT_CHROME = {'topbar', 'progress', 'rail', 'skip'}
|
|
171
168
|
_TEXT_BLOCK = {'address', 'article', 'aside', 'blockquote', 'caption', 'dd', 'div', 'dl', 'dt',
|
|
172
169
|
'figcaption', 'figure', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header',
|
|
173
170
|
'li', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'tbody', 'tfoot',
|
|
@@ -422,10 +422,9 @@ AssertionError: 금지 표현 유출: 조회 색인 → ['조회 색인']
|
|
|
422
422
|
|
|
423
423
|
⚠ **경어체 0건은 요청 자리 밖에만 거는 기준임.**
|
|
424
424
|
요청 자리(`cta`·`open_items`·PART I 간지(요청·결정 PART 일 때)·판권지 회신 안내·요청 절 항을 부탁하는 읽는 법 한 줄)는 **사실 문장까지 하십시오체로 맺음**(SKILL 5·5a).
|
|
425
|
-
두 문체
|
|
426
|
-
`open_items[].title`
|
|
427
|
-
|
|
428
|
-
서버 관문은 PART I 간지의 문장을, 두 관문은 읽는 법 요청 한 줄을 셈 — PART I 이 요청 PART 일 때 그 둘은 의도이고 고치지 않음(통과 기준은 lim-portal-format §10).
|
|
425
|
+
두 문체 관문(서버 `report_tone.php report_tone_warnings()`·로컬 `tone.mjs`)은 같은 요청 자리 넷(`open_items[].body`·`cta`·`colophon.note`·요청 PART 의 PART I 간지 도입문·물음)과 「」 인용을 빼고 셈(2026-09-29 · lim-portal-format §10).
|
|
426
|
+
`open_items[].title`·PART 제목·요청 절 `marg` 는 셈(제목은 「~ 요청」·물음·이름이 규칙). 건의 `how_to_check` 에서 걸린 요청문은 「요청 절로 옮김」 처방이 따로 섬.
|
|
427
|
+
읽는 법 요청 한 줄은 두 관문 모두 셈 — 그 한 줄은 의도이고 고치지 않음(통과 기준은 lim-portal-format §10).
|
|
429
428
|
|
|
430
429
|
개조식 `~함 / ~했음 / ~임` 은 **요청 자리 밖에서 우리·사물이 주어인 문장**의 문체임.
|
|
431
430
|
명사형 종결(`-ㅁ/-음`)은 청자 높임 등급이 없어, 상대에게 말 거는 자리에 쓰면 하대로 읽힘 —
|
|
@@ -82,7 +82,8 @@ python3 assets/render.py <report.json>
|
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
`gazette.py` 의 `build()` 가 이 순서로 조립한다.
|
|
85
|
-
|
|
85
|
+
가구 순서는 고정이다. `summary_position:"front"` 를 선택하면 `summary[]` 요지를 앞의 요약면에 함께 싣는다.
|
|
86
|
+
생략하면 기존 요약면(현황·수치)과 `kind:"summary"` 절의 배치를 유지한다.
|
|
86
87
|
인쇄하면 표지가 1쪽 단독, PART 간지가 각각 1쪽 단독, 절마다 새 쪽에서 시작한다.
|
|
87
88
|
인쇄에서 여백 주석은 절 머리의 가로 띠로 서고 본문은 쪽 폭(174mm)을 다 쓴다 — 본문 활자는 10.5pt(2026-09-27, §11-3 「넓은 표」).
|
|
88
89
|
|
|
@@ -108,6 +109,13 @@ python3 assets/render.py <report.json>
|
|
|
108
109
|
`REPORT_CLIENT_KEYS`(`report_publish.php report_client_fields()` 가 이것으로 깎는다)가 화이트리스트다.
|
|
109
110
|
**여기 없는 키는 조용히 버려진다** — 보낸 쪽은 실린 줄 안다.
|
|
110
111
|
|
|
112
|
+
**서버가 검증해 붙이는 근거는 작성 인자가 아니다.** 웹 대화의 보고서 worker가 현재 읽을 수 있는
|
|
113
|
+
원문을 확인한 뒤 붙이는 `report_evidence` 는 서버 전용 출력이다. 그 안의 `url`·`version` 은 확인한
|
|
114
|
+
원문 주소와 판의 표시값이며, 호출자가 넣은 값은 원문 검증이나 열람 권한 부여가 되지 않는다.
|
|
115
|
+
`publish_report`·`update_report` 의 원고에는 이 목록을 넣지 않는다 — `report_client_fields()` 가 제거한다.
|
|
116
|
+
대화 보고서의 `[R1]` 같은 참조는 worker가 실제로 확인한 현재 근거 목록에 속해야 하고, 목록 밖 참조는
|
|
117
|
+
검증에서 거절된다. 일반 원고의 작성 근거는 아래 `summary[].refs`·`cases[].source_url` 등 해당 자리의 계약을 쓴다.
|
|
118
|
+
|
|
111
119
|
### 3.1 표지·머리
|
|
112
120
|
|
|
113
121
|
| 칸 | 뜻 | 없으면 |
|
|
@@ -141,7 +149,7 @@ python3 assets/render.py <report.json>
|
|
|
141
149
|
| `sections` | 절 목록. 4절 참조 | 본문이 없다 |
|
|
142
150
|
| `groups` | 건 묶음 `[{key,no,name}]` | `cases` 가 어디에도 안 실린다(**거절**) |
|
|
143
151
|
| `cases` | 건 목록. 3.5절 참조 | `kind:"cases"` 절이 빈다 |
|
|
144
|
-
| `summary` | 요약 문단 `[{lead,body,refs[]}]
|
|
152
|
+
| `summary` | 요약 문단 `[{lead,body,refs[]}]`. `summary_position:"front"` 이면 앞 요약면에도 선다 | 요지 부분이 빈다 |
|
|
145
153
|
| `open_items` | 요청 항목 `[{title,priority,body,refs[]}]` | `kind:"asks"` 절이 빈다 |
|
|
146
154
|
| `cta` | 요청 절 머리 강조문(문자열 목록) | 강조문이 안 선다 |
|
|
147
155
|
| `grades` | 확인 등급 사전. 7절 참조 | 대조표 범례와 등급 표식이 안 선다 |
|
|
@@ -150,6 +158,7 @@ python3 assets/render.py <report.json>
|
|
|
150
158
|
|
|
151
159
|
| 칸 | 뜻 | 없으면 |
|
|
152
160
|
|---|---|---|
|
|
161
|
+
| `summary_position` | `"front"` 를 선택하면 `summary[]` 요지를 문서 앞 요약면에 싣는다. 앞 요약만 필요하면 `kind:"summary"` 절을 따로 두지 않는다 — 둘 다 두면 같은 요지가 두 번 실린다 | 기존 현황·수치 요약면과 `kind:"summary"` 절 배치 유지 |
|
|
153
162
|
| `notice` | 현황 줄 **객체** `{state,text}` | 현황 줄이 안 선다 |
|
|
154
163
|
| `bar` | 상태 막대 `[{value,label,tone}]`. 건을 세는 막대면 대기(`wait`) 합은 미결 건 수나 판단 항목 수, 완료 합은 나머지 건 수나 전체 건 수와 같아야 한다 — 어긋나면 렌더러 ⚠(§10). **건이 아닌 다른 것을 세는 막대는 `bar_note` 에 셈 기준을 밝힌다**(그러면 대조하지 않는다) | 막대가 안 선다 |
|
|
155
164
|
| `bar_alt` | 막대의 대체 텍스트(`role="img"` 의 이름) | 「전체 분포」로 선다 |
|
|
@@ -274,7 +283,9 @@ python3 assets/render.py <report.json>
|
|
|
274
283
|
| `count_unit` | 배지 단위 | 「건」 |
|
|
275
284
|
| `board_title` | `kind:"status"` 대조표의 캡션 | `name` 을 쓴다 |
|
|
276
285
|
| `board_hint` | 캡션 아래 보조 한 줄 | 보조 줄이 빠진다 |
|
|
277
|
-
| `paragraphs` | `kind:"note"` 강조
|
|
286
|
+
| `paragraphs` | `kind:"note"` 본문 문자열 목록. 기본은 강조 박스 항목, `presentation:"prose"` 이면 실제 산문 문단. 산문 문단은 최대 120개이며 비어 있지 않은 문자열이어야 한다 | 그 절이 빈다 |
|
|
287
|
+
| `presentation` | `kind:"note"` 에서 `"prose"` 를 선택하면 `paragraphs` 를 `<p>` 문단으로 싣는다. 다른 `kind` 의 장치는 바뀌지 않는다 | 기존 강조 박스·`limit_label` 유지 |
|
|
288
|
+
| `paragraph_kinds` | 산문 문단 역할 목록. `paragraphs` 와 같은 길이·순서로 `fact`·`context`·`analysis`·`proposal`·`unknown` 을 둔다. `analysis` 는 「해석」, `proposal` 은 「제안」, `unknown` 은 「추가 확인 필요」를 표시하고 `fact`·`context` 는 별도 표식 없이 읽힌다. 역할은 사실 검증이나 열람 권한을 대신하지 않는다 | 역할 표식 없음 |
|
|
278
289
|
| `limit_label` | 강조 박스의 머리 글자 | `name` 을 쓴다 |
|
|
279
290
|
| `note` | `kind:"status"` 에서 표 아래 한 줄 | 그 줄이 빠진다 |
|
|
280
291
|
| `flow` | 의존 흐름도 한 개(11-2절). `kind` 와 무관하다 | 도해가 빠진다 |
|
|
@@ -292,6 +303,10 @@ python3 assets/render.py <report.json>
|
|
|
292
303
|
예시 데이터가 `"no": "01"` 을 적고 있는 것은 사람이 읽기 위한 것이다 —
|
|
293
304
|
**순서와 다르게 적으면 문서와 어긋난 원고가 된다.**
|
|
294
305
|
|
|
306
|
+
`kind:"note", presentation:"prose"` 문단도 이 순번을 쓴다. 1번째 절의 2번째 문단은
|
|
307
|
+
`case-01-2` 앵커가 되고 요약의 `refs:["1.2"]`·`§1.2` 가 같은 실제 문단을 가리킨다.
|
|
308
|
+
그 문단을 사례로 다시 만들 필요가 없다. 절이나 문단 순서를 바꾸면 참조도 함께 고친다.
|
|
309
|
+
|
|
295
310
|
### ⚠ `groups[].no` 는 그 그룹을 싣는 절의 순번과 같아야 한다
|
|
296
311
|
|
|
297
312
|
`§n.n` 마커의 앞 숫자가 **두 곳에서 다른 뜻**이다.
|
|
@@ -316,10 +331,11 @@ python3 assets/render.py <report.json>
|
|
|
316
331
|
| `cases` | 건 필드표(증상·원인·조치·확인 방법·미결·원본) | 그 절의 `group` 에 속한 `cases[]` |
|
|
317
332
|
| `status` | 대조표(4괘선 + 확인 강도 표식) | **전체** `cases[]` · 절의 `board_title`·`board_hint`·`note` |
|
|
318
333
|
| `summary` | 요지 블록(리드 + 본문 + 해당 절) | `summary[]` |
|
|
319
|
-
| `note` | 강조 박스(미확인 사항 등) | 절의 `paragraphs[]` · `limit_label` |
|
|
334
|
+
| `note` | 기본은 강조 박스(미확인 사항 등), `presentation:"prose"` 를 선택하면 산문 문단 | 절의 `paragraphs[]` · 기본 박스의 `limit_label` · 산문의 `paragraph_kinds[]` |
|
|
320
335
|
|
|
321
336
|
`asks` 와 `summary` 는 **문서에 하나만 두는 것이 맞다** — 둘 다 최상위 목록을 통째로 그린다.
|
|
322
337
|
둘을 두 절에 걸면 같은 목록이 두 번 실린다.
|
|
338
|
+
`summary_position:"front"` 도 같은 요지를 앞에 추가하므로, 앞 요약만 원하는 문서에는 `kind:"summary"` 절을 두지 않는다.
|
|
323
339
|
|
|
324
340
|
---
|
|
325
341
|
|
|
@@ -369,7 +385,9 @@ python3 assets/render.py <report.json>
|
|
|
369
385
|
|
|
370
386
|
## 8. 요약 근거 게이트 — 발행이 **거절**된다
|
|
371
387
|
|
|
372
|
-
`summary[]` 의 문단마다 근거로 삼은
|
|
388
|
+
`summary[]` 의 문단마다 근거로 삼은 **실제 사례 번호 또는 산문 문단 번호**를 최소 하나 밝혀야 한다.
|
|
389
|
+
산문 문단은 `kind:"note", presentation:"prose"` 절의 비어 있지 않은 `paragraphs[]` 항목이다.
|
|
390
|
+
그 번호는 절·문단의 배열 순번이며 렌더러 앵커와 같다(4절).
|
|
373
391
|
|
|
374
392
|
- 두 검사가 짝이다: **참조 존재**(문단마다 하나 이상) · **참조 실재**(그 번호가 실제로 있어야).
|
|
375
393
|
- 두 모양을 다 센다: `refs: ["4.1"]` 과 본문 안 `§4.1`.
|
|
@@ -396,7 +414,7 @@ python3 assets/render.py <report.json>
|
|
|
396
414
|
| `cases[].group` 이 없는 그룹 | 그 건이 어디에도 안 실린다 |
|
|
397
415
|
| `sections[].part` 가 없는 PART 번호 | 조용히 첫 묶음으로 자리를 옮긴다 |
|
|
398
416
|
| `summary` 문단에 근거 표기 0개 | 독자가 근거를 찾아 헤맨다 |
|
|
399
|
-
| `summary` 가 없는
|
|
417
|
+
| `summary` 가 없는 사례·산문 문단 번호를 근거로 댐 | 같음 |
|
|
400
418
|
| `sections`·`cases`·`summary` 가 목록이 아님 | `{}` 를 보내면 뒤에서 날 TypeError 가 샌다 |
|
|
401
419
|
| `history`·`guide`·`parts`·`appendix`·`bar` 가 목록이 아님 | 같음 |
|
|
402
420
|
| `notice`·`colophon` 이 객체가 아님 | 같음 |
|
|
@@ -454,11 +472,11 @@ python3 assets/render.py <report.json>
|
|
|
454
472
|
|---|---|---|
|
|
455
473
|
| 「고객사 로고가 SVG 로 등록돼 있어 표지에 못 싣습니다」·「표지용 파생본이 아직 없습니다」 | 소속처 로고 설정의 상태다 | 소속처 관리 화면(사람) |
|
|
456
474
|
| 「바깥에서 받아 오는 것이 있습니다」 — 그 호스트가 **본문 링크**(`[글자](주소)`·맨 주소·건 `source_url`)뿐일 때 | 입고 검사가 `<a href>` 호스트까지 센다(§11-6). 누르는 링크는 받아 오는 자원이 아니다. `<img src>` 등으로 뜨면 작성자 몫 | 서버 검사 수리 전까지 사람이 호스트 목록을 대조 |
|
|
457
|
-
| 경어체 경고 —
|
|
475
|
+
| 경어체 경고 — 읽는 법(`guide`)의 요청 한 줄에서만 날 때 | 요청 자리(§12.5b)인데 자리로 못 가려 두 문체 관문 모두 센다 | 사람이 자리를 확인 |
|
|
458
476
|
| 레포의 렌더러·서버 관문이 운영보다 앞선 동안, 새 규칙대로 고친 자리에 운영 `dry_run` 이 옛 규칙으로 내는 경고 | 운영은 배포된 판으로 센다 — 되돌리면 새 규칙에 걸리고, 배포되면 사라진다 | 새 판에서 0 인지 먼저 잰다 — 렌더러 경고는 레포 작업본을 부르는 로컬 `render.py`, 서버 문체 관문·입고 검사·서식 등록부 칸은 레포 개발 스택의 `dry_run`(절차: genetics lim `cases/dev-스택이-OrbStack-덧판https-base_url으로-떠-있으면-…`). 0 이면 핸드오프에 「배포 뒤 해소」 한 줄 |
|
|
459
477
|
|
|
460
|
-
요청 절의 경어체는 이제 예외가 아니다.
|
|
461
|
-
`colophon.note
|
|
478
|
+
요청 절의 경어체는 이제 예외가 아니다. 두 문체 관문(서버 `report_tone.php report_tone_warnings()`·로컬 `tone.mjs`)은 같은 요청 자리(`open_items[].body`·`cta`·
|
|
479
|
+
`colophon.note`·요청 PART 의 PART I 간지 도입문·물음)와 「」 인용을 빼고 센다(2026-09-29 — `asks` 절 `marg`·PART 제목은 센다).
|
|
462
480
|
이 표의 셋째 행 밖에서 경어체 경고가
|
|
463
481
|
뜨면 요청 자리 밖이나, 판단 항목 `title`(명사형 「~ 요청」·물음이라 서버가 경어체를 세는 칸)이나, `guide` 에 요청 문장이 샌 것이다 — 요청 문장은 요청 절로 옮긴다(SKILL 반드시 지키는 것 5 — 요청 자리 밖에는 독자를 주어로 쓰지 않는다). 단 `guide` 에서 요청 절의 확인 요청을 부탁하는 한 줄은 허용한다(2026-09-15 사용자 결정) — 그 한 줄에서만 나는 경어체 경고는 §10 통과 기준 표의 행으로 넘긴다.
|
|
464
482
|
건의 `how_to_check` 에서 걸린 명령형은 「보고 칸에 요청문이 N곳 있습니다 — 요청 절(open_items)로 옮깁니다」로 따로 뜬다.
|
|
@@ -639,12 +657,6 @@ CSS 로는 못 한다. 우측 판독부에 남는 것은 문서 전체의 사실
|
|
|
639
657
|
모든 도판은 눌러서 **크게 보기**가 열린다(스크립트 없이 `:target`). 원본이 1400px 라 본문 단의 최대
|
|
640
658
|
1.8배다 — 하한을 못 넘긴 그림의 구제책이지 하한을 대신하지 않는다.
|
|
641
659
|
|
|
642
|
-
**접기(2026-09-30)** — 렌더러가 정한다(원고 칸 없음). 이미지 도판·영상은 절마다 첫 장만 펼치고 둘째부터
|
|
643
|
-
「그림 N-M 캡션」 한 줄로 접는다(도해 `.diagram` 은 안 접는다). 건 필드표는 증상·미결·원본은 늘 보이고
|
|
644
|
-
원인·조치·확인 방법만 접는다. 스크립트 없는 `<details>` 이고 인쇄는 전부 펼친다(`::details-content`).
|
|
645
|
-
본문의 `{{그림:id}}` 링크로 접힌 그림에 가면 브라우저가 펼친다(Chrome 실측 — Safari·Firefox 미측정).
|
|
646
|
-
그래서 **캡션 한 줄만으로 무슨 그림인지 서야 한다** — 접힌 동안 독자가 보는 것은 번호와 캡션뿐이다.
|
|
647
|
-
|
|
648
660
|
번호는 **그림 〈절 순번〉-〈그 절에서의 순서〉** 다. 절 4의 둘째 도판이면 `그림 4-2` 이고,
|
|
649
661
|
앵커는 `#fig-04-2` 다. 데이터로 바꿀 수 없다 — 절 번호와 같은 규약이다.
|
|
650
662
|
|
|
@@ -1354,9 +1366,8 @@ Submissions·WHO/SUPPORT 정책 브리프(1:3:25)가 **같은 뼈대**를 요구
|
|
|
1354
1366
|
|
|
1355
1367
|
명사형 종결(`-ㅁ/-음`)은 한국어 상대높임법의 **등급 밖**이라 청자 높임이 0 이다 —
|
|
1356
1368
|
중립이 아니라 기록체이고, 사람에게 직접 쓰면 하대로 읽힌다. 「부탁드림」도 존대가 아니다.
|
|
1357
|
-
문체
|
|
1358
|
-
|
|
1359
|
-
그래서 남는 경어체 경고는 **서버의 PART I 간지 문장(요청 PART 일 때)과 두 경로의 읽는 법 요청 한 줄**이다 — 둘 다 고치지 않는다(§10 통과 기준 표 · SKILL 「Lim 발행 규칙」).
|
|
1369
|
+
두 문체 관문(서버 `report_tone.php report_tone_warnings()`·로컬 `tone.mjs`)은 이 자리 가운데 넷(판단 항목 본문·`cta`·판권지 회신 안내·요청 PART 의 PART I 간지 도입문·물음)과 「」 인용을 빼고 센다(2026-09-29 · §10).
|
|
1370
|
+
그래서 남는 경어체 경고는 **읽는 법 요청 한 줄**뿐이다 — 고치지 않는다(§10 통과 기준 표 · SKILL 「Lim 발행 규칙」).
|
|
1360
1371
|
|
|
1361
1372
|
**「고객 언어로 바꾼다」는 규칙은 그대로다.**
|
|
1362
1373
|
개조식은 문체이지 내용이 아니다 — 내부 용어를 고객 용어로 바꾸는 일(0단계)을 건너뛰는 핑계가 되지 않는다.
|
|
@@ -228,8 +228,8 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
|
|
|
228
228
|
|
|
229
229
|
요청 자리 밖에서 문체를 안 바꾸면 낱말이 아니라 **조판의 문제**로 남는다 — 경어체 서술문은
|
|
230
230
|
관보 문법 위에서 겉돈다. 반대로 요청 자리에서 개조식을 고집하면 **하대로 읽힌다** — 이쪽이
|
|
231
|
-
거듭 반려된 자리다(SKILL 5·5a · 경위 history.md §5). 서버 `report_tone.php report_tone_warnings()`
|
|
232
|
-
|
|
231
|
+
거듭 반려된 자리다(SKILL 5·5a · 경위 history.md §5). 두 문체 관문(서버 `report_tone.php report_tone_warnings()`·로컬 `tone.mjs`)은 같은 요청 자리 넷(판단 항목 본문·`cta`·판권지 회신 안내·요청 PART 의 PART I 간지 도입문·물음)과 「」 인용을 뺀다(2026-09-29).
|
|
232
|
+
읽는 법(`guide`)의 요청 한 줄은 두 관문 모두 센다 — 남는 경어체 경고가 그 한 줄뿐이면 의도이므로 **사람이 걸러 읽고 그대로 둔다**.
|
|
233
233
|
|
|
234
234
|
### `summary` — 검수·보고판 4개의 `{lead, body, refs}`
|
|
235
235
|
|