genetics-mcp 2.25.0 → 2.27.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 (37) hide show
  1. package/NATIVE-CODEX-SESSION.md +182 -0
  2. package/bin/aarch64-apple-darwin/gcell +0 -0
  3. package/bin/aarch64-unknown-linux-musl/gcell +0 -0
  4. package/bin/manifest.json +5 -5
  5. package/bin/x86_64-apple-darwin/gcell +0 -0
  6. package/bin/x86_64-pc-windows-gnu/gcell.exe +0 -0
  7. package/bin/x86_64-unknown-linux-musl/gcell +0 -0
  8. package/codex-session-cli.mjs +82 -0
  9. package/codex-session.mjs +353 -0
  10. package/genetics.mjs +1865 -228
  11. package/package.json +5 -2
  12. package/skills/gazette-report/SKILL.md +11 -1
  13. package/skills/gazette-report/scripts/tone.mjs +45 -9
  14. package/skills/gazette-report/scripts/tone.test.mjs +70 -0
  15. package/skills/genetics-cell-id/SKILL.md +73 -54
  16. package/skills/genetics-define/SKILL.md +34 -1
  17. package/skills/genetics-report/SKILL.md +68 -70
  18. package/skills/genetics-report/assets/example/cases-briefing-designs.json +15 -5
  19. package/skills/genetics-report/assets/example/cases-briefing.json +14 -5
  20. package/skills/genetics-report/assets/example/cases.json +25 -9
  21. package/skills/genetics-report/assets/example/decision.json +313 -0
  22. package/skills/genetics-report/assets/example/report-briefing-designs.json +2 -2
  23. package/skills/genetics-report/assets/example/report-briefing.json +1 -1
  24. package/skills/genetics-report/assets/example/report.json +65 -21
  25. package/skills/genetics-report/assets/render.py +204 -52
  26. package/skills/genetics-report/references/content-pipeline.md +9 -10
  27. package/skills/genetics-report/references/decision-format.md +112 -0
  28. package/skills/genetics-report/references/diagrams.md +52 -94
  29. package/skills/genetics-report/references/edition-review.workflow.js +81 -31
  30. package/skills/genetics-report/references/history.md +35 -0
  31. package/skills/genetics-report/references/lim-portal-format.md +120 -253
  32. package/skills/genetics-report/references/linear-read-test.workflow.js +33 -10
  33. package/skills/genetics-report/references/process.md +34 -27
  34. package/skills/genetics-report/references/readability.md +9 -8
  35. package/skills/genetics-report/references/reader-review.workflow.js +167 -25
  36. package/skills/genetics-report/references/visual-first.md +54 -42
  37. package/skills/genetics-report/assets/diagram.mjs +0 -208
@@ -1,6 +1,7 @@
1
1
  // 선형 읽기 시험 — 원고를 「앞에서 뒤로 딱 한 번」 읽히고, 독자가 다른 자리로 뛰어야 이해되는 지점을 전부 센다.
2
2
  // 실행: Workflow 도구에 이 파일을 scriptPath 로 주고 args 를 넘긴다.
3
- // args = { text: "<렌더본 텍스트 절대경로(필수)>", file: "<그 렌더본을 뽑은 report.json 절대경로(필수)>", reader: "<독자 한 줄>", round: "<회차 표지, 예: 2차 측정 · 4판>" }
3
+ // args = { text: "<렌더본 텍스트 절대경로(필수)>", file: "<그 렌더본을 뽑은 report.json 절대경로(필수)>", reader: "<독자 한 줄>", round: "<회차 표지, 예: 2차 측정 · 4판>",
4
+ // skill: "<스킬 폴더 절대경로(선택) — 기본 ~/.claude/skills/genetics-report>" } // 오류 안내의 render.py 가 이 아래 — 읽는 넷은 받지 않는다
4
5
  // text 는 `python3 assets/render.py <report.json> --text <원고 폴더 밖 빈 폴더>/본문.txt` 로 뽑는다. file 은 렌더본이 원고보다 새로운지 재는 데만
5
6
  // 쓰고 읽는 넷에게는 주지 않는다 — 독자가 보는 것은 렌더본뿐이고, 읽는 넷은 CLAUDE.md 를 싣지 않는 Explore 유형으로 돈다(2026-09-26 스킬 검토 —
6
7
  // reader-review.workflow.js 머리 주석). 렌더본이 없거나 비었거나 원고보다 오래되면 읽기 전에 멈추고 무엇이 필요한지 말한다(Check — 파일은
@@ -8,8 +9,11 @@
8
9
  // 읽는 관점이 렌더본을 못 열었다고 답하면(opened=false) 그 관점은 빼고 head 「검토 미완 — 렌더본 못 엶 N(…)」·failed: true 가 붙는다.
9
10
  // 확인 전: MEMORY.md 까지 빠지는지는 첫 실행 전사의 첨부로 확인한다.
10
11
  // round 는 재측정 때 반드시 바꾼다 — 같은 프롬프트면 캐시가 옛 답을 돌려준다(genetics-define 스킬 4단계와 같은 함정).
11
- // 돌아오는 것: merged.jumps[](at·needed·severity·fix) 전부 + order_ok/order_note + overall(「뜀 N(3등급 이상 M) · 사소 K」 + 할 일).
12
+ // 돌아오는 것: merged.jumps[](at·needed·severity·fix) 전부 + order_ok/order_note + overall(「뜀 N(3등급 이상 M) · 사소 K」 + 할 일),
13
+ // filled[](읽는 관점이 이 파일 안 증거 줄을 못 댄 관찰 주장 — 일반 지식으로 메운 것. 뜀과 따로 센다 — 끝 줄이 overall 에 붙는다).
12
14
  // 목표: 뜀 0. 3등급(되짚어야 함) 이상이 하나라도 있으면 발행 전에 그 자리에서 푼다.
15
+ // 2026-10-01 관보 합의 착각 수리 — 「원고에 없는 지식으로 메웠다면 발견」 자기 신고 한 줄로는 화면 주장을 일반 지식으로 메운 독자가
16
+ // 뜀 0 으로 지나갔다. 그래서 화면·흐름 주장마다 이 파일 안 증거 줄을 대게 하고(claims), 못 대면 메운 것으로 센다.
13
17
  //
14
18
  // 2026-09-14 실사례(고객사 3차 보고) — 사용자 반려 「읽다가 시험보는 줄 알 것 같음. 보고서가 흐름이 이어지지 않고, 장을 넘나들면서
15
19
  // 이해를 해야 되는 구조임.」 2판 본문 교차 참조 62곳 → 절 순서를 고치고 교차 참조를 0 으로 만든 3판에도 이 시험이 뜀 45곳을 냈다
@@ -23,7 +27,9 @@ export const meta = {
23
27
  phases: [{ title: 'Check', detail: '렌더본이 있고 비지 않았고 원고보다 새로운지 — 명령 한 줄' }, { title: 'Read', detail: '선형 읽기 3 + 결정권자 1' }, { title: 'Merge', detail: '뜀 지점 합치기' }],
24
28
  }
25
29
  const A = args || {}
26
- const MAKE_TEXT = 'python3 assets/render.py <report.json> --text <원고 폴더 밖 빈 폴더>/본문.txt'
30
+ // 스킬 폴더 — 오류 안내의 render.py 가 이 아래다(reader-review.workflow.js 와 같은 상수). 읽는 넷의 프롬프트에는 싣지 않는다 — 렌더본 하나만 읽는다.
31
+ const SKILL = A.skill || '~/.claude/skills/genetics-report'
32
+ const MAKE_TEXT = `python3 ${SKILL}/assets/render.py <report.json> --text <원고 폴더 밖 빈 폴더>/본문.txt`
27
33
  if (!A.text) throw new Error(`args.text 가 필요하다 — 렌더본 텍스트 파일 절대경로. 읽는 넷은 이 파일 하나만 읽는다. 만드는 법: ${MAKE_TEXT}`)
28
34
  if (!A.file) throw new Error('args.file 이 필요하다 — 그 렌더본을 뽑은 report.json 절대경로. 렌더본이 원고보다 새로운지 재는 데만 쓰고 읽는 넷에게는 주지 않는다')
29
35
  const TEXT = A.text
