genetics-mcp 2.0.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.
@@ -0,0 +1,272 @@
1
+ # LIM 웹 리포트 서식 (`template: "lim-report"`)
2
+
3
+ 포털 발행 산출 중 **LIM 브랜드 계약을 따르는 판**이다. 포털의 다른 문서와 데이터 모델은
4
+ 같고, 그 위에 **팔레트 `lim` · 챕터 오프닝 · 번호형 전체 목차 · 일러스트 · EOF 엔드카드**가 얹힌다.
5
+
6
+ 정본 계약: 포털 저장소의 `DESIGN-lim-report.md`.
7
+
8
+ > 이 문서의 예시 값(고객사명·건수·본문 문장)은 **한 실사례의 값**이다. 규칙은 도메인과 무관하다.
9
+ 이 문서는 그 계약을 **스킬 사용자가 실제로 무엇을 채워야 하는가**로 옮긴 것이다.
10
+ 계약과 어긋나면 계약이 이긴다.
11
+
12
+ > **언제 이 서식을 쓰는가.** 포털로 나가는 문서는 전부 이 서식이다 — 고를 것이 없다.
13
+ > `template` 을 생략해도 서버가 이것으로 낸다(`REPORT_TEMPLATE_DEFAULT`). 팔레트도
14
+ > 계약이 정한 4색이라 `palette` 를 보내도 서버가 `lim` 으로 덮는다.
15
+
16
+ ---
17
+
18
+ > **만드는 길이 둘이다.** MCP·API 로 `template: "lim-report"` 를 주거나,
19
+ > 관리 화면 **새 문서**에서 「Lim 웹 리포트」를 고른다(2026-08-16 추가 — 그전에는 API 뿐이었다).
20
+
21
+ ## 1. 서식을 켜는 두 줄
22
+
23
+ ```json
24
+ { "template": "lim-report", "palette": "lim" }
25
+ ```
26
+
27
+ `template` 은 서버가 스타일시트·폰트를 고르는 열쇠다(Spoqa Han Sans Neo 정적 3벌).
28
+ `palette: "lim"` 은 표지를 **paper 아키타입**(흰 바탕 + Ink 활자)으로 만든다 —
29
+ 계약 1절이 검정 전면과 문단 단위 역상을 금지하기 때문이다.
30
+
31
+ ---
32
+
33
+ ## 2. 챕터 오프닝 — `chapters[]`
34
+
35
+ 절 앞에 펼쳐지는 여는 글이다. 계약 4.2절의 순서가 그대로 렌더된다:
36
+ **번호·짧은 제목·예상 시간 → 큰 제목 → 핵심 문장 → 일러스트 → 이 장에서 다룰 내용.**
37
+
38
+ ```json
39
+ "chapters": [{
40
+ "id": "ch-01",
41
+ "no": "01",
42
+ "short_title": "핵심 진단",
43
+ "reading_minutes": 3,
44
+ "title_lines": ["계산보다 먼저", "목표 설정을", "바로잡아야 합니다"],
45
+ "lead": "현재 방식은 도달해야 할 몸 상태가 아니라 지금 속한 칸의 바로 옆 칸을 목표로 삼습니다.",
46
+ "asset": "chapter-01",
47
+ "topics": ["반복된 핵심 패턴", "확인한 8건", "변경 영향 91.7%"]
48
+ }]
49
+ ```
50
+
51
+ 절과는 `sections[].chapter` 로 잇는다.
52
+
53
+ ```json
54
+ "sections": [{ "no": "01", "id": "sec-1", "name": "핵심 진단", "kind": "summary", "chapter": "ch-01" }]
55
+ ```
56
+
57
+ ### 반드시 알아야 할 것 넷
58
+
59
+ | 항목 | 규칙 | 왜 |
60
+ |---|---|---|
61
+ | `title_lines` | 줄바꿈을 **데이터가 정한다** | 브라우저에 맡기면 핵심 명사만 떨어져 나간다(계약 3절) |
62
+ | `name` vs `title_lines` | `name` 은 목차용 **짧은 이름**, `title_lines` 는 본문의 **큰 제목** | 계약 4.1절이 목차를 「번호·짧은 제목·한 줄 설명」으로 정의한다. 둘은 다른 정보다 |
63
+ | `lead` 와 `sections[].lede` | **둘 다 쓰지 말 것** | 챕터가 `lead` 를 가지면 렌더러가 절 도입문을 안 낸다(핵심 문장은 하나다). 다르면 경고를 찍는다 |
64
+ | 챕터를 하나라도 주면 | **번호형 전체 목차가 자동으로 선다** | 계약 4.1절 고정 순서. 따로 넣을 것이 없다 |
65
+
66
+ `index_line` 을 주면 전체 목차의 한 줄 설명이 되고, 없으면 `lead` 를 쓴다.
67
+
68
+ ### 챕터에 `asset` 을 붙이면 **데스크톱에서 2열로 갈린다** (2026-08-16 구현)
69
+
70
+ 961px 이상에서 `<main>` 이 격자가 되어 **글은 한쪽, 그림은 반대쪽**에 서고, 다음 챕터는
71
+ 좌우가 뒤집힌다(01 좌·02 우·03 좌…). 그 아래 폭에서는 예전처럼 한 열이다.
72
+
73
+ 저작할 때 알아야 할 것은 셋이다.
74
+
75
+ | | 내용 |
76
+ |---|---|
77
+ | 그림 비율 | 반폭(≈310–390px)에 서므로 **가로로 긴 그림**이 맞다. 세로로 긴 그림은 글 열보다 훨씬 길어져 여백이 생긴다 |
78
+ | 그림 높이 | 그림이 걸치는 세로 길이는 **그 챕터의 글 조각 수**로 정해진다(머리말+제목+`lead`+`topics`). `topics` 를 빼면 그림이 그만큼 짧아진다 |
79
+ | 표식 | `data-side`·`ch-span`·`ch-colend` 는 **렌더러가 붙인다.** 데이터에 적지 않는다 |
80
+
81
+ 교차는 챕터 **순서**로 정해진다 — 특정 장을 왼쪽에 두고 싶다고 지정할 수 없다.
82
+
83
+ ---
84
+
85
+ ## 2b. 포털이 문서 **둘레**에 더해 주는 것 (저작 대상 아님)
86
+
87
+ 발행물 안에 쓰지 말아야 할 것을 알기 위해 적는다. 아래는 전부 포털이 준다.
88
+
89
+ | 무엇 | 어디에 | 저작자가 할 일 |
90
+ |---|---|---|
91
+ | 진척률 바 | 발행물 최상단(5px, 스크롤 따라감) | 없음. 자동이고 인쇄에는 안 나온다 |
92
+ | 상단 바 | 포털 셸(72px · 고객사 / 문서 제목 / 도구) | 없음 |
93
+ | 검토 회신 | 포털 셸의 우측 패널 | **문서 안에 「댓글로 알려 주세요」 같은 문구를 쓰지 말 것.** 회신 자리는 이미 있다 |
94
+ | 핵심 요약 | 포털 셸의 팝업(누르면 생성) | 없음. 다만 **근거가 `source_json` 원문뿐**이라 절 제목·`lead`·`open_items` 가 부실하면 요약도 부실하다 |
95
+
96
+ 핵심 요약은 **발행 데이터가 있는 문서에만** 뜬다(MCP·API·편집기 서식 발행분). 파일로 올린
97
+ 문서에는 단추가 아예 안 나온다 — 요약할 원문이 없어서다.
98
+
99
+ ---
100
+
101
+ ## 3. 일러스트 — `assets[]`
102
+
103
+ **바이트를 직접 싣지 않는다.** `source` 에 원본 주소만 주면 MCP 가 받아와 규격대로 굳혀 보낸다.
104
+
105
+ ```json
106
+ "assets": [{
107
+ "id": "hero", "role": "hero", "provider": "higgsfield",
108
+ "alt": "…", "origin": "higgsfield:gpt_image_2:<job-id>",
109
+ "source": "https://…/hf_….png", "required": true
110
+ }]
111
+ ```
112
+
113
+ `mime`·`width`·`height` 는 **적지 않는다** — MCP 가 인코딩 결과에서 읽어 채운다.
114
+ 운영 문서가 1400×934 그림을 1400×1050 이라 선언해 브라우저가 세로로 12.4% 늘여 그린 적이 있다.
115
+ 선언을 안 받으면 그 결함이 구조적으로 안 생긴다.
116
+
117
+ ### 서버가 거절하는 것 (계약 7.1절)
118
+
119
+ | 조합 | 판정 |
120
+ |---|---|
121
+ | `role: hero`·`chapter` 인데 `provider ≠ higgsfield` | **거절** |
122
+ | `provider: deterministic` 인데 `role ≠ figure` | **거절** |
123
+ | `provider: user-provided` 인데 `origin` 이 빔 | **거절** |
124
+ | `provider: sample-exception` | **거절** (회귀 기준물 전용) |
125
+ | 선언한 `mime`/`width`/`height` 가 실물과 다름 | **거절** |
126
+ | 장당 80,000B · 합계 400,000B 초과 | **거절** |
127
+ | `alt` 누락 | 경고(발행은 된다) |
128
+
129
+ EOF 엔드카드만 `user-provided` 가 정상값이고, `origin` 에 제공자를 적는다.
130
+
131
+ > **꼬리 카드는 대개 안 준다**(2026-08-19). 서버가 기본 카드를 끼우므로 `assets[]` 에
132
+ > `role: eof` 를 넣을 이유는 **이 문서만의 카드가 있을 때뿐**이다. 그때도 규격이 다르다 —
133
+ > 무손실(PNG 또는 무손실 WebP) · **줄이지 않고 원본 크기** · 장당 상한 200,000B
134
+ > (일러스트의 80,000B 가 아니다). 기본 카드는 포털 **설정** 화면에서 관리자가 올린다.
135
+
136
+ ### 예산 실측 (2026-08-16, GPT Image 2 7장)
137
+
138
+ | | |
139
+ |---|---|
140
+ | 자산 합계 | 109,964B / 400,000B (**27%**) |
141
+ | 발행물 | 약 1,036,000B / 1,600,000B (**65%**) |
142
+
143
+ **흰 여백을 잘라내지 말 것.** 트림하면 오히려 **커진다**(7장 109,964B → 162,354B, +48%).
144
+ WebP 가 균일한 흰 면을 거의 공짜로 압축하는데, 잘라내면 같은 상자에 그림이 더 크게 들어가
145
+ 디테일 픽셀이 늘기 때문이다. 투명 배경은 3배가 된다(311,856B) — 문서 배경이 어차피 White 라 이득도 없다.
146
+
147
+ ---
148
+
149
+ ## 4. 요약 근거 게이트 — 발행이 **거절**된다
150
+
151
+ 계약 5.6.1절: 요약의 **모든 문단**은 근거로 삼은 **사례 번호**를 최소 하나 밝혀야 한다.
152
+
153
+ ```json
154
+ "summary": [{
155
+ "lead": "개선안을 운영 데이터에 적용하면 이용자 91.7%의 안내가 달라집니다.",
156
+ "body": "방향이 뒤집히는 분이 30.5%(§4.2), 근육 목표가 없어지는 분이 16.8%(§3.2)입니다."
157
+ }]
158
+ ```
159
+
160
+ | 함정 | 사실 |
161
+ |---|---|
162
+ | 「절 번호」가 아니다 | `§n.n` 은 **사례 번호**다. `{그룹 no}.{그 그룹 안 순번}` 으로 **계산**된다. `sections[].no`("01")를 적으면 거절된다 |
163
+ | `refs[]` 와 인라인 중 무엇을 쓰나 | **인라인 `§` 를 권장.** 둘 다 근거로 세지만, 인라인은 본문 필드라 편집기 왕복에서 확실히 살아남는다 |
164
+ | `§` 없는 맨 숫자 | 근거로 안 센다. `문제(3.1)` 는 죽은 활자이고 `문제(§3.1)` 는 링크가 된다 |
165
+
166
+ ---
167
+
168
+ ## 5. 출처 링크 문구 — `cases[].source_text`
169
+
170
+ 넷이 전부 "제보 원본 보기" 면 계약 10절 「목적을 알 수 있는 문구」를 못 지킨다.
171
+
172
+ ```json
173
+ { "source_url": "…", "source_text": "상담 원본 · 체성분 양호자 증량 문의" }
174
+ ```
175
+
176
+ 인쇄본에서는 URL 이 **안 펼쳐진다**(계약 8절) — 이용자 식별자가 들어간 관리 화면 주소가
177
+ 지면에 찍히던 것을 막은 규칙이다. 화면에서는 이 문구가 링크로 보인다.
178
+
179
+ ---
180
+
181
+ ## 6. 발행 전 자기 점검
182
+
183
+ - [ ] 요약 문단마다 `§n.n` 이 최소 하나 있고, 그 번호가 **실재**하는가
184
+ - [ ] hero·챕터 자산의 `provider` 가 전부 `higgsfield` 이고 `origin` 에 job 식별자가 있는가
185
+ - [ ] `mime`·`width`·`height` 를 **안 적었는가**(MCP 가 채운다)
186
+ - [ ] 챕터 `lead` 와 절 `lede` 를 **둘 다 쓰지 않았는가**
187
+ - [ ] `title_lines` 로 줄바꿈을 정했는가
188
+ - [ ] 출처 링크 문구가 서로 다른가
189
+ - [ ] 챕터 그림이 **가로로 긴** 비율인가(2열에서 반폭에 선다)
190
+ - [ ] 문서 안에 「댓글로」·「의견 주세요」 같은 문구가 없는가(회신 자리는 포털이 준다)
191
+
192
+ 발행 뒤에는 `get_report` 로 되읽어 자산 `provider`·`origin`·크기와 요약 근거를 눈으로 확인한다.
193
+
194
+ ---
195
+
196
+ ## 7. 운영 환경 제약 (렌더러를 고칠 때만)
197
+
198
+ | 제약 | 내용 |
199
+ |---|---|
200
+ | 파이썬 | 운영은 **3.6.8**. f-string 중괄호 식 안 **역슬래시 금지**(3.12+ 문법), walrus·match 금지 |
201
+ | 스타일시트 | 주석에도 `§n.n` 표기를 쓰지 말 것 — 절참조 게이트가 발행을 죽인다. 「5.1절」로 쓴다 |
202
+ | 인라인 `<svg>` | 편집기 일반 문서 경로의 입고 검사가 거절한다. 화살표는 문자(`↘`)나 CSS 로 |
203
+ | 편집기 | 챕터 오프닝 조각은 `<main>` **직계 형제**여야 한다. 감싸는 요소를 두면 절 이동이 남의 오프닝을 딸려 옮긴다 |
204
+
205
+ 로컬 파이썬이 3.12+ 면 첫 줄 함정이 **로컬에서 안 잡힌다.** 실제로 그 한 줄이 운영 발행을
206
+ 통째로 멈춘 적이 있다(2026-08-16). `tests/builder.test.py` 의 호환성 묶음이 그것을 읽어서 잡는다.
207
+
208
+ ## 절 앞에 세우는 두 블록 (2026-08-18)
209
+
210
+ 정본이 쓰던 서식인데 데이터 칸이 없어 못 만들던 둘이다. 이제 **쓰면 그려진다.**
211
+ 안 쓰면 안 그려진다 — 없는 문구를 지어내지 말 것.
212
+
213
+ ### `logic` — 대조 도해 (「무엇을 바꾸는가」가 한 장면일 때)
214
+
215
+ ```jsonc
216
+ { "kind": "summary",
217
+ "logic": {
218
+ "kicker": "CORE LOGIC",
219
+ "title_lines": ["‘다음 칸’이 아니라", "‘적정 상태’를 목표로 바꿉니다"],
220
+ "lede": "계산식이 아니라 목표로 삼는 도착점을 바꾸는 비교입니다.",
221
+ "models": [
222
+ { "label": "현재 방식", "flow": ["현재 상태", "인접 등급", "상한"], "body": "…" },
223
+ { "label": "개선 방식", "flow": ["현재 상태", "적정 체중", "그 상태"], "body": "…" }
224
+ ] } }
225
+ ```
226
+
227
+ 첫 모델이 「현재」, 그다음이 「개선」으로 그려진다 — **자리로 정한다.**
228
+ `flow` 의 **마지막 칸이 강조**된다(도착점). 단계 수는 자유다.
229
+
230
+ **언제 쓰나** — 바꾸는 것이 *값*이 아니라 *구조*일 때. 「A 를 B 로 고쳤다」는 건 카드에
231
+ 쓰고, 「도착점 자체가 달라진다」처럼 두 방식을 나란히 놓아야 이해되는 것만 여기 쓴다.
232
+
233
+ ### `principles` — 3열 카드 (규칙이 셋 안팎으로 나뉠 때)
234
+
235
+ ```jsonc
236
+ { "kind": "note",
237
+ "paragraphs": ["긴 설명은 그대로 여기에."],
238
+ "principles": [["적정 체중", "…"], ["체지방 목표", "…"], ["근육 유지", "…"]] }
239
+ ```
240
+
241
+ **번호는 주지 않는다** — 자리로 매겨진다. 순서를 바꾸면 번호도 따라온다.
242
+ 긴 문단은 `paragraphs` 에 그대로 두고, 카드에는 **짧은 제목 + 한두 문장**만 넣는다.
243
+ 카드가 문단의 요약이 되면 같은 말을 두 번 하는 문서가 된다.
244
+
245
+ **언제 쓰나** — 원칙·기준처럼 **병렬로 읽히는 규칙**일 때. 순서가 뜻을 가지면(1단계→2단계)
246
+ 카드가 아니라 문단이 맞다.
247
+
248
+ ## 발행 절차 — 초안으로 내고, 보고, 연다 (2026-08-18)
249
+
250
+ `publish_report` 는 **기본이 초안**이다. 만들어도 고객에게는 안 보인다.
251
+
252
+ ```
253
+ publish_report(… ) → 초안. 응답이 「아직 고객에게 보이지 않습니다」라고 말한다
254
+ ↓ 눈으로 확인
255
+ release_report(id) → 이때부터 고객 목록·열람에 뜬다
256
+ ```
257
+
258
+ 왜 이렇게 바뀌었나: 전에는 만드는 순간 고객이 볼 수 있었고 **물릴 방법이 없었다.**
259
+ 도구 설명의 「초안으로 올려 두고」는 「빈 칸이 있어도 발행이 막히지 않는다」는 뜻이었는데
260
+ 읽는 쪽은 「고객에게 아직 안 보인다」로 읽는다 — 그 둘은 결과가 정반대다.
261
+
262
+ | 도구 | 언제 |
263
+ |---|---|
264
+ | `publish_report(dry_run: true)` | 쓰기 전에 경고만 보고 싶을 때. 아무것도 저장하지 않는다 |
265
+ | `publish_report(publish: true)` | 확인이 끝났고 바로 열어도 될 때 |
266
+ | `release_report(id)` | 초안을 고객에게 열 때 |
267
+ | `unpublish_report(id, reason)` | 잘못 낸 것을 물릴 때. **지우지 않고 감춘다** — 이력은 남는다 |
268
+ | `update_report(dry_run: true)` | 이미 나간 링크를 덮기 전에 한 번 볼 때 |
269
+
270
+ 경고(`warnings`)는 이제 응답에 실린다. 그전에는 서버 로그로만 흘러 **에이전트가 볼 수
271
+ 없었고**, 그래서 「경고 없음」으로 읽혔다.
272
+