v2.2.258: /meet 화자 팀/역할 정규화 + 헤더 전조각 주입 + 검증 5종

STT 화자번호(참석자 N) 박멸→회사 표준 팀/역할 귀속, 회의 헤더 전 청크 주입, 전역 헤드라인 추출, 결정 게이트·담화 상태 태깅, 슬림 6섹션 포맷, 타임스탬프 근거, parseActionItems 헤더명 기반 재작성, 검증 패스 5종. 전체 698 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 18:10:32 +09:00
co-authored by Claude Opus 4.8
parent 5d02a8a56f
commit 6dc5f17dec
8 changed files with 333 additions and 164 deletions
+18 -6
View File
@@ -33,13 +33,14 @@ import {
transcriptHash, taskKey, loadRegisteredKeys, markRegistered,
savePending, loadPending, classifyAction,
registerAction, buildNotes, renderPendingQuestion, processConfirmDecisions,
loadGlossaryTerms, updateGlossary, extractGlossaryCandidates,
loadGlossaryTerms, updateGlossary, extractGlossaryCandidates, loadTeamRoster,
type PendingItem, type PendingFile,
} from './scheduling/meetRegistration';
import {
addBusinessDays,
toYmd,
extractMeetingDate,
extractMeetingHeader,
resolveTaskDate,
parseActionItems,
} from './scheduling/calendarHelpers';
@@ -579,12 +580,23 @@ async function runMeet(arg: string, view: Webview | undefined, context?: vscode.
// 중복 방지 키 — 동일 녹취 재실행 시 이미 등록된 액션을 건너뛰기 위한 해시 (원본 전체 기준).
const tHash = transcriptHash(transcript);
const userMetadata = metadata; // 용어집 후보 추출용 — 자동 보강 전 원본 보존
// [회의 헤더 파싱] STT 본문(첫 "참석자 N mm:ss" 줄) 앞의 헤더 블록(참석자 명단·
// 일시·장소·녹취 길이)을 메타데이터에 끌어올린다. 헤더는 첫 조각에만 있어 후반
// 조각이 명단을 못 보던 문제를, 모든 조각 프롬프트에 주입해 해소한다(화자 정규화·메타 추출).
const headerBlock = extractMeetingHeader(transcript);
if (headerBlock) {
metadata = `${headerBlock}\n${metadata ? '\n' + metadata : ''}`.trim();
}
// [회사 표준 팀 분류] 화자번호 → 팀/역할 귀속의 통제 어휘집. 모든 조각·병합에 주입.
metadata = `${metadata ? metadata + '\n' : ''}[회사 표준 팀/역할 분류 — 화자를 이 팀들 중 하나로 귀속할 것] ${loadTeamRoster()}`;
// [작성일] 회의 개요의 '작성일' 채움용 (모델은 오늘 날짜를 모름).
metadata = `${metadata}\n[작성일] ${toYmd(new Date())}`;
// [자동 용어집] 이전 /meet 들에서 누적된 인명·용어를 메타데이터에 보강 —
// meetPrompt 가 메타데이터를 STT 보정 용어집으로 쓰므로 반복 회의의 표기
// 일관성이 자동으로 좋아진다. 사용자 입력 메타데이터가 항상 우선(앞에 배치).
const glossaryTerms = loadGlossaryTerms();
if (glossaryTerms.length) {
metadata = `${metadata ? metadata + '\n' : ''}[자동 용어집 — 이전 회의에서 누적된 인명·용어 표기] ${glossaryTerms.join(', ')}`;
metadata = `${metadata}\n[자동 용어집 — 이전 회의에서 누적된 인명·용어 표기] ${glossaryTerms.join(', ')}`;
chunk(view, `📚 자동 용어집 ${glossaryTerms.length}개 용어 주입\n`);
}
// v2.2.211: 60K 하드 자르기 폐지 → 세그먼트 추출(Map) + 병합(Reduce).
@@ -696,8 +708,8 @@ async function runMeet(arg: string, view: Webview | undefined, context?: vscode.
return true;
}
// ── 검증 패스 (옵션, g1nation.meetVerifyPass) — 결정·액션을 근거 소스와 대조 ──
if (cfg.get<boolean>('meetVerifyPass', false)) {
// ── 검증 패스 (g1nation.meetVerifyPass, 기본 ON) — 결정·액션·화자번호·과확정·중복 점검 ──
if (cfg.get<boolean>('meetVerifyPass', true)) {
try {
chunk(view, `🔍 **검증 패스** — 결정·액션 근거 대조 중…`);
const t2 = Date.now();
@@ -782,7 +794,7 @@ async function runMeet(arg: string, view: Webview | undefined, context?: vscode.
if (cls.route === 'hold') {
holds.push({
idx: holds.length + 1,
owner: task.owner, work: task.work, detail: task.detail, deliverable: task.deliverable, due: task.due,
owner: task.owner, work: task.work, detail: task.detail, deliverable: task.deliverable, due: task.due, source: task.source,
kind: cls.kind, condition: cls.condition, suggestedDate: cls.suggestedDate,
});
continue;
@@ -796,7 +808,7 @@ async function runMeet(arg: string, view: Webview | undefined, context?: vscode.
if (cls.recurNote) extra.push(`↻ 반복 업무 언급(${cls.recurNote}) — 정책상 첫 1회만 등록합니다.`);
const notes = buildNotes({
detail: task.detail, meetTitle, owner: task.owner, deliverable: task.deliverable,
dueRaw: task.due, dateLabel: cls.date, extra,
dueRaw: task.due, dateLabel: cls.date, source: task.source, extra,
});
const r = await registerAction(context, {
title: evTitle, date: cls.date, notes,