운영 문서와 상태판 동기화
This commit is contained in:
parent
3a9f70a97b
commit
eb77d7ec7c
10 changed files with 369 additions and 145 deletions
|
|
@ -80,7 +80,7 @@ vignette/
|
|||
`lifespan`(startup/shutdown)에서:
|
||||
|
||||
1. `init_pool()` → DB 풀 생성, `ensure_runtime_tables()` / `ensure_review_tables()` 보장.
|
||||
2. `settings.auto_seed_personas` 면 `materialize_seed_personas()`로 시스템 페르소나 P1~P3과 저장소 `data/personas/P4~P7.json`을 `app.persona_card`에 누락분만 물리화한다. 기존 DB 저작본/보관본은 덮어쓰거나 되살리지 않는다.
|
||||
2. `settings.auto_seed_personas` 면 `materialize_seed_personas()`로 시스템 페르소나 P1~P3과 저장소 `data/personas/P4~P7.json`을 `app.persona_card`에 누락분만 물리화한다. 기존 DB 저작본/보관본은 덮어쓰거나 되살리지 않는다. 운영자는 `scripts/materialize-persona-seeds.py` dry-run으로 같은 seed/version manifest를 확인하고, 명시적 `--apply`에서만 DB pool을 초기화해 이 materializer를 호출할 수 있다.
|
||||
3. `engine_client.startup()` / `voice_service.startup()`로 httpx 클라이언트 준비.
|
||||
4. **DB 초기화 실패 시** `environment == "dev"`이면 예외를 삼키고 경고만 남긴 채 degraded 기동한다
|
||||
(그 외 환경은 raise). `app/main.py:47-53`.
|
||||
|
|
@ -216,6 +216,14 @@ RBAC×AIView로 차단된다. 이 모듈은 평가 신호만 산출한다.
|
|||
- 정답 라벨 enum은 `app/taxonomy.py`가 단일 원천(SoT). LLM 출력은 enum으로 안전 파싱(미지값 폐기,
|
||||
`_parse_technique`/`_parse_client_state`). 게이트웨이 structured 우선, 없으면 text에서 JSON 추출
|
||||
(`_structured_payload`, 코드펜스 관용).
|
||||
- evaluator structured 결과는 `evaluate_turn()`/`evaluate_session()` 경계에서 canonical
|
||||
`GenerateRequest` SHA-256 키의 인메모리 semantic cache로 재사용할 수 있다. `/admin/usage`는
|
||||
cache key·prompt·completion 없이 enabled/entries/hits/misses/stores/evictions/requests/hit_rate와
|
||||
일별 `daily_cost` bucket(day, turns, tokens, cost)을 관리자 관측값으로 반환한다.
|
||||
`EVALUATOR_SEMANTIC_CACHE_ENABLED`, `EVALUATOR_SEMANTIC_CACHE_TTL_SECONDS`,
|
||||
`EVALUATOR_SEMANTIC_CACHE_MAX_ENTRIES`로 제한하며, 원문 prompt/completion은 캐시에 저장하지 않는다.
|
||||
cache hit은 `engine.generate()`와 metadata-only `audit.llm_call_log` 기록을 건너뛰고,
|
||||
engine error·파싱 실패는 캐시하지 않는다.
|
||||
- **엔진/파싱 실패는 비치명적** — `error` 필드에 사유만 남기고 절대 raise 하지 않는다.
|
||||
- **주입 어댑터** `make_eval_hook(engine)`: orchestrator의 `EvalHook` 시그니처에 맞춘 클로저를 반환.
|
||||
세션 라우트가 `run_turn_generate(ctx, engine, eval_hook=make_eval_hook(engine_client))` 식으로 주입한다.
|
||||
|
|
@ -235,8 +243,9 @@ RBAC×AIView로 차단된다. 이 모듈은 평가 신호만 산출한다.
|
|||
허가된 0615 워크북·DSM·공식 지침 요약 청크다. 추가 RAG는 evaluator view로
|
||||
`theory/technique/supervisor_pattern/microskill/taxonomy` 근거만 회수한다.
|
||||
- 관리자 `POST /kb/live-coach/source-packs/sync`는 같은 source pack을 `kb.source`와 `kb.chunk`에
|
||||
content_hash 기반으로 증분 색인한다. 기본 visibility는 evaluator 전용이고, C/D·diagnostic 자료는
|
||||
sensitivity 2로 고정한다.
|
||||
content_hash 기반으로 증분 색인한다. `app.services.source_pack_sync`가 active `kb.document`의
|
||||
hash/version을 먼저 읽고, hash 변경 시 새 document version을 최신+1로 계산한다. 기본 visibility는
|
||||
evaluator 전용이고, C/D·diagnostic 자료는 sensitivity 2로 고정한다.
|
||||
- 출력은 `LiveCoachSuggestion` 구조화 JSON(`tone/focus/title/message/next_utterance/rationale/sources`).
|
||||
UI는 코칭 아바타 말풍선, 근거 모달, 발화별 코칭 이력 오버레이로 표시한다.
|
||||
- 전달된 코칭은 `app.live_coach_events`에 저장된다. 원문 축어록을 중복 저장하지 않고 PII 마스킹된 짧은
|
||||
|
|
@ -249,8 +258,20 @@ RBAC×AIView로 차단된다. 이 모듈은 평가 신호만 산출한다.
|
|||
회기 라이프사이클 메모리(4계층 매핑: ① working / ② episodic / ③ summary / ④ semantic).
|
||||
|
||||
- 회기 시작: `(persona_id, learner_id)` 안정 `case_profile`을 확보한 뒤
|
||||
`build_recall_context(...) -> RecallContext`를 조립한다. 현재 동기 seed는 직전
|
||||
`session_summary` 기반이고, episodic 단편/KB 단서는 백그라운드 warm cache로 붙는다.
|
||||
`build_recall_context(...) -> RecallContext`를 조립한다. 동기 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와 명시적 상담 약속만
|
||||
보수적으로 `app.pinned_fact`에 upsert한다. pinned fact 삽입 또는 값 변경은
|
||||
`app.pinned_fact_history`에 append-only 이력을 남기며, 같은 값 재확인과 `locked` fact는
|
||||
history를 늘리지 않는다. 명시적 상담 약속 철회/부정은 기존 non-locked
|
||||
`agreement:counseling` fact만 `status='contradicted'`로 격리하고 history reason
|
||||
`contradiction`을 남긴다. 새 contradicted fact를 임의 생성하거나 관계갈등·위기·임상 추론을
|
||||
자동 모순 처리하지 않는다. 세션 종료 저장 성공 뒤에는 마스킹된 client-visible 내담자 발화만
|
||||
background task가 `app.turn_embedding`에 BGE-M3 dense/sparse로 idempotent 색인한다.
|
||||
LLM digest 압축은 별도 후속이다.
|
||||
**회상 요약엔 CCD·정답·평가가 절대 들어가지 않는다**(내담자 뷰, M6).
|
||||
DB/RAG가 없으면 인자 None → 빈 RecallContext(첫 회기/in-proc 폴백).
|
||||
- 회기 종료: `make_carry_over(state, ...) -> CarryOver` — (A) `end_state = state.snapshot()`
|
||||
|
|
@ -283,17 +304,27 @@ server: ready → state(listening) → state(thinking) → transcript → reply
|
|||
learner만 허용.
|
||||
- 턴 실행은 동일하게 `orchestrator.prepare_turn` → `run_turn_generate`를 거치고, 응답 생성 *후에만*
|
||||
발화를 영속화한다(실패한 AI 턴이 학습자 단독 축어록을 남기지 않도록).
|
||||
- `audio_end.provider_events`와 STT provider 이벤트는 allowlist·size limit 후
|
||||
`TurnRecord.provider_events`/`app.turns.provider_events`에 보존한다. 저장 전 sanitizer는
|
||||
내부 taxonomy `event_type`/`category`를 붙이고, raw transcript/text payload는 보존하지 않는다.
|
||||
인증된 회기 리뷰 API는 정규화 taxonomy 중 일부를 `nonverbal` 칩으로만 파생 노출한다.
|
||||
provider/source/raw type/text/transcript는 응답하지 않고, 공개 공유 카드는 축어록과 provider raw를 싣지 않는다.
|
||||
- `text_turn` 경로는 접근성/결정론 테스트용 텍스트 전용 경로.
|
||||
|
||||
### 2.9 세션 라우트 — `app/routes/sessions.py` (실제 데이터 흐름)
|
||||
|
||||
학습자 전용. 모든 세션 작업은 소유권(learner_id)을 검사한다(`_load_session_or_404`).
|
||||
브라우저-facing 세션 목록/대시보드/상세/리뷰/공유 DTO와 deterministic response builder는
|
||||
`app/session_read_model.py`가 소유한다. `routes/sessions.py`는 route/auth/RLS DB read/persistence와
|
||||
session lifecycle을 유지하며, future Node read API는 이 read-model contract를 미러한다.
|
||||
|
||||
핵심 엔드포인트:
|
||||
|
||||
- `POST /sessions` — `get_catalog_persona(code)`로 승인 카드 조회 → `case_profile` upsert →
|
||||
직전 `session_summary` seed recall → `state_machine.init_state(...)` →
|
||||
`session_persistence.create_session(...)`. DB가 없으면
|
||||
case digest/직전 summary/pinned fact seed recall → `state_machine.init_state(...)` →
|
||||
`session_persistence.create_session(...)`. 프론트 세션 시작 전 화면은 `persona.theory_target`
|
||||
기본값을 쓰되 학습자가 `humanistic`/`cbt`/`integrative` 중 하나를 명시 선택해 기존
|
||||
`theory_mode` 계약으로 보낸다. DB가 없으면
|
||||
`runtime_fallback_allowed()` 확인 후 `store.create(...)`로 in-proc 생성.
|
||||
- `POST /sessions/{id}/turn` — 동기 경로. `prepare_turn` → `run_turn_generate` →
|
||||
학습자 발화 turn(speaker=`counselor`, 원문 `text` + `text_masked`) + 내담자 응답 turn(speaker=`client`)
|
||||
|
|
@ -305,15 +336,16 @@ server: ready → state(listening) → state(thinking) → transcript → reply
|
|||
- `GET /sessions/{id}/live-coach` — 현재 회기에서 학습자에게 실제 전달된 코칭 이력을 시간순으로 반환한다.
|
||||
세션 화면은 이 응답을 `turn_seq`별로 묶어 학습자 발화 우측 코칭 마커와 채팅 위 스크롤 오버레이에 표시한다.
|
||||
- `POST /kb/live-coach/source-packs/sync` — 관리자 전용. 로컬 라이브 코칭 source pack을 `kb.source` upsert 후
|
||||
`kb.document/kb.chunk`로 색인한다. 임베딩 모델이 없으면 BM25-only degraded 색인으로 진행한다.
|
||||
`kb.document/kb.chunk`로 색인한다. active hash가 같으면 skip하고, 다르면 최신 document version+1로 색인한다.
|
||||
임베딩 모델이 없으면 BM25-only degraded 색인으로 진행한다.
|
||||
- `POST /sessions/{id}/end` — `memory.make_carry_over(...)` → 세션 종료 + carry 준비 →
|
||||
`_schedule_session_evaluation(sess)`로 deep-loop 평가를 비동기 태스크로 발사.
|
||||
- `GET /sessions/dashboard` — 학습자 본인 세션만 `include_turn_evaluation=true`로 집계해
|
||||
`overview/growth/persona_progress/achievements/recent_feedback`를 반환한다. `overview.archived_sessions`는
|
||||
학습자별 보관 상태(`app.session_archive_state`) 기준 카운트이며, 보관된 종료 회기는 리뷰 대기 행동 큐에서
|
||||
제외한다. 성취는 공식 등급/수료가 아니라 실제 연습 milestone만 표시한다.
|
||||
- `GET /sessions/{id}/review` — 저장된 축어록 + 평가 AI 산출물로 학습자-안전 리뷰 구성
|
||||
(`_rubric_from_evaluation`, `_ai_review_points` 등). 리뷰 조회 시 발화별 fast-loop 평가는
|
||||
- `GET /sessions/{id}/review` — 저장된 축어록 + 평가 AI 산출물을
|
||||
`session_read_model.build_session_review(...)`가 학습자-안전 리뷰로 구성한다. 리뷰 조회 시 발화별 fast-loop 평가는
|
||||
`app.feedback_scores`/라벨 조인 테이블에서 `TurnRecord.evaluation` 형태로 hydrate한다.
|
||||
평가 미완이면 `degraded/reviewReady=false`로 표기. 학습자가 저장한 사례개념화 워크시트가 있으면
|
||||
자동 초안보다 `saved_by_learner` 저장본을 우선 반환한다. 교수자/관리자는 담당 범위 회기를 읽기
|
||||
|
|
@ -322,7 +354,8 @@ server: ready → state(listening) → state(thinking) → transcript → reply
|
|||
`effective_openness` 같은 내부 수치는 `effective openness(유효 개방도)`로 학술 용어화한다.
|
||||
상담자 질문/발화 근거는 `ReviewNote.quote`로 분리해 리뷰 카드 안에서 인용 블록으로 표시한다.
|
||||
- `POST /sessions/{id}/share` — 학습자가 종료된 본인 회기 리뷰를 URL로 공유하기 위해 공개 토큰을 생성한다.
|
||||
서버는 `app.session_share_link`에 토큰 해시와 sanitized preview payload만 저장하고, 원문 축어록·학습자
|
||||
서버는 `session_read_model.session_share_payload(...)`로 preview를 정규화한 뒤 `app.session_share_link`에
|
||||
토큰 해시와 sanitized preview payload만 저장하고, 원문 축어록·학습자
|
||||
식별자는 payload에 넣지 않는다. 토큰은 생성 응답에서만 반환되며 새 생성은 기존 토큰을 교체한다.
|
||||
- `DELETE /sessions/{id}/share` — 해당 회기의 공개 공유 토큰을 폐기한다.
|
||||
- `POST /sessions/{id}/archive` / `POST /sessions/{id}/restore` — 학습자 본인의 종료 회기를 보관/복원한다.
|
||||
|
|
@ -369,7 +402,19 @@ GET {ENGINE_URL}/ready|/health — readiness/liveness
|
|||
- 앱 전역 싱글톤 `engine_client`(lifespan에서 startup/shutdown).
|
||||
- Node.js 교체 가능성을 위해 wire contract는 `app/contracts/engine_gateway.py`가 소유한다.
|
||||
현재 FastAPI client와 Python gateway가 같은 `GenerateRequest`/`GenerateResponse`/`Stream*Event`
|
||||
모델과 SSE `token|done|error` 프레임 helper를 공유한다.
|
||||
모델, SSE `token|done|error` 프레임 helper, `EngineGatewaySseLineDecoder` parser를 공유한다.
|
||||
앱 서비스 레이어는 raw gateway SSE line을 직접 해석하지 않고 `EngineClient.stream_packets()`가
|
||||
반환하는 `EngineGatewaySsePacket`만 처리한다. Python gateway의 `/v1/generate`도
|
||||
`GenerateResponse.model_dump()`로 응답해 hand-mirrored dict drift를 줄인다.
|
||||
`apps/api/engine_gateway/golden/engine_gateway_contract.v1.json`와
|
||||
`apps/api/engine_gateway/golden/engine_gateway_schema.v1.json`는 generate request/response와
|
||||
stream token/done/error decoded packet fixture/schema를 고정한다.
|
||||
`scripts/check-engine-gateway-contract.mjs`는 같은 artifact를 Node.js에서 Python import 없이 검증하므로
|
||||
미래 Node.js gateway의 최소 conformance gate로 쓴다.
|
||||
`/v1/stream` 종료는 provider pass-through `data: [DONE]`가 아니라 `event: done` + JSON telemetry
|
||||
payload로 변환해야 한다.
|
||||
브라우저로 재방출되는 `/sessions/{id}/stream` SSE는 별도 앱 계약이며, engine gateway SSE의
|
||||
JSON token payload와 섞지 않는다.
|
||||
|
||||
### 2.11 in-memory 스토어 — `app/store.py` (degraded 폴백)
|
||||
|
||||
|
|
@ -388,6 +433,7 @@ DB `app.persona_card`가 승인 페르소나의 SoR. 이 모듈이 in-proc `Pers
|
|||
|
||||
- `load_file_personas()` / `built_in_personas()` — in-code P1~P3과 저장소 `data/personas/P4~P7.json`을 deterministic catalog로 합친다.
|
||||
- `materialize_seed_personas()` — built-in P1~P7을 초기 승인 카탈로그로 누락분만 insert(admin 롤). `ON CONFLICT DO NOTHING`이므로 교수 편집본을 덮어쓰거나 `archived` 보관본을 재승인하지 않는다.
|
||||
- `scripts/materialize-persona-seeds.py` — API 서버 없이 seed/version manifest를 보고하는 운영 runner. 기본은 dry-run이고, `--json`은 P1~P7 `seed_version`/deterministic `persona_id`/`source_provenance`를 출력하며, `--apply`일 때만 DB pool lifecycle을 감싼 뒤 기존 idempotent DB materializer를 실행한다.
|
||||
- `create_persona_revision_from_existing()` — 공개 승인본을 같은 `persona_id`의 다음 `version` draft/review로 복제한다. 이미 열린 draft/review가 있으면 새 버전을 만들지 않고 기존 초안을 돌려준다.
|
||||
- `archive_persona_family()` — 교수/관리자 UI의 삭제 동작. 세션 FK 보존을 위해 hard delete 대신 같은 `code` family의 비보관 버전을 모두 `status='archived'`로 전환한다.
|
||||
- `get_approved_persona(code)` / `list_approved_personas()` — 승인된 최신 버전 조회(AI 컨텍스트).
|
||||
|
|
@ -396,9 +442,17 @@ DB `app.persona_card`가 승인 페르소나의 SoR. 이 모듈이 in-proc `Pers
|
|||
- 페르소나 스튜디오: `/teach/personas`가 teacher/admin 전용 저작 작업면이다. 교수 콘솔은 진입점/triage만 맡고,
|
||||
실제 저작은 개요·임상·저항·회기·말투·안전·프롬프트 탭으로 분리한다.
|
||||
- RAG 첨부 SSOT: `POST /personas/sources`는 첨부/붙여넣기 자료를 `mask_pii()` 후
|
||||
raw 원문 hash-only 증거는 `kb.raw_source_artifact`에 따로 기록하고, sanitized 파생본만
|
||||
`kb.source/document/chunk`에 evaluator 전용 근거(`visible_to=['evaluator']`, `sensitivity=2`)로 등록한다.
|
||||
`rag.index_document()`는 `sensitivity=3` 또는 raw source marker chunk를 DB 접근 전에 거부하므로
|
||||
raw 원문은 `kb.chunk`/embedding/FTS 검색면에 들어가지 않는다.
|
||||
`POST /personas/drafts/generate`는 raw text가 아니라 `source_id` 기반 RAG 검색 결과를 생성 근거로 사용하고,
|
||||
draft `source_provenance`에 source id와 chunk id를 남긴다.
|
||||
draft `source_provenance`에 source id와 chunk id를 남긴다. 생성 요청 metadata와 provenance에는
|
||||
`persona-draft-rag@2026-06-28.1` prompt bundle id/version/hash도 함께 남겨 생성 프롬프트 버전 drift를 추적한다.
|
||||
- repo-managed source pack sync: `app.services.source_pack_sync`와 `scripts/sync-persona-sources.py`가
|
||||
active `kb.document.content_hash`를 비교한다. dry-run은 DB 상태를 읽어 would-apply version을 보고하고,
|
||||
`--apply`에서만 `kb.source` upsert와 `kb.document/kb.chunk` 색인을 수행한다. 이 runner는 seed
|
||||
materializer와 별개이며, 교수자가 업로드하는 `/personas/sources` UUID 자료를 임의로 재작성하지 않는다.
|
||||
- 교수 검수: `list_persona_review_queue(role)` / `update_persona_review_status(action=approve|reject)`
|
||||
— 승인/반려 시 `audit.audit_log`에 감사 기록.
|
||||
|
||||
|
|
@ -514,7 +568,7 @@ DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에
|
|||
teacher/admin 조회만 허용하며, 원 세션·발화·리뷰·공유 링크는 보존한다.
|
||||
- **발화** `app.turns` — ② EPISODIC append-only. `text`(마스킹 원문)/`text_masked`(외부전송용),
|
||||
`visible_to TEXT[]`(기본 `{client,counselor,evaluator}`), salience/is_pinned/contradicts,
|
||||
음성 paralinguistic(audio_ref/silence_ms/speech_rate/barge_in). `turn_technique`/`turn_client_state`
|
||||
음성 paralinguistic(audio_ref/silence_ms/speech_rate/barge_in/provider_events; review는 제한된 taxonomy 칩만 파생). `turn_technique`/`turn_client_state`
|
||||
다대다, `supervisor_comment`(rationale/critique + intent_deviation JSONB), `safety_events`.
|
||||
- **사례개념화 제출물** `app.case_worksheet` — 회기 리뷰의 축어록 기반 자동 초안을 학습자가 편집해 저장한 JSONB.
|
||||
`session_id` 단위 upsert이며, `GET /review`에서 자동 초안보다 우선된다.
|
||||
|
|
@ -524,19 +578,27 @@ DB는 PostgreSQL 16 + pgvector(단일 SoR). 초기화 SQL은 `infra/db/init/`에
|
|||
- **공개 공유 카드** `app.session_share_link` — `session_id` 단위 공개 토큰 해시와 sanitized preview payload.
|
||||
RLS는 학습자 본인 생성/폐기와 teacher/admin 열람, public route의 AI 컨텍스트 조회만 허용한다. 원문 축어록을
|
||||
저장하지 않는다.
|
||||
- **운영 콘솔** `app.admin_health_event` — 관리자 `/admin/health` 조회 시점의 서비스별 헬스 샘플을
|
||||
append-only로 남긴다. 이 값은 상시 모니터링 SLA가 아니라 운영 콘솔이 관측한 최근 샘플 이력이다.
|
||||
- **운영 콘솔** `app.admin_health_event` / `app.admin_health_daily_rollup` — 관리자 `/admin/health`
|
||||
조회 시점 또는 `scripts/record-admin-health-sample.py` synthetic sampler 실행 시점의 서비스별 원시
|
||||
헬스 샘플은 `app.admin_health_event`에 남긴다. `scripts/maintain-admin-health-events.py`는 명시
|
||||
인자를 받은 dry-run/apply 작업으로 오래된 원시 샘플을 일별 rollup에 먼저 집계한 뒤 retention window 밖
|
||||
raw row만 삭제한다. 이 값은 SLA 보장 수치가 아니라 운영 콘솔/샘플러가 관측한 최근 샘플 및 집계 이력이다.
|
||||
`app.support_ticket`은 인증 사용자가 제출한 문제·불만·장애 티켓을 저장하고, 관리자는 `/admin/tickets`에서
|
||||
상태·카테고리·우선순위·담당그룹·정체·검색 필터와 카테고리 큐를 실제 DB 기준으로 처리한다.
|
||||
티켓 접수와 관리자 수동 처리 변경은 `audit.audit_log`에 metadata-only로 남기며, 제목/본문 전문은
|
||||
감사 로그에 복제하지 않는다. 중복 병합, 자동 수정 후보, 이슈/PR 생성은 운영자 승인 전까지 실행하지 않는다.
|
||||
티켓 생성 시 결정론적 `fingerprint`를 저장해 같은 내용의 중복 후보를 힌트로 보여주고, 관리자는
|
||||
`parent_ticket_id`를 수동 지정/해제해 parent-child 관계를 남긴다. 이 힌트는 자동 병합·자동 우선순위
|
||||
변경·자동 담당그룹 배정에 쓰지 않는다. 티켓 접수와 관리자 수동 처리 변경은 `audit.audit_log`에
|
||||
metadata-only로 남기며, 제목/본문 전문은 감사 로그에 복제하지 않는다. Claude Recipe 자동 수정 후보,
|
||||
이슈/PR 생성은 운영자 승인 전까지 실행하지 않는다.
|
||||
RLS는 티켓 제출자 본인 insert/select와 admin 전체 처리만 허용한다.
|
||||
- **메모리 4계층**:
|
||||
- ① 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`
|
||||
(+`pinned_fact_history` append-only).
|
||||
(+`pinned_fact_history` append-only). 현재 자동 쓰기는 learner-owned case의 마스킹 identity/agreement
|
||||
fact만 허용하고, 삽입/값 변경 history와 명시적 상담 약속 철회 contradiction까지 남긴다.
|
||||
관계·임상 fact 승격과 광범위 자동 모순 판정은 후속이다.
|
||||
|
||||
### 5.2 audit 스키마 + app 평가/종단 (`infra/db/init/04_audit_eval_rls.sql`)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue