feat: expand infringement case matching to v1.3 precedent mapping

태그 동점 시 첫 케이스만 반환해 나머지를 버리던 문제를 고친다.
A1·A2·A3·A4·A5·A6·A15 는 주/보조 태그가 동일하고 실제 구별자는 원본의
종류라 태그로 좁혀지지 않는다. find_case -> find_cases 로 바꿔 동점군을
전부 내보내고, 확정은 사람이 원본 종류로 한다.

- cases_v1.3.json 신설(v1.2 삭제): 39건 전부에 대표판례·처리구분(●/○) 적재.
  판례 미지정 10건은 사유를 값으로 남긴다.
- detectable_internal 10 -> 19건 (v1.3 IX장 총괄표 ● 기준으로 정정)
- _assign_tags 주 태그 조합 3 -> 5종. 유사도로 판단 가능한 쟁점만 주 태그로
  낸다. 도달 케이스 3 -> 16건(● 19건 중).
- B3·C1·D1 은 게재 사실·편집 개입·성명표시가 필요해 텍스트로 알 수 없다.
  추측하지 않고 LegalContext 대기로 두며 경계를 테스트로 고정한다.
- 케이스 수 검증을 38~39 범위에서 39 로 고정. v1.3 본문 통계 줄(●16/○22=38)이
  같은 문서의 표(●19/○20=39)와 어긋난 것이 38/39 혼재의 원인이었다.
- docs/PRECEDENT_SOURCE_GAP.md: 대표판례이나 적재본에 없어 출처를 제시할 수
  없는 14건. 응답에서도 precedents_without_source 로 구분한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hbyang 2026-09-18 15:42:34 +09:00
parent aaabbdd8c6
commit 52a0fdcdf0
10 changed files with 1120 additions and 133 deletions

View File

