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.
- package/LICENSE +43 -0
- package/genetics.mjs +2141 -0
- package/package.json +23 -0
- package/skills/genetics-report/SKILL.md +290 -0
- package/skills/genetics-report/assets/example/cases.json +24 -0
- package/skills/genetics-report/assets/example/report.json +55 -0
- package/skills/genetics-report/assets/generate-illustrations.py +159 -0
- package/skills/genetics-report/assets/qa.py +183 -0
- package/skills/genetics-report/assets/render.py +161 -0
- package/skills/genetics-report/assets/subset_font.py +93 -0
- package/skills/genetics-report/assets/visual-baseline.py +459 -0
- package/skills/genetics-report/references/content-pipeline.md +891 -0
- package/skills/genetics-report/references/design-system.md +733 -0
- package/skills/genetics-report/references/font-embedding.md +161 -0
- package/skills/genetics-report/references/illustrations.md +473 -0
- package/skills/genetics-report/references/lim-portal-format.md +272 -0
- package/skills/genetics-report/references/process.md +634 -0
- package/skills/genetics-report/references/qa.md +722 -0
- package/skills/genetics-report/references/textbook-mode.md +111 -0
- package/skills/genetics-report/references/wysiwyg.md +751 -0
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
# 작업 절차
|
|
2
|
+
|
|
3
|
+
SKILL.md 는 "무엇을 만드는가"를 정하고, 이 문서는 **각 단계에서 실제로 무엇을 쓰고 무엇을 판단하는가**를 정한다.
|
|
4
|
+
데이터 모델·조판 규칙은 `content-pipeline.md`, 토큰 역할은 `design-system.md`,
|
|
5
|
+
검수 항목 전체는 `qa.md`, 편집기 마크업 계약은 `wysiwyg.md`, 폰트는 `font-embedding.md` 가 맡는다.
|
|
6
|
+
여기서는 그것들을 **어떤 순서로 어떤 판단을 거쳐 채우는가**만 다룬다.
|
|
7
|
+
|
|
8
|
+
이 문서의 모든 인용과 수치는 최종 자산(`assets/*.py`, `assets/*.css`, `assets/editor.js`)과
|
|
9
|
+
실제로 돌아가는 예시 프로젝트에서 확인했다.
|
|
10
|
+
확인하지 못한 것은 맨 끝 「미확정」에 남겼다.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 0. 전체 흐름
|
|
15
|
+
|
|
16
|
+
| 단계 | 하는 일 | 산출물 | 사용자에게 묻는가 | 자동 게이트 |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| 0 | 독자 정의 | 독자 문장 1개 + 어휘 정책 | **반드시 묻는다** | — |
|
|
19
|
+
| 1 | 자료 수집 | 원자료(티켓·로그·대화) | 소스·범위·"고객이 아는 참조"를 묻는다 | — |
|
|
20
|
+
| 2 | 건별 정리 | `cases.json` | 안 묻는다. 단 "확인 필요"는 되돌린다 | 빌드 assert |
|
|
21
|
+
| 3 | 등급 부여 | `cases.json` 의 `grade` | 등급 이름·개수만 묻는다 | QA 칩 개수 대조 |
|
|
22
|
+
| 4 | 요약·확인 요청 | `report.json` 의 `summary`/`open_items`/`cta` | 공통 원인의 실재 여부를 묻는다 | 빌드 `§`·`forbid` assert |
|
|
23
|
+
| 5 | 팔레트 | `report.json` 의 `palette` 한 줄 | 톤·브랜드색 사용 여부를 묻는다 | 빌드 팔레트 대비 assert |
|
|
24
|
+
| 6 | 조립 | 단일 HTML | 원자료의 "확인 필요"만 묻는다 | `build.py` assert 4종 |
|
|
25
|
+
| 7 | QA | 통과/실패 리포트 | 안 묻는다 | `qa.py` 13군, 실패 시 exit 1 |
|
|
26
|
+
| 8 | 전달 | 고객본 `.html` | **발송 직전 사람 승인** | 내보내기 `confirm` |
|
|
27
|
+
|
|
28
|
+
새 프로젝트에서 손대는 파일은 `report.json` 과 `cases.json` **둘뿐**이다.
|
|
29
|
+
`build.py`·`palette.py`·`report.css`·`editor.js`·`qa.py` 는 프로젝트 고유 데이터를 하나도 갖고 있지 않다.
|
|
30
|
+
|
|
31
|
+
명령은 두 줄이다.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python3 ~/.claude/skills/genetics-report/assets/build.py report.json
|
|
35
|
+
python3 ~/.claude/skills/genetics-report/assets/qa.py report.json # 실패 0 이어야 통과
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`qa.py` 는 `report.json` 의 `out` 을 읽어 **빌드가 실제로 뱉은 파일**을 검사한다.
|
|
39
|
+
빌드 없이 QA 만 돌리면 이전 산출물을 검사하게 되므로 항상 둘을 붙여서 돌린다.
|
|
40
|
+
|
|
41
|
+
예시 프로젝트 실측(18건): `523,464B` · 폰트 임베드 `300,544B → base64 400,728B` ·
|
|
42
|
+
QA `통과 48 · 경고 1 · 실패 0`. 경고 1건은 아래 9.3 참조.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 1. 0단계 — 독자 정의
|
|
47
|
+
|
|
48
|
+
**이 스킬에서 유일하게 반드시 사용자에게 확인해야 하는 단계다.** 나머지는 스스로 판단해도 된다.
|
|
49
|
+
|
|
50
|
+
### 묻는 것
|
|
51
|
+
|
|
52
|
+
| 질문 | 왜 이걸 묻는가 | 예시 답 |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| 이 문서를 **읽고 판정하는 사람**은 누구인가 — 직함이 아니라 *하는 일*로 | 직함("팀장")에서는 어휘 정책이 나오지 않는다. 행위("검증한다")에서는 나온다 | "고객사 검수 담당 — 우리 작업이 실제로 해결됐는지 확인하는 사람" |
|
|
55
|
+
| 읽고 나서 **해야 할 행동**은 무엇인가 | `cta` 문구와 각 건의 `how_to_check`·`remaining` 칸이 여기서 결정된다 | "각 건을 한 번씩 열어 확인하고, 남은 판단 사항에 답을 준다" |
|
|
56
|
+
| 문서에 실어도 되는 **참조 체계**는 무엇인가 | 독자가 확인할 수 없는 참조는 신뢰에 기여하지 않고 노이즈만 된다 | "본인이 제보한 원본 링크만. 내부 티켓 번호는 안 됨" |
|
|
57
|
+
| 배포 범위 — 파일 전달인가, 인쇄·PDF 도 도는가 | 인쇄 규칙(`@media print`)과 링크 URL 인쇄 여부가 갈린다 | "파일 전달 + 인쇄 가능해야 함" |
|
|
58
|
+
|
|
59
|
+
### 이 답에서 곧바로 정해지는 것
|
|
60
|
+
|
|
61
|
+
- `report.json` 의 `allow_external` — 세 번째 답이 그대로 QA 외부 리소스 예외 목록이 된다.
|
|
62
|
+
- `report.json` 의 `forbid` — 독자가 검증할 수 없는 내부 어휘의 정규식 목록.
|
|
63
|
+
- 절 구성(`sections`) — 독자가 바뀌면 절이 통째로 없어진다.
|
|
64
|
+
전 건 검수자에게는 `status` 절의 판정표가 핵심이지만, 임원 독자에게는 지표 밴드만 남기고 판정표를 빼는 게 맞다.
|
|
65
|
+
|
|
66
|
+
| 규칙 | 근거 | 어기면 |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| 독자를 문장 하나로 확정하기 전에는 한 건도 쓰지 않는다 | 어휘 정책·절 구성·`forbid` 가 전부 여기서 파생된다 | 전 건 재집필. 18건이면 18건 전부 |
|
|
69
|
+
| 독자를 "직함"이 아니라 "하는 일"로 받는다 | 하는 일이 정해져야 "이 사람이 확인할 수 있는가"를 매 문장에서 판정할 수 있다 | 매 건 즉흥 판단이 되고, 문서 안에서 어휘가 흔들린다 |
|
|
70
|
+
|
|
71
|
+
독자를 안 정하고 만들면 **개발 로그에 색만 칠한 물건**이 나온다.
|
|
72
|
+
예시 프로젝트에서 실제로 한 번 그렇게 만들었고, "개발팀 내부적인 작업 시나리오까지 섞어서 보고서로 보내고 있다"는 지적을 받았다.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 2. 1단계 — 자료 수집
|
|
77
|
+
|
|
78
|
+
### 규칙
|
|
79
|
+
|
|
80
|
+
| 규칙 | 근거 | 어기면 |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| 티켓 본문만 읽지 않는다. **코멘트·스레드까지** 읽는다 | 실제 조치 내용은 본문(notes)이 아니라 코멘트에 적히는 게 보통이다 | `fix` 칸이 통째로 빈다. 제목만 보고 쓴 건은 전부 "확인 필요"가 된다 |
|
|
83
|
+
| 건이 많으면 N건씩 묶어 병렬로 읽는다 | 품질 문제가 아니라 속도 문제다. 예시 프로젝트는 3건×6묶음 | (느릴 뿐) |
|
|
84
|
+
| 제보 출처 링크가 있으면 **그대로** 보존한다 | `cases.json` 의 `source_url` → 카드 상단 "제보 원본 보기 ↗" 링크 | 접수 건(`reported`)과 자체 발견 건(`own`)을 가르는 근거가 사라진다 |
|
|
85
|
+
| 링크는 **독자가 아는 것만** 남긴다 | 그 도메인을 `report.json` 의 `allow_external` 에 적어야 QA 를 통과한다 | QA 외부 리소스 검사가 실패한다(단일 파일 원칙) |
|
|
86
|
+
|
|
87
|
+
예시 프로젝트 실측: 18건 중 `source_url` 보유 9건 = 접수 건 9건과 정확히 일치.
|
|
88
|
+
`allow_external` 은 `["figma.com"]` 한 줄이다.
|
|
89
|
+
|
|
90
|
+
**묻는다**: 원자료 소스와 범위(기간·상태 필터), 어떤 링크가 "고객이 아는 참조"인지.
|
|
91
|
+
**판단한다**: 병렬 분할, 필드 추출, 어느 티켓이 한 건으로 합쳐지는지.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 3. 2단계 — 건별 정리 (한 건 = 한 레코드)
|
|
96
|
+
|
|
97
|
+
`cases.json` 은 객체 배열이다. 실제 스키마(예시 프로젝트 18건 전수에서 확인):
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
group "reported" | "own" — report.json 의 groups[].key 와 일치해야 한다
|
|
101
|
+
title 보고서 표제 (티켓 제목이 아니다 — 아래 참조)
|
|
102
|
+
grade report.json 의 grades 키 중 하나
|
|
103
|
+
symptom 무엇이 잘못 보였는가
|
|
104
|
+
cause 왜 그랬는가 (한 문장)
|
|
105
|
+
fix 이제 어떻게 되는가
|
|
106
|
+
how_to_check 고객이 자기 화면에서 밟을 수 있는 순서 ← 필수
|
|
107
|
+
remaining 우리가 못 닫은 것 (없으면 빈 문자열) ← 선택
|
|
108
|
+
source_url 제보 원본 링크 (없으면 생략)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
필드 정의와 조판 규칙의 상세는 `content-pipeline.md` 로 넘긴다. 여기서 정하는 건 **집필 규율**이다.
|
|
112
|
+
|
|
113
|
+
### 작성 규칙 6개조
|
|
114
|
+
|
|
115
|
+
> · 파일명·함수명·커밋해시·SQL·클래스명을 쓰지 마라. 고객은 모른다.
|
|
116
|
+
> · "무엇이 잘못 보였는가 → 왜 그랬는가 → 이제 어떻게 되는가" 순서로 쓴다.
|
|
117
|
+
> · 원인은 한 문장으로, 비유 없이, 사실만. 변명하지 마라.
|
|
118
|
+
> · 고객이 **직접 확인할 수 있는 방법**이 있으면 한 줄 덧붙인다.
|
|
119
|
+
> · 아직 안 끝난 게 있으면 숨기지 말고 "남은 것"으로 적는다.
|
|
120
|
+
> · 과장 금지. "완벽히 해결" 대신 무엇을 확인했는지 쓴다.
|
|
121
|
+
>
|
|
122
|
+
> 근거가 없으면 지어내지 말고 그 필드를 **"확인 필요"** 로 남긴다.
|
|
123
|
+
|
|
124
|
+
| 규칙 | 근거 | 어기면 |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| 서사 순서를 증상→원인→조치로 고정한다 | 카드 레이아웃이 이 순서를 물리적으로 강제한다 — `report.css` 의 `.dx`(진단 2열) → `.r-fix`(조치 전폭) → `.ck`(확인 2열) | 카드마다 순서가 달라 독자가 매번 읽는 법을 새로 배운다 |
|
|
127
|
+
| 원인은 한 문장·비유 없이 | 비유는 사실 진술처럼 보이지만 검증할 수 없다 | 검수 독자에게 변명으로 읽힌다 |
|
|
128
|
+
| 근거 없는 필드는 **"확인 필요"** 로 남기고 사용자에게 되돌린다 | 추측이 사실 진술의 활자로 인쇄되면 회복 불가능하다 | 발송 후에는 회수할 수 없다 |
|
|
129
|
+
| `how_to_check` 는 **전 건 필수** | `qa.py` 구조 검사가 `class="row r-check"` 개수와 건 수를 대조한다. 한 건이라도 비면 실패 | 검수 요청이 아니라 통보가 된다 |
|
|
130
|
+
|
|
131
|
+
실측 확인: 18건 중 한 건의 `how_to_check` 를 비우고 빌드하면 QA 가 `❌ 확인 방법 17/18` 로 잡는다.
|
|
132
|
+
예시 프로젝트 최종 `cases.json` 에는 "확인 필요"가 0건이다 — 되돌려 전부 채운 뒤 조립에 들어갔다는 뜻이다.
|
|
133
|
+
|
|
134
|
+
### `title` 은 티켓 제목이 아니다
|
|
135
|
+
|
|
136
|
+
원자료 제목에는 `>` 구분자, `#2`, `[후속]`, `(심각)`, `버그?` 처럼 티켓에서만 뜻이 통하는 표기와
|
|
137
|
+
`RN 앱 토큰 부활 경합` 같은 내부 용어가 섞여 있다. 전 건 제목을 **보고서 표제로 다시 쓴 뒤** `cases.json` 에 넣는다.
|
|
138
|
+
|
|
139
|
+
> 예: "RN 앱 토큰 부활 경합" → "로그아웃 직후 이전 로그인 상태로 되돌아가던 문제"
|
|
140
|
+
|
|
141
|
+
**주의**: `report.json` 의 `text_fix` 치환은 `symptom·cause·fix·how_to_check·remaining` 다섯 필드에만 걸린다
|
|
142
|
+
(`build.py` 의 `fields` 튜플). **`title` 은 치환을 거치지 않는다.** 제목은 처음부터 고객 언어로 써야 한다.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 4. 3단계 — 등급 부여 (독립 단계로 분리한다)
|
|
147
|
+
|
|
148
|
+
검수 독자가 가장 먼저 보는 축이다. "이걸 너희는 어디까지 확인했는가"에 답하는 장치다.
|
|
149
|
+
|
|
150
|
+
### 분류 규율
|
|
151
|
+
|
|
152
|
+
각 건의 `fix` / `how_to_check` 본문을 읽고, **본문에 실제로 적혀 있는 근거만으로** 분류한다.
|
|
153
|
+
|
|
154
|
+
예시 프로젝트의 4단계(강한 순):
|
|
155
|
+
|
|
156
|
+
| 등급 | 뜻 (문서에 범례로 함께 실린다) | 붙는 조건 |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| 운영 환경 확인 | 운영 환경에서 실제로 동작시켜 결과까지 확인 | 실제 환경에서 재현·확인했다고 본문에 적혀 있음 |
|
|
159
|
+
| 실데이터 대조 | 운영 데이터를 건별로 대조해 확인 | 데이터를 조회·대조했다고 적혀 있음 |
|
|
160
|
+
| 재발 점검 적용 | 같은 문제가 다시 생기면 걸러지도록 상시 점검 적용 | 재발 방지 점검을 걸었다고 적혀 있음 |
|
|
161
|
+
| 반영 확인 | 수정이 운영에 반영된 것까지 확인 **(화면 재현은 미실시)** | 위 어느 것도 명시되지 않고 수정 사실만 기술됨 |
|
|
162
|
+
|
|
163
|
+
| 규칙 | 근거 | 어기면 |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| **본문에 적힌 근거로만** 분류한다. 실제로 무엇을 했는지가 아니라 *문서가 주장할 수 있는 것*만 등급이 된다 | 독자는 문서 밖을 볼 수 없다 | 문서에 없는 작업이 등급의 근거가 되고, 등급은 자기 신고가 된다 |
|
|
166
|
+
| 승급의 근거는 **본문의 짧은 원문 인용**(30자 이내)으로 스스로 확인한다 | 인용이 안 잡히면 그 등급을 주장할 근거가 본문에 없다는 뜻이다 | 근거 없는 승급을 막을 수단이 사라진다 |
|
|
167
|
+
| **최약 등급이 기본값**이다 | 근거가 없으면 최약 등급 | 근거 없는 건이 중간 등급으로 흘러 등급 축 전체가 무의미해진다 |
|
|
168
|
+
| 최약 등급의 정의문에 **한계를 명시**한다 | `report.json` 의 `grades["반영 확인"][1]` = `"…확인 (화면 재현은 미실시)"` | 등급 이름만으로는 무엇을 안 했는지 알 수 없다. 검수 독자는 "전부 완료"보다 "여기까지만 확인함"을 훨씬 신뢰한다 |
|
|
169
|
+
| 등급 부여를 **요약 집필과 다른 판단으로** 분리한다(가능하면 다른 에이전트) | 요약을 쓰는 사람이 등급도 매기면 자기 요약을 뒷받침하도록 등급이 끌려간다 | 요약과 등급 축이 서로를 증명하는 순환이 된다 |
|
|
170
|
+
|
|
171
|
+
**등급 인용(evidence)은 최종 스키마에 남는 필드가 아니다.** `cases.json` 에는 `grade` 만 들어간다.
|
|
172
|
+
인용은 분류 근거를 스스로 검증하기 위한 **작업 중 산출물**이다. 문서에 발췌 인용을 넣지는 않는다 —
|
|
173
|
+
문장 중간에서 잘린 인용은 조치 본문과 중복이고 읽기만 방해한다.
|
|
174
|
+
|
|
175
|
+
### `grades` 선언
|
|
176
|
+
|
|
177
|
+
`report.json` 의 `grades` 에는 **실제로 쓰이는 등급만** 선언하는 것이 좋다 — 검수자에게
|
|
178
|
+
쓰지도 않는 등급 정의를 읽히지 않기 위해서다. 다만 강제는 아니다. 범례는 건수가 0이 아닌
|
|
179
|
+
등급만 그리고(`build.py`: `for k in grades if mc.get(k)`), `qa.py` 는 `grades` 를 읽지 않으므로
|
|
180
|
+
안 쓰는 등급을 남겨 두어도 검사는 통과한다(실측 확인).
|
|
181
|
+
|
|
182
|
+
실측 분포(예시 프로젝트 18건): 운영 환경 확인 10 · 실데이터 대조 4 · 반영 확인 3 · 재발 점검 적용 1.
|
|
183
|
+
|
|
184
|
+
**묻는다**: 등급 이름과 개수가 프로젝트에 맞는지.
|
|
185
|
+
**협상 대상이 아닌 것**: "근거 없으면 최약 등급", "최약 등급 정의에 한계 명시".
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 5. 4단계 — 요약·확인 요청 집필
|
|
190
|
+
|
|
191
|
+
건별 내용이 아니라 **문서의 판단 층**이다. 전부 `report.json` 안에 있다.
|
|
192
|
+
|
|
193
|
+
### 문체 규칙
|
|
194
|
+
|
|
195
|
+
> · 개발 용어(파일명·커밋해시·SQL·클래스명) 금지. **배포 단계 용어(스테이징/테스트환경) 금지.**
|
|
196
|
+
> · 결론을 먼저 쓴다. 각 문단은 굵게 강조할 리드 문장 하나로 시작한다.
|
|
197
|
+
> · 과장 금지. 확인한 것과 확인하지 못한 것을 구분해서 쓴다.
|
|
198
|
+
> · 전 건이 이미 조치·반영을 마쳤다면 **"해결했으니 검토해 달라"가 기본 입장**이다.
|
|
199
|
+
|
|
200
|
+
### `summary` — 4개의 `{lead, body}`
|
|
201
|
+
|
|
202
|
+
`lead` 는 결론 한 문장(`.ex-lead` 로 굵게 렌더), `body` 는 2~4문장. **건별 나열 금지.**
|
|
203
|
+
검수자가 첫 화면에서 판단을 끝낼 수 있어야 한다. 문단 골격:
|
|
204
|
+
|
|
205
|
+
1. 접수된 N건이 어떤 성격이었고 지금 어떤 상태인가
|
|
206
|
+
2. 확인 과정에서 함께 발견해 고친 것 중 영향이 컸던 것
|
|
207
|
+
3. 여러 건을 관통하는 **공통 원인**이 있다면 그것
|
|
208
|
+
4. 검토 요청 — 무엇을 봐 주면 되는지
|
|
209
|
+
|
|
210
|
+
③ 은 **실재할 때만 쓴다.** 없는데 만들어 내면 그게 이 문서에서 가장 나쁜 슬롭이다.
|
|
211
|
+
공통 원인이 실재할 때만 `report.json` 의 `figure` 로 도해(인라인 SVG)를 붙인다.
|
|
212
|
+
도해 색은 전부 `var(--…)` 토큰이어야 한다 — 인라인 SVG 는 사용자 정의 속성을 상속하므로
|
|
213
|
+
`fill="var(--primary-bg)"` 가 그대로 동작하고, 팔레트를 갈아끼워도 도해가 따라온다.
|
|
214
|
+
|
|
215
|
+
### `open_items` — 3~6개의 `{title, body, refs[]}`
|
|
216
|
+
|
|
217
|
+
건별 `remaining` 을 **성격별로 묶는다.** 건별로 다시 나열하지 않는다.
|
|
218
|
+
|
|
219
|
+
> 이건 고객 숙제 목록이 아니라 **우리가 확정하지 못한 것을 밝히는** 절이다. 주어를 우리로 써라.
|
|
220
|
+
|
|
221
|
+
이 한 줄이 문서의 성격을 바꾼다. 같은 데이터를 "고객이 해야 할 일"로 쓰면 책임 전가 문서가 되고,
|
|
222
|
+
"우리가 아직 못 닫은 것"으로 쓰면 신뢰 문서가 된다. 그래서 `open_items[].title` 은 전부 1인칭 완전문이다 —
|
|
223
|
+
`검증에 쓴 표본이 작습니다`, `같은 전화번호를 쓰는 계정의 주인은 저희가 판단할 수 없습니다`,
|
|
224
|
+
`같은 원인으로 생긴 피해 범위를 끝까지 세지 못했습니다`.
|
|
225
|
+
|
|
226
|
+
| 규칙 | 근거 | 어기면 |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| 확인 요청 절의 주어는 **우리**다 | 위 규칙 | 마무리 못 한 쪽이 상대에게 일을 넘기는 문서가 된다 |
|
|
229
|
+
| 결론 먼저, 문단당 리드 1문장 | `.ex-lead` 가 있어야 요약 그리드의 시각 위계가 선다 | 굵게 렌더할 것이 없어 4칸이 균질한 회색 덩어리가 된다 |
|
|
230
|
+
| 확인한 것과 확인 못 한 것을 **문장 안에서 구분**한다 | 등급 축(3단계)과 본문이 어긋나면 안 된다 | 검수 독자는 그 어긋남을 가장 먼저 찾아낸다 |
|
|
231
|
+
| 파괴적 동작은 **결과를 같이 적고, 두 곳에 중복**한다 | 예시: `[발송] 버튼은 실제로 고객에게 알림톡이 나가므로 누르지 말아 주시기 바랍니다` — `summary` 4번과 `cta` 두 곳 | 한 곳에만 있으면 훑어 읽는 독자가 놓친다. 이 중복은 실수가 아니라 설계다 |
|
|
232
|
+
|
|
233
|
+
### `cta` 는 유일한 raw HTML 필드
|
|
234
|
+
|
|
235
|
+
`build.py` 의 `asks` 분기는 `cta` 원소를 이스케이프하지 않고 `link()` 만 통과시킨다
|
|
236
|
+
(`f'<p>{link(p)}</p>'`). 그래서 `<strong>` 을 직접 쓸 수 있고, **동시에 `<`·`&` 를 그냥 쓰면 마크업이 깨진다.**
|
|
237
|
+
`figure` 로 지정한 파일도 통째로 삽입된다. 나머지 필드는 전부 `e()` 로 이스케이프된다.
|
|
238
|
+
|
|
239
|
+
### `§` 는 원고 마커다
|
|
240
|
+
|
|
241
|
+
절 참조는 원고에 `§3.1` 로 쓴다. `build.py` 의 `link()` 가 `<a class="xref" href="#s3-1">3.1</a>` 로 바꾸며
|
|
242
|
+
`§` 기호를 버린다(§ 는 법령·논문 기호이지 보고서 활자가 아니다). 검수자는 건과 건을 오가며 대조하므로
|
|
243
|
+
손으로 찾게 두면 안 된다.
|
|
244
|
+
|
|
245
|
+
**`link()` 를 통과하는 자리**: 절 `lede`, `summary` 의 `lead`/`body`, `open_items` 의 `body`/`refs`,
|
|
246
|
+
`cta`, `note` 절 `paragraphs`, 그리고 `chunk()` 를 거치는 건별 5개 본문 필드.
|
|
247
|
+
**통과하지 않는 자리**: 모든 제목(`title`, `open_items[].title`), 지표 라벨, 표지 메타.
|
|
248
|
+
|
|
249
|
+
제목에 `§` 를 쓰면 빌드가 중단된다(실측): `AssertionError: § 가 산출물에 남았다 — link() 를 거치지 않은 텍스트가 있다`.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 6. 5단계 — 팔레트
|
|
254
|
+
|
|
255
|
+
**색을 손으로 고르지 않는다.** `report.json` 의 `palette` 한 줄만 정하면 나머지는 유도된다.
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
"palette": "korean-navy"
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`palette.py` 의 `derive()` 가 팔레트 6색(primary·secondary·bg·surface·ink·mid)에서 문서용 토큰 21개를 유도하고,
|
|
262
|
+
`audit()` 가 17쌍의 대비를 되잰다. `build.py` 가 그 결과를 `:root` 로 만들어 문서 맨 앞에 주입한다.
|
|
263
|
+
`report.css` 는 색 토큰을 **하나도 선언하지 않는다** — 구조 스타일시트일 뿐이다.
|
|
264
|
+
|
|
265
|
+
유도가 필요한 이유: doc-pptx 의 큐레이션 팔레트는 **발표 슬라이드용**이라 문서 본문 기준으로는 대비가 모자란다.
|
|
266
|
+
Korean Navy 의 Gold `#C9A961` 은 흰 바탕에서 **2.25:1** 이라 글자로 쓰면 WCAG 를 통과하지 못한다.
|
|
267
|
+
그래서 같은 색을 용도별로 쪼갠다 — `--accent`(배경·괘선 전용) / `--accent-mid`(24px+ Bold, 3:1) /
|
|
268
|
+
`--accent-ink`(작은 글자, 4.5:1) / `--accent-chip`+`--accent-on`(칩 배경과 그 위 글자, 쌍으로만 쓴다).
|
|
269
|
+
토큰 역할의 전모는 `design-system.md`.
|
|
270
|
+
|
|
271
|
+
### 무엇을 묻고 무엇을 판단하는가
|
|
272
|
+
|
|
273
|
+
**묻는다**: 톤(격식 / 담백 / 임팩트), 고객사 브랜드색을 쓸 것인지.
|
|
274
|
+
**판단한다**: 그 답을 어느 팔레트 키로 옮길지. 색 값 자체는 판단하지 않는다.
|
|
275
|
+
|
|
276
|
+
| 독자·성격 | 팔레트 키 |
|
|
277
|
+
|---|---|
|
|
278
|
+
| 격식 보고·검수 요청·임원 열람 | `korean-navy` (기본) |
|
|
279
|
+
| 일반 B2B·신뢰 | `claude-classic` |
|
|
280
|
+
| 공문·법무·최대한 담백하게 | `claude-mono` |
|
|
281
|
+
| 데이터·금융 | `claude-blue-calm` |
|
|
282
|
+
| 한국 중견기업 B2B | `korean-brick` |
|
|
283
|
+
| 헬스·교육 | `korean-sage` |
|
|
284
|
+
| 임팩트 | `high-contrast` |
|
|
285
|
+
|
|
286
|
+
`palette.py` 의 `PALETTES` 에는 9개가 들어 있고(위 7개 + `claude-coral`·`claude-green`),
|
|
287
|
+
`python3 palette.py` 를 단독 실행하면 9개 전부의 감사 결과가 나온다. **9개 전부 OK 다**(실측).
|
|
288
|
+
Dark Editorial 은 다크 배경 팔레트라 흰 바탕 인쇄 전제와 맞지 않아 제외돼 있다.
|
|
289
|
+
|
|
290
|
+
### 브랜드색을 쓸 때
|
|
291
|
+
|
|
292
|
+
`palette` 자리에 문자열 대신 6색 딕셔너리를 직접 넣을 수 있다.
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
"palette": { "primary":"#FFD400", "secondary":"#7A5CFF", "bg":"#FFFFFF",
|
|
296
|
+
"surface":"#FAF9F5", "ink":"#141413", "mid":"#B0AEA5" }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`derive()` 가 명도만 낮춰 대비를 맞추므로 **색상·채도는 브랜드 그대로 살아남는다.**
|
|
300
|
+
위 형광 노랑 primary 도 그대로 통과한다(실측: 빌드 성공, QA 실패 0).
|
|
301
|
+
다만 `ink` 를 흐린 회색으로 주면 유도로 구제할 수 없어 **빌드가 중단된다**(실측):
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
AssertionError: 팔레트 대비 미달: [('본문 ink/paper', 3.45), ('본문 ink/surface', 3.38), …]
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
이게 정상 동작이다. 대비 미달을 안고 문서가 나가는 경로는 없다.
|
|
308
|
+
|
|
309
|
+
| 규칙 | 근거 | 어기면 |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| 한 문서 한 팔레트 | `:root` 는 하나만 주입된다 | — |
|
|
312
|
+
| **`--accent` 를 글자색으로 쓰지 않는다** | `qa.py` 가 `color:var(--accent)` 를 실패로 잡는다(하이픈 접두 속성은 제외하므로 `border-color` 는 정상) | 2.25:1. "좀 연하네"로만 보이고 대비 미달인 줄 모른다 |
|
|
313
|
+
| `--mid` 는 괘선 전용 | 같은 검사가 `color:var(--mid)` 도 실패로 잡는다 | 2.3:1 |
|
|
314
|
+
| 색을 손으로 추가하지 않는다 | 하드코딩 hex 는 QA 경고로 잡히고, 팔레트를 갈아끼울 때 그 색만 남는다 | 팔레트 교체가 반쪽이 된다 |
|
|
315
|
+
|
|
316
|
+
팔레트 교체는 실제로 한 줄이다. 예시 프로젝트를 `claude-mono`·`korean-brick`·`high-contrast` 로 바꿔
|
|
317
|
+
빌드·QA 를 돌리면 셋 다 `통과 48 · 경고 1 · 실패 0` 이다(실측).
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 7. 6단계 — 조립
|
|
322
|
+
|
|
323
|
+
`build.py` 가 하는 일만 알면 된다. 손댈 일은 거의 없다.
|
|
324
|
+
|
|
325
|
+
### 문서 순서
|
|
326
|
+
|
|
327
|
+
`report.json` 의 `sections` 배열 순서가 그대로 문서 순서다. `kind` 다섯 종류가 렌더 방식을 정한다.
|
|
328
|
+
|
|
329
|
+
| `kind` | 렌더 | 읽는 설정 |
|
|
330
|
+
|---|---|---|
|
|
331
|
+
| `summary` | 요약 2열 그리드 + (있으면) 도해 | `summary`, `figure` |
|
|
332
|
+
| `status` | 등급 범례 + 전 건 판정표 | `grades`, 전 건 |
|
|
333
|
+
| `cases` | 건별 카드 | `groups[].key` 로 짝지어진 `cases` |
|
|
334
|
+
| `asks` | CTA 박스 + 확인 요청 카드 2열 | `cta`, `open_items` |
|
|
335
|
+
| `note` | 꼬리 문단 | `paragraphs` |
|
|
336
|
+
|
|
337
|
+
표지(`cover`)·지표 밴드(`stats`)·목차(`toc`)·꼬리말(`footer`)은 `sections` 밖에서 자동으로 붙는다.
|
|
338
|
+
목차는 좌측 고정 열이다 — 본문 위에 얹으면 웹앱처럼 보인다.
|
|
339
|
+
|
|
340
|
+
건 카드 내부는 전 건 고정 3단이다.
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
진단 2열 (증상 · 원인) → 조치 전폭 → 확인 2열 (확인 방법 · 확인 요청)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
배치 자체가 "무엇이 보였나 → 왜 → 이제 어떻게 → 당신이 볼 것" 서사를 강제한다.
|
|
347
|
+
확인 요청이 없는 건은 `.ck.one` 으로 한 칸이 된다.
|
|
348
|
+
|
|
349
|
+
### 절 번호는 데이터에서 계산된다
|
|
350
|
+
|
|
351
|
+
`groups[].no` 아래로 1부터 매긴다 → `3.1`, `3.2`, … `4.1`.
|
|
352
|
+
어느 그룹에도 배정되지 않은 건이 있으면 빌드가 중단된다:
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
AssertionError: 그룹에 배정되지 않은 건이 있다: 17/18 — cases 의 group 값이 ['reported', 'own'] 중 하나여야 한다
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
지표 밴드·범례·판정표의 숫자도 전부 데이터에서 센다(`Counter(c['grade'] for c in cases)`).
|
|
359
|
+
**손으로 적은 숫자는 반드시 본문과 어긋나고, 그 어긋남을 독자가 먼저 찾는다.**
|
|
360
|
+
`stats` 의 값만은 사람이 적으므로(`report.json`), 여기만은 건 수와 맞는지 눈으로 확인한다.
|
|
361
|
+
|
|
362
|
+
### 자동으로 일어나는 텍스트 변환 3종
|
|
363
|
+
|
|
364
|
+
| 변환 | 무엇을 하는가 | 어디에 적는가 |
|
|
365
|
+
|---|---|---|
|
|
366
|
+
| `text_fix` | 개발 서술 → 고객 서술. 문자열 짝 치환 | `report.json` 의 `text_fix` 배열 |
|
|
367
|
+
| `link()` | `§3.1` → 그 절로 가는 앵커, `§` 제거 | 자동 |
|
|
368
|
+
| `chunk()` | 긴 산문 분절 + `(1)(2)` 열거 목록화 | 자동 |
|
|
369
|
+
|
|
370
|
+
`chunk()` 의 판정 규칙(`build.py` 의 `chunk()` docstring 에 근거가 있다):
|
|
371
|
+
|
|
372
|
+
- `(N)` 마커가 2개 이상이면 열거 후보. **단 마커 바로 뒤에 조사(`은는이가을를도와과의에서로`)가 붙으면 참조**로 보고 목록화하지 않는다 — "(1)은 새 일지를 열 때…"를 쪼개면 조사만 남고 문장이 부서진다.
|
|
373
|
+
- `(3)(4)` 처럼 번호가 붙어 나오면 두 항목을 함께 가리키는 한 덩어리로 합친다.
|
|
374
|
+
- 열거가 아니면서 `길이 > 180자` 이고 `문장 > 2개` 면 두 문장 단위로 `<p>` 분절. 문장 분리는 한국어 종결어 기준(`(?<=다\.)`, `(?<=요\.)`, `(?<=오\.)`).
|
|
375
|
+
|
|
376
|
+
### `text_fix` 작성 규칙
|
|
377
|
+
|
|
378
|
+
프로젝트마다 다르므로 `report.json` 에 적는다. **규칙 자체가 프로젝트 산출물이다.**
|
|
379
|
+
예시 프로젝트는 24쌍이고 그중 3쌍이 통째 삭제(`"to": ""`)다. 유형:
|
|
380
|
+
|
|
381
|
+
| 유형 | 원문(내부) | 치환 후(고객본) |
|
|
382
|
+
|---|---|---|
|
|
383
|
+
| 검수 환경 용어 | `테스트 매장의 테스트 고객` | `검수용 매장·고객` |
|
|
384
|
+
| 배포 용어 | `2026-08-09 운영 배포를 마쳤고` | `2026년 8월 9일 운영 환경에 반영했고` |
|
|
385
|
+
| 티켓 운영 | `별도 티켓으로 분리해 처리했습니다` | `§4.3에 따로 정리했습니다` (문서 안 참조로) |
|
|
386
|
+
| 내부 산출물 규모 | `저장 경로 6곳을 수정했고` | `저장이 일어나는 모든 경로를 수정했고` |
|
|
387
|
+
| 내부 검증 산출물 | `자동 검증 2건을 추가했습니다` | `같은 문제가 다시 나타나면 곧바로 걸러지도록 상시 점검을 걸어 두었습니다` |
|
|
388
|
+
| 앱 배포 경로 | `다음 스토어 빌드부터` | `다음 앱 업데이트부터` |
|
|
389
|
+
| 설계 검토 이력 | `처음 검토안 중 '…'은 …위험이 있어 제외했습니다.` | **삭제(`""`)** |
|
|
390
|
+
| 화면에 영향 없는 내부 잔여 | `이 밖에 지금은 쓰이지 않는 잔여 기능 정리가 별도 건으로 남아 있습니다(화면 동작에는 영향 없음).` | **삭제(`""`)** |
|
|
391
|
+
|
|
392
|
+
> **금지: 의미를 바꾸는 치환.** 24쌍은 전부 어휘 교체 또는 삭제이지 사실 변경이 아니다.
|
|
393
|
+
> "저장 경로 6곳" → "저장이 일어나는 모든 경로"는 **같은 사실의 다른 세는 단위**다(6곳이 전부였다).
|
|
394
|
+
> 이 선을 넘으면 치환표가 아니라 은폐가 된다.
|
|
395
|
+
|
|
396
|
+
치환은 **단순 문자열 `replace`** 다. 정규식이 아니고, 원문이 한 글자라도 다르면 조용히 안 걸린다.
|
|
397
|
+
그래서 `forbid` 가 따로 있다 — 치환이 빠진 것을 잡는 그물이다.
|
|
398
|
+
|
|
399
|
+
### 조립기의 방어선 4종 — 전부 빌드 중단(assert)
|
|
400
|
+
|
|
401
|
+
| # | 검사 | 메시지 |
|
|
402
|
+
|---|---|---|
|
|
403
|
+
| 1 | 그룹 미배정 건 | `그룹에 배정되지 않은 건이 있다: N/M` |
|
|
404
|
+
| 2 | 팔레트 대비 미달 | `팔레트 대비 미달: [...]` |
|
|
405
|
+
| 3 | `§` 잔존 | `§ 가 산출물에 남았다 — link() 를 거치지 않은 텍스트가 있다` |
|
|
406
|
+
| 4 | `forbid` 정규식 적중 | `금지 표현 유출: <패턴> → [...]` |
|
|
407
|
+
|
|
408
|
+
**`forbid` 는 조립기와 QA 가 같은 목록을 읽는다** — 둘 다 `report.json` 의 `forbid` 를 쓴다.
|
|
409
|
+
목록을 두 곳에 복사해 두면 한쪽만 고쳐져 조립기는 조용하고 QA 만 터지거나, 그 반대가 된다.
|
|
410
|
+
예시 프로젝트의 `forbid`:
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
["1217\\d{12}", "[Aa]sana", "운영 배포", "별도 티켓", "자동 검증 \\d건"]
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
첫 항목이 티켓 번호다. **내부 식별자 유출은 경고가 아니라 빌드 실패로 다룬다** —
|
|
417
|
+
독자가 확인할 수 없는 식별자가 인쇄되면 발송 후에 회수할 수 없다.
|
|
418
|
+
|
|
419
|
+
**묻는다**: 원자료에 남은 "확인 필요" 필드, 고객만 아는 고유명사 표기.
|
|
420
|
+
**판단한다**: 위 변환 전부.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## 8. 7단계 — QA
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
python3 ~/.claude/skills/genetics-report/assets/qa.py report.json
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
실패가 하나라도 있으면 `exit 1`. 경고는 판단해서 넘긴다.
|
|
431
|
+
검사 대상은 `<body>` 이후 `<script>` 이전 구간(본문)이고, 고객본 원칙·외부 리소스·색 검사는 문서 전체를 본다 —
|
|
432
|
+
**편집기 소스를 본문으로 오인하지 않기 위해서**다.
|
|
433
|
+
|
|
434
|
+
### 13군
|
|
435
|
+
|
|
436
|
+
| # | 검사 | 판정 |
|
|
437
|
+
|---|---|---|
|
|
438
|
+
| 1 | 미치환 플레이스홀더 `{...}` | 실패 |
|
|
439
|
+
| 2 | 가로 스크롤 유발 고정 px 폭 | 경고 |
|
|
440
|
+
| 3 | 색 대비 17쌍 — **문서에 박힌 `:root` 를 읽어 잰다** | 실패 |
|
|
441
|
+
| 4 | `--mid`·`--accent` 가 글자색으로 샜는가 | 실패 |
|
|
442
|
+
| 4b | 팔레트 밖 하드코딩 hex / rgba 리터럴 | 경고 |
|
|
443
|
+
| 5 | 폰트 화이트리스트 | 경고 |
|
|
444
|
+
| 6 | `@font-face` 존재 + `format("woff2")` | 실패 |
|
|
445
|
+
| 7 | 구조 일관 — 전 건이 절번호·증상·원인·조치·확인방법·등급칩을 갖는가 | 실패 |
|
|
446
|
+
| 8 | 목차 항목 수·판정표 행 수 = 건 수 | 실패 |
|
|
447
|
+
| 9 | 죽은 절 참조 | 실패 |
|
|
448
|
+
| 10 | 고객본 원칙 — `§` 0건 + `forbid` 전체 | 실패 |
|
|
449
|
+
| 11 | 카피 게이트 — 대시 대비 헤드라인 + AI 슬롭 어휘 | 실패 |
|
|
450
|
+
| 12 | `lang` 선언 · `<img>` alt · 외부 리소스 | 실패 |
|
|
451
|
+
| 13 | **고객본 내보내기 시뮬레이션** | 실패 |
|
|
452
|
+
|
|
453
|
+
3번이 요점이다. 빌드가 유도한 값이 아니라 **실제로 문서에 나간 `:root` 값**을 다시 잰다.
|
|
454
|
+
유도기를 잘못 고쳐도 산출물에서 잡힌다.
|
|
455
|
+
|
|
456
|
+
13번은 `editor.js` 의 `serialize(customer=true)` 와 같은 규칙으로 문서를 잘라 보고,
|
|
457
|
+
`data-rte-ui`·`showSaveFilePicker`·`syncVerdict`·`data-report-edit`·`data-internal="true"` 가
|
|
458
|
+
**하나도 남지 않는지** 확인한다. 크기도 원본의 98% 미만이어야 한다(실제로 안 지워졌으면 크기가 안 준다).
|
|
459
|
+
빌드가 편집 레이어에 표식을 안 붙이면 내보내기 코드는 **조용히 아무것도 못 지운다** — 그래서 기계로 검사한다.
|
|
460
|
+
|
|
461
|
+
### 프로젝트마다 채워야 하는 유일한 항목
|
|
462
|
+
|
|
463
|
+
`report.json` 의 `forbid` 와 `allow_external` 뿐이다.
|
|
464
|
+
나머지(대비 쌍, 슬롭 어휘, 구조 검사, 대시 게이트)는 스킬에 고정돼 있다.
|
|
465
|
+
|
|
466
|
+
### 자동 검수가 통과해도 반드시 브라우저로 연다
|
|
467
|
+
|
|
468
|
+
`qa.py` docstring 이 못박고 있다 — 사람이 봐야 하는 것(톤·독자 적합성·실제 렌더)은 이 검사기가 대신하지 못한다.
|
|
469
|
+
실제로 자동 검수를 다 통과한 문서에서 눈으로만 잡힌 것들: **안 보이는 배지, 빈 목록 항목,
|
|
470
|
+
한국어 낱말 중간 줄바꿈, 편집기가 판정표를 지워버리는 버그.**
|
|
471
|
+
시각 검수 목록은 `qa.md`.
|
|
472
|
+
|
|
473
|
+
### 남아 있는 경고 1건
|
|
474
|
+
|
|
475
|
+
예시 프로젝트에서 `⚠️ rgb/rgba 리터럴 2건` 이 뜬다. `report.css` 의
|
|
476
|
+
표지 `dl` 구분선 `rgba(255,255,255,.22)` 와 `.r-open .xref` 밑줄 `rgba(111,87,33,.35)` 다.
|
|
477
|
+
앞의 것은 어느 팔레트에서나 Primary 위 흰 반투명이라 문제없지만, **뒤의 것은 Korean Navy 의 골드에서
|
|
478
|
+
유래한 갈색 리터럴이라 팔레트를 바꿔도 그 색이 남는다.** 밑줄 1px 이라 대비 기준과는 무관하고
|
|
479
|
+
현재는 경고로 넘기고 있다. 팔레트를 바꿔 쓸 때 눈으로 한 번 볼 자리다.
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## 9. 8단계 — 전달
|
|
484
|
+
|
|
485
|
+
전달물은 `.html` 파일 하나다. 상대는 더블클릭만 하면 된다.
|
|
486
|
+
|
|
487
|
+
마스터 파일은 `<body data-report-edit="on">` 이고 편집 레이어를 품고 있다.
|
|
488
|
+
고객본은 하단 바의 **`고객본 내보내기`** 버튼으로 **별도 파일**(`<원본이름>_고객본.html`)로 뽑는다.
|
|
489
|
+
|
|
490
|
+
| 규칙 | 근거 | 어기면 |
|
|
491
|
+
|---|---|---|
|
|
492
|
+
| 최종 발송 직전에 **사람이 버튼을 누른다**(= 승인 행위) | `exportCustomer()` 의 `confirm` 이 제거 내역을 숫자로 명시한다: `내부 전용 블록 N개가 제거됩니다 / 편집 기능이 파일에서 완전히 삭제됩니다 / 원본은 그대로 둡니다` | 내부 전용 블록이 남았는지 사람이 확인할 마지막 기회가 사라진다 |
|
|
493
|
+
| 고객본은 별도 파일, **원본은 건드리지 않는다** | 같은 `confirm` 문구 | 내부 검토본이 사라져 다음 회차에 다시 만들어야 한다 |
|
|
494
|
+
| 문구 수정 요청은 **다시 빌드하지 말고** 문서에서 고친다 | `저장`(Cmd+S)이 **이 파일 자체**에 덮어쓴다. 사본을 만들면 어느 파일이 최신인지 알 수 없다 | `report.json` 과 HTML 이 갈라진다 |
|
|
495
|
+
| 편집기로 손댄 뒤 내보냈다면 **결과 파일을 열어 본다** | QA #13 은 빌드 산출물에서 시뮬레이션한 것이지 사람이 편집한 뒤의 파일이 아니다 | 절번호·판정표가 어긋난 채 나갈 수 있다(편집기가 재생성하지만 확인은 사람이 한다) |
|
|
496
|
+
|
|
497
|
+
편집기의 상세(마크업 계약, 내부 전용 블록, 저장 제스처 제약)는 `wysiwyg.md`.
|
|
498
|
+
절차상 알아야 할 것은 하나다 — **고객에게 가는 파일에는 내부 도구가 물리적으로 없다.**
|
|
499
|
+
`build.py` 가 편집 레이어를 `<style data-rte-src>` / `<script data-rte-src>` 로 감싸고
|
|
500
|
+
앞뒤에 `<!-- REPORT-EDITOR:BEGIN -->` / `<!-- REPORT-EDITOR:END -->` 주석을 출력하며,
|
|
501
|
+
`serialize(true)` 가 정확히 그 표식을 찾아 들어낸다. 꺼두는 것만으로는 흔적이 남는다.
|
|
502
|
+
|
|
503
|
+
**묻는다**: 최종 승인, 파일명 규칙.
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## 10. 카피 게이트 3종의 보고서 적용
|
|
508
|
+
|
|
509
|
+
doc-pptx 7단계는 슬라이드 카피의 구조적 슬롭 3종을 의무 FAIL 로 규정한다.
|
|
510
|
+
보고서에서는 **1·3번은 그대로 살리고 2번만 조건부로 완화한다.**
|
|
511
|
+
|
|
512
|
+
| # | 패턴 | 보고서 적용 | 기계 검사 |
|
|
513
|
+
|---|---|---|---|
|
|
514
|
+
| 1 | 대시 대비 헤드라인 "X — Y" | **예외 없이 금지** | `qa.py` #11 — `h1/h2/h3` 만 스캔해 ` — ` 또는 ` – ` 발견 시 실패 |
|
|
515
|
+
| 2 | 조사·체언 종결 조각문 | **레지스터로 갈라서 적용** (아래) | 없음 — 사람이 본다 |
|
|
516
|
+
| 3 | "A에서 B로" 전환 공식 | 헤딩에서는 금지. 본문은 **수치와 측정 주체가 있을 때만** | 없음 — 사람이 본다 |
|
|
517
|
+
|
|
518
|
+
### 게이트 2 — 왜 완화하는가, 어디까지 완화하는가
|
|
519
|
+
|
|
520
|
+
보고서의 목차 항목과 건 제목은 **명사구가 한국어 보고서의 관례**다.
|
|
521
|
+
"…던 문제", "처리 현황", "확인 요청 드리는 사항" — 전부 게이트 2에 걸린다.
|
|
522
|
+
그대로 적용하면 목차가 `사전상담 링크에서 다른 고객의 정보가 열렸습니다` 같은 문장 나열이 되어
|
|
523
|
+
길이가 들쭉날쭉해지고 **색인으로서 기능을 잃는다.**
|
|
524
|
+
|
|
525
|
+
그래서 카피를 두 레지스터로 나눈다.
|
|
526
|
+
|
|
527
|
+
**A. 색인용 라벨 — 체언 종결 허용**
|
|
528
|
+
|
|
529
|
+
- `h2` 절 표제: `요약` / `처리 현황` / `접수하신 9건` / `함께 발견해 처리한 9건` / `확인 요청 드리는 사항`
|
|
530
|
+
- `h3` 건 제목(`cases[].title`): `사전상담 링크에서 다른 고객의 정보가 열리던 문제` …
|
|
531
|
+
- 표 헤더·태그·범례: `증상` `원인` `조치` `확인 방법` `확인 요청`
|
|
532
|
+
|
|
533
|
+
**B. 주장용 카피 — 완전문 강제**
|
|
534
|
+
|
|
535
|
+
- `summary[].lead`: `접수해 주신 9건은 모두 조치를 마치고 운영에 반영했습니다.`
|
|
536
|
+
- `open_items[].title`: **같은 `h3` 인데 완전문이다** — `검증에 쓴 표본이 작습니다`
|
|
537
|
+
|
|
538
|
+
즉 **HTML 태그 레벨이 기준이 아니다.** 판별 기준은 하나다.
|
|
539
|
+
|
|
540
|
+
> 그 줄이 "어디에 있는지"를 알려주면 **라벨**이고, "무엇이 사실인지"를 주장하면 **문장**이다.
|
|
541
|
+
> 라벨은 명사구로 짧게, 주장은 서술어를 끝까지 붙여 책임을 진다.
|
|
542
|
+
|
|
543
|
+
체언 종결이 위험한 진짜 이유는 문법이 아니라 **책임 회피**다.
|
|
544
|
+
"성공의 열쇠 — 자동화"는 아무도 아무것도 주장하지 않는다. `검증에 쓴 표본이 작습니다` 는 우리가 주장하고 책임진다.
|
|
545
|
+
라벨은 애초에 주장이 아니므로 이 위험이 없다. 그래서 면제된다.
|
|
546
|
+
|
|
547
|
+
**세칙 둘**
|
|
548
|
+
|
|
549
|
+
- 라벨 레지스터에서도 **종결형을 통일**한다. 예시 프로젝트의 건 제목은 전부 `…던 문제` / `…(방침 확정)` / `…정리` 로 맞춰져 있다. *통일되지 않은 명사구 나열*이 슬롭처럼 보이는 것이지 명사구 자체가 문제가 아니다.
|
|
550
|
+
- **조사로 끝나는 조각문은 어느 레지스터에서도 금지**("…의", "…에서"). 이건 라벨도 문장도 아니다.
|
|
551
|
+
|
|
552
|
+
### 대시에 관한 중요한 구분
|
|
553
|
+
|
|
554
|
+
문서 본문에는 대시가 살아 있다 — 도해 출처 `해당 절 — 3.7 · 3.8 · 3.9 · 4.7`,
|
|
555
|
+
범례 정의 `반영 확인 — 수정이 운영에 반영된 것까지 확인`.
|
|
556
|
+
**대시를 문서에서 추방한 게 아니라 헤딩에서만 추방했다.**
|
|
557
|
+
라벨-값 구분자로서의 대시(`레이블 — 값`)는 캡션·마이크로카피에서 정상 활자다.
|
|
558
|
+
금지 대상은 *대비 수사*로서의 대시다. 검사기를 `h1/h2/h3` 로 한정한 것이 이 구분의 구현이다.
|
|
559
|
+
(주의: 검사는 **공백을 낀** ` — ` 만 잡는다. `X—Y` 처럼 붙여 쓰면 통과하므로 사람이 본다.)
|
|
560
|
+
|
|
561
|
+
### 4번째 게이트 — 보고서에만 있는 것
|
|
562
|
+
|
|
563
|
+
`qa.py` #10, `report.json` 의 `forbid`. **고객본 어휘 게이트**다.
|
|
564
|
+
|
|
565
|
+
슬라이드 카피 게이트는 "AI 처럼 들리는가"를 본다.
|
|
566
|
+
고객 보고서에서는 "**내부처럼 들리는가**"가 훨씬 자주 무너진다.
|
|
567
|
+
`qa.py` 의 AI 슬롭 어휘 목록(`혁신적인`, `차세대`, `재정의하는`, `한 차원 높은`, `최적화된 솔루션`,
|
|
568
|
+
`완벽한 경험`, `새로운 패러다임`, `고도화된`)은 스킬에 고정이고, `forbid` 만 프로젝트가 채운다.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 11. 같은 사실이 두 문서로 갈리는 지점
|
|
573
|
+
|
|
574
|
+
독자 정의가 왜 첫 단추인지를 보여주는 실제 사례다. 사실은 하나도 바뀌지 않았다.
|
|
575
|
+
|
|
576
|
+
| 사실(변하지 않음) | 내부 개발 로그 | 고객 보고서 |
|
|
577
|
+
|---|---|---|
|
|
578
|
+
| 배포 파이프라인을 통과했다 | "2026-08-09 운영 배포를 마쳤고" | "2026년 8월 9일 운영 환경에 반영했고" |
|
|
579
|
+
| 회귀 테스트를 2건 추가했다 | "자동 검증 2건을 추가했습니다" | "같은 문제가 다시 나타나면 곧바로 걸러지도록 상시 점검을 걸어 두었습니다" |
|
|
580
|
+
| 저장 경로 6곳을 고쳤다 | "저장 경로 6곳을 수정했고" | "저장이 일어나는 모든 경로를 수정했고" |
|
|
581
|
+
| 티켓을 분리했다 | "별도 티켓으로 분리해 처리했습니다" | "4.3에 따로 정리했습니다" (문서 안 참조) |
|
|
582
|
+
| 설계 대안 A를 검토 후 기각했다 | 기각 사유까지 기록 | **한 줄도 싣지 않는다** |
|
|
583
|
+
| 스토어 빌드 이후 반영된다 | "다음 스토어 빌드부터" | "다음 앱 업데이트부터" |
|
|
584
|
+
| 검수용 계정/매장을 썼다 | "테스트 매장의 테스트 고객" | "검수용 매장·고객" |
|
|
585
|
+
| 화면 재현 없이 반영만 확인했다 | "코드 확인" | "반영 확인 — 수정이 운영에 반영된 것까지 확인 (화면 재현은 미실시)" |
|
|
586
|
+
| 티켓 번호 `1217296144360763` | 식별자로 씀 | **싣지 않는다** |
|
|
587
|
+
|
|
588
|
+
관통하는 원리 셋:
|
|
589
|
+
|
|
590
|
+
1. **독자가 검증할 수 없는 참조는 싣지 않는다.** 티켓 번호·내부 시스템명은 확인 수단이 없어 노이즈만 된다. 반대로 제보 원본 링크는 독자가 자기 제보를 대조할 수 있으므로 남긴다.
|
|
591
|
+
2. **우리 조직의 내부 구조를 드러내는 명사는 전부 치환 대상이다.** 배포·티켓·테스트·경로 수 — 전부 "우리 팀이 어떻게 일하는가"이지 "당신 문제가 어떻게 됐는가"가 아니다.
|
|
592
|
+
3. **약한 근거는 숨기지 말고 이름을 붙여 노출한다.** 최약 등급을 지우는 게 아니라 정의를 달아 보여준다.
|
|
593
|
+
|
|
594
|
+
독자가 바뀌면 구조까지 바뀐다.
|
|
595
|
+
|
|
596
|
+
| 독자에서 나온 결정 | 구현 | 다른 독자였다면 |
|
|
597
|
+
|---|---|---|
|
|
598
|
+
| 전 건을 검증한다 | `status` 절의 전 건 판정표 | 임원 독자였다면 판정표를 빼고 지표 밴드만 남긴다 |
|
|
599
|
+
| 건과 건을 오가며 대조한다 | 절 참조가 전부 클릭 링크(`link()`) | 순차 낭독용 문서였다면 링크는 불필요하다 |
|
|
600
|
+
| 우리 작업의 완결성을 본다 | 확인 요청 절이 "고객 숙제"가 아니라 "우리가 확정 못 한 것" | 계약 정산 문서였다면 같은 데이터가 "잔여 작업 목록"이 된다 |
|
|
601
|
+
| 실제로 화면을 눌러본다 | 위험 행동 경고를 요약과 CTA 두 곳에 중복 | 읽기만 하는 독자였다면 이 문장 자체가 불필요하다 |
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## 12. 새 프로젝트 체크리스트
|
|
606
|
+
|
|
607
|
+
| # | 채울 것 | 어디에 | 어느 단계에서 |
|
|
608
|
+
|---|---|---|---|
|
|
609
|
+
| 1 | 독자 문장 1개 (하는 일로) | (문서 아님 — 작업 전제) | 0 |
|
|
610
|
+
| 2 | "고객이 아는 참조" 도메인 | `report.json` `allow_external` | 0 |
|
|
611
|
+
| 3 | 금지 어휘·식별자 정규식 | `report.json` `forbid` | 0·6 |
|
|
612
|
+
| 4 | 절 구성과 순서 | `report.json` `sections` + `groups` | 0 |
|
|
613
|
+
| 5 | 건별 9개 필드 | `cases.json` | 1·2 |
|
|
614
|
+
| 6 | 보고서 표제로 재작성한 전 건 제목 | `cases.json` `title` | 2 |
|
|
615
|
+
| 7 | 등급 이름·클래스·정의문 (최약 등급에 **한계 명시**) | `report.json` `grades` | 3 |
|
|
616
|
+
| 8 | 요약 4칸 · 확인 요청 3~6개 · CTA | `report.json` `summary`/`open_items`/`cta` | 4 |
|
|
617
|
+
| 9 | 지표 밴드 숫자 | `report.json` `stats` | 4 |
|
|
618
|
+
| 10 | 공통 원인 도해 (**실재할 때만**) | `figure.html` + `report.json` `figure` | 4 |
|
|
619
|
+
| 11 | 팔레트 키 (또는 브랜드 6색) | `report.json` `palette` | 5 |
|
|
620
|
+
| 12 | 고객 언어 치환쌍 | `report.json` `text_fix` | 6 |
|
|
621
|
+
| 13 | 표지·꼬리말·메타 | `report.json` `kicker`/`title`/`subtitle`/`meta`/`footer` | 6 |
|
|
622
|
+
|
|
623
|
+
건드리지 않는 것: `build.py`, `palette.py`, `report.css`, `editor.js`, `editor.css`, `qa.py`, `subset_font.py`.
|
|
624
|
+
폰트를 바꾸거나 커버리지를 조정할 때만 `font-embedding.md` 를 편다.
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## 13. 미확정
|
|
629
|
+
|
|
630
|
+
1. **`open_items` 개수 3~6 의 근거.** 예시 프로젝트가 6개이고 2열 그리드가 짝수에서 깔끔하다는 것 외에, 상한·하한을 정한 실측 근거는 없다.
|
|
631
|
+
2. **등급 4단이 최적인가.** 예시 프로젝트에서 4단이 잘 동작했다는 것만 확인했다. 건이 100건을 넘거나 성격이 다른 프로젝트에서 3단/5단이 나은지는 검증하지 않았다.
|
|
632
|
+
3. **`.r-open .xref` 의 rgba 리터럴**(9절 마지막). 토큰으로 바꿔야 하는지, 밑줄 1px 이라 그대로 두는 게 맞는지 판단하지 않았다. 현재는 QA 경고로 남아 있다.
|
|
633
|
+
4. **`qa.py` #13 의 `data-internal` 제거 정규식**(`<[^>]*\bdata-internal="true".*?</\w+>`)은 중첩 요소에서 실제 `serialize()` 와 다르게 동작할 수 있다. 예시 프로젝트에는 내부 전용 블록이 0개라 이 경로가 실제로 검증되지 않았다.
|
|
634
|
+
5. **팔레트 톤 질문을 `AskUserQuestion` 으로 강제할지.** 이 문서는 "톤만 묻는다"로 사양화했으나, 도구를 써서 묻도록 강제한 실행 기록은 없다.
|