v2.2.257: /meet 회의록 책임 소재·근거 정책 4종

실제 회의록 산출물 분석에서 드러난 4개 결함을 프롬프트 정책으로 차단.
공유 출력 형식(단일샷+reduce)과 추출(map) 단계 모두에 적용.

- 익명·번호 화자("참석자 1")를 액션 담당으로 확정 금지 → [미지정-확인필요].
  한 익명에 액션 몰리면 "(동일 화자 여부 확인)" — 가짜 책임 배정 차단.
- 내용 없는 인용("이렇게 이렇게/그거") 근거 금지 → [내용 확인필요].
- 기한 역참조: 리스크·논의의 마감("다음 주 수요일")을 결부된 액션 기한에 반영.
- 참석자 명단 정합성: 본문 화자가 명단에 없으면 "(명단 외 화자 — 확인필요)".

§4 지시문·최종 점검 체크리스트 반영. 회귀 가드 +10건, 전체 694 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-19 18:19:20 +09:00
parent 76d5fedfb5
commit 5d02a8a56f
4 changed files with 78 additions and 4 deletions
+9
View File
@@ -1,5 +1,14 @@
# Astra Patch Notes
## v2.2.257 (2026-06-19)
### 📝 `/meet` 회의록 — 책임 소재·근거 정책 4종 (익명 담당·빈 인용·기한·명단 정합)
실제 회의록 산출물 분석에서 드러난 4개 결함을 프롬프트 정책으로 차단. 공유 출력 형식(단일샷+reduce)과 추출(map) 단계 모두에 적용.
- **익명·번호 화자 책임 배정 금지**: "참석자 1" 같은 실명 미확인 화자를 액션 담당으로 확정하지 않고 `[미지정-확인필요]` 로 둠. 한 익명에 액션이 몰리면 "(동일 화자 여부 확인)" 표기 — 화자분리 오류로 인한 **가짜 책임 배정** 차단.
- **내용 없는 인용 금지**: "이렇게 이렇게/그거/이거" 같은 지시대명사뿐인 발화는 결정·액션 근거로 인용 불가 → 핵심 내용을 `[내용 확인필요]` 로 표기.
- **기한 역참조**: 리스크·논의에 등장한 마감("다음 주 수요일")을 결부된 액션 기한 칸에 연결 — 액션은 전부 "미정"인데 본문엔 마감이 떠 있는 모순 제거.
- **참석자 명단 정합성**: 본문 화자가 회의 개요 참석자에 없으면 "(명단 외 화자 — 확인필요)" 표기.
- §4 액션 지시문·최종 점검 체크리스트에 게이트 반영. 회귀 가드 테스트 +10건([meetPrompt.test.ts](tests/meetPrompt.test.ts)), 전체 694 통과. 코어 채팅 경로(v2.2.256)는 불변.
## v2.2.256 (2026-06-19)
### 🧩 코어 채팅 경로 — 큰 입력 청킹·통합 + 실제 컨텍스트 창 정렬 + 모델 핸들 race 수정
큰 입력을 넣으면 `Failed to acquire LM Studio model handle … Operation canceled` 로 턴 전체가 죽던 문제를 3계층으로 해결. `/meet`·`/review` 와 달리 **일반 채팅(코어 경로)** 은 그동안 단일 예산 호출이라 약한 모델·큰 입력에서 무너졌다 — 그 갭을 메움.
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "astra",
"displayName": "Astra",
"description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.",
"version": "2.2.256",
"version": "2.2.257",
"publisher": "g1nation",
"license": "MIT",
"icon": "assets/icon.png",
@@ -72,6 +72,10 @@ const OUTPUT_FORMAT = `# 작성 원칙 (회의록 품질 — 출력 전 반드
- **결과 중심**: 발언 순서·토론 과정·"누가 무슨 말을 했는지"를 나열하지 말고 *결과*를 적는다. (예: "PlayCanvas를 논의함"❌ → "PlayCanvas/Babylon.js 비교 검토 진행 예정"✅) 책임 소재나 입장 차이가 핵심일 때만 발언자를 밝힌다.
- **담당자는 개인 우선**: "개발팀/QA팀" 같은 조직 단위가 아니라 개인 이름(예: 송병준, 김원일 PD)으로 적는다. 실제로 개인이 안 정해졌으면 "개발팀 (담당자 지정 필요)" 형태로 표기.
- **증빙 보존**: 결정되지 않은 사항이라도 중요한 논의·리스크는 빠짐없이 기록한다(향후 이력·분쟁 근거).
- **익명·번호 화자에 책임 배정 금지(최우선)**: "참석자 1", "발언자 A", "(주체 불명확)"처럼 *실명이 확인 안 된 화자*를 액션 아이템 담당으로 확정하지 말 것. 담당 칸은 \`[미지정-확인필요]\`로 두고 근거 발언만 남긴다 — 익명에게 가짜 책임을 붙이는 것이 회의록 신뢰도를 가장 크게 해친다. 또한 **한 익명 화자에게 액션이 여러 건 몰리면** 화자분리 오류일 수 있으니 그 항목들 작업 상세 끝에 "(동일 화자 여부 확인)"을 덧붙인다.
- **내용 없는 인용 금지**: "이렇게 이렇게", "그거", "이거", "저렇게" 처럼 지시대명사뿐이라 *내용이 비어 있는* 발화는 결정·액션의 근거로 인용하지 말 것. 그런 발화만 근거인 항목은 핵심 내용을 \`[내용 확인필요]\`로 표기한다(빈 인용을 근거인 척 달지 말 것). 표기 오타와는 다른, *내용 공백* 문제다.
- **기한 역참조**: 리스크·논의·녹취 어디든 등장한 날짜·마감("다음 주 수요일", "이달 말" 등)은 *직접 결부된 게 분명한* 액션의 기한 칸에 연결한다. 결부가 불확실하면 기한 칸에 "(기한 후보: …)"로 보수적으로 표기한다 — 액션 기한을 전부 "미정"으로 비우면서 본문엔 마감이 떠 있는 모순을 막는다.
- **참석자 명단 정합성**: 본문(액션·결정·논의)에 등장한 발언자가 회의 개요 '참석자'에 없으면 그 항목 옆에 "(명단 외 화자 — 확인필요)"를 붙인다.
# 출력 형식 (Output Format — 정확히 이 구조를 유지)
@@ -91,7 +95,7 @@ const OUTPUT_FORMAT = `# 작성 원칙 (회의록 품질 — 출력 전 반드
(이번 회의에서 확정된 결정이 없으면 "이번 회의에서 확정된 결정사항 없음"이라고 명시한다 — 빈칸·생략 금지.)
## 4. 액션 아이템
회의 후 수행할 업무를 **담당·작업·기한·산출물 4요소**가 모두 드러나게 정리한다. 각 행은 반드시 녹취록 근거로 작성한다. 담당자는 개인 우선(없으면 "OO팀 (담당자 지정 필요)"). 회의에서 기한·산출물이 안 나왔으면 해당 칸에 "확인 필요"라고 적는다. 표 셀 안에서는 줄바꿈과 \`|\` 문자를 쓰지 말 것.
회의 후 수행할 업무를 **담당·작업·기한·산출물 4요소**가 모두 드러나게 정리한다. 각 행은 반드시 녹취록 근거로 작성한다. 담당자는 개인 우선(없으면 "OO팀 (담당자 지정 필요)"). **실명이 확인 안 된 번호·익명 화자는 담당으로 확정하지 말고 \`[미지정-확인필요]\`로 둔다**(위 작성 원칙 참조). 회의에서 기한·산출물이 안 나왔으면 해당 칸에 "확인 필요"라고 적되, **본문에 마감 날짜가 언급됐고 이 작업에 결부되면 그 날짜를 기한 칸에 반영**한다. 표 셀 안에서는 줄바꿈과 \`|\` 문자를 쓰지 말 것.
| 담당 | 작업 내용 | 작업 상세 | 산출물 | 기한 | 상태 |
| --- | --- | --- | --- | --- | --- |
@@ -125,7 +129,7 @@ const OUTPUT_FORMAT = `# 작성 원칙 (회의록 품질 — 출력 전 반드
- 핵심 논점 한 줄
# 최종 점검 (출력 전 내부 확인 — 체크 로그는 출력하지 말 것)
□ 결정사항에 확정된 것만 있는가(검토 필요 항목이 섞이지 않았나) □ 액션 아이템에 담당(개인)·작업·기한·산출물 4요소가 있는가 □ 오픈 이슈가 한곳에 모였는가 □ 리스크가 영향·대응방안과 함께 정리됐는가 □ 논의사항이 주제별 bullet로 간결한가 □ 요약이 결과 중심인가 □ 결정·액션에 근거 인용이 붙어 있는가
□ 결정사항에 확정된 것만 있는가(검토 필요 항목이 섞이지 않았나) □ 액션 아이템에 담당(개인)·작업·기한·산출물 4요소가 있는가 □ 익명·번호 화자를 담당으로 확정하지 않고 [미지정-확인필요]로 뒀는가 □ "이렇게/그거" 같은 빈 인용을 근거로 달지 않았는가([내용 확인필요] 처리) □ 본문에 뜬 마감 날짜를 결부된 액션 기한에 반영했는가 □ 명단 외 화자에 (확인필요) 표시를 했는가 □ 오픈 이슈가 한곳에 모였는가 □ 리스크가 영향·대응방안과 함께 정리됐는가 □ 논의사항이 주제별 bullet로 간결한가 □ 요약이 결과 중심인가 □ 결정·액션에 근거 인용이 붙어 있는가
위 형식을 정확히 따르고, 모든 내용은 한국어로 작성하시오.`;
@@ -143,7 +147,8 @@ export function buildMeetExtractPrompt(segment: string, metadata: string, segInd
# 규칙 (할루시네이션 방지)
- 이 조각에 없는 사실·수치·결정을 만들지 말 것. 발언 주체가 불명확하면 "(주체 불명확)"으로 표기.
- STT 오타는 문맥과 메타데이터(용어집 역할)로 정규화하되, 없는 사실을 지어내는 것은 금지.
- 각 항목 끝에 근거 발언 원문 일부(20자 내외)를 \`근거: "…"\` 로 붙인다.
- 각 항목 끝에 근거 발언 원문 일부(20자 내외)를 \`근거: "…"\` 로 붙인다. 단, "이렇게/그거/이거" 같은 지시대명사뿐인 *내용 공백* 발화는 근거로 쓰지 말고 핵심 내용을 "[내용 확인필요]"로 표기한다.
- 액션 담당이 실명으로 확인 안 된 화자(번호·익명)면 \`[담당]\`에 "[미지정]"으로 적고 임의 배정하지 말 것.
- 조각 경계에서 잘린 문장은 무리하게 해석하지 말고 "(조각 경계에서 잘림)"으로 표기.
[메타데이터]
+60
View File
@@ -0,0 +1,60 @@
/**
* Regression guard for the /meet prompt policy.
*
* These 4 rules were added after a real meeting record showed the failure modes:
* 1) anonymous/numbered speakers assigned as action owners (fake accountability)
* 2) content-empty deictic quotes ("이렇게 이렇게") passed off as 근거
* 3) deadlines mentioned in risks/discussion not reflected in action 기한
* 4) speakers in the body who aren't in the attendee list
*
* Prompts can't be unit-tested for model behavior, but we CAN guard that the
* policy text doesn't silently get dropped in a future refactor.
*/
import {
buildMeetPrompt,
buildMeetExtractPrompt,
buildMeetReducePrompt,
} from '../src/features/datacollect/prompts/meetPrompt';
const transcript = '참석자 1: 이거는 이렇게 이렇게 해주세요. 효희 팀장: 네 수정할게요.';
const metadata = '회의명: 테스트';
describe('/meet prompt — accountability & grounding policy', () => {
// The OUTPUT_FORMAT block is shared by the single-shot and reduce paths, so
// both must carry the policy.
const sharedFormatBuilders: Array<[string, string]> = [
['buildMeetPrompt', buildMeetPrompt(transcript, metadata)],
['buildMeetReducePrompt', buildMeetReducePrompt('## 액션\n- [미지정] 작업', metadata)],
];
test.each(sharedFormatBuilders)('%s forbids assigning anonymous speakers as owners', (_name, prompt) => {
expect(prompt).toContain('[미지정-확인필요]');
expect(prompt).toMatch(/익명·번호 화자/);
});
test.each(sharedFormatBuilders)('%s rejects content-empty deictic quotes', (_name, prompt) => {
expect(prompt).toContain('[내용 확인필요]');
expect(prompt).toMatch(/이렇게 이렇게/);
});
test.each(sharedFormatBuilders)('%s cross-references deadlines into action 기한', (_name, prompt) => {
expect(prompt).toMatch(/기한 역참조/);
});
test.each(sharedFormatBuilders)('%s flags speakers missing from the attendee list', (_name, prompt) => {
expect(prompt).toMatch(/명단 외 화자|참석자 명단 정합성/);
});
test('extract (map) stage also avoids anonymous owner assignment & empty quotes', () => {
const p = buildMeetExtractPrompt('참석자 1: 이거 이렇게요', metadata, 1, 3);
expect(p).toContain('[미지정]');
expect(p).toContain('[내용 확인필요]');
});
test('final checklist references the new gates', () => {
const prompt = buildMeetPrompt(transcript, metadata);
expect(prompt).toMatch(/익명·번호 화자를 담당으로 확정하지 않고/);
expect(prompt).toMatch(/빈 인용을 근거로 달지 않았는가/);
});
});