8d3b648b5f
뷰어 로컬 풀이 세션을 DS 로 흘려 학습엔진(SR/pattern/오답/4-A·4-B) 재생. 기본 inert(flag off). - 마이그 373~376: study_quiz_sessions 에 finalized_at(멱등 마커)·client_session_uuid·source + UNIQUE(client_session_uuid, study_topic_id) partial. - outcome.py derive_outcome = 채점 단일 소스(라이브 submit_attempt 도 이걸로 리팩터 → 정오 어휘 한 곳, ingest 는 raw 신호 selected+unsure 만 싣고 DS 산출 = '무수정 재생' 성립). - ingest_study.py: Bearer(VIEWER_SYNC_TOKEN)+study_ingest_enabled gate. pub_id→source_id→question 해소(graceful skip)·principal=question.user_id(mixed 거부)·topic 별 DS 세션(source=viewer·uuid) 생성+attempt+finalize_session 무수정 재생+finalized_at, 1-tx 원자. uuid 존재=already_ingested 캐시반환(멱등 → at-least-once 재전송에도 SR 이중 advance 0). - config study_ingest_enabled + compose 매핑 + main 등록. 검증: py_compile·ephemeral 마이그(373~376 라이브스키마 위 클린)·single-statement. 배포 후 합성 세션 멱등/무이중SR 실측 예정. 배포=inert(STUDY_INGEST_ENABLED 미설정=503). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 lines
1.3 KiB
Python
26 lines
1.3 KiB
Python
"""채점(outcome) 산출 단일 소스 (study-to-viewer P2).
|
|
|
|
라이브 attempt 엔드포인트(submit_attempt)와 뷰어 ingest 가 **동일 함수**로 채점 →
|
|
정오 어휘가 한 곳(서버)에서 결정(plan r2: ingest 는 raw 신호 selected+unsure 만 싣고
|
|
DS 가 산출 = '무수정 재생'을 실제로 성립시키는 형태). correct_choice 는 항상 현재 DB 값.
|
|
|
|
규칙(라이브 study_questions.py:1008-1020 동일):
|
|
is_unsure=True → (None, False, 'unsure') # unsure 가 정오 override, selected 폐기
|
|
selected None → ValueError # 선택 없고 unsure 도 아니면 무효(엔드포인트가 처리)
|
|
그 외 → selected==correct → (selected, is_correct, 'correct'|'wrong')
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def derive_outcome(
|
|
selected_choice: int | None, is_unsure: bool, correct_choice: int
|
|
) -> tuple[int | None, bool, str]:
|
|
"""(selected, is_correct, outcome) 반환. skipped 는 여기서 안 나옴(선택 없으면 호출측이 거부/skip)."""
|
|
if is_unsure:
|
|
return None, False, "unsure"
|
|
if selected_choice is None:
|
|
raise ValueError("selected_choice (1~4) 또는 is_unsure=true 가 필요합니다")
|
|
is_correct = selected_choice == correct_choice
|
|
return selected_choice, is_correct, ("correct" if is_correct else "wrong")
|