feat(safety): B-4 PR①② — licensed_restricted 차단 술어 + watch 폴더 license 주입
PR① licensed_restricted 단일 술어(_license_sql) — retrieval 3-leg(text/vec-doc/ vec-chunk) + digest loader 공유. a안(U-2①): 색인 허용·구매자료 verbatim 을 RAG 증거/ digest 발행에서 구조적 제외. 술어=COALESCE(extract_meta->'license'->>'restricted', 'false')<>'true' (restricted 부재/false 미제외 → 기존 코퍼스 결과 불변). 개인 파일 열람 미차단. chunk leg 는 outer 의 documents JOIN(항상) 활용 post-rank(restricted 소수). PR② file_watcher _TARGET_AXIS 확장 — Books/Papers_Purchased=restricted / Manuals= non-restricted(사용자 결정) / KGS=law·KR·kogl. ingest 시 extract_meta.license deterministic 주입(classify material IS NULL 일 때만 제안·meta 미기록=보존). PR③(KGS 버전 flip)=별 슬라이스 deferred(파일 포맷 조사 선행). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"""B-4 — licensed_restricted 차단 술어 + watch 타깃 (material/jurisdiction/license) 매핑 순수 테스트.
|
||||
|
||||
차단 술어(_license_sql)는 retrieval 3-leg + digest 가 공유하는 단일 술어. 실제 제외 동작은
|
||||
GPU 라이브(합성 restricted doc 검색 제외)로 검증 — 여기선 술어 형태 + 매핑 표 계약만.
|
||||
[[feedback_external_api_fixture_first]] / [[feedback_structural_integrity_over_path_discipline]]
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "app"))
|
||||
|
||||
from services.search.retrieval_service import _license_sql # noqa: E402
|
||||
from workers.file_watcher import _TARGET_AXIS # noqa: E402
|
||||
|
||||
|
||||
def test_license_sql_shape_with_alias():
|
||||
sql = _license_sql("d")
|
||||
assert sql.startswith(" AND ") # 항상 ' AND ...' (WHERE 합성용)
|
||||
assert "COALESCE(d.extract_meta -> 'license' ->> 'restricted', 'false')" in sql
|
||||
assert "<> 'true'" in sql # restricted=true 만 제외
|
||||
|
||||
|
||||
def test_license_sql_shape_no_alias():
|
||||
# alias='' = 단일 FROM documents (컬럼 직접 참조)
|
||||
sql = _license_sql("")
|
||||
assert "COALESCE(extract_meta -> 'license' ->> 'restricted', 'false')" in sql
|
||||
assert ".extract_meta" not in sql # 점 없는 컬럼 직접
|
||||
|
||||
|
||||
def test_axis_books_papers_are_restricted():
|
||||
for folder, mt in (("Books", "book"), ("Papers_Purchased", "paper")):
|
||||
material, jur, lic = _TARGET_AXIS[folder]
|
||||
assert material == mt
|
||||
assert jur is None # 책/논문 = 관할 없음(A-2 paper NULL 강제와 정합)
|
||||
assert lic["scheme"] == "proprietary"
|
||||
assert lic["restricted"] is True # RAG/digest 차단 대상
|
||||
assert lic["redistribute"] is False
|
||||
|
||||
|
||||
def test_axis_manuals_proprietary_but_not_restricted():
|
||||
material, jur, lic = _TARGET_AXIS["Manuals"]
|
||||
assert material == "manual"
|
||||
assert lic["scheme"] == "proprietary"
|
||||
assert lic["restricted"] is False # 사용자 결정 2026-06-13 (검색·RAG 활용)
|
||||
|
||||
|
||||
def test_axis_kgs_law_kr_public_not_restricted():
|
||||
material, jur, lic = _TARGET_AXIS["KGS_Code"]
|
||||
assert (material, jur) == ("law", "KR")
|
||||
assert lic["scheme"] == "kogl"
|
||||
assert lic["restricted"] is False # 법정 위임 공공 → 차단 아님
|
||||
|
||||
|
||||
def test_axis_non_target_folder_yields_none():
|
||||
# Inbox/Recordings 등 비대상 = (None, None, None) → material/license 미주입
|
||||
assert _TARGET_AXIS.get("Inbox", (None, None, None)) == (None, None, None)
|
||||
Reference in New Issue
Block a user