genetics-mcp 2.27.0 → 2.28.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.
Binary file
package/bin/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "aarch64-apple-darwin": "29f7251e4280479302e30ea07347cba90156b27a1b213d68b45d3d79024f2c5a",
3
- "aarch64-unknown-linux-musl": "b3afe23a3721e70304e5e44549990e718cdf84104268a4ebe74951dfccc129c8",
4
- "x86_64-apple-darwin": "3a7d05bba4a3f835f25f149ee304e24ac11034915fe091456ae7571e23b3f2f2",
5
- "x86_64-pc-windows-gnu": "b721bf3841d3dbf66774b662a33ece1f2996e7bc16b20b2ae722dd7580f6e04f",
6
- "x86_64-unknown-linux-musl": "b0f984221e5353aac43acefd603600b6b971a4ef29f075b919460baa7b8c6644"
2
+ "aarch64-apple-darwin": "ab17d9b3bd9a2a2c5f2ef788a79ff3898aa6a5fcc3ec536a96d4bdee9e964854",
3
+ "aarch64-unknown-linux-musl": "20cd63f8119812434e8cbfd38b4399049fe5cba8111a916c96221d922cadaf60",
4
+ "x86_64-apple-darwin": "7daaae4a0ff0e124c305d4b60ed726905fc8eb2ee21c5a77e8e3b858caaae354",
5
+ "x86_64-pc-windows-gnu": "5805d10cc17e9db2c4c0bbcf43b5ef2f5e99b1195cb53c8fd5aef1c1e91e62f2",
6
+ "x86_64-unknown-linux-musl": "010e6be4792373a0a867df05a8c5ff2babd5ad1e25f650b696ea09f1ba58f24f"
7
7
  }
Binary file
Binary file
Binary file
package/genetics.mjs CHANGED
@@ -1339,7 +1339,7 @@ const DEC_WHO = {
1339
1339
  * description 은 네 칸이 제 뜻 한 줄 뒤에 붙이는 한 문장이다(이 상수만 따로 나가는 자리는 없다 — 고칠 곳은 여기 한 곳).
1340
1340
  */
1341
1341
  const DEC_PROSE = {
1342
- description: '구조부터 — 견주기는 table · 차례는 steps · 이름→풀이는 items · 한 줄은 p · 한계는 note(블록 목록 — 블록마다 키 하나).',
1342
+ description: '구조부터 — 견주기는 table(칸 크기를 견주게 하려면 bar{col: 열 이름}) · 차례는 steps · 이름→풀이는 items · 한 예는 strip(칸 둘~셋 — 마지막이 결과) · 한 줄은 p · 한계는 note(블록 목록 — 블록마다 키 하나).',
1343
1343
  oneOf: [
1344
1344
  DEC_SENTENCE.oneOf[0],
1345
1345
  DEC_SENTENCE.oneOf[1],
@@ -1356,6 +1356,10 @@ const DEC_PROSE = {
1356
1356
  caption: { type: 'string', minLength: 1, maxLength: 80 },
1357
1357
  head: { type: 'array', minItems: 2, maxItems: 5, items: { type: 'string', minLength: 1 } },
1358
1358
  rows: { type: 'array', minItems: 1, maxItems: 12, items: { type: 'array', minItems: 2, maxItems: 5, items: DEC_SENTENCE } },
1359
+ bar: {
1360
+ type: 'object', properties: { col: { type: 'string', minLength: 1 }, max: { type: 'number', exclusiveMinimum: 0 } }, required: ['col'],
1361
+ description: '칸 막대 — 그 열(head 의 이름 그대로 · 첫 칸 빼고) 칸 글 앞의 수로 막대. 끝은 max, 없으면 칸이 모두 %면 100 · 아니면 그 열의 가장 큰 수.',
1362
+ },
1359
1363
  },
1360
1364
  required: ['head', 'rows'],
1361
1365
  },
@@ -1367,6 +1371,11 @@ const DEC_PROSE = {
1367
1371
  type: 'array', minItems: 1, maxItems: 12,
1368
1372
  items: { type: 'object', properties: { k: { type: 'string', minLength: 1, maxLength: 40 }, v: DEC_SENTENCE }, required: ['k', 'v'] },
1369
1373
  },
1374
+ strip: {
1375
+ type: 'array', minItems: 2, maxItems: 3,
1376
+ description: '예시 띠 — 한 예를 칸 둘~셋과 화살표로(「이 기간으로 배워 → 그다음 달을 맞혀 봄」). 칸은 k(머리 — 언제·무엇) · v(값 — 굵게) · s(곁말). 마지막 칸이 결과.',
1377
+ items: { type: 'object', properties: { k: DEC_SENTENCE, v: DEC_SENTENCE, s: DEC_SENTENCE }, required: ['v'] },
1378
+ },
1370
1379
  },
1371
1380
  },
1372
1381
  },