@ -80,6 +80,12 @@ async def taxonomy(request: Request) -> TaxonomyResponse:
], ],
cases=[ cases=[
{"case_id": c.case_id, "old_no": c.old_no, "subgroup": c.subgroup, {"case_id": c.case_id, "old_no": c.old_no, "subgroup": c.subgroup,
"handling": c.handling,
"representative_precedents": [
{"case_id": p.case_id, "in_runtime_corpus": p.in_runtime_corpus}
for p in c.representative_precedents
],
"representative_precedent_note": c.representative_precedent_note,
"title": c.title, "actor": c.actor, "title": c.title, "actor": c.actor,
"primary_tags": list(c.primary_tags), "secondary_tags": list(c.secondary_tags), "primary_tags": list(c.primary_tags), "secondary_tags": list(c.secondary_tags),
"detectable_internal": c.detectable_internal, "high_risk": c.high_risk, "detectable_internal": c.detectable_internal, "high_risk": c.high_risk,

View File

@ -122,6 +122,21 @@ class PartialPlagiarismSignal(BaseModel):
changed_elements: list[str] = Field(default_factory=list) # 바꿔치기한 요소 changed_elements: list[str] = Field(default_factory=list) # 바꿔치기한 요소
class CaseCandidate(BaseModel):
"""판정된 침해 케이스 후보 1건 + v1.3 총괄표의 대표판례."""
case_id: str
title: str
handling: Literal["technical_detection", "terms_or_report"]
representative_precedents: list[str] = Field(default_factory=list)
precedents_without_source: list[str] = Field(
default_factory=list,
description="대표판례이나 운영 적재본에 없어 출처를 제시할 수 없는 사건번호.",
)
precedent_note: str | None = Field(
default=None, description="대표판례 미지정 사유 (예: '확립 판례 없음').",
)
class MatchResult(BaseModel): class MatchResult(BaseModel):
source_doc: str source_doc: str
source_title: str | None = None source_title: str | None = None
@ -129,6 +144,11 @@ class MatchResult(BaseModel):
tags: list[InfringementTag] = Field(default_factory=list) tags: list[InfringementTag] = Field(default_factory=list)
case_id: str | None = None case_id: str | None = None
case_title: str | None = None case_title: str | None = None
case_candidates: list[CaseCandidate] = Field(
default_factory=list,
description="태그 동점 케이스 전부. 원본 종류(가사·기사·위키·교재 등)로 "
"사람이 확정한다. case_id 는 이 목록의 첫 항목이다.",
)
infringement_type: InfringementType = "unknown" infringement_type: InfringementType = "unknown"
evidence_spans: list[EvidenceSpan] = Field(default_factory=list) evidence_spans: list[EvidenceSpan] = Field(default_factory=list)
score_breakdown: ScoreBreakdown | None = None score_breakdown: ScoreBreakdown | None = None

View File

@ -17,6 +17,7 @@ import logging
from datetime import datetime, timezone from datetime import datetime, timezone
from app.api.schemas import ( from app.api.schemas import (
CaseCandidate,
TAG_LABEL_KO, TAG_LABEL_KO,
AiGenerationSignal, AiGenerationSignal,
DetectOptions, DetectOptions,
@ -604,15 +605,30 @@ class PlagiarismDetector:
) -> MatchResult: ) -> MatchResult:
legacy_type = _classify_legacy(hit) legacy_type = _classify_legacy(hit)
tags = self._assign_tags(hit, legacy_type) tags = self._assign_tags(hit, legacy_type)
case = self.taxonomy.find_case([t.tag for t in tags if t.role == "primary"]) if self.taxonomy else None cases = (self.taxonomy.find_cases([t.tag for t in tags if t.role == "primary"])
if self.taxonomy else ())
candidates = [
CaseCandidate(
case_id=c.case_id,
title=c.title,
handling=c.handling,
representative_precedents=[p.case_id for p in c.representative_precedents],
precedents_without_source=[
p.case_id for p in c.representative_precedents if not p.in_runtime_corpus
],
precedent_note=c.representative_precedent_note,
)
for c in cases
]
return MatchResult( return MatchResult(
source_doc=hit.doc_id, source_doc=hit.doc_id,
source_title=hit.title, source_title=hit.title,
similarity=round(hit.score, 4), similarity=round(hit.score, 4),
tags=tags, tags=tags,
case_id=case.case_id if case else None, case_id=cases[0].case_id if cases else None,
case_title=case.title if case else None, case_title=cases[0].title if cases else None,
case_candidates=candidates,
infringement_type=legacy_type, infringement_type=legacy_type,
evidence_spans=hit.evidence if return_evidence else [], evidence_spans=hit.evidence if return_evidence else [],
score_breakdown=ScoreBreakdown( score_breakdown=ScoreBreakdown(
@ -633,6 +649,12 @@ class PlagiarismDetector:
- lemma만 매우 높음 인용 표시 누락( 보조) - lemma만 매우 높음 인용 표시 누락( 보조)
- 인물 일치도 매우 높음(서사·구조 차용) 2차적저작물작성권() + 자기창작인양표시(보조) - 인물 일치도 매우 높음(서사·구조 차용) 2차적저작물작성권() + 자기창작인양표시(보조)
- 구조 미달 가공 신호 (text 낮음 + lemma 중간) 2차적저작물 미달 가공 - 구조 미달 가공 신호 (text 낮음 + lemma 중간) 2차적저작물 미달 가공
태그는 케이스 후보를 좁히는 유일한 입력이므로, 유사도 분포로 판단할
있는 쟁점은 보조가 아니라 태그로 낸다. 반대로 게재 사실·편집 개입·성명
표시처럼 텍스트에서 없는 사실은 태그로 만들지 않는다. 그래서 B3·C1·
D1 함수만으로 후보에 오르지 않으며, LegalContext 사람이 확인한
사실이 들어와야 한다.
""" """
text_sim = hit.text_sim text_sim = hit.text_sim
lemma_sim = hit.lemma_sim lemma_sim = hit.lemma_sim
@ -649,14 +671,25 @@ class PlagiarismDetector:
# 표절 실무 - 인용 누락 # 표절 실무 - 인용 누락
primary.append("citation_missing") primary.append("citation_missing")
# 표면 복제 + 구조 차용 동시 성립 (재수록·편집 수록형) → A10
elif lemma_sim >= 0.50 and char_sim >= 0.40:
primary.append("reproduction")
primary.append("derivative_work")
secondary.append("publication")
secondary.append("attribution")
# 2차적저작물작성권: 구조·서사 차용 (인물/모티프 일치 + 표면은 낮음) # 2차적저작물작성권: 구조·서사 차용 (인물/모티프 일치 + 표면은 낮음)
elif (char_sim >= 0.40 or motif_sim >= 0.50) and text_sim < 0.40: elif (char_sim >= 0.40 or motif_sim >= 0.50) and text_sim < 0.40:
primary.append("derivative_work") primary.append("derivative_work")
secondary.append("attribution") secondary.append("attribution")
secondary.append("citation_missing") # 구조를 차용하고 출처 표시가 없으면 인용 누락이 주 쟁점이다 → A16
# 미달 가공 가능성 if lemma_sim >= 0.40:
primary.append("citation_missing")
else:
secondary.append("citation_missing")
# 미달 가공: 원문 표현을 거의 남기지 않은 구조 차용 → A7/B2
if text_sim < 0.30 and lemma_sim < 0.50: if text_sim < 0.30 and lemma_sim < 0.50:
secondary.append("substandard_derivative") primary.append("substandard_derivative")
# 부분 변형 (text 중간 + 인물 일치) # 부분 변형 (text 중간 + 인물 일치)
elif text_sim >= 0.40 and char_sim >= 0.30: elif text_sim >= 0.40 and char_sim >= 0.30:
@ -690,7 +723,14 @@ class PlagiarismDetector:
) )
primary_labels = [t.label_ko for t in top.tags if t.role == "primary"] primary_labels = [t.label_ko for t in top.tags if t.role == "primary"]
tag_summary = ", ".join(primary_labels) if primary_labels else "확인 필요" tag_summary = ", ".join(primary_labels) if primary_labels else "확인 필요"
case_part = f" 추정 케이스 {top.case_id} ({top.case_title})." if top.case_id else "" if len(top.case_candidates) > 1:
ids = ", ".join(c.case_id for c in top.case_candidates)
case_part = (f" 추정 케이스 후보 {ids} — 태그만으로는 구별되지 않으므로 "
f"베껴온 원본의 종류를 확인해 확정해야 합니다.")
elif top.case_id:
case_part = f" 추정 케이스 {top.case_id} ({top.case_title})."
else:
case_part = ""
return ( return (
f"'{top.source_title}'와 검색 유사도 {top.similarity:.2%}로 후보 매칭. " f"'{top.source_title}'와 검색 유사도 {top.similarity:.2%}로 후보 매칭. "
f"검토 가설 태그: {tag_summary}.{case_part}{breakdown} " f"검토 가설 태그: {tag_summary}.{case_part}{breakdown} "

View File

@ -1,6 +1,10 @@
"""10종 메타 태그 분류체계 + 38개 케이스 로더. """10종 메타 태그 분류체계 + 39개 침해 케이스 로더.
PDF IV/IX장 그대로 JSON으로 보관 (data/taxonomy/). 부팅 1 로드. IV장(메타태그) IX장 침해 케이스 메타태그 매핑 총괄표 그대로 JSON으로
보관 (data/taxonomy/). 부팅 1 로드.
케이스 데이터는 실무방안 v1.3 기준이며, 케이스별 **대표판례** 처리 구분
( 기술검출 근거 / 약관·신고) 함께 담는다.
""" """
from __future__ import annotations from __future__ import annotations
@ -26,6 +30,12 @@ class MetaTagDef:
description: str description: str
@dataclass(frozen=True)
class RepresentativePrecedent:
case_id: str # 법원 사건번호 (케이스 ID 아님)
in_runtime_corpus: bool # precedents.jsonl 적재 여부. False 면 인용 시 출처 미확보.
@dataclass(frozen=True) @dataclass(frozen=True)
class CaseDef: class CaseDef:
case_id: str # A1, A7, B1, ... case_id: str # A1, A7, B1, ...
@ -38,6 +48,11 @@ class CaseDef:
detectable_internal: bool = False detectable_internal: bool = False
high_risk: bool = False high_risk: bool = False
note: str | None = None note: str | None = None
#: v1.3 총괄표의 처리 구분. technical_detection(●) / terms_or_report(○)
handling: str = "terms_or_report"
representative_precedents: tuple[RepresentativePrecedent, ...] = field(default_factory=tuple)
#: 대표판례가 지정되지 않은 이유("확립 판례 없음" 등). 빈 목록과 구분한다.
representative_precedent_note: str | None = None
@dataclass(frozen=True) @dataclass(frozen=True)
@ -53,35 +68,42 @@ class Taxonomy:
return t.label_ko return t.label_ko
return tag_id return tag_id
def find_case(self, primary_tags: Iterable[str]) -> CaseDef | None: def find_cases(self, primary_tags: Iterable[str]) -> tuple[CaseDef, ...]:
"""주 태그 조합이 가장 잘 매칭되는 케이스 추정. """주 태그 조합에 가장 잘 맞는 케이스 **전부**를 반환한다.
완벽 일치 우선, 없으면 부분 일치 (jaccard). 태그만으로는 케이스가 1:1 좁혀지지 않는다. A1·A2·A3·A4·A5·A6·A15
내부 검출 가능 케이스(A1~A5, A24, A25, B1, B2, D1) 가중치. /보조 태그가 완전히 같고, 실제 구별자는 베껴온 **원본의 종류**(가사·기사·
위키·교재·타인 자서전). 원본 종류 라벨은 코퍼스에 아직 없으므로, 동점
케이스 하나를 임의로 고르는 대신 동점군을 그대로 돌려준다. 호출자는
이를 "이 중 하나" 제시하고 사람이 원본 종류로 확정한다.
# ponytail: 원본 종류 라벨이 코퍼스에 들어오면 이 함수에 source_type 인자를
# 추가해 동점군을 좁힌다. 라벨 없는 상태에서 미리 배선하면 항상 None 이다.
""" """
target = set(primary_tags) target = set(primary_tags)
if not target: if not target:
return None return ()
best: CaseDef | None = None scored: list[tuple[float, CaseDef]] = []
best_score = -1.0
for c in self.cases: for c in self.cases:
primary = set(c.primary_tags) primary = set(c.primary_tags)
if not primary: if not primary:
continue continue
inter = len(target & primary) score = len(target & primary) / len(target | primary)
union = len(target | primary) # v1.3 에서 기술검출 근거(●)로 확인된 케이스에 작은 가중치.
score = inter / max(1, union)
if c.detectable_internal: if c.detectable_internal:
score += 0.1 score += 0.1
if score > best_score: scored.append((score, c))
best_score = score if not scored:
best = c return ()
return best if best_score > 0.3 else None best = max(score for score, _ in scored)
if best <= 0.3:
return ()
return tuple(c for score, c in scored if abs(score - best) < 1e-9)
def load_taxonomy(taxonomy_dir: Path) -> Taxonomy | None: def load_taxonomy(taxonomy_dir: Path) -> Taxonomy | None:
mt_path = taxonomy_dir / "meta_tags_v1.0.json" mt_path = taxonomy_dir / "meta_tags_v1.0.json"
cs_path = taxonomy_dir / "cases_v1.2.json" cs_path = taxonomy_dir / "cases_v1.3.json"
if not mt_path.exists() or not cs_path.exists(): if not mt_path.exists() or not cs_path.exists():
logger.warning("Taxonomy files not found in %s", taxonomy_dir) logger.warning("Taxonomy files not found in %s", taxonomy_dir)
return None return None
@ -108,6 +130,12 @@ def load_taxonomy(taxonomy_dir: Path) -> Taxonomy | None:
detectable_internal=c.get("detectable_internal", False), detectable_internal=c.get("detectable_internal", False),
high_risk=c.get("high_risk", False), high_risk=c.get("high_risk", False),
note=c.get("note"), note=c.get("note"),
handling=c.get("handling", "terms_or_report"),
representative_precedents=tuple(
RepresentativePrecedent(case_id=p["case_id"], in_runtime_corpus=p["in_runtime_corpus"])
for p in c.get("representative_precedents", [])
),
representative_precedent_note=c.get("representative_precedent_note"),
) )
for c in cs_data["cases"] for c in cs_data["cases"]
) )

View File

@ -1,99 +0,0 @@
{
"version": "1.2",
"source": "나누구_저작권침해_아카이빙_실무방안_v1.2.pdf (IX장)",
"total_cases": 38,
"groups": {
"A": {
"label": "저자(가해)",
"count": 27,
"share": 0.711,
"role": "본문 텍스트 표절 검출의 핵심 대상"
},
"B": {
"label": "저자(피해)",
"count": 4,
"share": 0.105,
"role": "신고·삭제 절차(notice & takedown) 대상"
},
"C": {
"label": "플랫폼",
"count": 3,
"share": 0.079,
"role": "약관·라이선스·동의 절차 대상"
},
"D": {
"label": "다른 사용자",
"count": 1,
"share": 0.026,
"role": "2차 창작 기능 운영 정책 대상"
},
"E": {
"label": "유족",
"count": 2,
"share": 0.053,
"role": "사후 권리 가이드라인 대상"
},
"X": {
"label": "분류체계 외",
"count": 2,
"share": 0.053,
"role": "별도 약관·운영 절차"
}
},
"cases": [
{"case_id": "A1", "old_no": 1, "subgroup": "A-1 외부 텍스트 인용·수록", "title": "시·노래 가사 본문 무단 인용", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "distribution"], "detectable_internal": true},
{"case_id": "A2", "old_no": 2, "subgroup": "A-1 외부 텍스트 인용·수록", "title": "소설·수필 본문 발췌 무단 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "distribution"], "detectable_internal": true},
{"case_id": "A3", "old_no": 3, "subgroup": "A-1 외부 텍스트 인용·수록", "title": "신문·잡지 기사 전문 옮겨 적기", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "distribution"], "detectable_internal": true},
{"case_id": "A4", "old_no": 4, "subgroup": "A-1 외부 텍스트 인용·수록", "title": "인터넷 블로그·SNS 글 무단 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": true},
{"case_id": "A5", "old_no": 5, "subgroup": "A-1 외부 텍스트 인용·수록", "title": "위키백과·백과사전 본문 그대로 사용", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": true},
{"case_id": "A6", "old_no": 6, "subgroup": "A-2 타인 자서전·회고", "title": "유명인 자서전 일부 베끼기", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "distribution"], "detectable_internal": false},
{"case_id": "A7", "old_no": 7, "subgroup": "A-2 타인 자서전·회고", "title": "다른 자서전 줄거리·서사 변형 차용", "actor": "저자(가해)", "primary_tags": ["derivative_work", "substandard_derivative"], "secondary_tags": ["reproduction", "publication", "attribution"], "detectable_internal": false},
{"case_id": "A8", "old_no": 8, "subgroup": "A-2 타인 자서전·회고", "title": "친구·가족 회고를 본인 글로 옮김", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["attribution", "false_authorship"], "detectable_internal": false},
{"case_id": "A9", "old_no": 9, "subgroup": "A-2 타인 자서전·회고", "title": "가족 일기·편지 무단 수록 (미공표)", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false},
{"case_id": "A10", "old_no": 10, "subgroup": "A-2 타인 자서전·회고", "title": "부모·조부모 자서전 통째 재수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "derivative_work"], "secondary_tags": ["distribution", "publication", "attribution"], "detectable_internal": false, "high_risk": true},
{"case_id": "A11", "old_no": 11, "subgroup": "A-2 타인 자서전·회고", "title": "학창시절 친구의 시·편지 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "attribution"], "secondary_tags": ["publication"], "detectable_internal": false},
{"case_id": "A12", "old_no": 12, "subgroup": "A-2 타인 자서전·회고", "title": "동료 이메일·업무문서 인용", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["attribution"], "detectable_internal": false},
{"case_id": "A13", "old_no": 36, "subgroup": "A-3 구술·강연·녹음", "title": "부모님·스승의 강연·설교 녹음해 본문에 옮김", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false, "high_risk": true},
{"case_id": "A14", "old_no": 38, "subgroup": "A-4 학술·교육 자료", "title": "본인 과거 논문·학위논문 발췌 무단 수록", "actor": "저자(가해)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "distribution", "attribution"], "detectable_internal": false},
{"case_id": "A15", "old_no": 39, "subgroup": "A-4 학술·교육 자료", "title": "교과서·교재 본문 그대로 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "citation_missing"], "secondary_tags": ["public_transmission", "distribution"], "detectable_internal": false},
{"case_id": "A16", "old_no": 31, "subgroup": "A-5 번역물", "title": "외국 자서전·도서 직접 번역해 본인 글로 수록", "actor": "저자(가해)", "primary_tags": ["derivative_work", "citation_missing"], "secondary_tags": ["reproduction", "public_transmission", "distribution"], "detectable_internal": false},
{"case_id": "A17", "old_no": 13, "subgroup": "A-6 이미지·시각 자산", "title": "인터넷 옛 사진·포스터 본문 삽입", "actor": "저자(가해)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false},
{"case_id": "A18", "old_no": 14, "subgroup": "A-6 이미지·시각 자산", "title": "졸업앨범 단체사진 무단 사용", "actor": "저자(가해)", "primary_tags": ["reproduction"], "secondary_tags": [], "detectable_internal": false},
{"case_id": "A19", "old_no": 15, "subgroup": "A-6 이미지·시각 자산", "title": "신문 스크랩·잡지 표지 사진 사용", "actor": "저자(가해)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false},
{"case_id": "A20", "old_no": 44, "subgroup": "A-6 이미지·시각 자산", "title": "만화 캐릭터·브랜드 로고 본문 삽입", "actor": "저자(가해)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false},
{"case_id": "A21", "old_no": 16, "subgroup": "A-7 음원·영상", "title": "오디오북 BGM에 상업 음원 사용", "actor": "저자(가해)", "primary_tags": ["reproduction", "public_transmission"], "secondary_tags": ["attribution"], "detectable_internal": false, "high_risk": true},
{"case_id": "A22", "old_no": 49, "subgroup": "A-8 디지털 사적 통신", "title": "동창회 카톡방·단톡방 대화 캡처 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["public_transmission", "attribution"], "detectable_internal": false, "high_risk": true},
{"case_id": "A23", "old_no": 51, "subgroup": "A-9 사후·고인 자료", "title": "사망한 친구·동료의 유작·일기 본문 수록", "actor": "저자(가해)", "primary_tags": ["reproduction", "publication", "attribution"], "secondary_tags": [], "detectable_internal": false, "high_risk": true},
{"case_id": "A24", "old_no": 17, "subgroup": "A-10 AI 도구 사용", "title": "AI memorization 반환 결과 사용", "actor": "저자(가해, 비의도)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "citation_missing"], "detectable_internal": true},
{"case_id": "A25", "old_no": 18, "subgroup": "A-10 AI 도구 사용", "title": "AI 생성물 우연 유사 (기존 저작물)", "actor": "저자(가해, 비의도)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission"], "detectable_internal": true},
{"case_id": "A26", "old_no": 19, "subgroup": "A-10 AI 도구 사용", "title": "AI 결과물을 본인 저작인 양 표시", "actor": "저자(가해)", "primary_tags": ["false_authorship"], "secondary_tags": ["attribution"], "detectable_internal": false},
{"case_id": "A27", "old_no": 20, "subgroup": "A-11 대필", "title": "대필 작가 작성분을 저자 단독 명의 출간", "actor": "저자·플랫폼", "primary_tags": ["false_authorship"], "secondary_tags": ["attribution"], "detectable_internal": false},
{"case_id": "B1", "old_no": 22, "subgroup": "B 저자(피해)", "title": "다른 사용자가 내 자서전 베낌", "actor": "저자(피해)", "primary_tags": ["reproduction"], "secondary_tags": ["public_transmission", "distribution", "attribution", "citation_missing", "false_authorship"], "detectable_internal": true},
{"case_id": "B2", "old_no": 23, "subgroup": "B 저자(피해)", "title": "다른 사용자가 내 서사·구조 차용", "actor": "저자(피해)", "primary_tags": ["derivative_work", "substandard_derivative"], "secondary_tags": ["attribution", "citation_missing"], "detectable_internal": true},
{"case_id": "B3", "old_no": 24, "subgroup": "B 저자(피해)", "title": "외부 사이트·SNS의 내 자서전 무단 게재", "actor": "저자(피해)", "primary_tags": ["reproduction", "public_transmission"], "secondary_tags": ["attribution"], "detectable_internal": false, "high_risk": true},
{"case_id": "B4", "old_no": 25, "subgroup": "B 저자(피해)", "title": "외부의 AI 학습 데이터로 무단 수집", "actor": "저자(피해)", "primary_tags": ["reproduction", "public_transmission"], "secondary_tags": [], "detectable_internal": false, "high_risk": true},
{"case_id": "C1", "old_no": 21, "subgroup": "C 플랫폼", "title": "편집자·교정자 손이 많이 들어간 경우", "actor": "플랫폼", "primary_tags": ["integrity"], "secondary_tags": ["derivative_work", "attribution"], "detectable_internal": false},
{"case_id": "C2", "old_no": 42, "subgroup": "C 플랫폼", "title": "유료 폰트 무단 사용 (본문·표지)", "actor": "저자·플랫폼", "primary_tags": ["reproduction"], "secondary_tags": ["distribution"], "detectable_internal": false},
{"case_id": "C3", "old_no": 54, "subgroup": "C 플랫폼", "title": "플랫폼이 사용자 자서전을 AI 학습 데이터로 사용", "actor": "플랫폼", "primary_tags": ["reproduction", "public_transmission"], "secondary_tags": ["derivative_work"], "detectable_internal": false, "high_risk": true},
{"case_id": "D1", "old_no": 26, "subgroup": "D 다른 사용자", "title": "2차 창작 기능에서 원저자 동의 없는 변형", "actor": "다른 사용자", "primary_tags": ["derivative_work", "attribution", "integrity"], "secondary_tags": ["publication"], "detectable_internal": true, "high_risk": true},
{"case_id": "E1", "old_no": 27, "subgroup": "E 유족", "title": "저자 사후 유족이 본문 임의 수정", "actor": "유족", "primary_tags": ["integrity"], "secondary_tags": ["reproduction", "distribution"], "detectable_internal": false},
{"case_id": "E2", "old_no": 28, "subgroup": "E 유족", "title": "사후 유고 자서전에 미공표 일기 포함", "actor": "유족", "primary_tags": ["reproduction", "publication"], "secondary_tags": ["attribution"], "detectable_internal": false},
{"case_id": "X1", "old_no": 29, "subgroup": "X 분류체계 외", "title": "자서전 등장 제3자의 사적 정보 노출", "actor": "저자(가해)", "primary_tags": [], "secondary_tags": [], "detectable_internal": false, "note": "사생활 침해 영역, 약관·운영 절차로 처리"},
{"case_id": "X2", "old_no": 30, "subgroup": "X 분류체계 외", "title": "자서전 등장 제3자의 명예 훼손 묘사", "actor": "저자(가해)", "primary_tags": [], "secondary_tags": [], "detectable_internal": false, "note": "명예훼손 영역, 약관·운영 절차로 처리"}
]
}

View File

@ -0,0 +1,907 @@
{
"version": "1.3",
"source": "v1.3 IX장 침해 케이스 ↔ 메타태그 매핑 총괄표",
"cases": [
{
"case_id": "A1",
"old_no": 1,
"subgroup": "A-1 외부 텍스트 인용·수록",
"title": "시·노래 가사 본문 무단 인용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
},
{
"case_id": "2021가합588060",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A2",
"old_no": 2,
"subgroup": "A-1 외부 텍스트 인용·수록",
"title": "소설·수필 본문 발췌 무단 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
},
{
"case_id": "2010다70520",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A3",
"old_no": 3,
"subgroup": "A-1 외부 텍스트 인용·수록",
"title": "신문·잡지 기사 전문 옮겨 적기",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2007다354",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A4",
"old_no": 4,
"subgroup": "A-1 외부 텍스트 인용·수록",
"title": "인터넷 블로그·SNS 글 무단 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2011가합60365",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A5",
"old_no": 5,
"subgroup": "A-1 외부 텍스트 인용·수록",
"title": "위키백과·백과사전 본문 그대로 사용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A6",
"old_no": 6,
"subgroup": "A-2 타인 자서전·회고",
"title": "유명인 자서전 일부 베끼기",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2006나16757",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A7",
"old_no": 7,
"subgroup": "A-2 타인 자서전·회고",
"title": "다른 자서전 줄거리·서사 변형 차용",
"actor": "저자(가해)",
"primary_tags": [
"derivative_work",
"substandard_derivative"
],
"secondary_tags": [
"reproduction",
"publication",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2006나16757",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A8",
"old_no": 8,
"subgroup": "A-2 타인 자서전·회고",
"title": "친구·가족 회고를 본인 글로 옮김",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"attribution",
"false_authorship"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2010도4468",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A9",
"old_no": 9,
"subgroup": "A-2 타인 자서전·회고",
"title": "가족 일기·편지 무단 수록 (미공표)",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2010도4468",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A10",
"old_no": 10,
"subgroup": "A-2 타인 자서전·회고",
"title": "부모·조부모 자서전 통째 재수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"derivative_work"
],
"secondary_tags": [
"distribution",
"publication",
"attribution"
],
"detectable_internal": true,
"high_risk": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
},
{
"case_id": "2011도3599",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A11",
"old_no": 11,
"subgroup": "A-2 타인 자서전·회고",
"title": "학창시절 친구의 시·편지 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"attribution"
],
"secondary_tags": [
"publication"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "공표권·복제 법리"
},
{
"case_id": "A12",
"old_no": 12,
"subgroup": "A-2 타인 자서전·회고",
"title": "동료 이메일·업무문서 인용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "A13",
"old_no": 36,
"subgroup": "A-3 구술·강연·녹음",
"title": "부모님·스승의 강연·설교 녹음해 본문에 옮김",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "A14",
"old_no": 38,
"subgroup": "A-4 학술·교육 자료",
"title": "본인 과거 논문·학위논문 발췌 무단 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"distribution",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2016고정432",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A15",
"old_no": 39,
"subgroup": "A-4 학술·교육 자료",
"title": "교과서·교재 본문 그대로 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"citation_missing"
],
"secondary_tags": [
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2010다70520",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A16",
"old_no": 31,
"subgroup": "A-5 번역물",
"title": "외국 자서전·도서 직접 번역해 본인 글로 수록",
"actor": "저자(가해)",
"primary_tags": [
"derivative_work",
"citation_missing"
],
"secondary_tags": [
"reproduction",
"public_transmission",
"distribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2011도3599",
"in_runtime_corpus": true
},
{
"case_id": "2007가합43936",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A17",
"old_no": 13,
"subgroup": "A-6 이미지·시각 자산",
"title": "인터넷 옛 사진·포스터 본문 삽입",
"actor": "저자(가해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2007가합16095",
"in_runtime_corpus": false
},
{
"case_id": "2019가단5207564",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A18",
"old_no": 14,
"subgroup": "A-6 이미지·시각 자산",
"title": "졸업앨범 단체사진 무단 사용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2007가합16095",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A19",
"old_no": 15,
"subgroup": "A-6 이미지·시각 자산",
"title": "신문 스크랩·잡지 표지 사진 사용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2007가합16095",
"in_runtime_corpus": false
},
{
"case_id": "2007다354",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A20",
"old_no": 44,
"subgroup": "A-6 이미지·시각 자산",
"title": "만화 캐릭터·브랜드 로고 본문 삽입",
"actor": "저자(가해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "어문 밖(상표)"
},
{
"case_id": "A21",
"old_no": 16,
"subgroup": "A-7 음원·영상",
"title": "오디오북 BGM에 상업 음원 사용",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"public_transmission"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2006가합8583",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A22",
"old_no": 49,
"subgroup": "A-8 디지털 사적 통신",
"title": "동창회 카톡방·단톡방 대화 캡처 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"public_transmission",
"attribution"
],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "A23",
"old_no": 51,
"subgroup": "A-9 사후·고인 자료",
"title": "사망한 친구·동료의 유작·일기 본문 수록",
"actor": "저자(가해)",
"primary_tags": [
"reproduction",
"publication",
"attribution"
],
"secondary_tags": [],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2013나2004096",
"in_runtime_corpus": false
},
{
"case_id": "2012다204587",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A24",
"old_no": 17,
"subgroup": "A-10 AI 도구 사용",
"title": "AI memorization 반환 결과 사용",
"actor": "저자(가해, 비의도)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"citation_missing"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "A25",
"old_no": 18,
"subgroup": "A-10 AI 도구 사용",
"title": "AI 생성물 우연 유사 (기존 저작물)",
"actor": "저자(가해, 비의도)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "A26",
"old_no": 19,
"subgroup": "A-10 AI 도구 사용",
"title": "AI 결과물을 본인 저작인 양 표시",
"actor": "저자(가해)",
"primary_tags": [
"false_authorship"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2019가단31377",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "A27",
"old_no": 20,
"subgroup": "A-11 대필",
"title": "대필 작가 작성분을 저자 단독 명의 출간",
"actor": "저자·플랫폼",
"primary_tags": [
"false_authorship"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "계약·성명표시(판례 약함)"
},
{
"case_id": "B1",
"old_no": 22,
"subgroup": "B 저자(피해)",
"title": "다른 사용자가 내 자서전 베낌",
"actor": "저자(피해)",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"public_transmission",
"distribution",
"attribution",
"citation_missing",
"false_authorship"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2012다73493",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "B2",
"old_no": 23,
"subgroup": "B 저자(피해)",
"title": "다른 사용자가 내 서사·구조 차용",
"actor": "저자(피해)",
"primary_tags": [
"derivative_work",
"substandard_derivative"
],
"secondary_tags": [
"attribution",
"citation_missing"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2006나16757",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "B3",
"old_no": 24,
"subgroup": "B 저자(피해)",
"title": "외부 사이트·SNS의 내 자서전 무단 게재",
"actor": "저자(피해)",
"primary_tags": [
"reproduction",
"public_transmission"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": true,
"high_risk": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2008다53812",
"in_runtime_corpus": false
},
{
"case_id": "2017도19025",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "B4",
"old_no": 25,
"subgroup": "B 저자(피해)",
"title": "외부의 AI 학습 데이터로 무단 수집",
"actor": "저자(피해)",
"primary_tags": [
"reproduction",
"public_transmission"
],
"secondary_tags": [],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "C1",
"old_no": 21,
"subgroup": "C 플랫폼",
"title": "편집자·교정자 손이 많이 들어간 경우",
"actor": "플랫폼",
"primary_tags": [
"integrity"
],
"secondary_tags": [
"derivative_work",
"attribution"
],
"detectable_internal": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2010다79923",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "C2",
"old_no": 42,
"subgroup": "C 플랫폼",
"title": "유료 폰트 무단 사용 (본문·표지)",
"actor": "저자·플랫폼",
"primary_tags": [
"reproduction"
],
"secondary_tags": [
"distribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "98나23616",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "C3",
"old_no": 54,
"subgroup": "C 플랫폼",
"title": "플랫폼이 사용자 자서전을 AI 학습 데이터로 사용",
"actor": "플랫폼",
"primary_tags": [
"reproduction",
"public_transmission"
],
"secondary_tags": [
"derivative_work"
],
"detectable_internal": false,
"high_risk": true,
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "확립 판례 없음"
},
{
"case_id": "D1",
"old_no": 26,
"subgroup": "D 다른 사용자",
"title": "2차 창작 기능에서 원저자 동의 없는 변형",
"actor": "다른 사용자",
"primary_tags": [
"derivative_work",
"attribution",
"integrity"
],
"secondary_tags": [
"publication"
],
"detectable_internal": true,
"high_risk": true,
"handling": "technical_detection",
"representative_precedents": [
{
"case_id": "2021가합25193",
"in_runtime_corpus": true
},
{
"case_id": "2011도3599",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "E1",
"old_no": 27,
"subgroup": "E 유족",
"title": "저자 사후 유족이 본문 임의 수정",
"actor": "유족",
"primary_tags": [
"integrity"
],
"secondary_tags": [
"reproduction",
"distribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2010다79923",
"in_runtime_corpus": true
},
{
"case_id": "2012다204587",
"in_runtime_corpus": true
}
],
"representative_precedent_note": null
},
{
"case_id": "E2",
"old_no": 28,
"subgroup": "E 유족",
"title": "사후 유고 자서전에 미공표 일기 포함",
"actor": "유족",
"primary_tags": [
"reproduction",
"publication"
],
"secondary_tags": [
"attribution"
],
"detectable_internal": false,
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2013나2004096",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
},
{
"case_id": "X1",
"old_no": 29,
"subgroup": "X 분류체계 외",
"title": "자서전 등장 제3자의 사적 정보 노출",
"actor": "저자(가해)",
"primary_tags": [],
"secondary_tags": [],
"detectable_internal": false,
"note": "사생활 침해 영역, 약관·운영 절차로 처리",
"handling": "terms_or_report",
"representative_precedents": [],
"representative_precedent_note": "저작권 밖(개인정보)"
},
{
"case_id": "X2",
"old_no": 30,
"subgroup": "X 분류체계 외",
"title": "자서전 등장 제3자의 명예 훼손 묘사",
"actor": "저자(가해)",
"primary_tags": [],
"secondary_tags": [],
"detectable_internal": false,
"note": "명예훼손 영역, 약관·운영 절차로 처리",
"handling": "terms_or_report",
"representative_precedents": [
{
"case_id": "2012도13718",
"in_runtime_corpus": false
}
],
"representative_precedent_note": null
}
]
}

View File

@ -173,7 +173,11 @@
| `ai_generation` | object | AI 생성 의심도 상세. 현재 학습 모델 사용 시 `available=true`, `is_stub=false` | | `ai_generation` | object | AI 생성 의심도 상세. 현재 학습 모델 사용 시 `available=true`, `is_stub=false` |
| `matches[]` | array | 매칭된 원본별 상세 (표절 시). 태그·케이스·근거 구간 포함 | | `matches[]` | array | 매칭된 원본별 상세 (표절 시). 태그·케이스·근거 구간 포함 |
| `matches[].tags[]` | array | 법령 태그. `role`: `primary`(주)/`secondary`(보조), `label_ko` 한글 표기 | | `matches[].tags[]` | array | 법령 태그. `role`: `primary`(주)/`secondary`(보조), `label_ko` 한글 표기 |
| `matches[].case_id` | string | 39종 침해 케이스 ID (예: A6) | | `matches[].case_id` | string | 39종 침해 케이스 ID. `case_candidates[0]` 과 같다 |
| `matches[].case_candidates[]` | array | 태그 동점 케이스 **전부**. 태그만으로는 1:1로 좁혀지지 않으므로(A1·A2·A3·A4·A5·A6·A15 는 태그가 동일) 원본의 종류로 사람이 확정한다 |
| `matches[].case_candidates[].handling` | string | `technical_detection`(v1.3 ●) / `terms_or_report`(○) |
| `matches[].case_candidates[].representative_precedents[]` | array | v1.3 IX장 총괄표의 대표판례 사건번호 |
| `matches[].case_candidates[].precedents_without_source[]` | array | 대표판례이나 적재본에 없어 출처 제시 불가. `docs/PRECEDENT_SOURCE_GAP.md` 참조 |
| `matches[].evidence_spans[]` | array | 본문 내 일치 구간 `{start, end, matched}` — 하이라이트용 | | `matches[].evidence_spans[]` | array | 본문 내 일치 구간 `{start, end, matched}` — 하이라이트용 |
| `matches[].partial_signal` | object | 군집화 기반 부분 표절(인물만 교체 등) 분해 — 침해요소 DB 적재용 | | `matches[].partial_signal` | object | 군집화 기반 부분 표절(인물만 교체 등) 분해 — 침해요소 DB 적재용 |
| `ccl_basis` | string\|null | 사람이 읽는 판정 근거 문장 | | `ccl_basis` | string\|null | 사람이 읽는 판정 근거 문장 |
@ -193,7 +197,7 @@
| GET | `/v1/plagiarism/batch/{job_id}` | 배치 상태·결과 조회 | | GET | `/v1/plagiarism/batch/{job_id}` | 배치 상태·결과 조회 |
| POST | `/v1/summary` | 스토리 요약 (과제2 ②) | | POST | `/v1/summary` | 스토리 요약 (과제2 ②) |
| GET | `/v1/precedents` | 전체 판례 검색·등급·저작물 유형 필터 | | GET | `/v1/precedents` | 전체 판례 검색·등급·저작물 유형 필터 |
| GET | `/v1/taxonomy` | 10종 법령 태그 + 39 케이스 정의 (동일 라벨 공유용) | | GET | `/v1/taxonomy` | 10종 법령 태그 + 39 케이스 정의 + 케이스별 대표판례 (동일 라벨 공유용) |
| GET | `/v1/health` | 엔진 상태·코퍼스 크기·버전 | | GET | `/v1/health` | 엔진 상태·코퍼스 크기·버전 |
### 맞춤 요약 옵션 ### 맞춤 요약 옵션

View File

@ -0,0 +1,25 @@
# 대표판례 출처 미확보 목록 — 컴북스 요청 대상
v1.3 IX장 총괄표가 지목한 대표판례 중 운영 적재본(`data/precedents/precedents.jsonl`, 545건)에
없어 결과에 출처를 제시할 수 없는 사건번호 **14건**이다.
대부분 `selection_audit.json``excel_without_official_detail_case_ids`(103건)에 속한다 —
한국저작권위원회 공식 상세 페이지를 찾지 못해 출처를 임의 생성하지 않고 제외한 건들이다.
요청 내용: 판결문 원문 또는 검증 가능한 공식 출처 URL.
| 사건번호 | 영향받는 침해 케이스 |
|---|---|
| 2006가합8583 | A21 |
| 2006나16757 | A6, A7, B2 |
| 2007가합16095 | A17, A18, A19 |
| 2007가합43936 | A16 |
| 2007다354 | A19, A3 |
| 2008다53812 | B3 |
| 2010도4468 | A8, A9 |
| 2012도13718 | X2 |
| 2013나2004096 | A23, E2 |
| 2016고정432 | A14 |
| 2017도19025 | B3 |
| 2019가단31377 | A26 |
| 2019가단5207564 | A17 |
| 2021가합588060 | A1 |

View File

@ -41,3 +41,47 @@ def test_out_of_scope_excluded_from_request():
ids = {x["case_id"] for x in rep["data_request_list"]} ids = {x["case_id"] for x in rep["data_request_list"]}
assert "C1" not in ids assert "C1" not in ids
assert rep["need_data_cases"] == 0 assert rep["need_data_cases"] == 0
# --- 태그 → 케이스 도달 범위 회귀 (v1.3) ---------------------------------
from pathlib import Path
from app.engine.taxonomy import load_taxonomy
ROOT = Path(__file__).resolve().parents[1]
#: _assign_tags 가 실제로 낼 수 있는 주 태그 조합 전부.
#: 이 목록이 곧 케이스 도달 범위의 상한이므로 조합이 바뀌면 여기도 바뀌어야 한다.
_EMITTED_PRIMARY = [
["reproduction", "citation_missing"],
["reproduction", "derivative_work"],
["derivative_work", "citation_missing"],
["derivative_work", "substandard_derivative"],
["reproduction"],
]
def _reachable():
tax = load_taxonomy(ROOT / "data/taxonomy")
return {c.case_id for combo in _EMITTED_PRIMARY for c in tax.find_cases(combo)}
def test_reachable_cases_cover_most_technical_detection_cases():
"""v1.3 ● 19건 중 16건이 태그만으로 후보에 오른다.
남은 B3·C1·D1 게재 사실·편집 개입·성명표시처럼 텍스트에서 없는
사실이 필요해 LegalContext 없이는 도달할 없다. 경계를 고정한다.
"""
tax = load_taxonomy(ROOT / "data/taxonomy")
detectable = {c.case_id for c in tax.cases if c.detectable_internal}
reachable = _reachable()
assert detectable - reachable == {"B3", "C1", "D1"}
assert len(reachable & detectable) == 16
def test_no_tie_group_is_silently_collapsed():
"""동점군이 2건 이상이면 전부 반환된다 — 하나만 남으면 나머지가 사장된다."""
tax = load_taxonomy(ROOT / "data/taxonomy")
assert len(tax.find_cases(["reproduction", "citation_missing"])) == 7
assert len(tax.find_cases(["derivative_work", "substandard_derivative"])) == 2

View File

@ -27,9 +27,11 @@ def test_taxonomy_loads_10_tags_and_cases():
tax = load_taxonomy(ROOT / "data/taxonomy") tax = load_taxonomy(ROOT / "data/taxonomy")
assert tax is not None assert tax is not None
assert len(tax.meta_tags) == 10, f"PDF IV장: 10종 메타 태그 필요, 현재 {len(tax.meta_tags)}" assert len(tax.meta_tags) == 10, f"PDF IV장: 10종 메타 태그 필요, 현재 {len(tax.meta_tags)}"
# PDF 본문에는 "38개"라고 명시되어 있으나 그룹별 통계 # v1.3 IX장 총괄표 본문의 통계 줄은 "●16/○22 = 38"로 적혀 있으나 표를 실제로
# (A27+B4+C3+D1+E2+X2)는 39건이므로 그룹별 통계를 기준으로 검증 # 세면 ●19/○20 = 39 다. 표를 기준으로 고정한다.
assert 38 <= len(tax.cases) <= 39, f"PDF IX장: 38~39 케이스, 현재 {len(tax.cases)}" assert len(tax.cases) == 39, f"v1.3 IX장 총괄표: 39 케이스, 현재 {len(tax.cases)}"
assert sum(c.detectable_internal for c in tax.cases) == 19
assert sum(c.handling == "technical_detection" for c in tax.cases) == 19
def test_taxonomy_has_required_legal_tags(): def test_taxonomy_has_required_legal_tags():
@ -51,12 +53,22 @@ def test_taxonomy_case_groups():
assert len(a_cases) == 27, f"PDF: A그룹(저자 가해) 27건, 현재 {len(a_cases)}" assert len(a_cases) == 27, f"PDF: A그룹(저자 가해) 27건, 현재 {len(a_cases)}"
def test_case_mapping_finds_a1_for_reproduction_citation(): def test_case_mapping_returns_full_tie_group_not_one_arbitrary_pick():
"""reproduction+citation_missing 은 7개 케이스가 주/보조 태그까지 동일하다.
하나만 고르면 나머지 6건이 결과에 영원히 등장하지 않으므로 동점군을 모두 낸다.
"""
tax = load_taxonomy(ROOT / "data/taxonomy") tax = load_taxonomy(ROOT / "data/taxonomy")
# A1: 시·노래 가사 본문 무단 인용 — 주 태그: reproduction, citation_missing ids = [c.case_id for c in tax.find_cases(["reproduction", "citation_missing"])]
case = tax.find_case(["reproduction", "citation_missing"]) assert set(ids) == {"A1", "A2", "A3", "A4", "A5", "A6", "A15"}, ids
assert case is not None assert all(i.startswith("A") for i in ids)
assert case.case_id.startswith("A"), f"reproduction+citation은 A그룹 매칭 기대, got {case.case_id}"
def test_every_case_carries_v13_precedent_mapping():
"""39건 전부가 대표판례를 갖거나, 없는 이유를 명시한다. 빈칸은 허용하지 않는다."""
tax = load_taxonomy(ROOT / "data/taxonomy")
for c in tax.cases:
assert c.representative_precedents or c.representative_precedent_note, c.case_id
def test_high_risk_cases_marked(): def test_high_risk_cases_marked():