Jev 내담자 평가·표현 v2와 속마음 공개

상담자 발화 판정(A)·감정(B)·표현(C) 20문항 질문 세트, 감쇠 없는 이번 턴 반응과 비대칭 기분 전이, 개방도 게이트로 생성 지시를 만들고 ccd.coping_strategy 전달 누락을 고친다.

trace v2와 고정 문구 속마음 요약(migration 24, AI 경로 차단 RLS)을 같은 트랜잭션에 저장하고 피드백 정책이 켜진 경우에만 done·TurnResponse·음성 reply·리뷰로 노출한다. 회기 화면 속마음 보기 토글, 리뷰 접힘 블록, 관리자 감정 관측 v2 표시를 추가한다.
This commit is contained in:
Yun Chan 2026-09-30 13:23:09 +09:00
parent 36cb847e38
commit 29c406d89f
39 changed files with 5726 additions and 343 deletions

View file

@ -0,0 +1,57 @@
-- =============================================================================
-- Vignette · migration 24 — 학습자·교수자용 속마음 요약 (jev-client-affect-v2 §8.2)
-- =============================================================================
-- app.client_affect_trace(23)는 관리자 전용이다. 이 테이블은 같은 client 턴에
-- 학습자·교수자에게 노출 가능한 고정 문구 요약만 담는다(숫자·확률·영문 코드 없음).
-- 앱 런타임은 client turn INSERT · client_affect_trace INSERT와 같은 트랜잭션에
-- 이 테이블 INSERT를 둔다.
CREATE TABLE IF NOT EXISTS app.client_inner_reaction (
turn_id UUID PRIMARY KEY REFERENCES app.turns(id) ON DELETE CASCADE,
session_id UUID NOT NULL REFERENCES app.sessions(id) ON DELETE CASCADE,
reaction JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_client_inner_reaction_session_created
ON app.client_inner_reaction (session_id, created_at);
ALTER TABLE app.client_inner_reaction ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS p_client_inner_reaction_select ON app.client_inner_reaction;
DROP POLICY IF EXISTS p_client_inner_reaction_insert_learner ON app.client_inner_reaction;
-- AI 경로(app.is_ai_context())는 절대 읽지 못한다: 속마음 문구가 프롬프트로
-- 역류하면 v2가 막으려는 겉과 속 차이 설계를 스스로 깨뜨린다.
CREATE POLICY p_client_inner_reaction_select
ON app.client_inner_reaction FOR SELECT
USING (
NOT app.is_ai_context()
AND EXISTS (
SELECT 1 FROM app.sessions AS s
WHERE s.id = app.client_inner_reaction.session_id
)
AND (
app.current_role_name() IN ('admin', 'instructor')
OR EXISTS (
SELECT 1 FROM app.sessions AS s
WHERE s.id = app.client_inner_reaction.session_id
AND s.learner_id = app.current_uid()
)
)
);
CREATE POLICY p_client_inner_reaction_insert_learner
ON app.client_inner_reaction FOR INSERT
WITH CHECK (
app.current_role_name() = 'learner'
AND EXISTS (
SELECT 1
FROM app.turns AS turn_row
JOIN app.sessions AS session_row ON session_row.id = turn_row.session_id
WHERE turn_row.id = app.client_inner_reaction.turn_id
AND turn_row.session_id = app.client_inner_reaction.session_id
AND turn_row.speaker = 'client'
AND session_row.learner_id = app.current_uid()
)
);