@@ -1428,7 +1437,7 @@ const DECISION_BRIEF = {
1428
1437
  type: 'object',
1429
1438
  properties: {
1430
1439
  diagram: { type: 'object', description: '설계 데이터(Archify IR) — 서버가 관보 그림으로 굽는다.' },
1431
- chart: { type: 'object', description: '차트 한 벌 — 그릴 행(rows)이나 점(points)이 있어야 한다.' },
1440
+ chart: { type: 'object', description: '차트 한 벌 — 그릴 행(rows)이나 점(points)이 있어야 한다. 절 charts[] 와 같은 꼴(범위 · 기울기 · 구성 띠 · 쌓은 막대 포함).' },
1432
1441
  plate: { type: 'string', description: '도판 id(assets[].id).' },
1433
1442
  caption: { type: 'string', description: '그림 캡션 — 번호 없이.' },
1434
1443
  source: { type: 'string', description: '출처 한 줄.' },
@@ -1789,7 +1798,7 @@ const REPORT_DATA = {
1789
1798
  + '그림 번호(`그림 5-1`)는 적지 않는다 — 자리가 매기고 `plates` 와 한 셈을 쓴다.\n'
1790
1799
  + '· `plates`: [assets[].id, …] — 절 본문 도판.\n'
1791
1800
  // ── 장치 목록에서 굽는 글 «tool-devices» — 손으로 고치지 않는다: python3 tools/contract-devices.py --write ──
1792
- + '· 시각 장치(정본 private/builder/devices.py — 둘 수 있는 칸 · 한도 · 만드는 법은 스킬 references/visual-first.md §4 표): 구조 → 구성도·도판(개념도) · 흐름 → 흐름도·절차도·데이터 흐름도 · 순서 → 순서도 · 상태 → 상태 변화도 · 변화 → 두 판 비교·도판(두 컷 비교) · 분포 → 막대 차트 · 시간에 따른 값 → 시계열 · 견주기 → 표·점 차트 · 원문 → 원문 인용·도판 · 화면 → 도판·화면 녹화. '
1801
+ + '· 시각 장치(정본 private/builder/devices.py — 둘 수 있는 칸 · 한도 · 만드는 법은 스킬 references/visual-first.md §4 표): 구조 → 구성도·도판(개념도) · 흐름 → 흐름도·절차도·데이터 흐름도 · 순서 → 표(사건 경과)·순서도 · 상태 → 상태 변화도 · 변화 → 기울기·두 판 비교·도판(두 컷 비교) · 분포 → 막대 차트·구성 띠 · 시간에 따른 값 → 시계열 · 견주기 → 막대 차트(수일 때)·점 차트·표(글이 섞일 때) · 원문 → 원문 인용·도판 · 화면 → 도판·화면 녹화. '
1793
1802
  + '구성도·절차도·순서도·데이터 흐름도·상태 변화도·두 판 비교는 도해 굽기가 켜진 서버에서만 새로 굽는다(포털 private/archify.on — 로컬 render.py 는 켜고 부른다) — 꺼진 서버는 굽혀 둔 그림만 싣고 새 그림은 같은 번호의 대기 상자로 둔다(「서버에서 실패한 그림이 N장」 — 원고를 고칠 일이 아니다). '
1794
1803
  + '화면 녹화는 영상 저장 연동(r2)이 켜진 서버에서만 — 꺼진 환경은 발행을 거절한다. '
1795
1804
  + '시각 우선(dry_run 이 ⚠ 로 센다 — 서식 문서 §10-1): 산문 400자 넘는 절에 표·흐름도·차트·원문 인용·도해·도판 가운데 하나도 없으면 ⚠, 문단 220자 안, 산문의 참조 번호 3개 이하, 판단 요청 6항 이상이면 한눈표+관문 흐름도, 3,000자 넘는 문서엔 핵심 굵게. '
@@ -1801,6 +1810,7 @@ const REPORT_DATA = {
1801
1810
  + 'kind 와 무관하게 쓴다(kind:status 의 `board_title` 대조표와는 다른 것 — 저건 건 전용이다). '
1802
1811
  + 'cols 는 열 제목, rows 는 행마다 cols 와 **같은 길이의 배열**(어긋나면 잘라 맞추고 ⚠ 로 센다). '
1803
1812
  + 'align 은 열마다 `l`·`r`·`c` — 수는 `r` 로 두어야 자릿수가 세로로 맞는다. '
1813
+ + 'bar{col: 열 이름, max?} 를 주면 그 열 칸 글 앞의 수로 칸 막대를 세운다(끝은 max, 없으면 칸이 모두 %면 100 · 아니면 그 열의 가장 큰 수) — 행끼리 크기를 견주는 열에만. '
1804
1814
  + 'note 는 표 아래 ※ 한정 조건, hint 는 그 아래 안내 한 줄. '
1805
1815
  + '표 번호(`표 5-1`)는 적지 않는다 — 자리가 매긴다. '
1806
1816
  + '⚠ caption 은 **라벨이지 산문이 아니다** — 20자 안쪽으로 두고 설명은 note 로 내려라 '
@@ -1813,11 +1823,16 @@ const REPORT_DATA = {
1813
1823
  + '그림 번호는 `flow`·`plates` 와 **한 셈**을 쓴다. 데이터가 있을 때만 그려진다 — 없는 문구를 지어내지 말 것.\n'
1814
1824
  + '· `charts[].ref`: [{value, label}] — **기준선**(점선). value 는 수(쉼표 표기 글자도 받음), label 은 원고 글자(「3초」「60초 한도」). 막대·시계열 모두. '
1815
1825
  + '`charts[].rows[].partial`: 참이면 그 행은 일부만 잰 값이라 막대 속을 비운다(행 이름 글자로 짐작하지 않는다). '
1816
- + '`charts[].form`: length(길이 — 0 기준선에서 뻗는 공통 축척 막대) · position(위치 — 같은 축 위의 점) — 없으면 막대는 length · 시계열은 position. '
1817
- + '셋 다 꼴이 틀리면 서버가 거절한다.\n'
1826
+ + '`charts[].form`: length(길이 — 0 기준선에서 뻗는 공통 축척 막대) · position(위치 — 같은 축 위의 점) · slope(기울기 — toggle{a,b} 두 축을 잇는 선, 묶음마다 a → b) · '
1827
+ + 'share(구성 띠 — rows[].value 가 한 덩이의 조각, 100% 띠 하나와 비율) — 없으면 막대는 length · 시계열은 position. '
1828
+ + '`charts[].rows[].range`: [아래, 위] — 점 차트(position)에서 값 둘레의 범위(옅은 막대). 범위를 쓰면 `range_key`(옅은 막대가 무엇인지 — 「달마다 오르내린 폭(95%)」) · '
1829
+ + '`value_key`(점이 무엇인지)를 함께 적는다 — 그림 위 한 줄로 서고, 값은 오른쪽 한 열에 세로로 맞는다. 0 이 기준이면 ref [{value: 0, label}] 로 「여기 닿으면 …」을 단다. '
1830
+ + '꼴이 틀리면 서버가 거절한다.\n'
1818
1831
  + '· `charts[].kind:"series"`: {kind:"series", caption, unit?, points:[{x,y}], marks?:[{x,label}], summary?:[{label,value,note?}], form?, ref?, note?} — '
1819
1832
  + '**시계열.** 하루·달 단위 값이 언제 계단을 만드는지 정지 SVG 로 보이고(기본은 점과 선 · form length 면 날마다 막대), 달마다 평균·최대를 글자 행으로 남긴다(그림이 안 보여도 문서가 선다). '
1820
- + 'x 는 YYYY-MM-DD 가 기본. marks[].x 는 어느 points[].x 와 같은 값이어야 선다(사건 세로선, 아니면 ⚠).\n'
1833
+ + 'x 는 YYYY-MM-DD 가 기본. marks[].x 는 어느 points[].x 와 같은 값이어야 선다(사건 세로선, 아니면 ⚠). '
1834
+ + '쌓은 막대: points[].parts(조각 수 — 아래부터, y 는 그 합) + parts:[{label, tone?}](조각 이름 — 그림 위 한 줄) · form "length". x 가 YYYY-MM 이면 막대마다 「3월」, 해가 바뀌는 자리에 「2026년」. '
1835
+ + 'marks[].detail: 사건 이름 줄 1~3(표식 이름 아래 — 「「네이버 로그인 버튼 클릭 오류」 394건」).\n'
1821
1836
  + '· `quotes`: [{text, lang?, source_text, source_url?, verdict?, translation?}] — **원문 인용.** 공식 문서·회신 문구를 원문 그대로 싣는다(표기 안 품, 줄바꿈 유지). '
1822
1837
  + 'source_text·source_url 둘 중 하나는 있어야 한다(없으면 ⚠). verdict 는 도판과 같은 축(직접 확인·조사 보고·미확인). 절 본문 맨 앞에 선다.\n'
1823
1838
  + '· `diagrams`: [{id?, caption, ir? | compare?, alt?, source_text?, verdict?, note?, wide?, origin?}] — **도해.** 설계 데이터를 넣으면 서버가 '
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genetics-mcp",
3
- "version": "2.27.0",
3
+ "version": "2.28.0",
4
4
  "description": "문서 포털 발행·세션 이식·사례 기억 MCP — 데이터를 주면 규격 문서가 나온다 (짝인 스킬 동봉)",
5
5
  "author": "주식회사 LIM (LIM Inc.)",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -19,9 +19,12 @@ import re
19
19
  # · `전환 완료. 4건은 …` 은 `4` 뒤가 마침표가 아니라 안 걸린다.
20
20
  # · `1. 첫째. 2. 둘째.` 처럼 사이에 글이 낀 열거도 안 걸린다.
21
21
  # · 앞이 숫자·마침표면 제외해 온전한 연도 꼴의 뒷부분을 물지 않는다(연도 꼴이 먼저 걸리므로 이중 방어).
22
+ # · 뒤에 시각(`10. 8. 09:40 켬`)이 와도 날짜다 — 「뒤에 숫자 금지」가 시각까지 막아 `10.` / `8.` / `09:40 켬`
23
+ # 세 줄로 쪼개졌다(2026-10-08, 관보 v3 시험 문서 #238 표 칸). 뒤 숫자가 `H:MM`·`HH:MM` 의 머리일 때만 풀고,
24
+ # `9. 8. 7.` 처럼 수가 하나 더 붙는 꼴은 그대로 날짜로 안 본다.
22
25
  DATE = re.compile(
23
26
  r'\d{4}\.\s*\d{1,2}\.(?:\s*\d{1,2}\.)?' # 2026. 8. 21. / 2026. 8.
24
- r'|(?<![\d.])\d{1,2}\.\s*\d{1,2}\.(?!\s*\d)' # 9. 8. (연도 없는 달·일)
27
+ r'|(?<![\d.])\d{1,2}\.\s*\d{1,2}\.(?!\s*\d(?!\d?:\d))' # 9. 8. · 10. 8. 09:40 (연도 없는 달·일 — 뒤 시각은 허용)
25
28
  )
26
29
  TAG = re.compile(r'<[^>]*>')
27
30
 
@@ -115,6 +118,10 @@ if __name__ == '__main__':
115
118
  ("9. 10. 출시됨", 0),
116
119
  ("9. 8.", 0),
117
120
  ("전체 출시가 9. 10. 에 끝났음. 아이폰은 대기임.", 1),
121
+ # 연도 없는 날짜 뒤 시각 — 2026-10-08 실측. 고치기 전엔 여기서 0 대신 2 가 나왔다
122
+ # (관보 v3 시험 문서 #238 표 칸 「10. 8. 09:40 켬」이 세 줄로 쪼개진 자국).
123
+ ("10. 8. 09:40 켬", 0),
124
+ ("스위치는 10. 8. 9:40 에 켬. 그 뒤 실패는 0 임.", 1),
118
125
  # 그 마스크가 삼키면 안 되는 것들 — 위 넷을 고치면서 깨지기 쉬운 자리.
119
126
  # 둘 다 옛 정규식과 **경계 수가 같음**을 대조로 확인함(2026-09-11, 8표본 중
120
127
  # 달라진 것은 연도 없는 날짜 하나뿐).
@@ -194,7 +194,7 @@ export function analyze(raw0) {
194
194
  // 날짜(2026. 8. 21.)·버전(iOS 26.4)·경로(api.php)는 문장 끝이 아니므로 먼저 가린다.
195
195
  const BLOCK = /<(p|li|td|dd|figcaption)\b[^>]*>([\s\S]*?)<\/\1>/g;
196
196
  // 연도 없는 점 날짜(8. 21.)도 문장 끝이 아니다 — 안 가리면 부정 종결의 문맥 창이 밀린다.
197
- const DATE = /\d{4}\.\s*\d{1,2}\.(?:\s*\d{1,2}\.)?|(?<!\d)\d{1,2}\.\s*\d{1,2}\.(?!\s*\d)/g;
197
+ const DATE = /\d{4}\.\s*\d{1,2}\.(?:\s*\d{1,2}\.)?|(?<!\d)\d{1,2}\.\s*\d{1,2}\.(?!\s*\d(?!\d?:\d))/g; // 뒤 시각(10. 8. 09:40)은 날짜 — boundary.py DATE 와 같은 식
198
198
  const BOUND = /(?<=[가-힣0-9)\]」』”'"A-Za-z])[.!?]\s+(?=[가-힣0-9「『※(\[]|[A-Z])/g;
199
199
  const runOn = [];
200
200
  const blockTexts = []; // ②b-3 이 같은 블록 단위를 다시 쓴다
@@ -33,6 +33,9 @@ test('한 문장 한 줄 — 회귀(기존 검사 유지)', () => {
33
33
  assert.equal(pos(bad.runOn.length), 1);
34
34
  const good = analyze('<p><span class="sn">첫 문장임.</span> <span class="sn">둘째 문장임.</span></p>');
35
35
  assert.equal(good.runOn.length, 0);
36
+ // 연도 없는 날짜 뒤 시각(10. 8. 09:40)은 문장 끝이 아니다 — 표 칸 하나를 「두 문장 한 덩어리」로 세지 않는다(2026-10-08 관보 v3 표 칸이
37
+ // 렌더러에서 세 줄로 쪼개진 꼴 · boundary.py DATE 와 같은 식). 고치기 전 식은 여기서 1 을 냈다.
38
+ assert.equal(analyze('<table><tr><td>10. 8. 09:40 켬</td></tr></table>').runOn.length, 0);
36
39
  });
37
40
 
38
41
  test('학생 보고서투 — 교대항 전수(하나를 빼는 뮤테이션은 여기서 죽는다), 「조사 결과」는 안 잡는다', () => {
@@ -213,7 +213,7 @@ Lim 보고서, Lim 에 올려줘, 고객 보고서, 수정 내역, 검수 요청
213
213
  | 1 | **한 장 이야기** | 문제 → 원인 → 해법(지금 상태 포함) → 정할 것. 칸 수가 아니라 이야기 순서다 — 요지 칸 수는 4~6단계 「요지」 한 곳이 정본. 다루는 일의 **사건 경과** 표 한 장을 1절에 둔다(이 문서의 판 이력은 `history` — 3c) |
214
214
  | 2 | **예시 한 명** | 실존 이용자 하나의 실제 숫자로 문서 전체를 관통시킨다(같은 사람이 그림·표·건에 반복) |
215
215
  | 3 | **용어 잠금 표** | 같은 낱말이 두 값을 가리키면 그 자리에서 문서가 죽는다. 뜻이 갈리는 낱말은 표 한 장으로 값·정의·보이는 자리를 박는다. **이름 열은 0단계 이름 대응표(물음 5)의 독자 화면·문서 이름에서만 가져온다** — 표에 정의했다고 작업하며 지은 이름이 독자의 말이 되지는 않는다(경위: `references/history.md` §16). 장치 이름(건 행 `labels` 값)은 절 이름·부제·표 열·캡션에 다시 쓰지 않고, 선택지 기호(A·B·C)는 한 목록에만 붙인다. **이 스킬이 선택지를 부르는 「길」·「바꾸면/그대로 두면」도 장치 이름이다** — 원고에서는 선택지를 그것이 실제로 무엇인지(고객이 부르는 이름)로 부르고, 물건을 비유로 부르지 않는다(반드시 지키는 것 12). 집행자: `gazette.py` `text_scan()` ⚠(건 행 이름 충돌·선택지 기호 충돌·「길」) · 독자 검토 first-time 관점(한 낱말 두 값) · 뜻이 같은지·비유인지는 사람 눈 |
216
- | 4 | **절마다 시각 장치 먼저** | <!-- 장치 목록에서 굽는 글 «skill-row» — 손으로 고치지 않는다: python3 tools/contract-devices.py --write -->내용 모양이 장치를 고른다 — 구조는 구성도·도판(개념도), 흐름은 흐름도·절차도·데이터 흐름도, 순서는 순서도, 상태는 상태 변화도, 변화는 두 판 비교·도판(두 컷 비교), 분포는 막대 차트, 시간에 따른 값은 시계열, 견주기는 표·점 차트, 원문은 원문 인용·도판, 화면은 도판·화면 녹화. 둘 수 있는 칸 · 서버 조건 · 한도 · 만드는 법은 `references/visual-first.md` §4 장치 표(정본 `private/builder/devices.py`). 글은 그 옆 3줄<!-- /장치 목록 «skill-row» --> |
216
+ | 4 | **절마다 시각 장치 먼저** | <!-- 장치 목록에서 굽는 글 «skill-row» — 손으로 고치지 않는다: python3 tools/contract-devices.py --write -->내용 모양이 장치를 고른다 — 구조는 구성도·도판(개념도), 흐름은 흐름도·절차도·데이터 흐름도, 순서는 표(사건 경과)·순서도, 상태는 상태 변화도, 변화는 기울기·두 판 비교·도판(두 컷 비교), 분포는 막대 차트·구성 띠, 시간에 따른 값은 시계열, 견주기는 막대 차트(수일 때)·점 차트·표(글이 섞일 때), 원문은 원문 인용·도판, 화면은 도판·화면 녹화. 둘 수 있는 칸 · 서버 조건 · 한도 · 만드는 법은 `references/visual-first.md` §4 장치 표(정본 `private/builder/devices.py`). 글은 그 옆 3줄<!-- /장치 목록 «skill-row» --> |
217
217
  | 5 | **판단 요청** | 결정 요청은 결정 블록의 칸(물음·기한·선택지·대칭 표)이 진다 — `references/decision-format.md`. 보고 모드의 판단 항목(검수 확인 요청)은 제목 「~ 요청」 · 본문 첫 문장 기한(5a) · 모양은 `references/visual-first.md` §5. 화면이 바뀌는 결정은 어느 모드든 도안까지(같은 §5 「화면 도안」). 집행자: `gazette.py` `brief_checks()` ⚠(기한) · ⚠ W1(권고 낱말) · 도안 유무는 **없음 — 사람의 눈**(`references/process.md` 7단계 표) |
218
218
  | 5a | **원본·증거 확인** | 주장·그림마다 원본을 **댈 수 있어야** 한다. 화면·흐름·화면 문구·동작을 말하는 문장(관찰 주장)은 **독자가 문서 안에서 볼 증거**를 그 건·절에 둔다 — 실제 캡처·녹화·원문 인용·외부 문서(센 대상이 있는 표는 수·대조 결과의 증거 — 화면 주장은 표만으로 받치지 않는다). 도안(「— 도안」·「— 재현」·「실제 화면 아님」, AI 로 만든 합성 그림)은 설명이지 증거가 아니고, 「— 합성」(실제 캡처 + 옮겨 적은 글자)은 증거다. 없으면 찍어 싣거나, 우리가 안 본 것이면 `remaining` 으로 옮긴다 — 「화면 미확인」「코드상」 같은 헤지 낱말과 확인 방법 끝 「…에서 봄」은 증거가 아니다. 출처 줄은 위치 한 구절(우리 도안은 비움 — 캡처는 8b), 원본 이름·찾을 낱말은 건(`source_url`·`how_to_check`)이나 부록에, 제작 메타는 `origin` 으로(`references/readability.md` R12e·R14 · 11번). 집행자: `gazette.py` `evidence_scan()` ⚠ · `gazette.py` `plate_scan()` ⚠(작은 캡처) · 독자 검토 evidence 관점 · source 관점(누를 수 있는 원본) · facts 관점(앱 동작·내부 수치·결정 주체) · `gazette.py` ⚠ W2 · `text_scan()` 제작 메타 ⚠ — 그 밖은 사람 눈 |
219
219
  | 6 | **표기** | 인라인 표기(`**굵게**`·`==강조==`·`{{ok|칩}}`·`[글자](주소)`·**맨 주소**)와 절·PART 의 `tone`, 차트 행 `tone`, 건의 `source_url`, 요약면 `notice.state`. 그림 가리킴은 손으로 번호를 치지 않고 `{{그림:<assets id>}}` 토큰으로(번호·조사를 렌더러가 셈 — `lim-portal-format.md` §11-6). 색은 뜻으로(`lim-portal-format.md` 「11-6. 인라인 표기」) |
@@ -109,6 +109,7 @@
109
109
  "question": "다음 분기에 검색 방식을 바꿀까?",
110
110
  "due": { "date": "2026-11-20", "why": "다음 분기 운영비가 11. 24. 예산 회의에서 정해져 그 전에 방식이 정해져야 함" },
111
111
  "now": "직원용 자료 검색은 지금 질문의 낱말이 자료에 그대로 있을 때 자료를 찾는 방식임. 시험한 {{이름:q200}}개 질문 가운데 78개는 {{이름:first-screen}}에 원하는 자료가 나오지 않았음.",
112
+ "figures": [{"chart": {"caption": "첫 화면에 원하는 자료가 나온 질문", "unit": "%", "rows": [{"label": "지금 방식", "value": "61", "note": "122개"}, {"label": "방식 A", "value": "82", "note": "164개", "tone": "info"}], "note": "같은 질문 200개 · 검증 환경에서 잼"}, "caption": "첫 화면에 원하는 자료가 나온 질문 — 같은 질문 200개", "source": "검색 시험 · 대장 2.1"}],
112
113
  "settled": [
113
114
  { "text": "검색 개선 예산을 다음 분기 예산 회의 안건으로 올리기로 정하심", "by": "customer", "record": "2026-09-18 예산 회의록" }
114
115
  ],
@@ -156,6 +157,7 @@
156
157
  "question": "검색 결과 화면을 어느 모양으로 둘까?",
157
158
  "due": { "date": "2026-12-04", "why": "새해 첫 주 사내 공지 전에 화면이 바뀌어 있어야 함" },
158
159
  "now": "검색 결과는 지금 제목 한 줄씩 10건이 목록으로 섬. 자료의 날짜와 담당 부서는 결과를 눌러 열어야 보임.",
160
+ "figures": [{"chart": {"caption": "원하는 자료를 먼저 찾은 도안", "unit": "명", "rows": [{"label": "도안 1 · 날짜 붙은 목록", "value": "7"}, {"label": "도안 2 · 카드", "value": "3"}], "note": "직원 10명 · 인쇄한 도안으로 잼 — 실제 화면과 같은 조건 아님"}, "caption": "원하는 자료를 먼저 찾은 도안 — 직원 10명", "source": "도안 시험 · 대장 2.2"}],
159
161
  "options": [
160
162
  {
161
163
  "id": "keep-list",
@@ -231,7 +233,7 @@
231
233
  "facts": [
232
234
  {
233
235
  "id": "hit-rate",
234
- "text": "같은 질문 200개에서 첫 화면에 원하는 자료가 나온 질문이 지금 방식 122개(61%), 방식 A 164개(82%)였음.",
236
+ "text": "같은 질문 200개에서 첫 화면에 원하는 자료가 나온 질문은 방식 A 쪽이 42개 많았음.",
235
237
  "basis": "tested",
236
238
  "where": "replica",
237
239
  "source": [{ "case": "srch01" }, { "ledger": "2.1" }],
@@ -260,7 +262,7 @@
260
262
  },
261
263
  {
262
264
  "id": "designs-shown",
263
- "text": "직원 10명에게 두 도안을 보이자 7명이 날짜 붙은 목록에서, 3명이 카드에서 원하는 자료를 먼저 찾았음.",
265
+ "text": "직원 10명에게 인쇄한 두 도안을 보이자 날짜 붙은 목록에서 원하는 자료를 먼저 찾은 사람이 더 많았음.",
264
266
  "basis": "tested",
265
267
  "where": "simulated",
266
268
  "source": [{ "ledger": "2.2" }],
@@ -12,7 +12,7 @@
12
12
  |---|---|---|
13
13
  | 필수(거절) | 결정마다 `name` · `question` · 선택지 둘 이상의 `name` · `line`, 공개 때 `reply_to.who` | 서버가 거절한다(`reply_to.who` 만은 초안 · dry_run 에서 알림) |
14
14
  | 권함(⚠) | `due` · `now` · 결정에 닿는 `facts` · `no_reply` | 거절하지 않는다 — 결정 이름 아래 ⚠ 한 줄. 화면에 「기한 없음」을 짓지 않는다 |
15
- | 선택(쓰면 서고, 안 쓰면 그리지 않음) | `options[].rows`(행 여섯) · `options[].cost` · `figures`(그림 칸 — 장치 표 `visual-first.md` §4) · `opinion` · `confirms` · `risks` · `unknowns` · `names` 와 그 밖의 칸 | 그 행 · 블록이 없다 — 빈 값 말을 짓지 않는다. 대칭: 한 선택지에 쓴 행 · 돈은 모든 선택지가 쓴다(한쪽만 쓰면 거절) |
15
+ | 선택(쓰면 서고, 안 쓰면 그리지 않음) | `options[].rows`(행 여섯) · `options[].cost` · `figures`(그림 칸 — 수를 견주면 먼저 쓴다(2절) · 장치 표 `visual-first.md` §4) · `opinion` · `confirms` · `risks` · `unknowns` · `names` 와 그 밖의 칸 | 그 행 · 블록이 없다 — 빈 값 말을 짓지 않는다. 대칭: 한 선택지에 쓴 행 · 돈은 모든 선택지가 쓴다(한쪽만 쓰면 거절) |
16
16
 
17
17
  - **돈** — 쓰면 `state`(듦 · 안 듦 · 모름)만 필수, `known_when`(언제 아나) · `payer`(누가 내나)는 아는 것만. 금액 · 견적 · 공수는 싣지 않는다 — 돈이 드는지는 고객의 고충이고 견적은 우리 과정이다.
18
18
 
@@ -33,7 +33,7 @@
33
33
 
34
34
  - **결정 하나는 물음 하나다.** 「화면 개선」처럼 여러 물음의 묶음이면 고객이 실제로 고를 물음마다 나눈다. 원고에 물음이 없으면 지어내지 말고 `question` 을 빈 값으로 둔다 — 그 빈 값이 사용자에게 물을 자리다.
35
35
  - **선택지는 그대로 두는 길까지다.** 그 길이 없으면 `no_current_why` 에 까닭을 적는다. `what` 에는 실제로 하는 일과 그 일이 끝나거나 풀리는 조건까지 쓴다 — 선택지 한 줄 · 대칭 표가 이미 말한 것은 되풀이하지 않는다.
36
- - **글 칸을 채우기 전에 구조부터 찾는다**(`now` · `what` · `facts_lead` · `opinion`). 여럿을 같은 잣대로 견주면 `table`, 순서와 누가 하는지가 있으면 `steps`, 이름 → 설명이면 `items`, 다른 칸이 이미 말했으면 지운다. 남는 말만 한 줄(`p`) · 한정(`note`)으로 쓴다 — 이 넷은 그 블록 목록을 받는다(꼴은 도구 스키마 `DEC_PROSE`). 구조가 없는 칸만 문장으로 쓴다(2026-10-08 사용자 「메타인지」). 본보기 `assets/example/decision.json` 의 「검색 방식」 의견 · 「방식 A 로 바꾸기」 설명 · 결과 화면 도안 둘의 설명이 이 꼴이다.
36
+ - **글 칸을 채우기 전에 구조부터 찾는다**(`now` · `what` · `facts_lead` · `opinion` · 사실 줄). **수를 둘 이상 견주면 그림 칸 차트(`figures[].chart`)가 먼저다** — 한 덩이의 구성은 구성 띠(`form: share` — 값이 % 면 % 그대로 · 합 100), 건수 · 비율 견주기는 막대(`length`), 흔들림이 있는 값은 점과 범위(`position` + `rows[].range`), 두 조건 사이 변화는 기울기(`slope`), 달마다 건수는 쌓은 막대(시계열 `parts`). 그린 수는 글에서 다시 늘어놓지 않는다 — 사실 줄은 그 결과 한 줄과 근거(어디서 · 어떻게 셌나)다. 수를 견주는 글이 두 곳 이상인데 차트가 없으면 결정 장 알림이 선다(2026-10-11 — 그 전에는 이 줄이 견주기를 표로만 보내, 실제 결정 문서가 결정 8 · 숫자 견줌 문장 14 · 차트 0 으로 나갔다). 글이 섞인 견줌은 `table`(한 열의 크기를 행끼리 견주면 `bar{col}` — 칸 막대), 순서와 누가 하는지가 있으면 `steps`, 이름 → 설명이면 `items`, 한 예를 보이면 `strip`(칸 둘~셋 — 마지막 칸이 결과이고 앞 문장에 「예를 들면」), 다른 칸이 이미 말했으면 지운다. 남는 말만 한 줄(`p`) · 한정(`note`)으로 쓴다 — 이 넷은 그 블록 목록을 받는다(꼴은 도구 스키마 `DEC_PROSE`). 구조가 없는 칸만 문장으로 쓴다(2026-10-08 사용자 「메타인지」). 본보기 `assets/example/decision.json` 의 「검색 방식」 의견 · 「방식 A 로 바꾸기」 설명 · 결과 화면 도안 둘의 설명이 이 꼴이다.
37
37
  - **한쪽만 문장인 행**(다른 쪽은 빈 값)은 알림이 선다 — 채울 수 있으면 채우고, 정말 모르면 그대로 두어 독자가 깊이 차이를 보게 한다.
38
38
  - **사실은 결과 문장이다.** 측정 조건·도구·환경은 사실 문장에 싣지 않는다. 근거 종류는 `basis`, 독자가 볼 증거는 `source` 가 진다 — 직접 본 것(`seen`)은 도판·원본 주소·건 가운데 하나가 있어야 하고, 대장의 우리 글만으로는 받지 않는다. 사실을 빼려면 데이터에서 지운다(그 차분이 사용자 보고에 실린다).
39
39
  - **판단은 `opinion` 하나에만 선다.** 다른 칸·첫 화면·제목·표에 「권고」「맞다고 봄」을 두지 않는다. 의견이 없으면 빈 값으로 둔다.
@@ -93,6 +93,7 @@
93
93
  - 깊이 비대칭(한 행에서 한쪽은 문장, 다른 쪽은 빈 값) — 2절.
94
94
  - 권고 낱말이 의견 칸 밖에 있음 — 그 문장을 `opinion` 으로 옮기거나 사실 문장으로 고친다.
95
95
  - 회신 받는 사람이 빔 — 공개 전에 채운다.
96
+ - 수를 글로 견줌(그림 칸에 차트 없이 수를 둘 이상 견주는 글이 두 곳 이상) — 2절 「구조부터」대로 그 수를 그림 칸 차트로 옮기고 사실 줄은 결과 한 줄과 근거로 줄인다. 한 덩이를 이루지 않는 비율(겹치는 %)은 구성 띠가 아니라 막대다.
96
97
  - 그 밖(해라체·과정 어휘·반려 이름·날짜·도판·증거)은 `lim-portal-format.md` §10·§10-1 의 같은 문구다.
97
98
  - 보고 모드의 길이 상한(문장·표 칸·문단·판단 항목 220자 네 문장·요약) · 「글로만 서 있습니다」 · 여백 주석 · 번호 가리킴(W5·XREF) · 브리핑 넷 · 요약면 막대 대조는 결정 모드에서 돌지 않는다. 그 자리가 조용한 것은 통과가 아니라 칸이 그 뜻을 진다는 뜻이다 — 칸이 지지 못하는 넷(선택지 사이 서술 깊이 · 판단이 문장 칸에 섞임 · 말투 · 고객이 못 여는 링크)은 6절의 독자가 본다.
98
99
 
@@ -272,3 +272,12 @@ D1(판정표 줄 번호)·v4.2(작업하며 붙인 정책 판 번호)는 작업
272
272
  안내 → 글자 경고 → 「경고 0」을 맞추려고 도해를 뺌, 관문 처방 문구에서 도해 누락. 대표 결정(2026-10-07)으로 서식은 하나(결정 블록이 있으면 결정 모드)이고,
273
273
  장치는 목록 한 벌(`private/builder/devices.py`)에서 렌더러가 읽고 스킬 · 도구 설명이 굽히며, 목록에 없는 장치 · 옵션을 말하면 `tools/contract-drift.py` 가 빨갛게 센다.
274
274
  결정 블록을 권하는 알림도 낱말이 아니라 내용(요청 절 판단 항목의 기한 + 선택지)으로 선다. 로컬 `render.py` 는 도해 굽기를 켜고 부른다 — 꺼진 채 「⚠0」을 맞추던 길이 도해를 지웠다.
275
+
276
+ ## 21. A4 쪽 — 맥나마라 (2026-10-08) — `process.md` 사람의 눈 표 「인쇄 미리보기」 행 · 결정 모드 문단
277
+
278
+ v3 결정 모드는 화면 첫 창에 할 일 목록이 들게 하려고 1쪽 단독 표지를 걷었고(§19 ③ · 설계 13-3), 인쇄는 쪽을 짜지 않고 화면 흐름을 쪽 나눔 규칙으로 잘랐다.
279
+ 확인은 화면 요소 개수 · 시험 · `dry_run` 경고 0 으로만 했다. 사용자(2026-10-08): 「v3 관보에서 잘못된 부분이 있다면, A4인쇄에 적합하지 않다는거임. 1p (표지)라는 개념이
280
+ 사라져버린 것 같음. … markdown느낌으로 바뀌어버렸다고 해야되나? … 맥나마라 오류 발생한 것 같은데?」. 같은 렌더러로 뽑은 A4 PDF 에서 1쪽이 표지 머리 + 목록 + 쪽번호 1,
281
+ 결정 첫 쪽에 장 머리 세 줄만(본문 옆 이름 칸 격자의 머리에 건 `break-after: avoid` 가 격자째 다음 쪽으로 밀었다), 구조 칸 표가 종이 폭(그 칸 440~459px)에서 칸마다 접힘,
282
+ 표 칸 「10. 8. 09:40」이 세 줄이었다. 처방: 화면 첫 창은 그대로 두고 종이에서만 1쪽이 v1 표지 단독(쪽번호 없음)으로 선다 — 렌더러가 머리를 한 상자로 묶고 인쇄 규칙이 한 면을 채운다.
283
+ 쪽이 섰는지는 A4 PDF 를 뽑아 v1 본보기와 쪽 차례를 나란히 보고 정한다 — 화면 요소 개수 · 시험 통과는 그 확인이 아니다.
@@ -501,6 +501,7 @@ python3 assets/render.py <report.json>
501
501
  | 절 N 「이름」이 글로만 서 있습니다(M자) — 장치 목록의 절 장치 중 하나를 세우십시오 | 산문 400자 이상인데 장치 목록(`private/builder/devices.py`)의 절 장치 0. 건 절(`kind:"cases"`)은 건 다섯 칸의 글과 건에 묶인 표·인용·도판까지 함께 잰다(2026-10-01 — 전에는 건 절이 셈 밖이라 그림 0 인 공개판이 ⚠0 이었다) | 그 절의 요지를 표·흐름도·차트·원문 인용·도해·도판 가운데 하나로 세운다 — 고르는 법은 내용 모양(`visual-first.md` §4 장치 표) |
502
502
  | %s 인용 %d 에 출처 줄이 없습니다 — 원본 위치 한 구절(주소·쪽·행)을 적습니다 | `quotes[]` 에 `source_text`·`source_url` 둘 다 없다(`%s` 는 「절 N」 또는 「건 NN-n」) | 원문의 위치 한 구절(주소·쪽·행)을 적는다(§11-8) |
503
503
  | %s 도해 「%s」의 글자가 표시 %dpx 로 섭니다 — %dpx 이상이 되게 wide 로 두거나 노드를 줄입니다 | 굽은 도해의 가장 작은 font-size × (표시 폭 ÷ viewBox 폭) < 15px(readability R1 과 같은 잣대 — 고정 판이 15px 로 굽으므로 대개 서지 않는다) | `wide: true` 로 전폭에 세우거나 노드·라벨을 줄인다(§11-9) |
504
+ | 절 %s 차트 「%s」 — 구성 띠(form "share")의 %% 값 합이 %s 입니다 — 한 덩이의 조각이 아니라 겹치는 비율이면 막대(form "length")로 그립니다 | `form:"share"` · `unit:"%"` 인데 조각 값의 합이 100 에서 1.5 넘게 벗어난다 — 구성 띠는 한 덩이를 100 으로 나눠 그리므로 겹치는 비율(「1위가 맞음 39.9% · 셋 안 56.0%」)을 넣으면 모양이 거짓이 된다 | 겹치지 않는 조각으로 다시 나누거나(「후보 2~3위 16.1%」처럼 차를 셈) 막대로 그린다 |
504
505
  | 절 %s 시계열 「%s」의 표식 「%s」가 점에 없습니다 — marks[].x 는 points[].x 와 같은 값이어야 섭니다 | `charts[].marks[].x` 가 어느 `points[].x` 와도 같지 않다 | 점의 x 값 그대로 적는다(§11-7) |
505
506
  | 절 %s 시계열 「%s」의 표식 라벨 「%s」와 「%s」가 %.0fpx 겹칩니다 — 라벨을 줄이거나 하나를 빼고 세로선만 남깁니다 | 표식 라벨은 전부 같은 높이(`T+13`)에 서고 렌더러가 밀어내지 않는다 — 가까운 표식 둘의 글자가 포개진다. 폭은 전각 1.0 · 공백 0.28 · 그 밖 0.55 로 어림한다(`_lblw`) | 라벨을 줄이거나, 하나는 `label` 없이 두어 세로선만 남긴다(§11-7) |
506
507
  | 절 %s 도해 「%s」의 svg 칸(미리 구운 SVG)은 싣지 않습니다 — %s | `diagrams[].svg` — 작성자가 굳혀 넣던 SVG 칸은 2026-10-07(설계 문서 10 의 4번)부터 싣지 않는다. 원본(설계 데이터)이 문서 밖에 남아 다시 굽거나 고칠 수 없었다. 같은 칸에 `ir` · `compare` 가 있으면 그것을 굽고, svg 칸만 있으면 그림 번호도 안 잡는다 | 구조 · 흐름 · 순서 · 상태 그림은 설계 데이터(`ir`)로 넣는다 — 서버가 굽는다. 수치 · 띠 그림은 차트(§11-4 · §11-7)나 도판(§11-1)으로 |
@@ -461,7 +461,8 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
461
461
  | 사람의 눈 | 이 문서가 **이 독자에게 맞는가** | 판단 |
462
462
 
463
463
  결정 모드는 독자 검토 층이 다르다 — 공개 문서마다 원고를 모르는 독자 한 번, 점수 없이 막힌 자리만(`decision-format.md` 6절).
464
- 아래 사람의 눈 표 가운데 표지 · 요약면 · PART 간지 · 여백 주석 · 의견 한 절 · 선택지 이름·순서 대조 행은 그 모드에 자리가 없다 — 첫 화면 머리와 결정 장이 서고, 선택지는 `options[]` 한 곳에서 찍힌다.
464
+ 아래 사람의 눈 표 가운데 요약면 · PART 간지 · 여백 주석 · 의견 한 절 · 선택지 이름·순서 대조 행은 그 모드에 자리가 없다 — 첫 화면 머리와 결정 장이 서고, 선택지는 `options[]` 한 곳에서 찍힌다.
465
+ 표지 행은 종이에서 본다 — 화면 첫 창은 머리 한 띠지만 인쇄하면 1쪽이 v1 표지 단독(쪽번호 없음)이다(경위: `references/history.md` §21).
465
466
 
466
467
  ### `dry_run` 이 실질적 유일한 품질 관문이다
467
468
 
@@ -553,7 +554,7 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
553
554
  | 본문 전체 | 진행 상태 어휘(정해짐·회신 대기·N판)·개수로 상태를 세는 캡션·직전 판과의 비교(「~ 그대로」)가 남았는가. 정해진 것은 사실로 배경에, 결정 요청에는 지금 열린 것만 — 기계는 **낱말과 개수로 상태를 세는 표 제목**까지 잡는다(`gazette.py` 과정 어휘 ⚠ · readability R11h). 표 제목 밖의 개수 표현·「~ 그대로」 비교는 사람의 눈 |
554
555
  | 부록 | 본문에서 실제로 참조되는 것만 있는가 |
555
556
  | 판권지 | 문서가 여기서 닫히는가. 꼬리 카드가 붙어 있으면 구버전이다 |
556
- | 인쇄 미리보기 | 절마다 새 쪽에서 시작하는가. 표가 쪽 경계에서 잘리지 않는가 |
557
+ | 인쇄 미리보기 | 절마다 새 쪽에서 시작하는가. 표가 쪽 경계에서 잘리지 않는가. 결정 모드는 1쪽이 표지 단독(쪽번호 없음)인가, 결정 장 머리가 그 본문과 같은 쪽에 서는가, 표가 표로 서는가(칸마다 접히지 않는가) — 미리보기 대신 A4 PDF 를 뽑아 v1 본보기와 쪽 차례를 나란히 본다(`gazette-report` `scripts/pdfcheck.sh` → `pdftoppm`). 화면 요소 개수는 이 행의 확인이 아니다(§21) |
557
558
 
558
559
  이 표의 행 가운데 기계가 일부만 잡는 것은 행 끝에 그 한계를 적었다. 틀 · 의견 자리 · 도안 유무 · 원본을 쟀는지 · 선택지 사이 대칭 · 날짜는 여전히 이 표가 그물이다(경위: `references/history.md` §4·§7·§8·§12).
559
560
 
@@ -64,11 +64,13 @@
64
64
  <!-- 장치 목록에서 굽는 글 «device-table» — 손으로 고치지 않는다: python3 tools/contract-devices.py --write -->
65
65
  | 장치 | 내용 모양 | 둘 수 있는 칸 → 원고 칸 | 서버 조건 · 한도 | 쓰는 법 |
66
66
  |---|---|---|---|---|
67
- | **표** | 견주기(여러 항목을 같은 축으로 · 사건 경과) | 절 `sections[].tables[]` · 건 `cases[].tables[]` | 칸 20자(5열 이상 12자) · ※ 주석 2문장 · 본문 단에 안 드는 표는 렌더러가 전폭 띠로 넓힌다 — 쪼개지 않는다 | 수 열은 align "r", 상태는 칩(`{{ok\|보통}}`). 캡션은 이름(20자 안)이고 설명은 note 로. 사건 경과는 날짜 · 일어난 일 · 상태 세 열에 일어난 일만 — 까닭은 건이 진다. 모든 행이 같은 값인 열은 열로 두지 않고 ※ 주석 한 줄로. |
67
+ | **표** | 견주기(글이 섞인 항목 — 글이 섞일 때) · 순서(일어난 일의 차례 — 사건 경과) | 절 `sections[].tables[]` · 건 `cases[].tables[]` | 칸 20자(5열 이상 12자) · ※ 주석 2문장 · 본문 단에 안 드는 표는 렌더러가 전폭 띠로 넓힌다 — 쪼개지 않는다 | 수 열은 align "r", 상태는 칩(`{{ok\|보통}}`). 캡션은 이름(20자 안)이고 설명은 note 로. 사건 경과는 날짜 · 일어난 일 · 상태 세 열에 일어난 일만 — 까닭은 건이 진다. 모든 행이 같은 값인 열은 열로 두지 않고 ※ 주석 한 줄로. 행끼리 크기를 견주는 열은 bar{col: 열 이름}(칸 막대 — 칸 글 앞의 수, % 칸이면 끝이 100). 칩 색의 뜻은 note 에 칩 그대로 적는다. |
68
68
  | **흐름도** | 흐름(「A 가 되면 B 가 되고 C 가 된다」 · 원인 사슬) | 절 `sections[].flow` | 머리 4칸 · 행마다 칸 3(칸 성격은 자리가 정한다) · 칸 20자 · note 12자 | 세 칸은 해야 할 것 → 이미 된 것 → 그러면 — 읽는 차례가 다르면 열 이름을 그 차례로 고쳐 적는다. 원인 사슬(사실 → 우리 상태 → 결과)은 mode "cause". 시스템 안쪽의 절차 · 데이터가 지나는 길은 도해(절차도 · 데이터 흐름도)다. |
69
- | **막대 차트** | 분포(비중 · 수의 크기) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 한 차트 한 축척 — 값 글은 막대 끝 | form 을 안 적으면 막대(length)다. 값은 표기 그대로("118,716") 적고 이름 있는 행만 선다. 기준선은 ref[]{value, label}(점선) · 일부만 잰 값은 rows[].partial(속 빈 막대) · 뜻 색은 rows[].tone · 두 축은 toggle{a, b}(한 축척). 단위가 % 면 0~100 바탕. |
70
- | **점 차트** | 견주기(같은 축 위의 위치 — 0 인 값도 점으로 선다) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | — | form "position" — 같은 축 위의 점이라 값이 0 인 행도 선다(길이로 견주기 어려운 작은 값 · 기준선 둘레의 차이). ref · partial(속 빈 점) · tone 은 막대와 같다. |
71
- | **시계열** | 시간에 따른 값(언제 계단이 생겼나) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 0 이 아닌 점이 12개를 넘으면 값 글은 가장 큰 점 · 마지막 점에만 · 표식은 points[].x 와 같은 x 에만 선다 | kind "series" · points[{x, y}] — x 가 YYYY-MM-DD 면 달마다 평균 · 최대 글자 행이 저절로 선다(summary 로 바꿔 줄 수 있다). 기본 모양은 점과 선이고 form "length" 면 날마다 막대. 사건은 marks(세로선) · 기준은 ref(가로 점선). |
69
+ | **막대 차트** | 견주기(항목마다 수 하나 — 수일 때) · 분포(비중 · 수의 크기) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 한 차트 한 축척 — 값 글은 막대 끝 | form 을 안 적으면 막대(length)다. 값은 표기 그대로("118,716") 적고 이름 있는 행만 선다. 기준선은 ref[]{value, label}(점선) · 일부만 잰 값은 rows[].partial(속 빈 막대) · 뜻 색은 rows[].tone · 두 축은 toggle{a, b}(한 축척). 단위가 % 면 0~100 바탕. |
70
+ | **점 차트** | 견주기(같은 축 위의 위치 — 0 인 값도 점으로 선다) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | — | form "position" — 같은 축 위의 점이라 값이 0 인 행도 선다(길이로 견주기 어려운 작은 값 · 기준선 둘레의 차이). ref · partial(속 빈 점) · tone 은 막대와 같다. 흔들림 · 오차 범위는 rows[].range [아래, 위](옅은 막대) + range_key · value_key (그림 위 한 줄 — 쉬운 말로) — 값은 오른쪽 한 열에 선다. 차이가 운이 아닌지는 0 기준 ref 와 「적어도 · 많게는」 범위로. |
71
+ | **기울기** | 변화(두 조건 · 두 때 사이에 묶음마다 값이 어떻게 움직였나) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 축척은 0 부터 — 작은 차이를 가파른 선으로 부풀리지 않는다 | form "slope" · toggle{a, b}(두 조건 이름) · rows[{label, a, b, tone?}] — 묶음마다 a → b 를 잇는 선. 이름은 양 끝에 서고, 강조할 묶음 하나만 tone(info). 묶음 크기(몇 건)는 이름에 함께 적는다. |
72
+ | **구성 띠** | 분포(한 덩이를 이루는 조각 — 합이 100%) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 비율은 정수 %이고 합이 100 이 되게 렌더러가 맞춘다 | form "share" · rows[{label, value, tone?}] — 100% 띠 하나와 아래 조각마다 이름 · 값 · 비율. 한 덩이의 조각이면 같은 톤을 주고(짙기 셋으로 갈린다), 다른 그림에서 다른 뜻으로 쓴 색은 피한다. 합은 캡션이 말한다. |
73
+ | **시계열** | 시간에 따른 값(언제 계단이 생겼나) | 절 `sections[].charts[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].chart` | 0 이 아닌 점이 12개를 넘으면 값 글은 가장 큰 점 · 마지막 점에만 · 표식은 points[].x 와 같은 x 에만 선다 | kind "series" · points[{x, y}] — x 가 YYYY-MM-DD 면 달마다 평균 · 최대 글자 행이 저절로 선다(summary 로 바꿔 줄 수 있다). 기본 모양은 점과 선이고 form "length" 면 날마다 막대. 사건은 marks(세로선) · 기준은 ref(가로 점선). 쌓은 막대는 points[].parts + parts[{label, tone?}](조각 이름 — 그림 위 한 줄), 사건 이름은 marks[].detail(1~3줄 — 「신규 551건 · 그 달 866건」 아래 이슈 이름). x 가 YYYY-MM 이면 막대마다 「3월」 · 해가 바뀌는 자리에 「2026년」. |
72
74
  | **원문 인용** | 원문(공식 문서 · 계약 · 회신의 문구) | 절 `sections[].quotes[]` · 건 `cases[].quotes[]` · 사실 근거 `decision_brief.facts[].source[].quote` | 출처 줄(source_text · source_url) 하나 이상 — 없으면 ⚠ | 문구를 손대지 않고 싣는다(표기를 풀지 않고 줄바꿈 그대로). 한 건의 거절문 · 회신은 그 건의 quotes 에. 우리말 풀이는 translation 한 문장. 결정 블록의 사실 근거에서는 quote 가 원문 한 줄(글자)이다. |
73
75
  | **구성도** | 구조(구성 요소 · 경계 · 연결) | 절 `sections[].diagrams[].ir` · 결정 그림 칸 `decision_brief.decisions[].figures[].diagram` | 본문 단 760px 4열 격자 · 전폭 1030px(wide) 5열 격자 | 로고는 내장 107개만 — 주소로 가져온 로고(brand 객체)는 굽기 전에 거절. 저장소 근거(meta.repository · components[].sources)는 서버가 걷고 그림만 굽는다(⚠). 가로 연결 라벨은 15px 에서 약 1.9배로 넓어진다 — 열 간격을 넓히거나 세로 연결로. |
74
76
  | **절차도** | 흐름(절차 · 관문 · 운영 절차) | 절 `sections[].diagrams[].ir` · 결정 그림 칸 `decision_brief.decisions[].figures[].diagram` | 본문 단 760px 4열 · 전폭 1030px(wide) 6열 | 누가 하는지(줄 lanes) · 멈추는 자리(예외 줄 variant "exception" · 연결 role "error")가 있는 차례는 이것으로 그린다. schema_version 2 만 굽는다 — 1 은 거절되고 사유에 판 올림 명령이 실린다. 노드 폭이 모자라면 사유의 고칠 값(라벨 ~N px)대로 그 노드에 width 를 준다. 주 경로를 굵게 보이려면 그 연결에 variant "emphasis". |
@@ -79,7 +81,7 @@
79
81
  | **도판** | 화면(실제 화면의 확인 자리 · 바뀔 화면의 도안) · 변화(화면이 바뀌는 선택지 — 두 컷 비교) · 구조(개념 · 원리 — 개념도) · 원문(스프레드시트 칸 · 문서 쪽) | 절 `sections[].plates[] → assets[]` · 건 `cases[].plates[] → assets[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].plate` · 사실 근거 `decision_brief.facts[].source[].plate` | 장당 300,000B · 합계 2,400,000B · 도판 층 R0~R10 · R13(글자 15px · 대비 · 뜻 색 셋 · 캡처 틀 문법) — references/readability.md §1 · 캡처는 긴 변 300px · 짧은 변 100px 이상 | 캡처는 `shot.mjs`(번호 표식 · 이름 가림 `shot.mjs --mask`) · 화면이 바뀌는 선택지는 `shot.mjs --hide … --after … --geom` 으로 전후를 찍어 `pair.mjs` 로 좌우 한 쌍 · 고객 앱 화면 도안은 `mockshot.mjs` · 개념도는 표시 폭 HTML 을 `figure.mjs` 로(여러 장은 `figure.mjs --batch plates.json --report report.json`) · 스프레드시트 칸은 `xlsx-plate.py`. 직접 찍은 화면은 assets[].file 에 로컬 절대경로. 캡처 캡션 끝에 증거 범위(찍은 환경 · 날짜), 도안은 「— 도안」. |
80
82
  | **화면 녹화** | 화면(이용자가 여러 화면을 지나는 동선) | 절 `sections[].plates[] → assets[]` · 건 `cases[].plates[] → assets[]` · 결정 그림 칸 `decision_brief.decisions[].figures[].plate` · 사실 근거 `decision_brief.facts[].source[].plate` | **서버**: 영상 저장 연동(r2)이 켜진 서버에서만 — 꺼진 환경은 발행을 거절한다 · 인쇄에는 재생기가 없고 캡션 글자만 남는다 — 같은 동선의 단계 캡처를 곁에 둔다 | assets[].file 에 로컬 mp4 절대경로(role "video") — 도구가 올리고 ref · 시크바 썸네일(thumbs)을 채운다. 캡션 끝에 찍은 환경 · 날짜. |
81
83
 
82
- - 차트(막대 차트·점 차트·시계열) — 글자 15px · 두 폭 760·312px(그림이 놓이는 단의 폭으로 고르고, 인쇄는 넓은 폭).
84
+ - 차트(막대 차트·점 차트·기울기·구성 띠·시계열) — 글자 15px · 두 폭 760·312px(그림이 놓이는 단의 폭으로 고르고, 인쇄는 넓은 폭).
83
85
  - 도해(구성도·절차도·순서도·데이터 흐름도·상태 변화도·두 판 비교) — **서버**: 도해 굽기가 켜진 서버에서만 새로 굽는다(포털 private/archify.on — 로컬 render.py 는 켜고 부른다) — 꺼진 서버는 굽혀 둔 그림만 싣고 새 그림은 같은 번호의 대기 상자로 둔다(「서버에서 실패한 그림이 N장」 — 원고를 고칠 일이 아니다) · 화면 글자 15px — 고정 판 Archify 가 이 기준으로 굽고, 안 들면 거절하며 사유에 고칠 값(노드 width · 필요한 폭)을 싣는다 · 그림 250,000B · 문서의 그림 속성 합 60,000 · 한 장 10초 · 문서 12초.
84
86
  <!-- /장치 목록 «device-table» -->
85
87