genetics-mcp 2.23.0 → 2.25.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/bin/aarch64-apple-darwin/gcell +0 -0
- package/bin/aarch64-unknown-linux-musl/gcell +0 -0
- package/bin/manifest.json +5 -5
- package/bin/x86_64-apple-darwin/gcell +0 -0
- package/bin/x86_64-pc-windows-gnu/gcell.exe +0 -0
- package/bin/x86_64-unknown-linux-musl/gcell +0 -0
- package/genetics.mjs +2068 -239
- package/package.json +2 -2
- package/skills/gazette-report/SKILL.md +11 -10
- package/skills/gazette-report/scripts/tone.mjs +17 -5
- package/skills/gazette-report/scripts/tone.test.mjs +15 -2
- package/skills/gazette-report/template/skeleton.html +10 -10
- package/skills/genetics-define/SKILL.md +2 -0
- package/skills/genetics-report/SKILL.md +123 -102
- package/skills/genetics-report/assets/example/cases-briefing.json +1 -1
- package/skills/genetics-report/assets/example/cases.json +3 -3
- package/skills/genetics-report/assets/example/report-briefing-designs.json +26 -26
- package/skills/genetics-report/assets/example/report-briefing.json +3 -3
- package/skills/genetics-report/assets/example/report.json +11 -11
- package/skills/genetics-report/assets/mcp-call.mjs +160 -0
- package/skills/genetics-report/assets/patch.py +411 -0
- package/skills/genetics-report/assets/render.py +223 -0
- package/skills/genetics-report/assets/xlsx-plate.py +203 -0
- package/skills/genetics-report/references/content-pipeline.md +26 -26
- package/skills/genetics-report/references/edition-review.workflow.js +120 -23
- package/skills/genetics-report/references/font-embedding.md +1 -1
- package/skills/genetics-report/references/history.md +76 -2
- package/skills/genetics-report/references/lim-portal-format.md +109 -48
- package/skills/genetics-report/references/linear-read-test.workflow.js +50 -14
- package/skills/genetics-report/references/process.md +54 -48
- package/skills/genetics-report/references/reader-review.workflow.js +118 -33
- package/skills/genetics-report/references/visual-first.md +34 -17
- package/skills/gazette-report/scripts/package-lock.json +0 -24
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
// 판 갱신 검토 — 한 판의 **변경
|
|
1
|
+
// 판 갱신 검토 — 한 판의 **변경 자리**를 규칙·사실 대조로, 새 판 렌더본 전체를 선형 독자로 읽고 심각도 3 이상은 반박한다.
|
|
2
2
|
// 실행: Workflow 도구에 이 파일을 scriptPath 로 주고 args 를 넘긴다(배열·객체는 JSON 값 그대로).
|
|
3
|
-
// args = { file: "<새 판 report.json 절대경로>",
|
|
4
|
-
// backup: "<직전 판 백업 절대경로>", // 새 판을 만든
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// args = { file: "<새 판 report.json 절대경로>", // 편집을 적용한 새 판 원고 — 교체에 싣는 인자 파일·교체 뒤 되읽은 판이 아니다
|
|
4
|
+
// backup: "<직전 판 백업 절대경로>", // 새 판을 만든 편집의 출발점
|
|
5
|
+
// edits: "<edits.json 절대경로>", // assets/patch.py 편집 목록 — 변경 기록의 기본
|
|
6
|
+
// patch: "<patch.py 절대경로>", // 편집 목록일 때 — 편집 목록을 굳힌 그 patch.py. 기본 ~/.claude/skills/genetics-report/assets/patch.py
|
|
7
|
+
// // (없거나 그 목록을 못 읽는 판이면 시작 전 검사에서 멈춘다 — 스킬 폴더가 다른 트리의 심링크인 기계는 옛 판일 수 있다)
|
|
8
|
+
// canon: "<정본을 가리키는 한 줄>", // 수치 편집을 대조할 정본 — 파일 경로와 자리를 글로(「…/점검표.md 의 끝 7줄 · …tsv」). 여러 출처여도 한 줄로.
|
|
9
|
+
// // 안 주면 검토자는 doc 글과 handoff 에서 정본을 찾고, 어디에도 없으면 수치 편집을 「정본 없음」으로 적는다
|
|
10
|
+
// edit_script: "<edit-N.py 절대경로>", // 옛 기록: put/sub 호출로 변경 자리가 전부 적힌 스크립트(멱등). edits 가 없을 때만 쓴다
|
|
11
|
+
// doc: "<문서 이름 한 줄>", // 예: "고객사 결정 브리핑 16판" — 프롬프트 머리 「대상:」에 글자 그대로 실린다
|
|
7
12
|
// renderer: "<gazette.py 절대경로>", // 기본 report-portal private/builder/gazette.py
|
|
8
|
-
// handoff: "<HANDOFF.md 절대경로>"
|
|
13
|
+
// handoff: "<HANDOFF.md 절대경로>", // 있으면 그 판의 절을 배경으로 준다(선형 독자는 안 받는다)
|
|
14
|
+
// text: "<새 판 렌더본 텍스트 절대경로>" } // 필수 — python3 assets/render.py <새 판 report.json> --text <원고 폴더 밖 빈 폴더>/본문.txt
|
|
9
15
|
//
|
|
10
16
|
// 언제 쓰나 — 구조(PART·절·표)가 그대로이고 낱말·출처 줄·여백 주석만 고친 판. 구조가 바뀐 판은
|
|
11
17
|
// `reader-review.workflow.js`(여덟 관점)다. 낱말 손질 판을 검토 없이 발행하자 다음 판 8자리 손질이
|
|
@@ -14,36 +20,127 @@
|
|
|
14
20
|
// 세 관점 — 선형 독자(그 자리에서 뜻이 닫히나·뒤 절 번호를 가리키나·조사·중복) · 규칙 대조(렌더러 text_scan 의
|
|
15
21
|
// W2·R12h·RX_PROC·장치 이름·SOURCE_MAX·그림 번호를 코드 줄로 대조) · 사실 대조(옛 문구의 사실이 바뀌지 않았나,
|
|
16
22
|
// 백업↔새 판 JSON diff 에 스크립트가 바꾼 자리가 빠짐없이 있고 기록 안 된 변경이 없는지 — 삽입·삭제가 섞이면 줄 수는 호출 수와
|
|
17
|
-
// 다르니 자리로 센다, 수치
|
|
18
|
-
//
|
|
23
|
+
// 다르니 자리로 센다, 수치 무변경. 편집 목록이면 직전 판 사본에 patch.py 를 적용한 결과가 새 판과 같은지, 수치를 바꾼 편집은 모두 적는다).
|
|
24
|
+
// 심각도 3 이상만 반박 단계(최대 6).
|
|
25
|
+
// 편집 목록(edits)을 정식 입력으로 받는 까닭 — 2026-09-29 관보 한 판이 patch.py 편집 목록으로 만들어졌는데 이 워크플로는
|
|
26
|
+
// edit_script 만 받아, 목록을 edit_script 에 넣고 「JSON 편집 목록이다」라는 풀이를 doc 에 적어야 했다(두 번 돌림).
|
|
27
|
+
// 선형 독자는 새 판 렌더본 텍스트(args.text) 하나만 받고 CLAUDE.md 를 싣지 않는 Explore 유형으로 돈다 — 편집 스크립트·옛 문구·핸드오프를
|
|
28
|
+
// 받은 채 읽으면 처음 읽는 사람이 아니다(2026-09-26 스킬 검토: 변경 판 검토의 선형 독자 15/15 가 원고 밖 과정 파일을 열었다).
|
|
29
|
+
// 그래서 변경 자리가 아니라 문서 전체를 처음부터 읽는다. 확인 전: MEMORY.md 까지 빠지는지는 첫 실행 전사의 첨부로 확인한다.
|
|
30
|
+
// 반박은 진단(참/부분/거짓/미확인)과 처방 적합을 따로 판정한다. 진단 거짓만 refuted, 처방이 규칙에 걸리면 kept 에 남기고 rx 「처방 다시 — 까닭」.
|
|
31
|
+
// 결과 — { head·failed(검증이 실패했거나 관점이 결과를 못 냈거나 선형 독자가 렌더본을 못 열었을 때만 — 「검토 미완 — 검증 N건 실패」),
|
|
32
|
+
// kept(진단이 거짓이 아닌 발견 + rx), refuted(진단 거짓), weak(심각도 2 이하 — 사람이 훑어 고를 것), unverified(상한 6 밖·검증 실패 — 사람이 훑는다), passed }.
|
|
33
|
+
// 시작 전 검사(Check): 렌더본 파일(args.text)이 없거나 비었거나 새 판 원고(args.file)보다 오래되면 읽기 전에 멈추고 무엇이 필요한지 말한다.
|
|
34
|
+
// 편집 목록이면 patch.py 도 잰다 — 없거나, 새 판에 그 목록을 --dry 로 돌렸을 때 목록을 못 읽거나(모르는 op · 트레이스백 · JSON 아님)
|
|
35
|
+
// 「바꿈 N」(N>0 — 새 판에 편집이 아직 적용돼 있지 않다: file 과 backup 을 바꿔 줬을 때)이면 멈춘다. 종료 코드로는 가리지 않는다(금지어가 남은 정상 판도 1 이다).
|
|
36
|
+
// 워크플로 스크립트는 파일을 못 연다 — 에이전트 하나가 명령 한 줄의 출력을 옮기고 판정은 JS 가 한다(reader-review.workflow.js 머리 주석과 같다).
|
|
19
37
|
export const meta = {
|
|
20
38
|
name: 'report-edition-review',
|
|
21
|
-
description: '보고서 한
|
|
39
|
+
description: '보고서 한 판을 선형 독자(렌더본 텍스트만)·규칙 대조·사실 대조(변경 자리 — patch.py 편집 목록 또는 edit-N.py) 세 관점으로 읽고, 심각도 3 이상은 진단·처방을 따로 반박 검증한다',
|
|
22
40
|
phases: [
|
|
41
|
+
{ title: 'Check', detail: '렌더본이 있고 비지 않았고 새 판 원고보다 새로운지 · 편집 목록이면 patch.py 가 그 목록을 읽는지 — 명령 한 줄' },
|
|
23
42
|
{ title: 'Review', detail: '세 관점 병렬 — 선형 독자 · 렌더러 규칙 대조 · 사실 대조' },
|
|
24
|
-
{ title: 'Verify', detail: '심각도 3 이상 발견을 반박(최대 6)' },
|
|
43
|
+
{ title: 'Verify', detail: '심각도 3 이상 발견을 반박(최대 6) — 진단 거짓만 refuted' },
|
|
25
44
|
],
|
|
26
45
|
}
|
|
27
46
|
const A = args || {}
|
|
28
|
-
if (!A.file || !A.backup || !A.edit_script) throw new Error('args.file · args.backup
|
|
47
|
+
if (!A.file || !A.backup || !(A.edits || A.edit_script)) throw new Error('args.file · args.backup 과 args.edits(patch.py 편집 목록) 또는 args.edit_script(edit-N.py) 가 필요하다')
|
|
48
|
+
const MAKE_TEXT = 'python3 assets/render.py <새 판 report.json> --text <원고 폴더 밖 빈 폴더>/본문.txt'
|
|
49
|
+
if (!A.text) throw new Error(`args.text 가 필요하다 — 새 판 렌더본 텍스트 파일 절대경로. 선형 독자는 이 파일 하나만 읽는다. 만드는 법: ${MAKE_TEXT}`)
|
|
50
|
+
phase('Check')
|
|
51
|
+
// 렌더본이 있고 비지 않았고 새 판 원고보다 새로운지 — 파일 상태는 에이전트가 옮긴 명령 출력으로만 읽고 판정은 여기서 한다(머리 주석 「시작 전 검사」).
|
|
52
|
+
const shq = (p) => `'${String(p).replace(/'/g, `'\\''`)}'`
|
|
53
|
+
// patch.py — 편집 목록일 때만 쓴다. 글로만 가리키면 검토자가 다른 트리의 옛 사본을 찾는다(이 맥은 스킬 폴더가 심링크라 `find -type d` 로 안 잡힌다 —
|
|
54
|
+
// 2026-09-30 적대 검토). 그래서 경로를 주고, 시작 전 검사에서 셋째 파일로 잰다(`~` 는 파이썬이 푼다). 편집 스크립트 쪽 명령은 그대로다.
|
|
55
|
+
// 있는지만 재면 모자란다 — 기본 경로가 다른 트리의 옛 patch.py 로 풀리면(심링크 설치본) 새 op·[label=] 경로를 못 읽어 사실 관점이 재다 죽는다.
|
|
56
|
+
// 그래서 새 판에 그 목록을 --dry 로 한 번 돌려 넷째 칸(rc·tb·dry·out)으로 옮긴다 — 목록을 **읽는지**와 새 판에 이미 적용돼 있는지(「바꿈 0」)만
|
|
57
|
+
// 여기서 가리고, 값이 맞는지는 사실 관점 ①이 잰다. 종료 코드로 가리지 않는다 — 금지어가 남은 정상 판도 「바꿈 0」 뒤에 1 로 끝난다.
|
|
58
|
+
// 트레이스백은 따로 한 칸(tb), 「바꿈 N · …」 줄도 따로 한 칸(dry)이다 — out 은 끝 300자라 경로가 길면 「Traceback」 낱말과 앞줄이 잘린다.
|
|
59
|
+
const PATCH = A.patch || '~/.claude/skills/genetics-report/assets/patch.py'
|
|
60
|
+
const STAT_PY = 'dict(f=os.path.isfile(p), b=(len(open(p,"rb").read().strip()) if os.path.isfile(p) else -1), m=(os.path.getmtime(p) if os.path.isfile(p) else -1))'
|
|
61
|
+
const STAT_CMD = A.edits
|
|
62
|
+
? `python3 -c 'import json,os,subprocess,sys; a=list(map(os.path.expanduser, sys.argv[1:])); st=[${STAT_PY} for p in a[:3]]; r=subprocess.run([sys.executable, a[2], a[1], a[3], "--dry"], capture_output=True, text=True) if all(os.path.isfile(p) for p in a[1:]) else None; print(json.dumps(st + [dict(rc=(r.returncode if r else -1), tb=bool(r and "Traceback" in r.stderr), dry=next((l for l in (r.stdout if r else "").splitlines() if l.startswith("바꿈 ")), ""), out=((r.stdout + r.stderr)[-300:] if r else ""))]))' ${shq(A.text)} ${shq(A.file)} ${shq(PATCH)} ${shq(A.edits)}`
|
|
63
|
+
: `python3 -c 'import json,os,sys; print(json.dumps([${STAT_PY} for p in sys.argv[1:]]))' ${shq(A.text)} ${shq(A.file)}`
|
|
64
|
+
const PRE = { type: 'object', properties: { stdout: { type: 'string', description: '명령의 표준 출력 한 줄 — 글자 그대로' }, exit: { type: 'integer' } }, required: ['stdout', 'exit'] }
|
|
65
|
+
const pre = await agent(`아래 명령을 Bash 로 **한 번만, 글자 그대로** 실행하고 표준 출력 한 줄을 stdout 에 고치지 말고 옮긴다. 종료 코드는 exit 에. 명령을 바꾸거나 다른 명령·파일을 열지 않는다.\n${STAT_CMD}`,
|
|
66
|
+
{ label: 'check:files', phase: 'Check', schema: PRE, effort: 'low' })
|
|
67
|
+
let st = null
|
|
68
|
+
try { st = pre && pre.exit === 0 ? JSON.parse(pre.stdout) : null } catch (e) { st = null }
|
|
69
|
+
if (!Array.isArray(st) || st.length !== (A.edits ? 4 : 2)) throw new Error(`시작 전 검사 실패 — 렌더본·원고${A.edits ? '·patch.py' : ''} 파일 상태를 못 읽었다(${pre ? `exit ${pre.exit} · ${String(pre.stdout).slice(0, 200)}` : '검사 에이전트 결과 없음'}). resumeFromRunId 없이 새로 띄운다`)
|
|
70
|
+
if (!st[1].f) throw new Error(`args.file 파일이 없다 — ${A.file}. 새 판 report.json 절대경로를 준다`)
|
|
71
|
+
if (!st[0].f) throw new Error(`args.text 파일이 없다 — ${A.text}. 만드는 법: ${MAKE_TEXT}`)
|
|
72
|
+
if (st[0].b <= 0) throw new Error(`args.text 파일이 비었다 — ${A.text}. 렌더가 실패했을 수 있다 — 다시 뽑고 출력의 ⚠·오류를 본다: ${MAKE_TEXT}`)
|
|
73
|
+
if (A.edits && !st[2].f) throw new Error(`patch.py 가 없다 — ${PATCH}. args.patch 로 스킬 설치본의 assets/patch.py 절대경로를 준다(사실 관점이 편집 목록을 이 파일로 잰다)`)
|
|
74
|
+
if (A.edits && st[3].rc === -1) throw new Error(`args.edits 파일이 없다 — ${A.edits}. 편집 목록(edits.json) 절대경로를 준다`)
|
|
75
|
+
if (A.edits && (st[3].tb || /모르는 op|JSON 으로 못 읽었습니다/.test(String(st[3].out)))) throw new Error(`patch.py 가 이 편집 목록을 못 읽는다 — ${PATCH} (${String(st[3].out).trim().split('\n').pop().slice(0, 200)}). 편집 목록을 굳힌 그 patch.py 의 절대경로를 args.patch 로 준다 — 기본 경로가 다른 트리의 옛 판으로 풀렸을 수 있다`)
|
|
76
|
+
if (A.edits && Number((/^바꿈 (\d+) ·/.exec(String(st[3].dry)) || [])[1]) > 0) throw new Error(`새 판에 편집 목록이 아직 적용돼 있지 않다 — ${A.file} 에 --dry 로 돌리니 「${st[3].dry}」. args.file 은 편집을 적용한 새 판, args.backup 이 그 출발점이다(둘을 바꿔 주지 않았는지 본다)`)
|
|
77
|
+
if (st[0].m < st[1].m) throw new Error(`렌더본이 새 판 원고보다 오래됐다 — ${A.text} 가 ${A.file} 보다 ${Math.round(st[1].m - st[0].m)}초 앞선다. 새 판을 고친 뒤 다시 뽑는다: ${MAKE_TEXT} (그다음 resumeFromRunId 없이 새로 띄운다)`)
|
|
29
78
|
const RENDERER = A.renderer || '레포 report-portal 의 private/builder/gazette.py(args.renderer 가 없으면 이 기계에서 경로를 찾아 쓴다 — 못 찾으면 규칙 관점 결과에 「렌더러 못 읽음」으로 적는다)'
|
|
79
|
+
// 반박에도 렌더러 경로를 준다 — 2026-09-30 실제 1회에서 반박 하나가 args.renderer 대신 다른 트리의 옛 렌더러를 읽고 판정했다.
|
|
80
|
+
const RENDERER_PATH = A.renderer || '레포 report-portal 의 private/builder/gazette.py'
|
|
30
81
|
const DOC = A.doc || A.file
|
|
31
|
-
|
|
82
|
+
// 변경 기록이 무엇인지(CTX)와 사실 관점 ①(기록 대조), 반박이 읽을 기록의 이름(src)만 기록 종류에 따라 갈린다. edit_script 쪽 세 값은 전과 한 글자도 같다.
|
|
83
|
+
// 「제자리에서 고친다」 경고는 CTX 에 둔다 — 규칙 관점·반박도 patch.py 를 돌릴 수 있다.
|
|
84
|
+
// 정본 — 글로만 「doc·handoff 가 가리키는 정본」이라 하면 검토자는 그 인자 이름을 본 적이 없다(CTX 는 「대상」·「배경」으로만 싣는다).
|
|
85
|
+
// args.canon 을 받아 CTX 에 「정본」으로 싣고, 없으면 프롬프트에 **보이는 자리**(「대상」 글 · 배경 파일)를 가리킨다 — 정본을 doc 글에 적어
|
|
86
|
+
// 넘기던 호출(2026-09-29 실제 호출: 「새 사실의 정본은 …md 의 끝 7줄」)이 끊기지 않게, 어디에도 없을 때만 「정본 없음」이다(2026-09-30 적대 검토).
|
|
87
|
+
const CANON = A.canon ? '②에서 그 수치를 원고 안의 다른 자리와, 위 정본에 대조한다'
|
|
88
|
+
: '②에서 그 수치를 원고 안의 다른 자리와 대조하고, 위 「대상」 글이나 배경 파일이 정본을 가리키면 거기에도 대조한다 — 어디에도 정본이 없으면 수치 편집마다 「정본 없음」으로 적는다'
|
|
89
|
+
const REC = A.edits ? {
|
|
90
|
+
src: '편집 목록',
|
|
91
|
+
change: `${A.edits} 의 patch.py 편집 목록에 전부 적혀 있다 — JSON 배열이고 항목마다 op 하나다. patch.py 는 ${PATCH} 이다 — op 의 칸과 뜻은 그 파일 머리 주석의 op 표를 읽는다. patch.py 는 준 파일을 제자리에서 고친다 — 새 판·직전 판에는 --dry 로만 돌리고, 적용은 빈 임시 폴더에 복사한 사본에 한다.`,
|
|
92
|
+
count: '① 새 판에 patch.py 를 --dry 로 돌려 「바꿈 0」인지 보고, 직전 판 사본에 편집 목록을 적용한 결과가 새 판과 JSON 값까지 같은지 본다 — 다르면 기록되지 않은 변경이 있다. 두 판을 diff 해 forbid 밖의 편집마다 diff 에 보이는지 path 로 센다(set 한 번이 표의 여러 행을 바꾸므로 diff 줄 수는 편집 수와 다르다). forbid 는 바꾸지 않고 남은 낱말을 센다. 수치(인원·kg·cm·날짜)를 바꾼 편집은 path 와 옛 값 → 새 값으로 모두 센다(목록 밖 변경은 위 사본 대조가 잡는다) — ' + CANON + '.',
|
|
93
|
+
} : {
|
|
94
|
+
src: '스크립트',
|
|
95
|
+
change: `${A.edit_script} 에 put/sub 호출로 전부 적혀 있다(옛 문구 → 새 문구).`,
|
|
96
|
+
count: '① 직전 판과 새 판의 JSON 을 diff 해 스크립트의 put/sub·삽입·삭제가 바꾼 자리가 빠짐없이 보이는지, 기록되지 않은 변경이 없는지 자리로 센다(삽입·삭제가 섞이면 diff 줄 수는 호출 수와 다르다). 수치(인원·kg·cm·날짜)가 한 곳도 안 바뀌었는지도 센다.',
|
|
97
|
+
}
|
|
98
|
+
const CTX = `대상: ${DOC}. 직전 판 → 이 판의 변경은 ${REC.change} 새 판 원고는 ${A.file}, 직전 판은 ${A.backup}.${A.handoff ? ` 배경은 ${A.handoff} 의 이 판 절.` : ''}${A.canon ? ` 정본(수치의 출처)은 ${A.canon}.` : ''} 한글로 답한다. 파일은 읽기만 한다 — 고치지 않는다.`
|
|
99
|
+
// 선형 독자의 머리말 — 위 CTX(편집 스크립트·직전 판·핸드오프)를 받지 않는다. 독자가 보는 것은 렌더본뿐이다(render.py --text).
|
|
100
|
+
const TEXT_CTX = `[읽기 전용. 한글로 답한다. 철저함: very thorough — 발췌하지 말고 파일 전체를 처음부터 끝까지 읽는다.]
|
|
101
|
+
읽을 것: ${A.text} — 새 판 렌더본에서 화면에 보이는 글만 화면 순서대로 뽑은 텍스트(그림·영상 자리는 「[그림]」「[영상]」, 표 칸은 「 | 」).
|
|
102
|
+
이 파일 하나만 연다. 원고에 없는 지식으로 뜻을 메웠다면 그것 자체가 발견이다. 원고 JSON·편집 스크립트·핸드오프·같은 폴더의 다른 파일은 열지 않는다.
|
|
103
|
+
이 파일을 끝까지 읽었으면 opened=true. 열지 못했거나 비어 있으면 opened=false 로 두고 findings·passed 는 비운다 — 다른 파일로 대신 읽지 않는다.
|
|
104
|
+
where 는 이 파일에 보이는 절 번호·이름·표 이름으로, evidence 는 이 파일의 줄 번호와 그 줄 글자로 적는다.`
|
|
32
105
|
const FINDINGS = { type: 'object', properties: { findings: { type: 'array', items: { type: 'object', properties: { where: { type: 'string' }, severity: { type: 'integer' }, claim: { type: 'string' }, evidence: { type: 'string' }, fix: { type: 'string' } }, required: ['where', 'severity', 'claim', 'evidence'] } }, passed: { type: 'array', items: { type: 'string' } } }, required: ['findings', 'passed'] }
|
|
33
|
-
|
|
106
|
+
// 렌더본 관점(선형 독자)은 파일을 열었는지부터 답한다 — 못 연 관점의 「발견 0」을 「문제 없음」으로 읽지 않게.
|
|
107
|
+
const FINDINGS_TEXT = { type: 'object', properties: { ...FINDINGS.properties, opened: { type: 'boolean', description: '렌더본 파일을 열어 끝까지 읽었으면 true, 못 열었거나 비었으면 false' } }, required: [...FINDINGS.required, 'opened'] }
|
|
108
|
+
// 진단과 처방을 따로 판정한다 — 한 칸(refuted)에 「처방이 다른 규칙을 어기면」「확신이 없으면」까지 묶어 진단이 참인 발견이 기각됐다(2026-09-26 스킬 검토).
|
|
109
|
+
const VERDICT = { type: 'object', properties: {
|
|
110
|
+
diagnosis: { type: 'string', enum: ['참', '부분', '거짓', '미확인'], description: '발견의 주장이 맞나 — 확신이 없으면 미확인' },
|
|
111
|
+
rx_fit: { type: 'string', enum: ['맞음', '다시'], description: '처방(fix)이 규칙에 맞나 — 진단과 따로' },
|
|
112
|
+
rx_why: { type: 'string', description: '다시면 걸린 규칙과 까닭 한 줄, 맞음이면 빈 문자열' },
|
|
113
|
+
reason: { type: 'string' } }, required: ['diagnosis', 'rx_fit', 'rx_why', 'reason'] }
|
|
34
114
|
const LENSES = [
|
|
35
|
-
{ key: 'linear', prompt: `${
|
|
115
|
+
{ key: 'linear', agentType: 'Explore', text: true, prompt: `${TEXT_CTX}\n[선형 독자] 새 판을 처음 읽는 고객 담당이 되어 파일 처음부터 끝까지 순서대로 읽는다. 자리마다 (a) 그 자리에서 뜻이 닫히는가 (b) 앞에서 정의되지 않은 낱말·번호를 가리키는가 — 뒤 절 번호 가리킴은 금지 규칙이고 표 번호·「다음 절」로 바꿔 놓은 것도 독자를 뒤로 보내면 적는다 (c) 어색한 문장·조사·중복(절 이름과 부제, 같은 답 묶음 안의 되풀이)이 있는가 (d) 인쇄본에서 죽는 화면 어휘(「누르면」)가 있는가 (e) 대상·판·시험·상태·선택지를 부르는 낱말마다, 독자가 문서 밖(자기 화면 글자, 원본 문서, 공급사 공식 명칭)에서 본 글자인가? 이 문서가 붙인 이름이면 정의가 있어도 발견이다. 처방은 뜻풀이가 아니라 원래 이름으로 바꾸는 것이다 — 원래 이름을 이 파일만으로 알 수 없으면 fix 에 이름을 지어 넣지 말고 「원래 이름으로 바꾼다(이 파일에 없음)」라고 적는다. 문제가 없는 자리도 passed 에 적는다. severity 1~5(5=독자가 뜻을 잃음).` },
|
|
36
116
|
{ key: 'rules', prompt: `${CTX}\n[규칙 대조] 렌더러 ${RENDERER} 의 text_scan 규칙 — W2 출처 줄(rx_loc: 쪽·행·https·건 §·§ n·부록 N, user-provided 만; rx_meta 제작 설명·그림 번호), R12h 앞 절→뒤 절 가리킴(rx_fwd_case/rx_fwd_sec/rx_other_doc, fwd_spot 이 훑는 칸), RX_PROC 과정 어휘, 장치 이름 충돌(건 행 이름 labels 낱말이 다른 절 표 열·부제에), SOURCE_MAX, 그림·표 번호 가리킴, 문장 60자·괄호 부연·표 주석 문장 수 — 를 코드에서 직접 읽고, 변경 자리의 새 문구가 각 규칙을 만족하는지, 새 문구가 다른 규칙을 새로 어기지 않는지 하나씩 대조한다. 판정 근거는 렌더러 파일의 줄 번호로 적는다.` },
|
|
37
|
-
{ key: 'facts', prompt: `${CTX}\n[사실 대조]
|
|
117
|
+
{ key: 'facts', prompt: `${CTX}\n[사실 대조] ${REC.count} ② 변경 자리마다 새 문구가 옛 문구의 사실을 바꾸지 않았는지 원고 안에서 대조한다 — 가리키는 부록·표·용어가 실제로 있는가, 이름으로 바꾼 위치가 같은 대상인가, 사실문으로 고친 문장이 요지·다른 절과 같은 사실인가. 다른 문서를 인용한 자리는 그 문서를 열 수 있으면 열어 대조하고 못 열면 「확인 불가」로 적는다. 바뀐 사실이 있으면 severity 4 이상.` },
|
|
38
118
|
]
|
|
39
119
|
const reads = await pipeline(LENSES,
|
|
40
|
-
(l) => agent(l.prompt, { label: `review:${l.key}`, phase: 'Review', schema: FINDINGS }).then((r) => r && { lens: l.key, ...r }))
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
120
|
+
(l) => agent(l.prompt, { label: `review:${l.key}`, phase: 'Review', schema: l.text ? FINDINGS_TEXT : FINDINGS, ...(l.agentType ? { agentType: l.agentType } : {}) }).then((r) => r && { lens: l.key, ...r }))
|
|
121
|
+
// 렌더본을 못 열었다고 답한 관점 — 그 발견은 쓰지 않고 머리에 적는다. 결과를 못 낸 관점(lensFail)과 따로 센다.
|
|
122
|
+
const unread = LENSES.filter((l, i) => l.text && reads[i] && reads[i].opened !== true).map((l) => l.key)
|
|
123
|
+
const all = reads.filter((r) => r && !unread.includes(r.lens))
|
|
124
|
+
const strongAll = all.flatMap((r) => r.findings.filter((f) => f.severity >= 3).map((f) => ({ lens: r.lens, ...f })))
|
|
125
|
+
const strong = strongAll.slice(0, 6)
|
|
126
|
+
log(`발견 ${all.reduce((n, r) => n + r.findings.length, 0)} · 심각도≥3 ${strongAll.length}(반박 ${strong.length}) · passed ${all.reduce((n, r) => n + r.passed.length, 0)}`)
|
|
44
127
|
const verdicts = await parallel(strong.map((f) => () =>
|
|
45
|
-
agent(`${CTX}\n[반박] 다음 발견을
|
|
46
|
-
|
|
128
|
+
agent(`${CTX}\n[반박] 다음 발견을 원고·${REC.src}·렌더러(${RENDERER_PATH})를 직접 읽어 반박해 본다. 발견: (${f.lens}) ${f.where} — ${f.claim}. 근거: ${f.evidence}. 처방: ${f.fix || '(없음)'}.${f.lens === 'linear' ? ` 이 발견은 렌더본 텍스트 ${A.text} 만 읽은 독자가 냈다 — 독자에게 보이는 글로 판정한다. 문서가 붙인 이름을 짚은 발견이면 문서 안의 정의·캡션은 반증이 아니다 — 독자가 문서 밖에서 본 글자인지를 판정한다.` : ''}
|
|
129
|
+
diagnosis(진단): 발견이 참/부분/거짓/미확인. 사실이 아니거나 규칙상 문제가 아니면 거짓. 확신이 없으면 미확인.
|
|
130
|
+
진단과 처방은 따로 판정한다 — 처방이 다른 규칙을 어겨도(포인터·원래 이름 대신 새 이름 짓기·만든 이름에 뜻풀이만 더하기 포함) diagnosis 는 그대로 두고 rx_fit=다시, rx_why 에 걸린 규칙과 까닭. 규칙에 맞으면 rx_fit=맞음, rx_why 는 빈 문자열.
|
|
131
|
+
reason 은 파일·줄·문구 인용으로.`, { label: `verify:${f.lens}`, phase: 'Verify', schema: VERDICT }).then((v) => ({ ...f, verdict: v }))))
|
|
132
|
+
// 진단 거짓만 refuted. 처방이 규칙에 걸린 발견은 kept 에 남기고 rx 를 단다. 상한 밖과 검증 실패는 unverified 로 돌려준다 —
|
|
133
|
+
// 전에는 상한 6 밖의 심각도 3 이상 발견이 결과 어디에도 없었고, 검증이 실패한 발견도 kept·refuted 양쪽에서 조용히 빠졌다.
|
|
134
|
+
const judged = verdicts.filter((v) => v && v.verdict).map((v) => ({ ...v, rx: v.verdict.rx_fit === '다시' ? `처방 다시 — ${v.verdict.rx_why || '규칙에 걸림'}` : '' }))
|
|
135
|
+
const kept = judged.filter((v) => v.verdict.diagnosis !== '거짓')
|
|
136
|
+
const vfail = strong.filter((_, i) => !(verdicts[i] && verdicts[i].verdict))
|
|
137
|
+
const unverified = [...strongAll.slice(6).map((f) => ({ ...f, why: '검증 상한 6 초과' })), ...vfail.map((f) => ({ ...f, why: '검증 실패' }))]
|
|
47
138
|
const weak = all.flatMap((r) => r.findings.filter((f) => f.severity < 3).map((f) => ({ lens: r.lens, ...f })))
|
|
48
|
-
|
|
49
|
-
|
|
139
|
+
const lensFail = LENSES.filter((_, i) => !reads[i]).map((l) => l.key)
|
|
140
|
+
if (lensFail.length) log(`⚠ 관점 ${lensFail.length}개가 결과를 못 냈다(API 과부하 등) — resumeFromRunId 로 다시 돌리면 끝난 관점은 캐시를 탄다`)
|
|
141
|
+
if (unread.length) log(`⚠ 렌더본을 못 열었다고 답한 관점 ${unread.join(', ')} — 그 발견은 쓰지 않았다. 경로·권한을 고친 뒤 새로 띄운다`)
|
|
142
|
+
if (strongAll.length > strong.length) log(`반박 상한 6 밖 ${strongAll.length - strong.length}건 — unverified 로 돌려준다`)
|
|
143
|
+
// 실패는 결과 머리에 적는다 — 실패를 「발견 0」으로 읽지 않게(reader-review.workflow.js 와 같은 머리).
|
|
144
|
+
const failHead = (vfail.length || lensFail.length || unread.length) ? `검토 미완 — ${[vfail.length && `검증 ${vfail.length}건 실패`, lensFail.length && `관점 ${lensFail.length}개 실패(${lensFail.join(', ')})`, unread.length && `렌더본 못 엶 ${unread.length}(${unread.join(', ')})`].filter(Boolean).join(' · ')}` : ''
|
|
145
|
+
if (failHead) log(failHead)
|
|
146
|
+
return { ...(failHead ? { head: failHead, failed: true } : {}), kept, refuted: judged.filter((v) => v.verdict.diagnosis === '거짓'), weak, unverified, passed: all.map((r) => ({ lens: r.lens, passed: r.passed })) }
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
| 경로 | 무슨 일이 일어나는가 | 근거 |
|
|
9
9
|
|---|---|---|
|
|
10
|
-
| 로컬 렌더 | `cfg.update(t['lim-report'])` 가 `font` 키를 통째로 교체 | `assets/render.py
|
|
10
|
+
| 로컬 렌더 | `cfg.update(t['lim-report'])` 가 `font` 키를 통째로 교체 | `assets/render.py main()` |
|
|
11
11
|
| 포털 발행 | `font` 가 `REPORT_CLIENT_KEYS` 에 없어 `report_client_fields()` 가 깎아 냄 | `report_publish.php:31-` |
|
|
12
12
|
|
|
13
13
|
그래서 `font.embed: false` 도 안 먹는다 — 교체된 블록에 `embed` 키가 없어 기본값 `True` 로 돌아간다.
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
반려 원문 — 「뒷 내용을 나는 알고 너는 알아도, 독자는 모름. 이해관계자 입장 고려 안 해?」
|
|
42
42
|
그래서 회차 낱말만이 아니라 진행 상태 어휘·상태 열·개수로 상태를 세는 표 제목을 함께 금하고, `text_scan()` 과정 어휘 ⚠ 를 두었다.
|
|
43
43
|
|
|
44
|
-
## 5.
|
|
44
|
+
## 5. 말투 반려 — 요청 자리와 주어 (2026-09-02 ~ 09-26) — SKILL 반드시 지키는 것 5·5a
|
|
45
45
|
|
|
46
46
|
앞의 세 처방이 모두 **종결을 못 건드린 채 어휘만 갈았다.** 같은 실수를 반복하지 않도록 경위를 남긴다.
|
|
47
47
|
|
|
@@ -51,6 +51,8 @@
|
|
|
51
51
|
| 2026-09-03 · 검수 보고 | 동의해 주시면 됨 | 이런 말투 존나 싸가지 없지 않아? | 「부탁드림」으로 교체 |
|
|
52
52
|
| 2026-09-03 · 같은 보고서 | 보고 칸의 요청문 | 보고와 요청의 차이를 잘 모르는거야? | 요청문은 요청 절에만 |
|
|
53
53
|
| 2026-09-11 · 결정 브리핑 | 부탁드**림** · 진행하겠**음** | 존나 마음에 안듦 · 관보가 원래 이런말투임? | **종결을 하십시오체로** |
|
|
54
|
+
| 2026-09-17 · 결정 브리핑 | …7월 31일을 보라. | 싸가지 없지 않겠어? | 해라체 명령 ⚠(`RX_CMD`, §13) |
|
|
55
|
+
| 2026-09-26 · 기술 점검 보고 | 초를 셀 **것** · 업체에 물어야 **함** · 정하는 것은 고객 **몫임** · 보면 **됨** | 싸가지없는 말투 몇개 좀 검토해서 genetics 개선이 필요해보이는데? · 보강이 아니라 더 근본 먼저 스킬 검토가 우선 아니야? | **규칙을 주어 하나로 합침**(아래) |
|
|
54
56
|
|
|
55
57
|
네 번째 반려가 겨눈 것은 **2·3차 처방 그 자체**였다. 종결을 못 바꾼 이유는
|
|
56
58
|
「톤 게이트가 `습니다` 를 세므로 이쪽은 바꿀 수 없다」는 전제였는데 **그 전제가 틀렸다** — 게이트는 경고이지 거절이 아니다.
|
|
@@ -63,6 +65,14 @@
|
|
|
63
65
|
9/3 에 반려된 「회신 주시면 됨」을 계속 처방하고 있었다. 시험도 그 문장을 경고 0 인 깨끗한 문서로 굳혀 두었다.
|
|
64
66
|
서버 처방을 하십시오체로 바꾸고, 도구 설명에 남은 반려 문구는 `tools/contract-drift.py` 가 세게 했다.
|
|
65
67
|
|
|
68
|
+
2026-09-26 — 여섯째 반려에서 규칙이 아니라 **스킬 구조**를 대조했다. 다섯 번의 처방은 모두 증상이 난 자리의 어미만 갈았다.
|
|
69
|
+
원인은 세 겹이었다. ① 칸 정의가 독자를 주어로 만들었다 — 확인 방법 「고객이 밟을 순서」, 확인 요청 「상대의 판단이 필요한 것」, Advice 「어디를 참조하라」.
|
|
70
|
+
그런데 규칙 5 는 그 칸을 「우리·사물이 주어인 기록 자리」로 묶어 개조식만 허락하고 요청문은 막았다 — 남는 문장은 명령뿐이다.
|
|
71
|
+
② 본보기가 명령을 가르쳤다(확인 방법 「열어 볼 것」, Advice 「함께 읽을 것」 — 뒤의 것은 다른 고객 관보에 글자 그대로 복제됨).
|
|
72
|
+
③ 관보 원전(행정안전부·KISA 지침서)은 위에서 아래로 지시하는 문서라, 조판과 함께 그 말투(「~할 것」·「~ 필요」)까지 들여왔다.
|
|
73
|
+
실측(로컬 관보 원고 71벌 · 서로 다른 문장 15,355): 보고 칸의 「~시면」 요청 158 · 「~면 됨」 32 · 「~해야 함」 36 — 확인 방법·확인 요청·여백 주석에 몰림.
|
|
74
|
+
처방은 덧대기가 아니라 합치기였다 — 「톤은 주어와 자리가 함께 정한다」 하나(SKILL 반드시 지키는 것 5·5a), 칸 정의를 사물·화면 주어로, 본보기 교체, 원전 말투를 들이지 않는다는 한 줄.
|
|
75
|
+
|
|
66
76
|
## 6. 스킬에 값을 박은 사고 (2026-08-17) — SKILL 반드시 지키는 것 9
|
|
67
77
|
|
|
68
78
|
스킬 표에 특정 업종 아이콘을 적어 두었고, 검수기에는 그 테넌트의 강조색 hex 를 상수로 박아 두었다.
|
|
@@ -120,7 +130,7 @@
|
|
|
120
130
|
- **검사기가 남의 문서의 절 번호를 뒤 절로 오인** — R12h 정규식이 「검수 보고 4차 제5절」·「제10절」·「제11절」을 이 문서(7절까지)의 뒤 절로 세어, 15판이 세 자리의 위치 구절을 억지로 지웠다(3.17kg 의 자리가 사라짐).
|
|
121
131
|
→ `text_scan` W5 「N차 … 제N절」 예외 · 16판이 표 이름(「두 계산식의 차이 실측」)으로 위치를 되살림. 표 번호 선참조(「표 7-1」)를 셀지는 미결.
|
|
122
132
|
- **사용자 결정 둘(2026-09-15)** — 두 물음 「읽는 법에 확인 요청 한 줄을 둬도 되나」·「「바로 반영」 지시가 판 갱신 검토보다 앞서도 되나」에 둘 다 「응」.
|
|
123
|
-
→ SKILL
|
|
133
|
+
→ SKILL 5 요청 자리 목록(당시 5a)·108행·0.5단계 7행 · process.md · lim-portal-format §10 경어체 행·§12.5b · genetics lim 결정 두 장.
|
|
124
134
|
|
|
125
135
|
## 13. 「그 자리 길」「복제본 길」 (2026-09-17) — SKILL 반드시 지키는 것 12 · 0.5단계 3행 · 카피 게이트 새 행
|
|
126
136
|
|
|
@@ -163,3 +173,67 @@ cases 절의 DOM 은 간지 → 여백 주석 → 건 전부 → 인용 → 자
|
|
|
163
173
|
절 인용을 문서대로 kind 블록 앞으로, `_plate_ids()`·`_tables_of()` 로 경고 스캔(세로 긴 도판·앞 절 가리킴·표 번호·안 걸린 도판)이 건의 것도 세게,
|
|
164
174
|
건 안의 전폭 자산 ⚠, 서버 `report_data_validate()` 건 `plates` 게이트, `api.php` 자리 잡은 도판 셈, MCP 스키마 세 칸, CSS `.sheet__ev`,
|
|
165
175
|
시험 「건별 근거」. 집필 규칙은 SKILL 14 · §4 주석 · §11-1 「놓을 절」 · §11-10. 편집기는 이 칸을 아직 모른다(절 `quotes`·`tables` 와 같은 처지).
|
|
176
|
+
|
|
177
|
+
## 16. 작업하며 지은 판·칸 이름 (2026-09-21) — SKILL 반드시 지키는 것 12 · 0단계 물음 5 · 0.5단계 3행 · 본보기
|
|
178
|
+
|
|
179
|
+
고객사 산식 개편 관보 28차 발행 직후. 사용자가 정의한 적 없는 지은 이름들을 직역으로 바꾸라며 반려했다(뜻을 알아볼 수 없다는 까닭).
|
|
180
|
+
경위 — 원고가 앱의 두 배포 채널과 산식·등급표를 작업하며 지은 이름 넷(고객사가 반려한 판·칸 이름 — 이름 자체는 소속처 반려 결정에만 둔다)으로 불렀다. 문서 안에 판 이름 넷의 표가 있었지만
|
|
181
|
+
그 이름 자체가 독자 화면 어디에도 없는 말이라 읽히지 않았다 — 「정의가 앞에 있나」만 묻는 독자 검토로는 못 잡는다.
|
|
182
|
+
독자 화면의 이름과 맞춘 대응표(관리자 화면의 채널 이름 그대로 + 「앱」 · 산식은 날짜 · 등급표는 고객 쪽 문서 번호)는 발행 뒤에야 만들었고,
|
|
183
|
+
원고 257곳·도판 16장·영상 머리 칩을 한꺼번에 바꿨다 — 한 번 지은 이름은 도판 칩까지 퍼진다.
|
|
184
|
+
그때 스킬과 렌더러에는 반영이 0 이었고, 본보기 `report-briefing-designs.json` 은 그 가운데 한 이름을 원고 칸 24곳에 싣고 있었다.
|
|
185
|
+
처방(2026-09-26 스킬 검토 ①·④) — 반드시 지키는 것 12 에 「작업하며 지은 이름은 정의했어도 쓰지 않는다」, 0단계 물음 5 와 이름 대응표 `names.md`,
|
|
186
|
+
용어 잠금 표의 이름 열은 그 대응표에서만, 본보기의 그 24곳을 「<독자 화면의 채널 이름> 앱」 자리 표시로,
|
|
187
|
+
렌더러 소속처 반려 이름 ⚠ 과 그 목록(이날 반려된 넷이 첫 항목 — 반려를 기록할 때 늘린다. 처음엔 렌더러 저장소의 장부 파일이었고,
|
|
188
|
+
같은 날 고객 자료를 제품 저장소에 두지 않으려고 소속처 반려 결정의 `rejected_names` 칸으로 옮겼다 — §18 끝. 첫 항목은 서버 배포 뒤에 적는다 · 운영 반영 확인 전).
|
|
189
|
+
|
|
190
|
+
## 17. 대체어 · 시간순 · 「탓」 (2026-09-22) — SKILL 반드시 지키는 것 12 · 카피 게이트 새 행 · lim-portal-format §10 · §10-1
|
|
191
|
+
|
|
192
|
+
고객사 운영 DB 판올림 관보, 같은 날 두 판.
|
|
193
|
+
|
|
194
|
+
- **6판** — 사용자 반려 셋: 필요한 내용은 공들여 보이지 않고 덜 중요한 것은 요약으로 채워 FCG 의 작업이 안 보인다 ·
|
|
195
|
+
밤새 한 검증을 작성자 시선의 낮춘 표현으로 적었다 · 관보를 시간순으로 적었다.
|
|
196
|
+
원인 셋 — 회차마다 새 건을 뒤에 덧대 시간순이 뼈대가 됐다 · 비교 시험과 설정 전수 대조를 렌더러 길이 관문에 맞춰 한 줄 행으로 눌러 검증 설계가 안 보였다 ·
|
|
197
|
+
전수 대조가 잡아 고친 것을 작성자의 점검표 시선(「뒤늦게」)으로 썼다.
|
|
198
|
+
처방은 소속처 결정문(위험 → FCG 검증 → 결과 순서, 시간순은 부록의 경과 표와 발행 이력에만)이다. 스킬 반영: **미반영** —
|
|
199
|
+
2026-09-26 스킬 검토 제안 ①~⑤ 밖이라 이번 개정에 넣지 않았다. 뼈대 규칙으로 올릴지는 사람이 정한다.
|
|
200
|
+
- **7판(로컬본)** — 사용자 반려: 책임을 가리키는 낱말과, 직역 대신 맥락으로 지어낸 다른 낱말을 쓰지 말 것 · 유치한 문구가 군데군데 남았다.
|
|
201
|
+
경위 — 기술 대상 다섯(설정 넷과 인스턴스 하나)을 원래 기술 이름 대신 작업하며 지은 설명형 대체어로 불렀다
|
|
202
|
+
(대체어와 원래 이름의 짝은 소속처 반려 결정에만 둔다).
|
|
203
|
+
스킬 12번이 「요금·기능은 그것이 무엇인지로 부르고(「구버전 유지 요금」)」라고 가르친 모양 그대로였다.
|
|
204
|
+
「8.4 탓」·「새 버전 탓」은 렌더러 참조 번호 경고(「8.0」·「8.4」를 절 번호로 셈)를 피하려고 바꿔 적은 것이고,
|
|
205
|
+
5열 표 칸 한도가 17자 원래 설정 이름에는 경고를 주고 그 5자 대체어는 통과시켰다 — 셈이 원래 이름을 비싸게 매기면 작성자는 이름을 짓는다.
|
|
206
|
+
9/17~9/22 사이 전체 검토 10회·판 갱신 검토 12회가 그 대체어를 문제로 짚은 발견은 0건이었다.
|
|
207
|
+
처방(2026-09-26) — 12번을 조건문으로(독자가 보는 이름이면 본명 + 첫 등장 괄호 풀이), 렌더러에 「탓」 ⚠(`RX_BLAME`) · 대화 이력 ⚠(`RX_TALK`) ·
|
|
208
|
+
반려 이름 목록(이날 반려된 대체어 셋 — 소속처 반려 결정의 `rejected_names` 칸), 길이·참조 번호 셈에서 원래 이름과 그 판 번호를 빼고 표 칸 경고에 「경고를 피하려고 이름을 바꾸지 말고 …」.
|
|
209
|
+
|
|
210
|
+
## 18. 「D1 IAM v4.2 부착」 — 작업 색인 이름 (2026-09-26) — SKILL 개요 원칙 셋 · 체크리스트 7단계 독자 검토 행 · 9a·9b 끝 행 · visual-first §7
|
|
211
|
+
|
|
212
|
+
고객 문서가 아니라 채팅 답이다. 운영 DB 판올림 전환 판정표에서 사용자가 할 일을 「D1 IAM v4.2 부착」이라고만 적었다.
|
|
213
|
+
사용자 반려 원문: 「IAM v4.2가 과거 오래 전 채팅일 수 있어서 … 과거 채팅내역을 또 찾아야돼」 · 「이런 부분 신경 안 써줄거면 그냥 여기서 EOF하자. 나도 힘들다.」
|
|
214
|
+
D1(판정표 줄 번호)·v4.2(작업하며 붙인 정책 판 번호)는 작업 쪽 색인이지 독자의 말이 아니다 — 고객 문서에서 반려된 판 이름·대체어(§16·§17)와 같은 뿌리다.
|
|
215
|
+
|
|
216
|
+
이 반려로 「독자가 이해 못 함」 계열 반려 19건(2026-09-01~09-26)을 되짚는 스킬 검토를 했다. 스킬의 「독자는 과정을 모른다」 요구를 확인하는 장치 둘이 모두 과정을 아는 쪽이었다.
|
|
217
|
+
- 렌더러 경고는 그날 반려된 낱말 목록이라 다음 반려는 목록 밖의 새 이름으로 났다 — 반려 문구 18개를 넣어 보니 4개만 잡혔다.
|
|
218
|
+
- 독자 검토 에이전트는 결정 기록·핸드오프·메모리를 먼저 받은 채 원고 JSON 을 읽었다 — 「처음 읽는 사람」 관점 23회 중 13회가 원고 밖 과정 파일을 스스로 열었다.
|
|
219
|
+
- 검증 칸 12개가 사실 틀림(가중 +10)으로 차 읽기 발견이 늘 검증 밖이었고(15회 중 14회), 거를 사유 하나로 진단이 참인 발견이 버려졌고,
|
|
220
|
+
사용량 한도로 검증이 전부 실패한 실행이 「반영할 발견 0」으로 찍혔다.
|
|
221
|
+
|
|
222
|
+
처방 —
|
|
223
|
+
① 스킬 글: 12번 조건문 · 지은 이름 금지 · 0단계 물음 5 · 개요 원칙 셋 · 본보기 자리 표시 · 포인터 처방 정리(치환 유형 C·10번 — 뒤 절이 앞 절을 되짚는 방향만).
|
|
224
|
+
② 독자 검토 입력을 렌더본 텍스트로(`render.py --text` · 두 관점 Explore 유형 · 이름 물음).
|
|
225
|
+
③ 검증 칸 등급 분리 · 진단과 처방 따로 · 실패는 결과 머리에 · 체크리스트 7단계 통과 기준(뜀 심각도 3 이상 0 · 만든 이름 0).
|
|
226
|
+
④ 렌더러 ⚠ 셋과 길이 셈 · 포털 `forbid` 경고(그 전에는 입구에서 깎여 포털 그물이 0 이었다).
|
|
227
|
+
⑤ 이 절과 앞 두 절 · 9a·9b 끝 행(반려 기록 때 「스킬 반영」 칸과 반려 결정의 `rejected_names` 칸).
|
|
228
|
+
|
|
229
|
+
채팅 답에는 이 스킬의 관문이 닿지 않는다. 이 기계에서는 Stop 훅 `~/.claude/hooks/reply-judge.py` 가 그 몫을 한다 —
|
|
230
|
+
답 안의 D1·v4.2·「앞서 말한」 같은 이름이 같은 답 안에서 풀이됐는지 판정 모델에 묻고, 어겼으면 「보충 —」 한 문단을 덧붙이게 한다.
|
|
231
|
+
사용자 설정에 등록돼 돈다(2026-09-26 확인). 발행 직전 훅 `~/.claude/hooks/report-gate.py` 는 렌더러의 반려 이름 검사를 부르도록 작성됐지만
|
|
232
|
+
같은 날 어느 설정에도 등록돼 있지 않았다. 둘 다 이 기계의 파일이고 이 스킬과 함께 배급되지 않는다.
|
|
233
|
+
|
|
234
|
+
반려 이름 목록의 자리(2026-09-26, 사용자 결정 「가」 — 포털 서버의 소속처 자료에 둔다) — 처음엔 렌더러 저장소의 장부 파일에 소속처별로 두었는데, 그러면 고객사의 반려 원문과
|
|
235
|
+
문서 번호가 제품 저장소에 실린다. 그래서 목록을 **그 소속처의 반려 결정 장**(`remember_decision` 의 `rejected_names` 칸)으로 옮겼다 —
|
|
236
|
+
반려 한 번이 쓰기 한 번이고(까닭·날짜·잊기·뒤집기가 결정 장에 이미 있다), 포털은 발행·모의 발행 때 서버가 그 목록을 렌더러에 넘기며,
|
|
237
|
+
로컬 렌더와 발행 직전 훅은 `list_rejected_names` 로 받는다. 흔한 낱말인 이름은 정규식 대신 함께 설 낱말(`near`)로 가른다 —
|
|
238
|
+
렌더 자리는 소속처들이 함께 쓰고 파이썬 정규식은 되짚기 상한이 없다.
|
|
239
|
+
운영 반영 확인 전 — 서버 배포와 첫 항목 기록 전까지는 포털·로컬 렌더·훅 어느 쪽도 이 목록으로 세지 않는다(`lim-portal-format.md` §10-1 머리 ⚠).
|