This commit is contained in:
parent
d6d9dc5f61
commit
ed3252ede0
23 changed files with 197 additions and 29 deletions
|
|
@ -307,10 +307,12 @@ RBAC×AIView로 차단된다. 이 모듈은 평가 신호만 산출한다.
|
|||
|
||||
회기 라이프사이클 메모리(4계층 매핑: ① working / ② episodic / ③ summary / ④ semantic).
|
||||
|
||||
- 회기 시작: `(persona_id, learner_id)` 안정 `case_profile`을 확보한 뒤
|
||||
`build_recall_context(...) -> RecallContext`를 조립한다. 동기 seed는
|
||||
`case_profile.case_digest` + 직전 `session_summary` + client-visible `pinned_fact`
|
||||
기반이고, episodic 단편/KB 단서는 백그라운드 warm cache로 붙는다.
|
||||
- 회기 시작: `continue`는 선택한 owned `case_id`(구클라이언트는 가장 최근 사례)를 같은
|
||||
생성 트랜잭션 안에서 잠그고 `build_recall_context(...) -> RecallContext`를 조립한다.
|
||||
`fresh`는 활성 회기 검사를 먼저 통과한 뒤 빈 `case_profile`을 새로 만들어 항상 1회기·빈
|
||||
recall로 시작한다. 동기 seed는 이어지는 사례의 `case_profile.case_digest` + 직전
|
||||
`session_summary` + client-visible `pinned_fact` 기반이고, episodic 단편/KB 단서는
|
||||
백그라운드 warm cache로 붙는다.
|
||||
- 회기 종료: 마스킹된 client-visible 축어록으로 fallback `session_summary.digest`를 만들고,
|
||||
같은 트랜잭션에서 `case_profile.case_digest`, `rapport_trajectory`, `alliance_level`을
|
||||
갱신한다. 동시에 마스킹된 client-visible 발화에서 `[NAME]`/`[ORG]` identity와 명시적 상담 약속만
|
||||
|
|
@ -391,9 +393,11 @@ session lifecycle을 유지하며, future Node read API는 이 read-model contra
|
|||
|
||||
핵심 엔드포인트:
|
||||
|
||||
- `POST /sessions` — `get_catalog_persona(code)`로 승인 카드 조회 → `case_profile` upsert →
|
||||
case digest/직전 summary/pinned fact seed recall → `state_machine.init_state(...)` →
|
||||
`session_persistence.create_session(...)`. 생성 시 승인 페르소나의 `persona_id`와 `persona_version`을
|
||||
- `POST /sessions` — `get_catalog_persona(code)`로 승인 카드 조회 → `start_mode=fresh|continue`와
|
||||
선택 `case_id`를 영속 생성 트랜잭션에 전달 → 사례별 digest/직전 summary/pinned fact seed recall →
|
||||
`state_machine.init_state(...)` → `session_persistence.create_session(...)`. `fresh`는 기존 사례의
|
||||
기억을 읽지 않는 별도 case를 만들고, `continue`는 소유한 해당 case만 이어간다. 생성 시 승인 페르소나의
|
||||
`persona_id`와 `persona_version`을
|
||||
세션에 고정하고 시작/상세 응답에도 두 값을 반환한다. 이후 더 높은 버전이 승인돼도 기존 회기는 고정된
|
||||
역사 버전을 해석한다. DB 영속 생성 실패는 안전하지 않은 성공으로 흡수하지 않고 안정적인
|
||||
`503 session_persistence_unavailable`로 반환한다. 프론트 세션 시작 전 화면은 `persona.theory_target`
|
||||
|
|
@ -443,6 +447,11 @@ session lifecycle을 유지하며, future Node read API는 이 read-model contra
|
|||
제외한다. `growth.training_exposure`는 종료 회기만 집계하고 4회 미만이면 `insufficient`, 4회 이상에서
|
||||
최다 페르소나 비중이 0.75 이상이면 `훈련 집중 주의`, 그 밖에는 `balanced`로 표시한다. 투명한 노출 비중이지
|
||||
공정성·임상 진단이 아니다. 성취는 공식 등급/수료가 아니라 실제 연습 milestone만 표시한다.
|
||||
- `GET /sessions/cases?persona_code=...` — 같은 NPC의 사례별 누적 회기·상담자에게 보인 턴·누적
|
||||
회기 시간과 진행 중 회기를 DB 전체에서 집계한다. 런타임 추정값은 반환하지 않으며 DB read가 실패하면
|
||||
503으로 닫아 UI가 이어가기를 열지 않는다. `GET /sessions/cases/{case_id}/memory`는 foldout을 연
|
||||
학습자에게만 소유 사례의 압축 digest·미해결 주제·client-visible 고정 기억을 제한 길이로 반환하며,
|
||||
원문 축어록·evaluator·CCD·episodic 벡터는 반환하지 않는다.
|
||||
- `GET /sessions/{id}/review` — 저장된 축어록 + 평가 AI 산출물을
|
||||
`session_read_model.build_session_review(...)`가 학습자-안전 리뷰로 구성한다. 리뷰 조회 시 발화별 fast-loop 평가는
|
||||
`app.feedback_scores`/라벨 조인 테이블에서 `TurnRecord.evaluation` 형태로 hydrate한다.
|
||||
|
|
@ -775,7 +784,7 @@ React 19 + Vite. 라우팅은 `apps/web/src/App.tsx`(react-router-dom).
|
|||
## 5. 데이터베이스 스키마 개요
|
||||
|
||||
DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에 번호순으로 적용되며,
|
||||
개선관리 계약까지 필요한 현행 끝점은 `17_improvement_workbook_contracts.sql`이다.
|
||||
개선관리·회기 순차성 계약까지 필요한 현행 끝점은 `21_single_active_session.sql`이다.
|
||||
스키마는 **4분할**: `app` / `kb` / `audit` / `ds`.
|
||||
|
||||
### 5.1 app 스키마 (`infra/db/init/02_schema.sql`)
|
||||
|
|
@ -791,7 +800,10 @@ DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에
|
|||
`app.counselor_profile`(상담사 AI).
|
||||
- **라벨 코드테이블**(taxonomy 3축) — `stage_def`, `technique_label_def`, `client_state_def`, `scale_def`.
|
||||
- **세션** `app.sessions` — case_id/persona_id/persona_version 핀, stage_path. `case_id`는
|
||||
(persona_id, learner_id) 복합 인스턴스 식별.
|
||||
같은 `(persona_id, learner_id)` 안에서도 새 사례와 이어지는 사례를 구분하는 별도 사례 식별이다.
|
||||
migration 21의 partial unique index는 같은 learner-persona의 미종료 회기를 하나로 제한한다.
|
||||
종료가 durable하게 기록된 뒤에만 선택한 case의 다음 `session_no` 또는 빈 새 case의 1회기를
|
||||
생성한다.
|
||||
- **회기 보관 상태** `app.session_archive_state` — `session_id`/`learner_id` 단위의 학습자 보기 상태.
|
||||
`archived_at`/`updated_at`만 저장하고 restore 시 row를 삭제한다. RLS는 학습자 본인의 보관/복원과
|
||||
teacher/admin 조회만 허용하며, 원 세션·발화·리뷰·공유 링크는 보존한다.
|
||||
|
|
@ -921,7 +933,7 @@ DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에
|
|||
- ① WORKING `app.session_state` — 상태머신 수치 체크포인트(매 턴 UPSERT, openness/ideation CHECK 제약).
|
||||
- ② EPISODIC 임베딩 `app.turn_embedding` — BGE-M3 dense `vector(1024)` + sparse, HNSW 인덱스.
|
||||
- ③ SUMMARY `app.session_summary` — (A) end_state 무손실 carry-over + (B) digest narrative.
|
||||
- ④ SEMANTIC `app.case_profile`(evolving, `UNIQUE(persona_id, learner_id)`) + `app.pinned_fact`
|
||||
- ④ SEMANTIC `app.case_profile`(evolving, learner-persona당 여러 종료 사례 허용) + `app.pinned_fact`
|
||||
(+`pinned_fact_history` append-only). 현재 자동 쓰기는 learner-owned case의 마스킹 identity/agreement
|
||||
fact만 허용하고, 삽입/값 변경 history와 명시적 상담 약속 철회 contradiction까지 남긴다.
|
||||
관계·임상 fact 승격과 광범위 자동 모순 판정은 후속이다.
|
||||
|
|
@ -934,6 +946,26 @@ DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에
|
|||
기존 DB는 owner가 단일 트랜잭션으로 실행한다. 애플리케이션 역할 startup은 readiness만 확인하며 runtime
|
||||
DDL로 빠진 계약을 보충하지 않는다. 누락되면 migration 17 적용을 요구하며 fail-closed한다.
|
||||
|
||||
### 5.1.2 단일 활성 회기 migration 21
|
||||
|
||||
`infra/db/init/21_single_active_session.sql`은 `(learner_id, persona_id)`에 대해 `ended_at IS NULL`인
|
||||
row를 하나만 허용하는 online partial unique index를 추가한다. API도 learner-persona advisory transaction
|
||||
lock 안에서 active row를 확인해 409 `active_session_exists`와 기존 `session_id`를 돌려준다. 종료와 시작은
|
||||
사례 선택/생성 및 state recall을 같은 durable 경계에서 처리하므로 새 회기가 S1의 미완료 summary를 읽는
|
||||
중간 상태를 만들지 않는다. 따라서 종료 후 다음 회기는 평가 완료와
|
||||
무관하게 허용하되, 진행 중인 회기를 자동 종료하거나 병렬로 새 회기를 만들지 않는다. migration은 중복 active
|
||||
row와 invalid/wrong-named index를 전·후 condition으로 fail-closed한다. 기존 DB 적용 전 owner는 읽기 전용
|
||||
점검 뒤 보존·정리 방식을 명시적으로 결정해야 한다.
|
||||
|
||||
### 5.1.3 복수 사례 migration 22
|
||||
|
||||
`infra/db/init/22_case_profile_multi_case.sql`은 legacy
|
||||
`UNIQUE(persona_id, learner_id)` constraint만 정확히 찾아 제거해 같은 NPC에 새 사례를 만들 수 있게 한다.
|
||||
기존 `case_profile`·세션·요약·고정 기억은 수정하거나 병합하지 않는다. activity read index는
|
||||
`CREATE INDEX CONCURRENTLY`로 만들고, 다중 legacy constraint·invalid/wrong target index는 전·후 condition으로
|
||||
fail-closed한다. migration 21의 learner-persona 단일 활성 회기 제약은 유지한다. 기존 production에는 migration
|
||||
21 preflight에서 발견된 중복 활성 row 보존·종료 기준을 owner가 결정한 뒤에만 21→22 순서로 적용한다.
|
||||
|
||||
### 5.2 audit 스키마 + app 평가/종단 (`infra/db/init/04_audit_eval_rls.sql`)
|
||||
|
||||
- 평가: `app.feedback_scores`(발화별 점수·rationale, `visible_to='{evaluator}'`, loop fast/deep),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue