Contact.RelationshipNote는 CRUD는 이미 있었지만 draftRequest에 필드 자체가 없어
ai-service 프롬프트에 전혀 전달되지 않는 저장 전용 스텁이었다. 이번 변경으로 실제
초안 생성에 반영되게 만든다.
- core-backend/aiservice.go: draftRequest에 RelationshipNote string 필드 추가
(relationship_tier 옆, omitempty, 빈 문자열 = 무영향)
- core-backend/persona.go: resolveRelationshipNote() 추가. 티어/자율성과 달리
메모는 순전히 개인별이라 전역 기본 메모 개념이 없음 -- 그룹 대화나 매칭되는
Contact가 없으면 빈 문자열로 귀결. resolveRelationshipTier/resolveAutonomyLevel/
resolveRelationshipNote 셋이 복붙하던 "1:1 상대 Contact 찾기" 루프를
findCounterpartContact() 공용 헬퍼로 추출해 중복 제거
- core-backend/main.go: POST /conversations/:id/draft 핸들러가 resolveRelationshipNote
결과를 draftRequest에 실어 보내도록 연결
- ai-service/app/generation.py: system_prompt_for_tier()가 relationship_note를
받아 "[관계 메모] {note} -- ..." 문단을 관계 티어 지침과 별도로 추가(빈 값이면
기존과 동일). draft_reply()도 파라미터 통과만 함 -- 에스컬레이션/정체성 게이팅은
전혀 영향 없음
- ai-service/app/main.py: DraftRequest에 relationship_note 필드 추가, /draft가
draft_reply로 그대로 전달
- 테스트: core-backend Go 64개(신규 3개: 메모 전달/빈 값/그룹 스킵) 전부 통과,
ai-service pytest 52개(신규 5개) 전부 통과, mobile flutter analyze/test 변경 없이
그대로 6개 통과(이 기능은 새 UI가 필요 없음 -- 필드는 이미 있었음)
- docs/roadmap.md §2.7-E, docs/deploy-checklist.md N4-C5a/b/c 완료 처리 + NOW/
바로 다음 5개 요약 갱신
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YSB5PqF38raTxP5ABgr9m
PRD.md §3.1 P0 "자율성 설정(L0~L2) | 전역 기본값 + 상대별 예외 설정" / §4 엣지케이스
대비 미구현 갭 해소. 관계별 페르소나(2.7-B)의 RelationshipTier 오버라이드 패턴을
그대로 미러링:
- core-backend/models.go: Contact.AutonomyLevel *AutonomyLevel 추가(nil = 전역
기본값), validAutonomyLevel() 검증 헬퍼 추가(twin-settings PATCH의 인라인 검증도
이 헬퍼로 통일)
- core-backend/autonomy_resolve.go: resolveAutonomyLevel() 신규 — 연락처 오버라이드
(1:1 전용) → 전역 TwinSettings 기본값 → L0 순으로 해석. L1/L2가 아니라 L0으로
폴백하는 이유는 이 코드베이스 전반의 안전 우선 기본값과 동일(불확실하면 항상 초안만
생성, 사람이 직접 발송). 그룹 대화는 RelationshipTier와 동일하게 항상 전역 기본값만
사용 — main.go의 그룹 대화 무조건 차단과 이중으로 안전
- core-backend/main.go: POST /conversations/:id/messages의 자율성 게이트가
TwinSettings 전역값만 읽던 걸 resolveAutonomyLevel() 호출로 교체. peer-veto→그룹
차단→도배 감지→에스컬레이션 순서와 각 하드게이트는 그대로 유지, "level" 계산
방식만 바뀜
- core-backend/a1_a2_routes.go: createContactRequest/updateContactRequest에
AutonomyLevel 필드 추가, contactJSON()에 포함, 생성/수정 핸들러가 RelationshipTier와
동일한 전체 교체(full-replace) 시맨틱으로 처리(PATCH에서 필드 생략 시 nil로 리셋)
- core-backend/autonomy_resolve_test.go: 연락처 오버라이드 우선순위, 전역 기본값
폴백, 그룹 대화는 오버라이드 무시, 잘못된 값 검증 거부, PATCH 전체 교체 리셋 커버
- mobile: models.dart에 Contact.autonomyLevel(nullable) 추가, api_client.dart
createContact/updateContact에 선택적 autonomyLevel 파라미터 스레딩,
contacts_screen.dart에 _AutonomyLevelPicker(_RelationshipTierPicker와 동일 구조)
추가해 추가/수정 다이얼로그에 배치 + 연락처 목록 서브타이틀에 표시
ai-service는 변경 없음 — 자율성 레벨은 발송 게이트 로직일 뿐 초안 톤에 영향을
주지 않아 ai-service 프롬프트까지 전달될 필요가 없음.
테스트: go test ./... 61개 전부 PASS, flutter analyze/test 클린(기존 무관 info
린트 1건 제외).
docs/roadmap.md §2.7-D, docs/deploy-checklist.md N4-C4a/b/c를 done으로 갱신하고
NOW/바로 다음 5개 요약도 동기화.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YSB5PqF38raTxP5ABgr9m