@@ -43,10 +49,14 @@ if (st[0].b <= 0) throw new Error(`args.text 파일이 비었다 — ${TEXT}.
43
49
  if (st[0].m < st[1].m) throw new Error(`렌더본이 원고보다 오래됐다 — ${TEXT} 가 ${A.file} 보다 ${Math.round(st[1].m - st[0].m)}초 앞선다. 원고를 고친 뒤 다시 뽑는다: ${MAKE_TEXT} (그다음 resumeFromRunId 없이 새로 띄운다)`)
44
50
  const READER = A.reader || '고객사 담당(비개발자). 이 보고서를 처음 읽는다'
45
51
  const ROUND = A.round || '1차 측정'
52
+ // 그림 자리 표지와 메움 세기는 reader-review.workflow.js 와 같은 글이다.
53
+ const MARKS = '그림·영상 자리는 「[그림] <도판 id> · <갈래>」「[영상] <id> · <갈래>」 한 줄이다 — 갈래는 캡처·녹화·도안·합성·문서이고 도안은 우리가 그린 설명 그림이다. 이 표지 줄과 글 끝의 「[그림 파일]」 목록은 검토용이라 독자 화면에 없다(그 id 를 이름 발견으로 세지 않는다).'
54
+ const FILL_STEP = '메움 세기 — 화면·흐름·화면 문구·동작을 말하는 문장(「…뜸·보임·켜짐·막힘·넘어감·저장됨」, 「」로 옮긴 화면 글자)마다 claims 에 한 행을 적는다: 그 줄 번호, 그리고 그것을 보여 주는 증거(캡처·녹화·합성 그림 자리 · 원문 인용 · 센 대상이 있는 표)가 선 이 파일의 본문 줄 번호(shown_at — 끝 목록 줄은 대지 않는다). 댈 줄이 없거나 도안뿐이면 「없음」 — 읽으며 떠올린 화면이 이 파일의 어느 줄에서 왔는지 못 대면 일반 지식으로 메운 것으로 센다.'
46
55
  const CTX = `[${ROUND}] [읽기 전용. 파일을 수정하지 말 것. 한글로 답할 것. 철저함: very thorough — 발췌하지 말고 파일 전체를 처음부터 끝까지 읽는다.]
47
- 읽을 것: ${TEXT} — 보고서 렌더본에서 화면에 보이는 글만 화면 순서대로 뽑은 텍스트(그림·영상 자리는 「[그림]」「[영상]」, 표 칸은 「 | 」). 순서는 표지 → 발행 이력 → 차례 → 활용법(이 문서 읽는 법) → 요약면 → PART 간지 → 절(요지 문단 끝의 「근거」는 링크 단추 · 건은 「NN-1」… · 판단 항목) → 부록 → 판권지.
48
- 이 파일 하나만 연다. 원고에 없는 지식으로 뜻을 메웠다면 그것 자체가 발견이다. 원고 JSON·같은 폴더의 다른 파일·저장소·메모·다른 문서는 열지 않는다.
49
- (읽는 관점) 이 파일을 끝까지 읽었으면 opened=true. 열지 못했거나 비어 있으면 opened=false 로 두고 jumps 는 비운 채 overall 에 까닭을 적는다 — 다른 파일로 대신 읽지 않는다.
56
+ 읽을 것: ${TEXT} — 보고서 렌더본에서 화면에 보이는 글만 화면 순서대로 뽑은 텍스트(표 칸은 「 | 」). ${MARKS} 순서는 표지 → 발행 이력 → 차례 → 활용법(이 문서 읽는 법) → 요약면 → PART 간지 → 절(요지 문단 끝의 「근거」는 링크 단추 · 건은 「NN-1」… · 판단 항목) → 부록 → 판권지.
57
+ 이 파일 하나만 연다 — 끝 「[그림 파일]」 목록에 경로가 적힌 그림은 독자가 보는 그림이라 Read 로 열어 봐도 된다. 원고 JSON·같은 폴더의 다른 파일·저장소·메모·다른 문서는 열지 않는다.
58
+ (읽는 관점) ${FILL_STEP}
59
+ (읽는 관점) 이 파일을 끝까지 읽었으면 opened=true. 열지 못했거나 비어 있으면 opened=false 로 두고 jumps·claims 는 비운 채 overall 에 까닭을 적는다 — 다른 파일로 대신 읽지 않는다.
50
60
  독자: ${READER}
51
61
  판정 기준: 앞에서 뒤로 한 번 읽어 내려가면 이해돼야 하고, 어떤 문장도 독자를 다른 절·표·부록·원고 밖 문서로 보내면 안 된다. 뒤 절이 앞 절을 되짚는 링크(도판 출처 줄의 「건 §n.n」)는 뜀이 아니다. 활용법·요약면 수치 칸의 「N절로」는 지도 구실이라 뜀이 아니다.
52
62
  대상·판·시험·상태·선택지를 부르는 낱말마다, 독자가 문서 밖(자기 화면 글자, 원본 문서, 공급사 공식 명칭)에서 본 글자인가? 이 문서가 붙인 이름이면 정의가 있어도 발견이다 — jumps 에 적는다. 처방은 뜻풀이가 아니라 원래 이름으로 바꾸는 것이다 — 원래 이름을 이 파일만으로 알 수 없으면 fix 에 이름을 지어 넣지 말고 「원래 이름으로 바꾼다(이 파일에 없음)」라고 적는다.`
@@ -60,7 +70,14 @@ const JUMPS = { type: 'object', properties: { jumps: { type: 'array', items: { t
60
70
  order_note: { type: 'string', description: '순서가 끊기는 곳과 바꿀 순서(있으면)' },
61
71
  overall: { type: 'string' } }, required: ['jumps', 'order_ok', 'order_note', 'overall'] }
62
72
  // 읽는 관점은 파일을 열었는지부터 답한다 — 못 연 관점의 「뜀 0」을 「뜀 없음」으로 읽지 않게. 합치기 결과(merged)는 JUMPS 그대로다.
63
- const JUMPS_READ = { type: 'object', properties: { ...JUMPS.properties, opened: { type: 'boolean', description: '렌더본 파일을 열어 끝까지 읽었으면 true, 못 열었거나 비었으면 false' } }, required: [...JUMPS.required, 'opened'] }
73
+ // claims 는 메움 세기(FILL_STEP) — 합치기에는 넘기지 않고 JS 가 센다.
74
+ const CLAIM_ROW = { type: 'object', properties: {
75
+ line: { type: 'integer', description: '주장이 선 줄 번호' },
76
+ claim: { type: 'string', description: '그 문장 — 줄 글자 그대로(길면 앞 60자)' },
77
+ shown_at: { type: 'string', description: '그것을 보여 주는 증거가 선 이 파일의 줄 번호와 그 줄 글자 — 없거나 도안뿐이면 「없음」' } },
78
+ required: ['line', 'claim', 'shown_at'] }
79
+ const JUMPS_READ = { type: 'object', properties: { ...JUMPS.properties, opened: { type: 'boolean', description: '렌더본 파일을 열어 끝까지 읽었으면 true, 못 열었거나 비었으면 false' },
80
+ claims: { type: 'array', items: CLAIM_ROW, description: '화면·흐름·화면 문구·동작을 말하는 문장마다 한 행 — 상한 없음' } }, required: [...JUMPS.required, 'opened', 'claims'] }
64
81
  phase('Read')
65
82
  const LENSES = [
66
83
  ['first-time-a', '처음 읽는 사람 A — 문서를 위 렌더 순서대로 딱 한 번 읽는다. 앞에서 뒤로 읽다가 「이 낱말/번호/표가 뭐지, 앞에서 봤나, 뒤에 있나」 하고 멈추는 지점을 전부 적는다. 뒤에 있는 것을 앞에서 전제하거나, 앞에 있던 것을 뒤에서 다시 찾아 올라가야 하거나, 정의가 부록·원고 밖(앞 회차 보고)에만 있으면 전부 뜀이다.'],
@@ -73,11 +90,17 @@ const lensFail = LENSES.filter((_, i) => !res[i]).map(([k]) => k)
73
90
  const unread = LENSES.filter((_, i) => res[i] && res[i].opened !== true).map(([k]) => k)
74
91
  const reads = res.filter((r) => r && r.opened === true)
75
92
  log(`선형 읽기 ${reads.length}/${LENSES.length} · 뜀 ${reads.reduce((n, r) => n + r.jumps.length, 0)}${unread.length ? ` · 렌더본 못 엶 ${unread.join(', ')}` : ''}`)
93
+ // 메움 — 읽는 관점이 이 파일 안 증거 줄을 못 댄 관찰 주장(FILL_STEP). 뜀과 따로 센다 — 뜀 0 이어도 화면 주장을 일반 지식으로 메웠을 수 있다.
94
+ const filled = LENSES.flatMap(([k], i) => (res[i] && res[i].opened === true && Array.isArray(res[i].claims) ? res[i].claims : [])
95
+ .filter((c) => /^\s*없음/.test(String(c.shown_at))).map((c) => ({ lens: k, ...c })))
96
+ const fillLine = `메움(증거 줄 없음) ${new Set(filled.map((c) => c.line)).size}줄 — ${LENSES.map(([k]) => `${k} ${filled.filter((c) => c.lens === k).length}`).join(' · ')} · 뜀과 따로 센다`
97
+ log(fillLine)
76
98
  // 실패는 결과 머리에 적는다(reader-review.workflow.js 와 같은 머리). 렌더본을 못 연 관점이 하나라도 있으면 합쳐도 검토 미완이다.
77
99
  const headOf = () => `검토 미완 — ${[lensFail.length && `관점 ${lensFail.length}개 실패(${lensFail.join(', ')})`, unread.length && `렌더본 못 엶 ${unread.length}(${unread.join(', ')})`].filter(Boolean).join(' · ')}`
78
- if (reads.length < 3) { log('읽기 세션이 셋 미만 — 측정이 아니다. 한도가 풀린 뒤 round 를 바꿔 새로 띄운다'); return { head: headOf(), merged: null, raw: reads, failed: true } }
100
+ if (reads.length < 3) { log('읽기 세션이 셋 미만 — 측정이 아니다. 한도가 풀린 뒤 round 를 바꿔 새로 띄운다'); return { head: headOf(), merged: null, filled, raw: reads, failed: true } }
79
101
  const failHead = unread.length ? headOf() : ''
80
102
  if (failHead) log(failHead)
81
103
  phase('Merge')
82
- const merged = await agent(`${CTX}\n[합치기] 아래 관점들의 뜀 지점을 같은 자리끼리 합치고 severity 합산으로 정렬해 전부 남겨라(상한 없음). 관점 하나만 짚었고 severity 1 인 것은 「사소」로 따로 세어 overall 에 수만 적고 jumps 에서는 빼라. 각 항목의 fix 는 가장 구체적인 것을 고르되 「다른 절을 보라」는 처방은 금지 — 그 자리에 넣을 문장 또는 뺄 문장으로만. order_ok 가 하나라도 false 면 order_note 를 합쳐 바꿀 순서를 하나로 제안하라. overall 첫 줄에 「뜀 N(3등급 이상 M) · 사소 K」를 적고, 이어서 「작성자가 지금 바로 할 일」을 순서대로 5줄 안.\n${JSON.stringify(reads)}`, { label: 'merge', phase: 'Merge', schema: JUMPS })
83
- return { ...(failHead ? { head: failHead, failed: true } : {}), merged, raw: reads }
104
+ const merged = await agent(`${CTX}\n[합치기] 아래 관점들의 뜀 지점을 같은 자리끼리 합치고 severity 합산으로 정렬해 전부 남겨라(상한 없음). 관점 하나만 짚었고 severity 1 인 것은 「사소」로 따로 세어 overall 에 수만 적고 jumps 에서는 빼라. 각 항목의 fix 는 가장 구체적인 것을 고르되 「다른 절을 보라」는 처방은 금지 — 그 자리에 넣을 문장 또는 뺄 문장으로만. order_ok 가 하나라도 false 면 order_note 를 합쳐 바꿀 순서를 하나로 제안하라. overall 첫 줄에 「뜀 N(3등급 이상 M) · 사소 K」를 적고, 이어서 「작성자가 지금 바로 할 일」을 순서대로 5줄 안.\n${JSON.stringify(reads.map(({ claims, ...r }) => r))}`, { label: 'merge', phase: 'Merge', schema: JUMPS })
105
+ if (merged && typeof merged.overall === 'string') merged.overall = `${merged.overall}\n${fillLine}`
106
+ return { ...(failHead ? { head: failHead, failed: true } : {}), merged, filled, raw: reads }
@@ -51,16 +51,17 @@ python3 ~/.claude/skills/genetics-report/assets/render.py report.json
51
51
  | 읽고 나서 **해야 할 행동**은 무엇인가 — 할 일이 둘이면 둘 다 목록으로 | `cta`·`open_items`·건별 `how_to_check` 가 여기서 결정된다. 할 일 목록은 독자 검토 `args.reader` 에 그대로 싣는다 | 「① 결정 물음에 회신한다 ② <독자 화면의 채널 이름> 앱에서 확인한다」 |
52
52
  | 문서에 실어도 되는 **참조 체계**는 무엇인가 | 독자가 확인할 수 없는 참조는 신뢰에 기여하지 않고 노이즈만 된다 | 「본인이 제보한 원본 링크만. 내부 티켓 번호는 안 됨」 |
53
53
  | 전달 경로 — 포털 링크인가, 파일 하나인가, 인쇄도 도는가 | 포털은 셸이 문서 둘레에 요약·댓글을 놓는다. 파일 전달은 그것이 없다 | 「포털 링크 + 인쇄 가능해야 함」 |
54
- | 읽고 나서 **무엇을 결정하는가** — 선택지·선택지마다 달라지는 것·기한. 우리 의견을 낼지는 따로 묻는다 | 답이 있으면 「결정한다」 모드다. `open_items` 가 고객이 고를 **물음**이 되고 기한 ⚠ 가 걸린다. 의견은 내면 한 절 한 자리(lim-portal-format §12.3b) | 「[방식 A] 를 들일지, 그대로 둘지 — 12월 31일까지」 |
54
+ | 읽고 나서 **무엇을 결정하는가** — 선택지·선택지마다 달라지는 것·기한. 우리 의견을 낼지는 따로 묻는다 | 답에 정할 것이 기한과 함께 있으면 결정 블록(`decision_brief.decisions`)을 쓴다 — 문서가 결정 모드로 선다(`decision-format.md`). 결정마다 물음·기한·선택지가 칸이 되고, 의견은 내면 결정마다 `opinion` 칸 하나. 사용자 확인에 「결정 요청으로 낼까요, 보고로 낼까요」 한 줄 | 「[방식 A] 를 들일지, 그대로 둘지 — 12월 31일까지」 |
55
55
  | **이미 정해진 것**은 무엇이고 **누가·어디서** 정했는가(체크리스트 0a) | 정해진 것은 사실로 배경에 서고 결정 요청에서 빠진다 — 주체와 기록을 확인하지 않고 쓰면 열린 항이 닫힌 사실로 실리거나, FCG 가 대화에서 정한 것이 고객 결정처럼 읽힌다(SKILL 3b 「결정 주체」). 작업 폴더 `decisions.json`(발행 안 함): 항 · 내용 · 결정권(고객/FCG) · 정한 주체 · 기록(회신 원문·회의록·결정문의 이름과 날짜) · 사용자 확인 여부. 미확인 항은 원고에 쓰기 전에 한 번에 묻는다 | 「화면 문구 교체 — 결정권 고객 · 고객 회신 메일(날짜) · 확인함」 |
56
56
  | 원고에서 부를 대상(판·환경·인스턴스·설정·요금·문서)마다 **독자가 보는 이름**은 무엇인가(SKILL 0단계 물음 5) | 작업하며 지은 이름은 문서 안에서 정의해도 독자가 모른다 — 대응표 없이 쓰기 시작하면 설명형 새 이름을 짓게 된다(SKILL 반드시 지키는 것 12). 작업 폴더 `names.md`(발행 안 함): 우리가 부르던 이름 / 독자 화면·문서의 이름 / 그 이름이 보이는 자리. 자료(화면 캡처·콘솔·원본 문서)에서 먼저 찾고 못 찾은 것만 한 번에 묻는다 | 「예비판 → <독자 화면의 채널 이름> 앱 · 고객 관리자 화면의 채널 목록」 |
57
+ | 독자가 믿어야 할 **관찰 주장**(화면·흐름·화면 문구·동작)마다 무엇을 보여 줄 것인가 — 누가 찍고, 무슨 접근이 필요한가(SKILL 0단계 물음 6) | 우리가 코드·로그·대화로 본 것은 문서에 실리지 않으면 독자에게 없다. 원고를 다 쓴 뒤에 찾으면 결론 문장만 남는다. 작업 폴더 `evidence.md`(발행 안 함): 관찰 주장 / 보여 줄 것(캡처·녹화·원문·센 대상이 있는 표) / 누가 찍나 / 필요한 접근(계정·기기·창·메일함·자동 조작 허락). 모자란 접근은 원고 전에 대화창에서 한 번에 청한다. 구조 주장(「X 하면 항상 Y」)은 관찰 하나로 단정하지 않는다 — 코드 분기로 확인하고 팀 지식(`search_cases`)을 먼저 뒤진다 | 「저장한 주문이 목록 첫 줄에 나타남 — 캡처 · 우리가 운영 관리자 웹에서 · 운영 관리자 계정」 |
57
58
 
58
59
  ### 이 답에서 곧바로 정해지는 것
59
60
 
60
- - **모드** — 판정한다 / 배운다 / 결정한다 셋 중 하나(SKILL.md 「세 가지 독자」). 결정한다면 `doc_type` 에 「브리핑」을 적어 렌더러 ⚠ 를 켠다.
61
+ - **모드** — 판정한다 / 배운다 / 결정한다 셋 중 하나(SKILL.md 「세 가지 독자」). 결정한다면 결정 블록을 쓴다 — 결정 모드는 원고 내용이 정한다(서식 이름 · `doc_type` 낱말이 아니다).
61
62
  - **금지 어휘 목록** — 독자가 검증할 수 없는 내부 어휘와 식별자.
62
63
  `forbid` 정규식으로 적는다 — 로컬 렌더는 걸리면 멈추고, 포털 발행은 경고로 센다(6단계 「`forbid`」).
63
- - **부를 이름** — 원고에서 부를 대상마다 독자 화면·문서의 이름(위 표 마지막 물음의 대응표). 원고와 용어 잠금 표는 이 이름만 쓴다.
64
+ - **부를 이름** — 원고에서 부를 대상마다 독자 화면·문서의 이름(위 표 `names.md` 대응표). 원고와 용어 잠금 표는 이 이름만 쓴다.
64
65
  - **PART 구성** — 독자가 바뀌면 읽기 순서가 바뀐다.
65
66
  검수자에게는 「지금 부탁드리는 것」이 PART 1 이지만, 사후 열람자에게는 「경과」가 앞이다.
66
67
  - **절 구성(`sections`)** — 독자가 바뀌면 절이 통째로 없어진다.
@@ -107,8 +108,8 @@ grade grades 키 중 하나
107
108
  symptom 무엇이 잘못 보였는가
108
109
  cause 왜 그랬는가 (한 문장)
109
110
  fix 이제 어떻게 되는가
110
- how_to_check 고객이 자기 화면에서 볼 수 있는 결과 (주어는 화면·값)
111
- remaining 우리가 못 닫은 것 — 미확인·미결인 사실 (부탁은 요청 절. 없으면 생략)
111
+ how_to_check 독자가 그 결과를 볼 자리 + 우리가 그것을 본 때·환경 (주어는 화면·값 — 안 본 결과는 remaining)
112
+ remaining 우리가 못 닫은 것 — 미확인·미결인 사실, 우리가 안 본 결과 (부탁은 요청 절. 없으면 생략)
112
113
  source_url 제보 원본 링크 (없으면 생략. http(s) 필수)
113
114
  ```
114
115
 
@@ -120,7 +121,7 @@ source_url 제보 원본 링크 (없으면 생략. http(s) 필수)
120
121
  > · 파일명·함수명·커밋해시·SQL·클래스명을 쓰지 마라. 고객은 모른다.
121
122
  > · 「무엇이 잘못 보였는가 → 왜 그랬는가 → 이제 어떻게 되는가」 순서로 쓴다.
122
123
  > · 원인은 한 문장으로, 비유 없이, 사실만. 변명하지 마라.
123
- > · 모든 건에 고객이 **자기 화면에서 볼 수 있는 결과**를 한 줄 적는다 — 어디를 열면 무엇이 보이는지, 주어는 화면·값.
124
+ > · 모든 건에 **독자가 그 결과를 볼 자리**와 **우리가 그것을 본 때·환경**을 한 줄 적는다 — 볼 자리는 이 문서의 그림·영상·원문 인용(`{{그림:id}}`) 또는 독자 화면(어디를 열면 — 이것뿐이면 렌더러 ⚠ 가 남는다, 10단계). 주어는 화면·값, 동사는 우리가 본 수준까지. 우리가 안 본 결과는 「남은 것」에만.
124
125
  > · 아직 안 끝난 게 있으면 숨기지 말고 「남은 것」으로 적는다.
125
126
  > · 과장 금지. 「완벽히 해결」 대신 무엇을 확인했는지 쓴다.
126
127
  >
@@ -158,21 +159,21 @@ source_url 제보 원본 링크 (없으면 생략. http(s) 필수)
158
159
 
159
160
  ### 분류 규율
160
161
 
161
- 각 건의 `fix`·`how_to_check` 본문을 읽고, **본문에 실제로 적혀 있는 근거만으로** 분류한다.
162
+ 각 건의 `fix`·`how_to_check` 본문과 그 건에 실린 증거를 보고, **본문에 보이는 증거만으로** 분류한다 — 관찰한 결과(운영 환경 확인·실데이터 대조)는 「확인함」이라는 문장이 아니라 독자가 볼 증거(캡처·녹화·원문·센 대상이 있는 표)로 선다.
162
163
 
163
164
  예시(네 등급, 강한 순):
164
165
 
165
166
  | 등급 | 뜻 (범례로 문서에 함께 실린다) | 붙는 조건 |
166
167
  |---|---|---|
167
- | 운영 환경 확인 | 운영 환경에서 실제로 동작시켜 결과까지 확인 | 실제 환경에서 재현·확인했다고 본문에 적혀 있음 |
168
- | 실데이터 대조 | 운영 데이터를 건별로 대조해 확인 | 데이터를 조회·대조했다고 적혀 있음 |
168
+ | 운영 환경 확인 | 운영 환경에서 실제로 동작시켜 결과까지 확인 | 실제 환경에서 본 결과가 **본문에 보이는 증거**(캡처·녹화·원문)로 있음 |
169
+ | 실데이터 대조 | 운영 데이터를 건별로 대조해 확인 | 조회·대조한 결과가 **본문에 보이는 증거**(센 대상이 있는 표·원문)로 있음 |
169
170
  | 재발 점검 적용 | 같은 문제가 다시 생기면 걸러지도록 상시 점검 적용 | 재발 방지 점검을 걸었다고 적혀 있음 |
170
171
  | 반영 확인 | 수정이 운영에 반영된 것까지 확인 **(화면 재현은 미실시)** | 위 어느 것도 명시되지 않고 수정 사실만 기술됨 |
171
172
 
172
173
  | 규칙 | 근거 | 어기면 |
173
174
  |---|---|---|
174
- | **본문에 적힌 근거로만** 분류한다 | 독자는 문서 밖을 볼 수 없다. 등급은 *문서가 주장할 수 있는 것*이지 실제로 한 일이 아니다 | 등급이 자기 신고가 된다 |
175
- | 승급의 근거를 **본문의 짧은 원문 인용**(30자 이내)으로 스스로 확인한다 | 인용이 안 잡히면 그 등급을 주장할 근거가 본문에 없다는 뜻이다 | 근거 없는 승급을 막을 수단이 사라진다 |
175
+ | **본문에 보이는 증거로만** 분류한다 | 독자는 문서 밖을 볼 수 없다. 등급은 *문서가 보여 줄 수 있는 것*이지 실제로 한 일이 아니다 | 등급이 자기 신고가 된다 |
176
+ | 승급의 근거를 **본문의 짧은 원문 인용**(30자 이내)으로 — 관찰 등급이면 그 증거의 자리(도판 id·인용)까지 — 스스로 확인한다 | 인용이나 자리가 안 잡히면 그 등급을 주장할 증거가 본문에 없다는 뜻이다 | 근거 없는 승급을 막을 수단이 사라진다 |
176
177
  | **최약 등급이 기본값**이다 | 근거가 없으면 최약 등급 | 근거 없는 건이 중간 등급으로 흘러 등급 축 전체가 무의미해진다 |
177
178
  | 최약 등급의 정의문에 **한계를 명시**한다 | 등급 이름만으로는 무엇을 안 했는지 알 수 없다 | 검수 독자는 「전부 완료」보다 「여기까지만 확인함」을 훨씬 신뢰한다 |
178
179
  | 등급 부여를 **요약 집필과 다른 판단으로** 분리한다(가능하면 다른 에이전트) | 요약을 쓰는 사람이 등급도 매기면 자기 요약을 뒷받침하도록 등급이 끌려간다 | 요약과 등급 축이 서로를 증명하는 순환이 된다 |
@@ -228,8 +229,8 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
228
229
 
229
230
  요청 자리 밖에서 문체를 안 바꾸면 낱말이 아니라 **조판의 문제**로 남는다 — 경어체 서술문은
230
231
  관보 문법 위에서 겉돈다. 반대로 요청 자리에서 개조식을 고집하면 **하대로 읽힌다** — 이쪽이
231
- 거듭 반려된 자리다(SKILL 5·5a · 경위 history.md §5). 서버 `report_tone.php report_tone_warnings()` 는 요청 자리(`open_items` 본문·`cta`·판권지 `note`·`asks` 절 여백 주석)와 「」 인용을 안 세고,
232
- 로컬 `tone.mjs` 는 요청 자리 가운데 넷(판단 항목 본문·`cta`·요청 PART 의 PART I 간지·판권지 회신 안내)과 「」 인용을 뺀다(2026-09-26). 읽는 법(`guide`)의 요청 한 줄은 두 경로 모두 센다. 그래서 남는 경어체 경고는 서버의 PART I 간지(요청 PART 일 때) 문장과 두 경로의 읽는 법 요청 한 줄이고, 둘 다 의도이므로 **사람이 걸러 읽고 그대로 둔다**.
232
+ 거듭 반려된 자리다(SKILL 5·5a · 경위 history.md §5). 두 문체 관문(서버 `report_tone.php report_tone_warnings()`·로컬 `tone.mjs`)은 같은 요청 자리 넷(판단 항목 본문·`cta`·판권지 회신 안내·요청 PART 의 PART I 간지 도입문·물음)과 「」 인용을 뺀다(2026-09-29).
233
+ 읽는 법(`guide`)의 요청 한 줄은 두 관문 모두 센다 — 남는 경어체 경고가 그 한 줄뿐이면 의도이므로 **사람이 걸러 읽고 그대로 둔다**.
233
234
 
234
235
  ### `summary` — 검수·보고판 4개의 `{lead, body, refs}`
235
236
 
@@ -242,14 +243,12 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
242
243
  3. 여러 건을 관통하는 **공통 원인**이 있다면 그것 — **실재할 때만 쓴다.** 없는데 만들어 내면 그게 이 문서에서 가장 나쁜 슬롭이다
243
244
  4. 검토 요청 — 요청 절에 남은 항 이름과 기한
244
245
 
245
- 「결정한다」판은 4~6문단이고 순서가 다르다 — 무엇을 언제까지 결정하는가 / 검토한 선택지와 편익·비용·불확실성 /
246
- 확인한 사실과 근거의 등급·성숙도(권고 없음 — 의견은 별도 절 한 자리) / 결정 뒤 이어지는 것(SKILL.md 4~6단계 브리핑판).
247
- 결정에 직접 닿는 문단만 `body`(세 문장 안)를 쓰고, 근거 문단은 `lead` 한 줄 + `refs` 로 두고 `body` 를 비운다 — 본문은 건이 가진다(readability R12g).
246
+ 결정 모드는 요약을 받지 않는다(SKILL.md 4~6단계).
248
247
  집행자: 독자 검토 structure 관점 · 사람 눈 — 기계 없음.
249
248
 
250
249
  ### 확인 프로필 표 — 시험판·검수에서 무엇을 넣어 보면 되는가
251
250
 
252
- 결정 문서의 둘째 할 일(시험판 확인 요청)에는 확인 프로필 표를 곁에 둔다. 모양의 정본은 `lim-portal-format.md` 「12.3b 브리핑 서사 공식」이고, 여기는 싣기 전 확인만 적는다.
251
+ 시험판·검수 확인 요청에는 확인 프로필 표 — 독자가 무엇을 만들어 무엇을 보면 되는지 — 를 곁에 둔다(결정 모드는 확인의 `steps` 와 근거 자료 표).
253
252
  - 경계마다 포함 쪽·제외 쪽 두 행을 둔다(≤·< 가 행 이름에 드러나게). 날짜로 정해지는 경계는 확인일 기준 상대값과 계산 예 하나.
254
253
  - 각 행을 **판정 코드나 정의로 확인한 뒤** 싣는다 — 문서의 나이·키 같은 정의가 앱의 정의(만 나이/세는 나이 등)와 같은지 먼저 본다.
255
254
  - 앱에서 만들 수 없는 조건은 행을 지우지 않고 대안을 적는다.
@@ -283,8 +282,7 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
283
282
  이 순서가 문서의 성격을 바꾼다.
284
283
  같은 데이터를 「고객이 해야 할 일」만으로 쓰면 책임 전가 문서가 되고, 「우리가 아직 못 닫은 것」을 먼저 밝히면 신뢰 문서가 된다.
285
284
  검수·보고 문서의 `open_items[].title` 은 「~ 요청」+기한 괄호(SKILL 5a)이고, 본문 첫 문장이 우리가 못 닫은 사실이다 — 「검증에 쓴 표본이 작습니다」·「같은 전화번호를 쓰는 계정의 주인은 저희가 판단할 수 없습니다」.
286
- 결정 문서(브리핑)의 판단 항목은 다르다 — 고객이 고를 **물음**이다(SKILL 0.5단계 5행 · lim-portal-format §12.5b).
287
- 독자의 할 일이 둘이면(결정 + 시험판 확인) 둘째는 `open_items` 두 번째 건 「… 확인 요청」으로 두고 본문 첫 문장에 상대 기한을 넣는다 —
285
+ 결정 문서는 결정 블록을 쓴다 — 정할 것은 `decisions`, 확인 요청은 `confirms` 로 서고 결정 모드는 `open_items` 를 받지 않는다(`decision-format.md`).
288
286
  표지·현황 줄에는 사실문으로만 올린다. 읽는 법(`guide`)에는 요청 절의 확인 요청을 가리키는 요청 한 줄을 둘 수 있다(2026-09-15 사용자 결정) — 그 밖의 요청문은 두지 않는다(요청 자리 밖, SKILL 5). 집행자: `gazette.py` `brief_checks()` 기한 ⚠(「확인 요청」 문구로 갈림) · 독자 검토 decider 관점.
289
287
 
290
288
  | 규칙 | 어기면 |
@@ -462,6 +460,9 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
462
460
  | 독자 검토(`reader-review.workflow.js`) | 처음 읽는 사람·결정권자가 **읽히는가** · 도판을 열어 잰 틀 · 1차 자료와 맞는가 | Verify 를 통과한 발견 반영 · 「⚠ 도판 N장 미열람」 없음(SKILL 체크리스트 7단계 독자 검토 행 — 미열람·「서버 보관」 줄의 id 가 모두 원고에서 보관 표식인 장이면 사람이 열람 주소에서 보고 핸드오프에 적어 통과) |
463
461
  | 사람의 눈 | 이 문서가 **이 독자에게 맞는가** | 판단 |
464
462
 
463
+ 결정 모드는 독자 검토 층이 다르다 — 공개 문서마다 원고를 모르는 독자 한 번, 점수 없이 막힌 자리만(`decision-format.md` 6절).
464
+ 아래 사람의 눈 표 가운데 표지 · 요약면 · PART 간지 · 여백 주석 · 의견 한 절 · 선택지 이름·순서 대조 행은 그 모드에 자리가 없다 — 첫 화면 머리와 결정 장이 서고, 선택지는 `options[]` 한 곳에서 찍힌다.
465
+
465
466
  ### `dry_run` 이 실질적 유일한 품질 관문이다
466
467
 
467
468
  `publish_report(dry_run: true)` 는 렌더까지 돌리고 아무것도 저장하지 않는다.
@@ -476,7 +477,7 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
476
477
  지금은 dry_run 과 실제 발행 응답 **양쪽에** 실린다.
477
478
 
478
479
  ⚠ 가 하나라도 있으면 그것부터 고친다. 작성자가 없앨 수 없는 경고(`lim-portal-format.md` §10 통과 기준 표의 행)는
479
- 줄마다 까닭을 핸드오프에 적는다 — 경고 기준선을 기계로 대조하는 도구는 아직 없어, 새 경고가 그 속에 묻히지 않게 사람이 판마다 대조한다.
480
+ 줄마다 까닭을 핸드오프와 공개·교체 승인 물음에 적는다 — 경고 기준선을 기계로 대조하는 도구는 아직 없어, 새 경고가 그 속에 묻히지 않게 사람이 판마다 대조한다.
480
481
  경고를 안고 고객에게 링크를 보내지 마라.
481
482
 
482
483
  ### 검사기 8종
@@ -538,15 +539,16 @@ RANK_TAG = ['live', 'data', 'done', 'soon'] # 배지 종류
538
539
  | 본문 전체 | 낱말 중간에서 줄이 바뀐 곳이 없는가 |
539
540
  | 본문 전체 | 독자가 조회할 수 없는 식별자가 남아 있지 않은가 — 해시·코드 파일·개발 도구·커밋·브랜치 같은 개발 식별자는 `gazette.py` `text_scan()` ⚠(두 경로), 고객사·제품명 같은 문서마다 다른 금칙 값은 포털 발행에 그물이 없어 **여기가 마지막 관문이다** |
540
541
  | 본문 전체 | (코드 작업을 녹인 문서) 「반영함·보이지 않음·빠짐」 같은 완료형 동사가 원고 밖 상태 표의 확인 수준(코드·시험판·실기기·운영)을 넘지 않는가 — 기계 없음, 독자 검토 state 관점(`args.state`) · 사람의 눈(4단계 「코드 작업을 녹일 때」) |
542
+ | 건 · 절 산문 | 화면·흐름·화면 문구·동작을 말하는 문장(관찰 주장)마다 **독자가 볼 증거가 문서 안에 있는가** — 그 건·절의 실제 캡처·녹화·원문 인용·외부 문서(센 대상이 있는 표는 수·대조 결과의 증거 — 화면 주장은 표만으로 받치지 않는다). 도안(「— 도안」·「— 재현」)은 설명이지 증거가 아니다. 없으면 찍어 실었는가, 우리가 안 본 것이면 남은 것 칸으로 옮겼는가 — 「화면 미확인」·「코드상」 같은 헤지로 넘기지 않는다. 자리 세기는 `gazette.py` `evidence_scan()` ⚠(readability R14), 그 증거가 그 주장을 실제로 보이는지는 독자 검토 evidence 관점 · **사람의 눈** |
541
543
  | 배경 · 결정 요청 | 「정해진 것」으로 쓴 항마다 결정 장부에 결정권·정한 주체·기록·확인이 있는가. 결정권이 고객인 항을 기록 없이 사실로, FCG 가 정한 항을 고객 결정처럼 쓰지 않았는가 — 주체 없는 결정 명사만 `gazette.py` `text_scan()` 과정 어휘 ⚠, 그 밖은 사람의 눈 · 독자 검토 facts 관점(SKILL 3b 「결정 주체」) |
542
544
  | 표지 · 판권지 · 발행 이력 | 작성일 세 자리(`meta` 작성 · 판권지 작성 · `history` 마지막 `date`)가 한 값이고 공개하는 날인가. 공개 전 판을 `history` 에 쌓지 않았는가 — 세 자리 대조는 `gazette.py` `date_scan()` ⚠(두 경로), 공개하는 날인지와 `history` 행 수는 **사람의 눈**(SKILL 3c · 10단계) |
543
545
  | 본문 전체 | 「A에서 B로」 전환 공식 헤드라인이 없는가 — **기계가 안 잡는다**(SKILL.md 카피 게이트 표) |
544
546
  | 본문 전체 | 부정 서술의 주어가 사람·조직·국가가 아닌가 — 기계는 「이유 없는 부정 종결」까지만 잡는다(content-pipeline §6.4) |
545
- | 본문 전체 | (결정권이 고객에게 있는 문서) 권고 낱말이 제목·표 열·절 이름·여백 주석·요약면에 배어 **동의만 받는 틀**인가. 우리 의견은 한 절 한 자리에만 있는가 — 기계는 **낱말까지**(`gazette.py` ⚠ W1). 동의만 받는 틀인지 · 의견 한 자리 여부는 **사람의 눈**(SKILL.md 카피 게이트 표 · lim-portal-format §12.6b) |
546
- | 도판 출처 줄 · 인용 | 도판 출처 줄이 **위치 한 구절**인가(readability R12e — 쪽·행·주소·건 § 가운데 하나, 우리 도안은 비움). 원본 이름·찾을 낱말은 건이나 부록 출처 목록에 있는가. 「흐리다」「못 연다」는 말은 원본 해상도로 **잰 뒤** 쓴 것인가 — 고객·제3자 자료에서 낸 도판(`user-provided`)의 원본 위치 누락은 `gazette.py` ⚠ W2, 재고 썼는지와 인용이 원문 그대로인지는 **사람의 눈**(독자 검토 「원본 대조」 관점) |
547
- | 보이는 자리의 제작 메타 | 출처 줄·캡션·부록·요청 본문에 독자의 할 일에 닿지 않는 제작 설명(합성이며·재현임·배율·잘라냄·촬영 환경·결정 경로)이 있는가. 제작 기록은 `origin` 과 도판 HTML 머리 주석에만, 정직성은 캡션의 한 낱말(도안·재현·합성)이면 된다 — 출처 줄은 `gazette.py` `text_scan()` 제작 메타 ⚠, 캡션·부록·요청 본문은 **사람의 눈** · 독자 검토 Verify 의 노이즈 거름 |
547
+ | 본문 전체 | (결정권이 고객에게 있는 문서) 권고 낱말이 제목·표 열·절 이름·여백 주석·요약면에 배어 **동의만 받는 틀**인가. 우리 의견은 한 절 한 자리에만 있는가 — 기계는 **낱말까지**(`gazette.py` ⚠ W1). 동의만 받는 틀인지 · 의견 한 자리 여부는 **사람의 눈**(SKILL.md 카피 게이트 표) |
548
+ | 도판 출처 줄 · 인용 | 도판 출처 줄이 **위치 한 구절**인가(readability R12e — 쪽·행·주소·건 § 가운데 하나, 캡처는 「화면 이름 · 날짜」, 우리 도안은 비움). 원본 이름·찾을 낱말은 건이나 부록 출처 목록에 있는가. 「흐리다」「못 연다」는 말은 원본 해상도로 **잰 뒤** 쓴 것인가 — 고객·제3자 자료에서 낸 도판(`user-provided`)의 원본 위치 누락은 `gazette.py` ⚠ W2, 재고 썼는지와 인용이 원문 그대로인지는 **사람의 눈**(독자 검토 「원본 대조」 관점) |
549
+ | 보이는 자리의 제작 메타 · 증거 범위 | 출처 줄·캡션·부록·요청 본문에 제작 메타(「합성이며」·「재현임」 같은 서술·제작 도구·배율·자르기 좌표·스크립트 이름·결정 경로)가 있는가 — 그것은 `origin` 과 도판 HTML 머리 주석에만. 반대로 캡처·영상 캡션 끝에는 **증거 범위** 한 구절(찍은 환경·기기·날짜·옮겨 적은 부분 — 「… · 운영 관리자 웹 · 8. 23. 촬영」·「… · 알림 문구는 옮겨 적음 — 합성」)이 있는가(readability R12e). 도안·합성의 정직성은 캡션 끝 한 낱말(「— 도안」·「— 재현」·「— 합성」 — AI 로 만든 합성 그림은 「— 도안」, readability R14) — 출처 줄은 `gazette.py` `text_scan()` 제작 메타 ⚠, 캡션 꼬리·부록·요청 본문은 **사람의 눈** · 독자 검토 Verify 의 노이즈 거름 |
548
550
  | 결정 요청 | 결정에 **이용자 화면의 변화**(팝업·안내·칸의 유무)가 따르는데 고객 디자인 시스템 규격의 **도안**이 없는가 — **없음 — 사람의 눈**(절차는 visual-first 「화면 도안」) |
549
- | 결정 요청 · 선택지 | 선택지마다 **같은 틀·같은 잣대**인가(이름·수·순서가 한눈표·선택지 비교 행렬·의견 표·도판 칩·조건표에서 같은가). 한 선택지만 합성·실사·부연·크게·먼저가 아닌가. 조건표의 각 행이 **모든 도안 그림과 앱 코드**에 맞는가(대조 없이 「공통」이라 적지 않았는가) — 기계는 `asks` 절 표의 모든 행이 같은 열(`gazette.py` `brief_checks()` ⚠)과 도판 틀(`figure.mjs` R13)까지, 그 밖은 독자 검토 figures 관점 · **사람의 눈**(lim-portal-format 「12.3b 브리핑 서사 공식」) |
551
+ | 결정 요청 · 선택지 | 선택지마다 **같은 틀·같은 잣대**인가(이름·수·순서가 한눈표·선택지 비교 행렬·의견 표·도판 칩·조건표에서 같은가). 한 선택지만 합성·실사·부연·크게·먼저가 아닌가. 조건표의 각 행이 **모든 도안 그림과 앱 코드**에 맞는가(대조 없이 「공통」이라 적지 않았는가) — 기계는 `asks` 절 표의 모든 행이 같은 열(`gazette.py` `brief_checks()` ⚠)과 도판 틀(`figure.mjs` R13)까지, 그 밖은 독자 검토 figures 관점 · **사람의 눈** |
550
552
  | 확인 프로필 표 | 경계마다 포함·제외 두 행인가. 각 행을 판정 코드나 정의로 확인했는가(문서의 나이·키 정의가 앱의 정의와 같은가). 날짜 경계는 확인일 기준 상대값인가 — **없음 — 사람의 눈**(4단계 「확인 프로필 표」) |
551
553
  | 본문 전체 | 진행 상태 어휘(정해짐·회신 대기·N판)·개수로 상태를 세는 캡션·직전 판과의 비교(「~ 그대로」)가 남았는가. 정해진 것은 사실로 배경에, 결정 요청에는 지금 열린 것만 — 기계는 **낱말과 개수로 상태를 세는 표 제목**까지 잡는다(`gazette.py` 과정 어휘 ⚠ · readability R11h). 표 제목 밖의 개수 표현·「~ 그대로」 비교는 사람의 눈 |
552
554
  | 부록 | 본문에서 실제로 참조되는 것만 있는가 |
@@ -642,7 +644,7 @@ MCP 가 찍는 요약 줄은 **옛 서식의 셈**만 읽는다(`genetics.mjs ou
642
644
  ### 열람 주소를 연다
643
645
 
644
646
  블록 목록은 「무엇이 섰는가」만 말한다. 칩·굵게·링크가 원문 글자(`**`·`{{`·`](`)로 찍혔는지, 도판 쌍·판단 절이 제 폭으로 섰는지는
645
- 열람 주소를 열어야 보인다. 못 열었으면(로그인·브라우저 점유) 까닭을 핸드오프에 적는다 — 「안 봄」을 「이상 없음」으로 적지 않는다.
647
+ 열람 주소를 열어야 보인다. 못 열었으면(로그인·브라우저 점유) 까닭을 핸드오프와 공개·교체 승인 물음에 적는다 — 「안 봄」을 「이상 없음」으로 적지 않는다.
646
648
 
647
649
  ---
648
650
 
@@ -655,6 +657,9 @@ MCP 가 찍는 요약 줄은 **옛 서식의 셈**만 읽는다(`genetics.mjs ou
655
657
  `cover_date` 는 요약면 「기준」 날짜(수치의 기준일)라 이 셋에 묶지 않는다.
656
658
  2. 로컬 렌더 → 받은 판의 `body_rev` 를 실은 dry_run → 같은 `body_rev` 로 `update_report` 한 번(수정 절차 4~6 — 날짜만 고친 판이라 판 갱신 검토는 돌리지 않는다) → 9단계 두 행.
657
659
  3. 사용자 승인을 받고 `release_report(id)` 로 연다 — 그것이 사람의 승인 행위다.
660
+ 승인 물음과 답에는 **이 판에서 건너뛴 단계**(0단계 사용자 확인 · 독자 검토 · 열람 확인 등)와 **증거 없는 관찰 주장 수**(로컬 `render.py` 의 `evidence_scan()` ⚠ 「화면을 말했는데 …」의 N곳 — 포털 dry_run 은 렌더러 운영 반영 뒤부터)를 반드시 싣는다 — 교체(`update_report`) 승인도 같다.
661
+ 볼 자리가 독자 자기 화면뿐인 확인 방법(「주문 목록을 열면 …」)도 2단계 정의에 맞는 꼴이지만 그 ⚠ 는 지워지지 않고 이 수에 든다 — 확인 방법 끝 「…에서 봄」은 증거로 치지 않는다(그 꼬리 한 줄이 캡처 대신 경고를 지우는 싼 길이 되므로, readability R14).
662
+ 「간단히」는 분량 지시이지 단계 면제가 아니다. 「바로 반영」(2026-09-15 사용자 결정)으로 뒤따라 돌릴 검토는 아직 안 돈 단계로 싣는다.
658
663
 
659
664
  공개 뒤 내용이 바뀐 update 에만 `history` 행을 더한다. 문서 밖 결정의 날짜는 본문에 적지 않는다(결정 장부).
660
665
 
@@ -662,8 +667,9 @@ MCP 가 찍는 요약 줄은 **옛 서식의 셈**만 읽는다(`genetics.mjs ou
662
667
  |---|---|
663
668
  | 작성일 세 자리가 한 값이고 공개일과 같다 · 공개 전 판을 `history` 에 쌓지 않는다 | 세 자리 대조는 `gazette.py` `date_scan()` ⚠ · 공개일과 `history` 행 수는 사람(7단계 표 「표지 · 판권지 · 발행 이력」 행) — 공개 때 날짜 안내(`release_report`)는 기계가 아직 없다 |
664
669
  | 공개는 사람이 한다 | `release_report` — 도구가 `publish` 를 참으로 주지 않는 한 초안이 기본값 |
670
+ | 공개·교체 승인 물음에 건너뛴 단계와 증거 없는 관찰 주장 수를 싣는다 | 셈은 로컬 `render.py` 의 `evidence_scan()` ⚠ 「화면을 말했는데 …」의 N곳(포털 dry_run 은 렌더러 운영 반영 뒤부터) · 물음에 싣는 것은 작성자 — 기계 없음 |
665
671
 
666
- **묻는다**: 공개일, 공개 승인(반드시).
672
+ **묻는다**: 공개일, 공개 승인(반드시 — 건너뛴 단계 · 증거 없는 관찰 주장 수와 함께).
667
673
 
668
674
  ---
669
675
 
@@ -708,6 +714,7 @@ MCP 가 찍는 요약 줄은 **옛 서식의 셈**만 읽는다(`genetics.mjs ou
708
714
  | 1a | 정해진 것의 결정권·정한 주체·기록·확인 여부 | 작업 폴더 `decisions.json`(발행 안 함) | 0a |
709
715
  | 2 | 금지 어휘·식별자 정규식 | `forbid` (로컬 렌더는 멈춤 · 포털 발행은 경고) | 0·6 |
710
716
  | 2a | 부를 이름 대응표(우리가 부르던 이름 / 독자 화면·문서의 이름 / 보이는 자리) | 작업 폴더 `names.md`(발행 안 함) | 0 |
717
+ | 2b | 증거 계획(관찰 주장 / 보여 줄 것 / 누가 찍나 / 필요한 접근) | 작업 폴더 `evidence.md`(발행 안 함) | 0 |
711
718
  | 3 | PART 구성 | `parts` | 0·6 |
712
719
  | 4 | 절 구성과 순서 | `sections` + `groups` | 0·6 |
713
720
  | 5 | 건별 필드 | `cases` | 1·2 |
@@ -722,7 +729,7 @@ MCP 가 찍는 요약 줄은 **옛 서식의 셈**만 읽는다(`genetics.mjs ou
722
729
  | 14 | 고객사 로고 (있으면) | `assets` — `role:"logo"` | 6 |
723
730
  | 14a | 도판 — 도판 HTML·PNG · 일괄 판정 매니페스트 | `assets` 의 `role:"figure"` + `sections[].plates` · 작업 폴더 `plates.json` | 6 |
724
731
  | 15 | (브리핑) 판단 항목마다 물음 제목과 기한 · 둘째 할 일이면 「… 확인 요청」 · 두 길 대칭 한눈표 · 선택지 전치 행렬 · 의견 절 하나 · 바꾸는 길의 위험 · 회신 뒤 일정 | `open_items` · `sections[].tables` · `note` 절 넷 | 4·6 |
725
- | 16 | (브리핑) `doc_type` 에 「브리핑」 — `brief_checks()` 경고가 켜진다 | `doc_type` | 0 |
732
+ | 16 | (옛 결정 브리핑을 고칠 때) `doc_type` 에 「브리핑」 — `brief_checks()` 경고가 켜진다 | `doc_type` | 0 |
726
733
  | 17 | (코드 작업을 녹이면) 원고 밖 상태 표 | 작업 폴더(발행 안 함) · 독자 검토 `args.state` | 4 |
727
734
 
728
735
  건드리지 않는 것: `build.py`·`gazette.py`·`gazette.css`·`sentbreak.py`·`boundary.py`.
@@ -36,32 +36,33 @@
36
36
  | R5 근접성 | 텍스트 상자 겹침 **0** · 텍스트 상자 사이 ≥ **1em** · 라벨 중심↔자기 표식 가로 오프셋 ≤ 1em · 표식 사이 ≥ 0.5em | figure.mjs | 겹침·표식 ✗ · 간격·오프셋 ⚠ |
37
37
  | R6 대비 | 글자/배경 ≥ **4.5:1**(24px 이상 굵은 글자 3:1). 표시 19px 미만 회색 글자는 7:1 미만이면 ⚠. **뜻을 나르는 도형**(띠·막대·핀)/배경 ≥ **3:1**. 배경은 포털 도판 바탕 `#f5f6f7` 까지 합성 | figure.mjs | ✗ |
38
38
  | R7 색 수 | 채도 있는 색(뜻 색) ≤ **3** + 검정·회색·흰. HSL 색상 30° 버킷으로 센다. 같은 뜻엔 같은 색 | figure.mjs | ✗ |
39
- | R8 선명도 | 출력 픽셀 폭 ≥ 표시 폭 × min(**1.8**, 1400 ÷ 표시 폭) − 0.01 — 서버 긴 변 상한이 1400 이라 본문 단 1.79 · 전폭 1.35 가 하한이다. 평면 그림(HTML 개념도·도표)은 `provider: deterministic`(무손실). 화면 캡처만 `user-provided`(손실 사다리) | figure.mjs · genetics.mjs 힌트 | ⚠ (늘려 그려지면 ✗) |
39
+ | R8 선명도 | 출력 픽셀 폭 ≥ 표시 폭 × min(**1.8**, 1400 ÷ 표시 폭) − 0.01 — 서버 긴 변 상한이 1400 이라 본문 단 1.79 · 전폭 1.35 가 하한이다. 평면 그림(HTML 개념도·도표)은 `provider: deterministic`(무손실). 화면 캡처만 `user-provided`(손실 사다리) — provider 는 인코딩 축이고, 증거 갈래(캡처·녹화·도안·합성·문서)는 따로 가린다(R14) | figure.mjs · genetics.mjs 힌트 | ⚠ (늘려 그려지면 ✗) |
40
40
  | R9 세로 | 표시 높이 ≤ **702px**(0.78 × 900) — 포털은 `max-height: 78vh` 로 세로 긴 그림의 **폭을 깎는다**. 넘으면 위아래 두 장으로. 단 비교 컷은 위아래로 가르지 않고 두 칸을 같은 구간으로 자른다(R13a). figure.mjs 는 R9 를 판정 맨 앞(R0 다음)에 찍고 이 폭에서 허용 소스 높이를 알린다 — R1·R1c ✗ 가 세로 초과로 폭이 깎인 결과면 그 꼬리말이 붙는다(높이부터 줄인다) | figure.mjs · gazette.py dry_run | ⚠ |
41
41
  | R10 중복·용어 | 제목·캡션·본문이 같은 말을 세 번 하지 않음. 통계 기호(SD·σ·p)는 부록에만 — `--forbid` 정규식 | figure.mjs 옵션 · 사람 눈 | ✗(forbid) |
42
42
  | R11 본문·표 | 문단 사이 ≥ 1.5em · 한 줄 한글 14~45자 · 헤더 ≥ 본문 ×1.5 굵게 · 문단 ≤ 220자 · 산문 참조 번호 ≤ 3 | gazette.css 토큰 · gazette-report `read.mjs` · §10-1 | ⚠ |
43
43
  | R11a 문장 | **한 문장 ≤ 60자**(공백 제외). 관보는 한 문장을 한 줄로 세우므로 문장 길이가 곧 줄 길이 — 본문 단은 한 줄에 45자, 60자면 1.4줄. 판단 항목·건처럼 가장 많이 읽는 자리는 **45자 안**으로 써 한 줄에 세운다. 접히는 문장은 마침표에서 둘로 끊는다(실측: 고객사 결정 브리핑의 앞선 판에서 45~57자 문장 20개가 한 번씩 접혔음) | gazette.py `text_scan`(60자) · 45자는 사람 눈 | ⚠ |
44
44
  | R11b 표 칸 | 칸 ≤ **20자**(4열 이하) · ≤ **12자**(5열 이상) — 열 폭 130~180px 에서 두 줄. 설명은 ※ 주석·본문으로. 흐름도 칸 ≤ 20자·note ≤ 12자(칸 폭 200px), 조건은 note. 칸에 넣던 숫자 나열은 **행으로 푼다**(「A 구간 1,234 · B 구간 5,678 …」 한 칸 → 구간마다 한 행) | gazette.py `text_scan`(칸·흐름도 칸·note) · 숫자 나열은 사람 눈 | ⚠ |
45
- | R11c 도판 글 | 캡션 ≤ **60자** 한 문장(독자가 볼 자리만, 명사형 — 문장 수도 센다) · 출처 줄 ≤ **40자**, 원본 위치 한 구절만(R12e) | gazette.py `text_scan` | ⚠ |
45
+ | R11c 도판 글 | 캡션 ≤ **60자** 한 문장(독자가 볼 자리만, 명사형 — 문장 수도 센다. 캡처·영상 캡션은 끝에 증거 범위 한 구절, R12e) · 출처 줄 ≤ **40자**, 원본 위치 한 구절만(R12e) | gazette.py `text_scan` · 증거 범위 꼬리는 사람 눈 | ⚠ |
46
46
  | R11d 요약면 | 현황 줄 ≤ **80자** 한두 문장 · 수치 칸 라벨 ≤ **16자**(이름표) · 요약 문단 본문 ≤ 160자 세 문장 | gazette.py `text_scan`(자수) · 문장 수는 사람 눈 | ⚠ |
47
47
  | R11e 절 머리 | 도입문 ≤ 90자 두 문장 · 여백 주석 why 30 · key 45 · advice 40자(19자/줄 단) | gazette.py `text_scan`(자수) · 도입문 문장 수는 사람 눈 | ⚠ |
48
- | R11f 판단 항목 | 본문 ≤ 220자 네 문장 — 첫 문장은 기한, 상세는 건으로 | gazette.py `text_scan`(자수 · 문장 수는 R12b) | ⚠ |
48
+ | R11f 판단 항목 | 본문 ≤ 220자 네 문장 — 첫 문장은 기한, 상세는 건으로. 보고 모드 한정 — 결정 모드는 칸이 네 문장의 뜻을 진다(`due`·`options[].name` / `now`·이용자가 겪는 일 / `options[].what` / 대칭 표·`no_reply`) | gazette.py `text_scan`(자수 · 문장 수는 R12b) | ⚠ |
49
49
  | R11g 부연 | 한 문장에 괄호 부연 ≤ 1, 괄호 안 ≤ 20자(공백 제외). 숫자 나열은 문장이 아니라 표 | gazette.py `text_scan`(괄호 수 · 괄호 안 자수) · 숫자 나열은 사람 눈 | ⚠ |
50
- | R11h 과정 어휘 | 본문에 **진행 상태 어휘 0** — 「정해짐 · 회신 대기 · 남은 물음 · 정해진 것 · N판」, 개수로 상태를 세는 표 제목(「정해진 것 셋과 남은 것 하나」), 주체 없는 결정 명사(「정한 사항」·「결정된 사항」). 독자는 앞 회차·회신·판을 모른다. 정해진 것은 **사실**로 배경(요지)에 — 다만 결정권이 고객에게 있는 항은 고객이 정한 기록을 원고 밖에서 확인한 뒤에만(lim-portal-format §12.3b 「배경」 행). 결정 요청에는 **지금 열린 것만**, 회차는 `history` 에만. 원고는 직전 판의 차분이 아니라 독자의 0 상태에서 다시 쓴다(2026-09-11 「뒷 내용을 나는 알고 너는 알아도 독자는 모름」) | gazette.py `text_scan` · 결정 기록 확인은 사람 눈 | ⚠ |
50
+ | R11h 과정 어휘 | 본문에 **진행 상태 어휘 0** — 「정해짐 · 회신 대기 · 남은 물음 · 정해진 것 · N판」, 개수로 상태를 세는 표 제목(「정해진 것 셋과 남은 것 하나」), 주체 없는 결정 명사(「정한 사항」·「결정된 사항」). 독자는 앞 회차·회신·판을 모른다. 정해진 것은 **사실**로 배경(요지)에 — 다만 결정권이 고객에게 있는 항은 고객이 정한 기록을 원고 밖에서 확인한 뒤에만(SKILL 3b 「결정 주체」). 결정 요청에는 **지금 열린 것만**, 회차는 `history` 에만. 원고는 직전 판의 차분이 아니라 독자의 0 상태에서 다시 쓴다(2026-09-11 「뒷 내용을 나는 알고 너는 알아도 독자는 모름」) | gazette.py `text_scan` · 결정 기록 확인은 사람 눈 | ⚠ |
51
51
  | R12 덩어리 층 | 글 층(R11)이 문장·칸 하나의 길이를 재면 이 층은 **덩어리**(※ 주석 · 판단 항목 · 표·흐름도 · 요청 장치 · 도판 출처 · 같은 항의 되풀이)의 **문장 수와 자릿수**를 잰다. 값은 R12a~g. 전부 ⚠ 이고 거절이 아니다(실사례 2026-09-11, 고객사 결정 브리핑 — 문장은 짧아졌는데 같은 항이 여러 자리에 되풀이돼 반려 · 2026-09-12 회신 없는 정황 보고 — 같은 건이 두 PART 에 문장만 바꿔 섬) | a·b·e gazette.py `text_scan` · c·d·f·g 없음 — 사람 눈(g 는 독자 검토 「구조」 관점도) | ⚠ · — |
52
52
  | R12a 표 주석 | `tables[].note`(※ 주석) ≤ **2문장** — 문장은 렌더러가 문장 블록을 세우는 판별(`boundary.py`)로 센다 — 날짜 마침표(「2026. 9. 30.」·「9. 8.」)는 경계가 아니다. R11a 의 문장 길이도 같은 분할이다. 셋째 문장부터 ⚠ | gazette.py `text_scan` | ⚠ |
53
- | R12b 판단 항목 문장 | `open_items[].body` ≤ **4문장**(R11f 의 「네 문장」과 같은 값 — 자수 220 은 R11f, 문장 수는 여기서 센다). 다섯째 문장부터 ⚠ | gazette.py `text_scan` | ⚠ |
53
+ | R12b 판단 항목 문장 | `open_items[].body` ≤ **4문장**(R11f 의 「네 문장」과 같은 값 — 자수 220 은 R11f, 문장 수는 여기서 센다). 다섯째 문장부터 ⚠. 보고 모드 한정 | gazette.py `text_scan` | ⚠ |
54
54
  | R12c 표 하나 | 한 절에 **같은 행 키**(같은 항·같은 선택지를 행으로 세운) 표·흐름도 ≤ **1** | 없음 — 사람 눈 | — |
55
- | R12d 요청 장치 | `cta` 기본 **[]** — 결론 한 줄은 `notice.text` 의 몫(lim-portal-format §12.3b) | 없음 — 사람 눈 | — |
56
- | R12e 도판 출처 | 출처 줄(`assets[].source_text`)은 **원본 위치 한 구절** — 쪽·행·주소·건 §·부록 N 가운데 하나(R11c 의 40자 안). 결정 절처럼 건보다 앞에 서는 도판은 뒤 절 § 대신 규격이 실린 부록 N 을 가리킨다(뒤 절 § 는 R12h 에 걸린다). 제3자 자료에서 낸 도판은 그 한 구절로 독자가 원본에 닿아야 한다(주소, 또는 `source_url` 이 있는 건 §). `source_url` 은 도판에 그려지지 않으므로 대신하지 못한다. **제작 방식**(합성·재현·예시·자리 표시·잘라냄·배율·촬영 환경)과 결정 경로는 `origin`(렌더 안 됨)과 도판 HTML 머리 주석에만 적는다. 바깥 원본이 없는 우리 도안·흐름은 출처 줄을 비운다. 그림 번호는 출처 줄에 쓰지 않는다(번호는 옮겨 다닌다). 정직성은 캡션의 한 낱말(「— 도안」·「— 재현」·「— 합성」)이면 된다. 기계는 두 가지를 센다 — 위치 없음은 `provider:"user-provided"`(파일로 싣는 합성 포함)만(W2), 제작 설명·그림 번호는 `role:"figure"` 전부의 출처 줄. 캡션은 안 본다 | gazette.py `text_scan`(W2 · 제작 메타) · 캡션·부록의 노이즈는 사람 눈 | ⚠ |
55
+ | R12d 요청 장치 | `cta` 기본 **[]** — 결론 한 줄은 `notice.text` 의 몫(결정 모드는 `cta` 를 받지 않는다) | 없음 — 사람 눈 | — |
56
+ | R12e 도판 출처 | 출처 줄(`assets[].source_text`)은 **원본 위치 한 구절** — 쪽·행·주소·건 §·부록 N 가운데 하나(R11c 의 40자 안). 캡처는 「화면 이름 · 날짜」가 위치다(「주문 목록 화면 · 8. 23.」) — 형식을 맞추려고 부록 N 을 붙이지 않는다. 결정 절처럼 건보다 앞에 서는 도판은 뒤 절 § 대신 규격이 실린 부록 N 을 가리킨다(뒤 절 § 는 R12h 에 걸린다). 제3자 자료에서 낸 도판은 그 한 구절로 독자가 원본에 닿아야 한다(주소, 또는 `source_url` 이 있는 건 §). `source_url` 은 도판에 그려지지 않으므로 대신하지 못한다. **제작 메타**(제작 도구·배율·자르기 좌표·스크립트 이름)와 결정 경로는 `origin`(렌더 안 됨)과 도판 HTML 머리 주석에만 적는다. **증거 범위**는 캡처·영상 캡션 끝 한 구절로 보인다 — 찍은 환경(독자가 부르는 이름)·기기·날짜·옮겨 적은 부분(「… · 운영 관리자 웹 · 8. 23. 촬영」·「… · 알림 문구는 옮겨 적음 — 합성」), 캡션 60자 안(R11c). 바깥 원본이 없는 우리 도안·흐름은 출처 줄을 비우고, 정직성은 캡션 끝 한 낱말(「— 도안」·「— 재현」)이 말한다 — AI 로 만든 합성 그림도 「— 도안」이고, 「— 합성」은 실제 캡처에 글자를 옮겨 적은 것에만 단다(R14). 그림 번호는 출처 줄에 쓰지 않는다(번호는 옮겨 다닌다). 기계는 두 가지를 센다 — 위치 없음은 `provider:"user-provided"`(파일로 싣는 합성 포함)만(W2 — 「화면·창·페이지 이름 + 날짜」 꼴도 위치로 친다), 제작 설명·그림 번호는 `role:"figure"` 전부의 출처 줄. 캡션은 안 본다 | gazette.py `text_scan`(W2 · 제작 메타) · 캡션 꼬리의 증거 범위와 캡션·부록의 노이즈는 사람 눈 | ⚠ |
57
57
  | R12f 되풀이 | **같은 항의 이름·기한**이 문서 전체에서 서는 자리 ≤ **3** — 네 자리부터는 되풀이 | 없음 — 사람 눈 | — |
58
58
  | R12g PART 사이 | 같은 사실(시각·금액·건 제목·핵심 명제)이 **두 PART** 에 서면 한쪽은 건 번호로 가리키기만 한다. 요지·대조표·건(같은 건의 세 배율)은 한 PART — 요청 없는 문서에서 「경과 / 원인」으로 가르지 않는다(process.md 「PART 를 먼저 가른다」). 두 절 `marg.key` 가 낱말만 다르고 같은 명제면 되풀이다 — 글자 비교로는 안 잡힌다. 요약면 수치·요지 lead 가 문서 전체를 줄여 말하는 것은 예외(요지 문단이 건을 하나씩 옮겨 적으면 예외 아님). 실사례 2026-09-12: PART I 사실 27개 중 21개가 PART II 에 다시 섬, dry_run 경고 0 | 없음 — 독자 검토 「구조」 관점 · 사람 눈(렌더러 ⚠ 는 제안 단계) | — |
59
- | R12h 선참조 | 앞 절이 **뒤 절**을 가리키지 않는다 — 요지 문단·판단 항목 본문의 `§n.n`(근거는 `refs[]` 로만 — 「해당 절」·「근거」 단추가 되므로 뜀이 아니다), 흐름도 「건」 열의 뒤 절 건 번호, 도판 출처 줄의 뒤 절 `§`, 「NN절」 낱말(남의 문서의 절 번호 「검수 보고 4차 제5절」처럼 「N차 … 제N절」 꼴은 이 문서의 뒤 절이 아니라 세지 않는다 — 2026-09-15). 낱말·규칙·예시 선언은 **첫 등장 자리에서 한 구절**(부록·앞 회차 보고에만 두지 않는다). 뒤 절이 앞 절을 되짚는 방향만 허용. 되풀이 금지(R12g)와 다른 축이다 — 되풀이를 빼되 그 자리에서 뜻이 서게 하는 한 구절은 남긴다. 실사례 2026-09-14 고객사 3차 보고 「읽다가 시험보는 줄 알 것 같음」: 2판 교차 참조 62 → 순서를 고친 3판에도 선형 읽기 뜀 지점 45(정의가 부록·원고 밖 / 앞 절의 뒤 절 번호) → 4판 0 | gazette.py `text_scan`(W5 — 절 i 의 산문(이름·부제·도입문·문단·표·흐름도 좌표·칸·여백 주석·같은 그룹의 건·판단 항목·강조문·도판 캡션·출처 줄)에서 앞 숫자가 i 보다 큰 `§n.n`·「NN절」을 센다. `summary[]`·`refs[]` 는 안 센다. 본보기 두 벌의 뒤 절 참조 10곳과 서식 문서 §12.5b 를 같은 날 같이 고쳤다) · 정의 위치(①)는 독자 검토 「선형 읽기」 관점(`reader-review.workflow.js` linear, jumps 0 목표) · 사람 눈 | ⚠ · — |
59
+ | R12h 선참조 | 앞 절이 **뒤 절**을 가리키지 않는다(결정 모드는 번호 대신 이름 고리라 W5 가 돌지 않는다) — 요지 문단·판단 항목 본문의 `§n.n`(근거는 `refs[]` 로만 — 「해당 절」·「근거」 단추가 되므로 뜀이 아니다), 흐름도 「건」 열의 뒤 절 건 번호, 도판 출처 줄의 뒤 절 `§`, 「NN절」 낱말(남의 문서의 절 번호 「검수 보고 4차 제5절」처럼 「N차 … 제N절」 꼴은 이 문서의 뒤 절이 아니라 세지 않는다 — 2026-09-15). 낱말·규칙·예시 선언은 **첫 등장 자리에서 한 구절**(부록·앞 회차 보고에만 두지 않는다). 뒤 절이 앞 절을 되짚는 방향만 허용. 되풀이 금지(R12g)와 다른 축이다 — 되풀이를 빼되 그 자리에서 뜻이 서게 하는 한 구절은 남긴다. 실사례 2026-09-14 고객사 3차 보고 「읽다가 시험보는 줄 알 것 같음」: 2판 교차 참조 62 → 순서를 고친 3판에도 선형 읽기 뜀 지점 45(정의가 부록·원고 밖 / 앞 절의 뒤 절 번호) → 4판 0 | gazette.py `text_scan`(W5 — 절 i 의 산문(이름·부제·도입문·문단·표·흐름도 좌표·칸·여백 주석·같은 그룹의 건·판단 항목·강조문·도판 캡션·출처 줄)에서 앞 숫자가 i 보다 큰 `§n.n`·「NN절」을 센다. `summary[]`·`refs[]` 는 안 센다. 본보기 두 벌의 뒤 절 참조 10곳과 서식 문서 §12.5b 를 같은 날 같이 고쳤다) · 정의 위치(①)는 독자 검토 「선형 읽기」 관점(`reader-review.workflow.js` linear, jumps 0 목표) · 사람 눈 | ⚠ · — |
60
60
  | R13 캡처 틀 문법 | 캡처를 품은 **틀**을 선언 없이 찾는다 — img 에서 위로 올라가며 테두리가 보이는 첫 조상(자기 포함), 없으면 가장 바깥 overflow 자르개, 그것도 없으면 img 자신(`figure.mjs` `frameOf`). 틀이 둘 이상이면 「비교 컷」이다. 값은 R13a~d. 틀이 하나뿐인 도판(번호 표식 캡처·합성 한 장)에는 R13a 의 가로세로비·R13b·R13c 만 선다. 알려진 한계: 칩 이름표까지 품은 카드에 테두리를 두르면 그 카드가 틀로 잡혀 칩 글자가 R13b 로 걸린다 — 테두리는 캡처 상자에 둔다 | figure.mjs | a·b·c ✗ · d ⚠ |
61
61
  | R13a 좌우 같은 틀 | 비교 틀은 **좌우로 나란히** 선다 · 나란한 틀의 높이 차·폭 차 ≤ `R13.heightTol`·`widthTol`(2px) · 이미지 배율 차 ≤ 1% · 가로세로비 왜곡 ≤ 1%(왜곡은 틀 하나여도). 칸 폭 = (표시 폭 − 좌우 여백×2 − 사이) ÷ 2 — 숫자는 `PAIR`(전폭 `wide` · 본문 단 `column`)가 정본이고 `pair.mjs` 가 그대로 쓴다. 틀 높이는 두 칸 중 큰 쪽, 짧은 쪽은 흰 여백 — 늘리거나 따로 잘라 맞추지 않는다. 예외: 모든 틀이 가로 띠(폭 ≥ 높이×3)이고 같은 폭이면 위아래 허용 | figure.mjs · pair.mjs | ✗ |
62
62
  | R13b 틀 안 글자 0 | 틀 안(틀의 자손이거나 글리프 중심이 틀 안)에 HTML 글자 **0**. 빈 자리는 회색 점선이 말하고, 이름은 틀 위 칩(R13d)이 말한다. 예외는 원 번호 한 글자(①~⑳ — 읽는 순서) | figure.mjs | ✗ |
63
63
  | R13c 표식 색 | 틀 안 표식은 **검정 실선** = 있는·바뀔 자리, **회색 점선** = 빠진 자리, **원 번호** = 읽는 순서만(이름표로 쓰지 않는다). 틀 안 유채색 표식(배경·테두리·원 번호 글자색) 0 — 유채색은 캡처 틀이 없는 상태 개념도에만. 캡처에 구워 넣은 배지는 기계가 못 보므로 `shot.mjs` 기본값(검정 원·흰 링)이 집행자다 | figure.mjs · shot.mjs 기본값 | ✗ |
64
64
  | R13d 칩 이름표 | 비교 틀마다 틀 위(64px 안)에 **밝은 무채색 칩** 하나 — 칩 글자는 문서가 그 대상을 부르는 이름 그대로(기본 「그대로 두면」/「바꾸면」, 한눈표가 없으면 캡션의 이름). 칩 없음·검정·유채색 ⚠. `--caption "…"` 을 주면 칩 글자가 캡션에 없을 때 ⚠(alt·origin 은 대조 안 함). 칩 문구의 뜻과 도판 사이 대칭(선택지마다 같은 촬영 규격·같은 틀인가)은 기계가 못 가른다 | figure.mjs · 독자 검토 「도판」 관점 · 사람 눈 | ⚠ |
65
+ | R14 관찰 주장 ↔ 독자가 볼 증거 | 화면·흐름·화면 문구·동작을 말하는 문장(관찰 주장)은 그 건·절에 **독자가 볼 증거**가 있어야 한다 — 실제 캡처·녹화·원문 인용·외부 문서, 또는 그 증거를 가리키는 `{{그림:id}}`. 센 대상이 있는 표는 수·대조 결과의 증거다 — 표는 우리가 옮겨 적은 글이라 화면 주장의 증거로는 렌더러가 치지 않고, 표로만 받친 화면 주장의 ⚠ 곳 수는 승인 물음에 싣는다(`lim-portal-format.md` §10 통과 기준 표). 도안(캡션 「실제 화면 아님」·「— 도안」·「— 재현」, AI 로 만든 합성 그림)은 설명이지 증거가 아니고, 「— 합성」(실제 캡처 일부 + 옮겨 적은 글자)은 증거다. 도판 갈래는 렌더러가 `role`·캡션·`provider`·`origin`·출처 줄로 가린다 — 캡션의 도안 표지가 먼저이고, 찍은 낱말(촬영·캡처·녹화·스크린샷·실기기·시뮬레이터 …)이 캡처를 가른다(순서와 낱말 목록은 `lim-portal-format.md` §10-1). 증거가 없으면 찍어 싣거나, 우리가 안 본 것이면 남은 것 칸으로 옮긴다. 헤지(「화면 미확인」·「(확인 전)」·「코드상」)와 확인 방법 끝 「…에서 봄」은 증거가 아니라 경고를 지우지 못한다 — 그 꼬리 한 줄이 캡처 대신 경고를 지우는 싼 길이 되기 때문이다. 그래서 볼 자리가 독자 자기 화면뿐인 확인 방법(SKILL 1·2단계 정의에 맞는 꼴)도 ⚠ 가 남고, 그 수는 공개·교체 승인 물음에 싣는다(SKILL 체크리스트 10단계). 건에 실물이 있어도 도안 토큰(도해·흐름도 포함)만 가리킨 문장과 「코드상·코드로 봄·설계상」처럼 화면 밖 근거를 스스로 밝힌 문장은 그 문장대로 센다. 관찰 주장으로 치지 않는 것: 확인 안 했음을 말하는 문장(「…보이는지는 확인하지 않았음」 — 단정 뒤에 붙인 고백 「…보임 — 화면은 확인하지 않았음」·「…나타나지만 실기기는 보지 않았음」은 센다) · 「수 있음·수 없음」 가능성 문장 · 표 칸(확인 프로필·조건표·계획처럼 기대 결과라 실물이 있을 수 없다). 「…나타나는 것까지 확인함」처럼 화면·동작을 품은 우리 확인 기록은 관찰 주장이다 | gazette.py `evidence_scan`(건 다섯 칸 · 절 문단·흐름도 칸 — 도안 밖 도판·원문 인용·그 가리킴·원문을 말한 문장의 건 원본 링크를 증거로 센다) · gazette.py `plate_scan`(캡처 갈래 도판의 실린 바이트가 긴 변 300px·짧은 변 100px 미만이면 자리 표시) · 표가 받치는 수·대조 주장과, 그 증거가 그 주장을 보이는지는 독자 검토 증거 가시성(visual-first §7)과 사람 눈 | ⚠ |
65
66
 
66
67
  ## 2. 사람 눈이 보는 것 (기계가 못 잰다)
67
68