genetics-mcp 2.16.7 → 2.17.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/genetics.mjs +120 -2
- package/package.json +1 -1
- package/skills/genetics-report/SKILL.md +29 -5
package/genetics.mjs
CHANGED
|
@@ -1140,6 +1140,34 @@ const MASK = '[가림: 서버에 올리며 지움]';
|
|
|
1140
1140
|
const DROP_TYPES = new Set(['file-history-snapshot', 'file-history-delta', 'attachment',
|
|
1141
1141
|
'last-prompt', 'queue-operation', 'system']);
|
|
1142
1142
|
|
|
1143
|
+
/**
|
|
1144
|
+
* 남기는 attachment(2026-09-03, 오너 결정 「브라우저 픽은 세션과 지식에 실린다」) — 사용자가 브라우저에서
|
|
1145
|
+
* 집은 요소(iab 픽)는 훅이 프롬프트에 끼운 「[iab 픽 N] …」 줄로만 존재하고, 전사에는 attachment
|
|
1146
|
+
* (hook_additional_context) 레코드로 남는다. 위 집합이 그것을 통째로 버려 다른 기계의 resume·두뇌 장·
|
|
1147
|
+
* 세션 요지에 픽이 0건이었다(실측 2026-09-03: 한 세션에 113건 중 8건이 픽). 그래서 **그 줄만** 남긴다.
|
|
1148
|
+
* ⚠ 서버(agent_session.php 의 agent_session_keep_attachment)와 **같은 술어·같은 접두 리터럴**이어야 한다 —
|
|
1149
|
+
* smoke 가 두 벌을 대조한다. 큐가 남은 판(「[iab 새 픽 N / 큐 M]」)은 안 남긴다(그 줄은 매 프롬프트 반복이라 잡음).
|
|
1150
|
+
* content 는 실측상 **문자열 하나짜리 배열**이고 그 안에 \n 으로 줄이 들어 있다 — 원소가 아니라 줄로 본다.
|
|
1151
|
+
*/
|
|
1152
|
+
const KEEP_ATTACHMENT_PREFIX = '[iab 픽';
|
|
1153
|
+
function isKeptAttachment(r) {
|
|
1154
|
+
if (!r || r.type !== 'attachment') return false;
|
|
1155
|
+
const a = r.attachment;
|
|
1156
|
+
if (!a || typeof a !== 'object' || a.type !== 'hook_additional_context') return false;
|
|
1157
|
+
const parts = Array.isArray(a.content) ? a.content : [a.content];
|
|
1158
|
+
return parts.some((s) => typeof s === 'string' && s.split('\n').some((line) => line.startsWith(KEEP_ATTACHMENT_PREFIX)));
|
|
1159
|
+
}
|
|
1160
|
+
/** 남긴 픽 줄의 홈 경로 상대화 — 서버 agent_session_mask_home_paths 와 같은 뜻(/Users/<x>·/home/<x>·/root·C:\Users\<x> → ~).
|
|
1161
|
+
* relHome 은 cwd 칸의 접두만 보므로 줄 가운데 박힌 절대경로(훅 shortPath 가 못 자른 것)는 여기서 걷는다. */
|
|
1162
|
+
function maskHomeInPick(content) {
|
|
1163
|
+
const one = (s) => (typeof s === 'string'
|
|
1164
|
+
? s.replace(/(?<![\p{L}\p{N}_])\/(?:Users|home)\/[^/\s]+/gu, '~')
|
|
1165
|
+
.replace(/(?<![\p{L}\p{N}_])\/root(?=\/|\s|$)/gu, '~')
|
|
1166
|
+
.replace(/(?<![\p{L}\p{N}_])[A-Za-z]:[\\/]Users[\\/][^\\/\s]+/giu, '~')
|
|
1167
|
+
: s);
|
|
1168
|
+
return Array.isArray(content) ? content.map(one) : one(content);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1143
1171
|
function maskSecrets(text) {
|
|
1144
1172
|
let n = 0;
|
|
1145
1173
|
for (const [, re] of SECRET_SHAPES) {
|
|
@@ -1223,7 +1251,8 @@ function scrubTranscript(raw) {
|
|
|
1223
1251
|
const k = relHome(r.cwd);
|
|
1224
1252
|
cwds.set(k, (cwds.get(k) || 0) + 1);
|
|
1225
1253
|
}
|
|
1226
|
-
if (DROP_TYPES.has(r.type)) { dropped++; continue; }
|
|
1254
|
+
if (DROP_TYPES.has(r.type) && !isKeptAttachment(r)) { dropped++; continue; }
|
|
1255
|
+
if (r.type === 'attachment') r.attachment.content = maskHomeInPick(r.attachment.content); // 남긴 픽 줄뿐이다(위 술어)
|
|
1227
1256
|
if ('toolUseResult' in r) { r.toolUseResult = MASK; redacted++; }
|
|
1228
1257
|
if (typeof r.cwd === 'string') r.cwd = relHome(r.cwd);
|
|
1229
1258
|
const c = r?.message?.content;
|
|
@@ -2518,6 +2547,13 @@ const TOOLS = [
|
|
|
2518
2547
|
description: '이 사례가 걸린 **명령 문구**(예: "INSERT INTO rp_agent_presence"). 다른 세포가 그 문구가 든 명령을 치기 직전에 이 사례를 본다.' },
|
|
2519
2548
|
errors: { type: 'array', items: { type: 'string' },
|
|
2520
2549
|
description: '이 사례의 **오류 문자열**(예: "CONSTRAINT ck_tree_machine failed"). 지금은 적어 두기만 한다.' },
|
|
2550
|
+
picks: { type: 'array', maxItems: 20, items: { type: 'object', required: ['selector', 'text'], properties: {
|
|
2551
|
+
selector: { type: 'string', description: '페이지에서 다시 잴 자리 — 훅 줄의 sel `…` 그대로' },
|
|
2552
|
+
text: { type: 'string', description: '사람이 본 글자 — 훅 줄의 "…" 그대로' },
|
|
2553
|
+
source: { type: 'string', description: '고칠 자리 — 훅 줄의 <저장소 상대 경로>:<줄> 그대로(없으면 비움). 경로는 paths 트리거에 자동으로 들어간다' },
|
|
2554
|
+
url: { type: 'string', description: '그 화면 주소(알면)' },
|
|
2555
|
+
} }, description: '사용자가 브라우저에서 **집은 요소**(iab 픽). 사용자가 "iab N" 이라 했으면 훅이 끼운 「#N <tag> · 경로:줄 · sel `…` · "글자"」 줄에서 selector·text·source 를 **그대로** 옮긴다 — 지어내지 않는다. '
|
|
2556
|
+
+ '픽은 이 세션 밖으로 안 넘어가므로(다른 기계·다른 사람은 못 본다) 이 칸이 유일한 기록이다. 장에 「집은 자리」 절로 선다(최대 20, 칸당 300자).' },
|
|
2521
2557
|
},
|
|
2522
2558
|
required: ['tenant', 'title', 'symptom', 'fix'],
|
|
2523
2559
|
},
|
|
@@ -2551,10 +2587,63 @@ const TOOLS = [
|
|
|
2551
2587
|
tags: { type: 'array', items: { type: 'string' }, description: '갈래(최대 8). ★ 이것이 있어야 이 결정이 「일」 후보 계산에 들어간다.' },
|
|
2552
2588
|
work: { type: 'string', description: '**이 결정이 곧 과업이면** 그 일의 열쇠(영문 소문자·숫자·붙임표, 예: hnl-wait). 적으면 다음 바퀴에 그 이름의 일이 「계획」으로 선다 — 착수 전에 세우는 정문이다. 이미 열린 일의 열쇠면 이 결정이 그 일의 **항목**(작업 리스트 한 줄)으로 서고 간트에 저장 즉시 보인다 — 항목 여럿이면 결정을 여러 번 적는다(항목마다 제 근거를 갖는다).' },
|
|
2553
2589
|
order: { type: 'array', items: { type: 'string' }, description: '일 사이 **순서**를 정하는 결정이면 일의 열쇠를 앞선 것부터(최대 24). 표에 저장하지 않고 일 목록이 이 결정을 읽어 그 순서로 선다 — 순서가 바뀌면 새 결정을 적는다.' },
|
|
2590
|
+
plan: { type: 'array', maxItems: 64, items: { type: 'object', required: ['item', 'from', 'to'], properties: {
|
|
2591
|
+
item: { type: 'string', description: '항목의 결정 장 경로(예 decisions/W-01-….md) — works 가 보여 주는 항목 열쇠 그대로' },
|
|
2592
|
+
from: { type: 'string', description: '계획 시작일 YYYY-MM-DD' },
|
|
2593
|
+
to: { type: 'string', description: '계획 종료일 YYYY-MM-DD (시작 이상)' },
|
|
2594
|
+
} }, description: '항목별 **계획 기간**을 정하는 결정이면 항목마다 {item, from, to}(최대 64). 표에 저장하지 않고 간트가 이 결정을 읽어 「계획」 열과 점선 막대로 그린다 — 관측(막대)과 다른 축이다. 항목 하나만 고치려면 그 항목만 적은 새 결정을 남기면 된다(항목 단위로 가장 새 결정이 이긴다).' },
|
|
2595
|
+
picks: { type: 'array', maxItems: 20, items: { type: 'object', required: ['selector', 'text'], properties: {
|
|
2596
|
+
selector: { type: 'string', description: '페이지에서 다시 잴 자리 — 훅 줄의 sel `…` 그대로' },
|
|
2597
|
+
text: { type: 'string', description: '사람이 본 글자 — 훅 줄의 "…" 그대로' },
|
|
2598
|
+
source: { type: 'string', description: '고칠 자리 — 훅 줄의 <저장소 상대 경로>:<줄> 그대로(없으면 비움)' },
|
|
2599
|
+
url: { type: 'string', description: '그 화면 주소(알면)' },
|
|
2600
|
+
} }, description: '사용자가 브라우저에서 **집은 요소**(iab 픽) — remember_case 의 같은 칸. 사용자가 "iab N" 이라 했으면 훅 줄의 #N 에서 그대로 옮긴다, 지어내지 않는다. 장에 「집은 자리」 절로 선다(최대 20).' },
|
|
2554
2601
|
},
|
|
2555
2602
|
required: ['tenant', 'title', 'what'],
|
|
2556
2603
|
},
|
|
2557
2604
|
},
|
|
2605
|
+
{
|
|
2606
|
+
name: 'forget_decision',
|
|
2607
|
+
description:
|
|
2608
|
+
'**결정 장 하나를 잊는다** — 그 소속처 지식의 `decisions/` 에서 걷어내 휴지통(trash/decisions, 시각 붙은 사본)으로 옮긴다. '
|
|
2609
|
+
+ '검색·목록·일 항목·굽기에서 빠진다.\n'
|
|
2610
|
+
+ '언제 부르는가: 잘못 만든 장을 걷어낼 때 — 제목 오타, 원문자 같은 특수문자가 경로에 들어가 get_case 가 못 여는 장, '
|
|
2611
|
+
+ '합본 뒤 남은 조각, 같은 결정의 중복. 사람이 "지워줘 / 걷어내 / 스텁 치워" 라고 할 때.\n'
|
|
2612
|
+
+ '★ **뒤집힌 결정은 잊지 않는다** — status 를 「뒤집힘 → …」로 적어 남긴다. 왜 그렇게 정했었는지가 값이다.\n'
|
|
2613
|
+
+ '★ 되돌리는 도구는 없다 — 복구는 서버 휴지통에서 사람이 한다. 지우기 전에 get_case 로 전문을 한 번 읽어라.',
|
|
2614
|
+
inputSchema: {
|
|
2615
|
+
type: 'object',
|
|
2616
|
+
properties: {
|
|
2617
|
+
tenant: { type: 'string', description: '대상 소속처 slug(이름도 받는다 — list_my_tenants 참조).' },
|
|
2618
|
+
path: { type: 'string', description: 'search_cases·remember_decision 이 준 path 그대로(decisions/….md). 제목을 줘도 저장과 같은 자로 찾는다.' },
|
|
2619
|
+
},
|
|
2620
|
+
required: ['tenant', 'path'],
|
|
2621
|
+
},
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
// 사례 잊기(2026-09-03, 오너 결정 (e)) — 결정 잊기와 **같은 자**(wiki_page_forget, kind='cases'),
|
|
2625
|
+
// 다른 폴더. 서버 창구는 DELETE /api/wiki/case(scope decision.write).
|
|
2626
|
+
name: 'forget_case',
|
|
2627
|
+
description:
|
|
2628
|
+
'**사례 장 하나를 잊는다** — 그 소속처 지식의 `cases/` 에서 걷어내 휴지통(trash/cases, 시각 붙은 사본)으로 옮긴다. '
|
|
2629
|
+
+ '검색·트리거(도구 직전 알림)·목록에서 빠진다.\n'
|
|
2630
|
+
+ '언제 부르는가: 잘못 만든 장을 걷어낼 때 — 제목 오타, 원문자 같은 특수문자가 경로에 들어가 get_case 가 못 여는 장, '
|
|
2631
|
+
+ '증상을 지어내 사례로 잘못 적은 것(정한 것이면 remember_decision 으로 다시), 같은 문제의 중복. '
|
|
2632
|
+
+ '사람이 "지워줘 / 걷어내 / 그 사례 치워" 라고 할 때.\n'
|
|
2633
|
+
+ '★ **「같은 제목이면 덮어쓴다」와 다르다** — 덮어쓰기는 장을 고치는 것(제목이 같아야 한다), 잊기는 장을 없애는 것. '
|
|
2634
|
+
+ '틀린 내용을 고칠 것이면 remember_case 로 같은 제목에 다시 적는 쪽이 맞다. '
|
|
2635
|
+
+ '잊은 뒤 같은 제목으로 remember_case 하면 **새 장**으로 다시 선다(옛 본문은 휴지통에만).\n'
|
|
2636
|
+
+ '★ 두뇌 장이 이 사례를 가리키고 있으면 감사에 고아로 선다 — 잊기는 그 링크를 안 고친다.\n'
|
|
2637
|
+
+ '★ 되돌리는 도구는 없다 — 복구는 서버 휴지통에서 사람이 한다. 지우기 전에 get_case 로 전문을 한 번 읽어라.',
|
|
2638
|
+
inputSchema: {
|
|
2639
|
+
type: 'object',
|
|
2640
|
+
properties: {
|
|
2641
|
+
tenant: { type: 'string', description: '대상 소속처 slug(이름도 받는다 — list_my_tenants 참조).' },
|
|
2642
|
+
path: { type: 'string', description: 'search_cases·remember_case 가 준 path 그대로(cases/….md). 제목을 줘도 저장과 같은 자로 찾는다.' },
|
|
2643
|
+
},
|
|
2644
|
+
required: ['tenant', 'path'],
|
|
2645
|
+
},
|
|
2646
|
+
},
|
|
2558
2647
|
{
|
|
2559
2648
|
name: 'list_breaks',
|
|
2560
2649
|
description:
|
|
@@ -4112,12 +4201,14 @@ async function callTool(name, args = {}) {
|
|
|
4112
4201
|
title: args.title, what: args.what,
|
|
4113
4202
|
who: args.who || '', when: args.when || '', why: args.why || '',
|
|
4114
4203
|
reopen: args.reopen || '', status: args.status || '', tags: args.tags || [],
|
|
4115
|
-
work: args.work || '', order: args.order || [],
|
|
4204
|
+
work: args.work || '', order: args.order || [], plan: args.plan || [],
|
|
4205
|
+
picks: Array.isArray(args.picks) ? args.picks : [], // 집은 자리(2026-09-03)
|
|
4116
4206
|
// ★ 출처는 우리가 채운다 — 모델에게 안 묻는다(remember_case 와 같은 규율). 표지가
|
|
4117
4207
|
// 열린 일과 만나 항목으로 설 때 「누가 심었나」(간트의 세션 자국)가 이것이다.
|
|
4118
4208
|
...myCitation(),
|
|
4119
4209
|
});
|
|
4120
4210
|
const lines = [`${r.note} — ${r.tenant} · ${r.path}`];
|
|
4211
|
+
if (Number(r.picks) > 0) lines.push(`집은 자리 ${r.picks}건 실림 — 다른 기계·다른 사람도 그 요소를 본다.`);
|
|
4121
4212
|
// 안 적은 것을 **그렇게 말한다** — 조용히 열린 결정을 만들거나 계산 밖에 두지 않는다.
|
|
4122
4213
|
if (!args.reopen) {
|
|
4123
4214
|
lines.push('재개 조건을 안 적어 이 결정은 「아직 열린 것」으로 읽힌다. 끝난 결정이면 reopen 에 "조건 없음(종결)" 을 적을 것.');
|
|
@@ -4125,6 +4216,9 @@ async function callTool(name, args = {}) {
|
|
|
4125
4216
|
if (!args.tags || !args.tags.length) {
|
|
4126
4217
|
lines.push('갈래(tags)가 없어 이 결정은 「일」 후보 계산에 안 들어간다.');
|
|
4127
4218
|
}
|
|
4219
|
+
if (Array.isArray(args.plan) && args.plan.length) {
|
|
4220
|
+
lines.push(`계획 기간 ${args.plan.length}건을 적었다 — 그 항목의 간트 「계획」 열·점선 막대에 바로 선다(항목 단위로 가장 새 결정이 이긴다).`);
|
|
4221
|
+
}
|
|
4128
4222
|
// 전체 맥락 정리 줄이 섰는지도 말한다 — 결정 저장이 종합의 박자가 됐다(2026-08-31). 옛 서버(칸 없음)는 침묵.
|
|
4129
4223
|
if (r.insights_queued === true) {
|
|
4130
4224
|
lines.push('이 결정으로 전체 맥락 정리가 다시 돕니다(몇 분 뒤 지식 화면에).');
|
|
@@ -4145,17 +4239,41 @@ async function callTool(name, args = {}) {
|
|
|
4145
4239
|
}
|
|
4146
4240
|
return lines.join('\n');
|
|
4147
4241
|
}
|
|
4242
|
+
case 'forget_decision': {
|
|
4243
|
+
const r = await api('DELETE', '/api/wiki/decision?tenant=' + encodeURIComponent(args.tenant)
|
|
4244
|
+
+ '&path=' + encodeURIComponent(String(args.path || '')));
|
|
4245
|
+
const lines = [`${r.note} — ${r.tenant} · ${r.path}`];
|
|
4246
|
+
if (r.trashed_to) lines.push(`휴지통: ${r.trashed_to} (복구는 서버에서 사람이 파일을 되돌린다)`);
|
|
4247
|
+
if (typeof r.index_dropped === 'number') {
|
|
4248
|
+
lines.push(r.index_dropped ? `index.md 에서 ${r.index_dropped}줄 걷었다.` : 'index.md 에는 이 장의 줄이 없었다.');
|
|
4249
|
+
}
|
|
4250
|
+
return lines.join('\n');
|
|
4251
|
+
}
|
|
4252
|
+
case 'forget_case': {
|
|
4253
|
+
// forget_decision 과 같은 꼴(2026-09-03) — 서버 note·trashed_to·index_dropped 를 **그대로** 옮긴다.
|
|
4254
|
+
// 프로즈를 여기서 다시 지으면 두 벌이 된다(remember_decision 의 work_note 교훈, 2026-09-01).
|
|
4255
|
+
const r = await api('DELETE', '/api/wiki/case?tenant=' + encodeURIComponent(args.tenant)
|
|
4256
|
+
+ '&path=' + encodeURIComponent(String(args.path || '')));
|
|
4257
|
+
const lines = [`${r.note} — ${r.tenant} · ${r.path}`];
|
|
4258
|
+
if (r.trashed_to) lines.push(`휴지통: ${r.trashed_to} (복구는 서버에서 사람이 파일을 되돌린다)`);
|
|
4259
|
+
if (typeof r.index_dropped === 'number') {
|
|
4260
|
+
lines.push(r.index_dropped ? `index.md 에서 ${r.index_dropped}줄 걷었다.` : 'index.md 에는 이 장의 줄이 없었다.');
|
|
4261
|
+
}
|
|
4262
|
+
return lines.join('\n');
|
|
4263
|
+
}
|
|
4148
4264
|
case 'remember_case': {
|
|
4149
4265
|
const r = await api('POST', '/api/wiki/case?tenant=' + encodeURIComponent(args.tenant), {
|
|
4150
4266
|
title: args.title, symptom: args.symptom, cause: args.cause || '', fix: args.fix,
|
|
4151
4267
|
evidence: args.evidence || '', tags: args.tags || [],
|
|
4152
4268
|
paths: args.paths || [], commands: args.commands || [], errors: args.errors || [],
|
|
4269
|
+
picks: Array.isArray(args.picks) ? args.picks : [], // 집은 자리(2026-09-03) — 그대로 넘긴다, 모양은 서버가 검사
|
|
4153
4270
|
// ★ **출처는 우리가 채운다 — 모델에게 안 묻는다.** 스키마에 노출하면 지어낸다
|
|
4154
4271
|
// (DESIGN-session-as-vcs.md:136-141). 모르면 안 보내고, 서버는 안 적는다.
|
|
4155
4272
|
...myCitation(),
|
|
4156
4273
|
});
|
|
4157
4274
|
// 밀기 결과도 그대로 옮긴다 — 몇에게 갔고 누가 왜 못 받았는지(구서버는 필드가 없어 침묵).
|
|
4158
4275
|
const lines = [`${r.note} — ${r.tenant} · ${r.path}`];
|
|
4276
|
+
if (Number(r.picks) > 0) lines.push(`집은 자리 ${r.picks}건 실림 — 다른 기계·다른 사람도 그 요소를 본다.`);
|
|
4159
4277
|
// ★ 창구가 낸 경고를 **맨 앞에** 옮긴다 — 쓰는 그 순간이 고치기 가장 싼 자리다(2026-09-01).
|
|
4160
4278
|
if (r.warn) lines.push('⚠ ' + r.warn);
|
|
4161
4279
|
if (Array.isArray(r.matched_paths)) {
|
package/package.json
CHANGED
|
@@ -76,7 +76,8 @@ version: "4.0.0"
|
|
|
76
76
|
오래 안 적혀 있어서 사고가 났다(2026-09-02, 보고서 #32) — 「~해 주셔야 함」·「회신 필요」·
|
|
77
77
|
「확인 필요」로 나갔고 고객이 **「이거 너무 싸가지없는 거 아니야?」**로 반려했다.
|
|
78
78
|
고치는 법은 금지 어휘를 쓰는 것이 **아니라** 높임 어간 `-시-` 를 되살리는 것이다 —
|
|
79
|
-
|
|
79
|
+
「확인 부탁드림」·「정해 주시면 반영하겠음」·「회신 주시면 이어서 진행함」. 제목은 명사형 「~ 요청」.
|
|
80
|
+
⚠ **「~하시면 됨」도 요청 자리에서는 하대다**(2026-09-03 재반려) — 아래 5a.
|
|
80
81
|
서버가 `dry_run` 경고로 센다(`lib/report_tone.php`).
|
|
81
82
|
- `tenant` 는 키가 가리키는 고객사와 일치해야 한다(오발행 방지 가드). 값은 소속처 slug 우선·이름 폴백 — 아래 :228 의 `slug` 는 **보고서** slug 라 다른 것이다.
|
|
82
83
|
- `sections[].kind` 는 `summary|status|cases|asks|note` 다섯 가지뿐 — 그 밖의 값은 절이 통째로 사라지므로 서버가 거절한다.
|
|
@@ -359,12 +360,35 @@ render·css·폰트를 함께 얹는다. 직접 부르면 옛 서식 시트가
|
|
|
359
360
|
|
|
360
361
|
| 상대가 할 일 | 쓰지 않는다 | 쓴다 |
|
|
361
362
|
|---|---|---|
|
|
362
|
-
| 제목 | ~해 주셔야 함 · ~ 확인 필요 | **~ 요청** (명사형이 공문 표준) |
|
|
363
|
-
| 회신 청함 | 회신 필요. ·
|
|
364
|
-
| 확인 청함 | 설치해 확인하면 됨. |
|
|
365
|
-
| 값을 정해 달라 함 | 네 글자로 지정 — 반영함 | 네 글자로 정해
|
|
363
|
+
| 제목 | ~해 주셔야 함 · ~ 확인 필요 · **서술문 제목** | **~ 요청** + 기한 괄호(명사형이 공문 표준) |
|
|
364
|
+
| 회신 청함 | 회신 필요. · **회신 주시면 됨.** | 회신 **부탁드림** · 표시해 회신 주시면 **반영하겠음** |
|
|
365
|
+
| 확인 청함 | ~인지 확인. · 설치해 확인하면 됨. | 의견을 **부탁드림** · 보시면 **확인됨** |
|
|
366
|
+
| 값을 정해 달라 함 | 네 글자로 지정 — 반영함 | 네 글자로 정해 **주시면 반영하겠음** |
|
|
367
|
+
| 우리가 아쉬운 요청 | **동의해 주시면 됨.** | 동의 여부를 **요청드림** |
|
|
366
368
|
|
|
367
369
|
`-시-` 는 금지 어휘가 아니라서 **개조식을 깨지 않고** 정중해진다.
|
|
370
|
+
|
|
371
|
+
⚠ **`-시-` 만으로는 부족하다 — 이 규칙의 두 번째 반려**(2026-09-03, 보고서 #112).
|
|
372
|
+
「① 계약 기간을 10월 30일까지 연장하는 것에 동의해 주시면 됨」이 **「이런 말투 존나 싸가지
|
|
373
|
+
없지 않아? 전반적으로 말장난하는 어투네?」**로 반려됐다. `-시-` 를 살려도 **「됨」은 사실
|
|
374
|
+
통보의 종결**이라, 고객이 주어인 문장에 붙으면 「그것만 하면 된다」는 지시가 되고 —
|
|
375
|
+
특히 우리가 아쉬워서 드리는 요청(계약 연장·매장 협조)에서 어긋난다. 같은 종결이 문서
|
|
376
|
+
전체에 반복되면 문체가 아니라 말버릇으로 읽힌다(반려 문구의 「말장난하는 어투」).
|
|
377
|
+
**갈리는 자리는 종결 어미가 아니라 문장의 주어다** — 주어가 우리면 개조식, 주어가 고객이면
|
|
378
|
+
요청형(요청드림·부탁드림·정해 주시면 반영하겠음·보시면 확인됨). 「~하시면 됨」은 고객이
|
|
379
|
+
**이미 하기로 한 절차의 안내**에만 남기고 새로 부탁하는 자리에는 쓰지 않는다.
|
|
380
|
+
정본은 genetics 결정문
|
|
381
|
+
`decisions/고객-문서-어투-상대가-주어인-문장은-요청드림-부탁드림으로-맺는다.md`(hnl) —
|
|
382
|
+
이 스킬은 패키지로 덮어써지므로 여기 적은 것은 사본이다.
|
|
383
|
+
|
|
384
|
+
⚠ **보고 칸에 요청문을 두지 마라 — 세 번째 반려**(2026-09-03 저녁, 같은 보고서).
|
|
385
|
+
건의 `how_to_check`·`fix`·`remaining`, 절 `paragraphs`, `summary` 는 **보고 자리**다.
|
|
386
|
+
거기에 「…을 수용하실 수 있는지 의견을 부탁드림」「…를 보시면 확인됨」을 넣자
|
|
387
|
+
**「보고와 요청의 차이를 잘 모르는거야?」**로 반려됐다. 보고 칸은 사실과 계획만 —
|
|
388
|
+
「검수 기준. A가 됨. B가 뜸.」「셈법은 01절 ③ 회신에 따라 확정함」. 요청은 `asks` 절의
|
|
389
|
+
`open_items`·`cta` 와 PART I 간지에만 둔다. 계사 「~임」으로 끝나는 판정문
|
|
390
|
+
(「순서는 다른 항목 뒤임」)도 무성의하게 읽힌다 — 우리 행위 동사로 적는다
|
|
391
|
+
(「다른 항목을 마친 뒤 착수함」). 정본: genetics `decisions/고객-문서-보고-칸에는-요청문을-두지-않는다-요청은-요청-절에만.md`(hnl).
|
|
368
392
|
⚠ **관형 명사구는 고치지 마라** — 「회신이 필요한 것은 4가지임」의 주어는 고객이 아니라
|
|
369
393
|
「것」이라 이름이지 명령이 아니다. 「자격이 필요함」처럼 주어가 사물인 「필요」도 그대로 둔다.
|
|
370
394
|
여기까지 높이면 표지 통계·색인 라벨이 말을 거는 문장이 되어 오히려 어색해진다.
|