POSA_Copyrighter/docs/diagrams/evidence-dataflow.dataflow.json
changukyu 994852d920 feat: 신뢰 출처 — 자사·계약처 도메인은 위험 신호가 아니다 (SCORER_VERSION v4)
8/8 실효성 평가가 "남은 것: 신뢰출처 판정 자체. 목록만 정해지면
cleared_reference 와 같은 패턴으로 바로 붙는다"로 남겨둔 항목이다. 전제였던
"호스트가 저장 시점에 파괴되는" 문제는 9/18 에 고쳤고, 저장 위치는 지식DB 로
정해졌다.

  지식DB 의 trusted_host 항목 — 이름이 호스트, 별칭이 같은 주체의 다른 도메인
  신뢰 철회는 기존 활성/비활성 수명주기 그대로 (두 번째 스위치를 만들지 않는다)

핵심은 **행 단위 제외**라는 것이다. 케이스 단위로 끄면 자사 사본이 있다는
이유로 스크래퍼 게시까지 덮인다. 실측: 우리 CDN 완전일치 + 블로그 게시가 같이
있을 때 신뢰 등록 전 80/high, 등록 후 35/medium — 블로그만 남는다.

제외된 행은 점수에서 빠지되 사유로는 남는다("신뢰 출처 posar.info — 위험
점수에서 제외"). 증거 목록에는 그 행이 그대로 보이므로, 왜 점수가 증거보다
조용한지 운영자에게 말해주지 않으면 도구를 불신하게 된다.

경계 처리:
  서브도메인은 같은 주체다 (cdn.posar.info)
  posar.info.evil.test 는 접미사가 아니라 다른 도메인이다
  점 없는 값은 무시한다 — "com" 하나가 웹 전체를 신뢰 처리하면 안 된다
  엔티티 라벨은 영향 없다 — "어디에 떠 있나"가 아니라 "무엇이 찍혔나"다
  신선한 CSE 행은 host 키가 없어 domain(displayLink)에서 해석한다

호스트 해석이 store_serialization._result_host 와 따로 사는 이유는 층 때문이다.
analysis 는 server 를 import 할 수 없고, 한쪽은 값을 영속화하고 다른 쪽은
운영자 목록과 대조한다. 우선순위는 같게 맞추고 그 사실을 양쪽 주석에 적었다.

빈 목록이면 v3 과 동작이 같다. 등록하지 않은 배포는 아무것도 달라지지 않는다.

다이어그램 사실 게이트(9/21 신설)가 v3 -> v4 를 3개 다이어그램에서 자동으로
잡았다. 스펙을 고치고 rebuild-diagrams.ps1 로 재생성했다 — 게이트의 첫 실사용이고
의도대로 동작했다.

검증: ruff clean, pytest 632 passed (스코어러 7건 + 스토어 3건 추가).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BStHFrjQj2VypecSG9ex1V
2026-09-21 12:18:31 +09:00

322 lines
7.8 KiB
JSON

{
"schema_version": 1,
"diagram_type": "dataflow",
"meta": {
"title": "증거 데이터 흐름 — 수집에서 판정까지",
"output": "docs/diagrams/evidence-dataflow.html",
"quality_profile": "showcase",
"views": [
{
"id": "collect-boundary",
"label": "수집 경계",
"focus": [
"vision",
"cse",
"naver",
"policy",
"normalizer"
],
"note": "외부 응답이 Evidence 가 되기까지 통과하는 데이터 등급 경계."
},
{
"id": "scoring",
"label": "채점",
"focus": [
"normalizer",
"scorer",
"knowledge"
],
"note": "제공자별 풀·버킷과, 풀링 대상이 아닌 지식DB 승격 경로."
},
{
"id": "roundtrip",
"label": "라운드트립",
"focus": [
"payload",
"sqlite",
"restore",
"scorer"
],
"note": "저장과 복원이 원 점수를 재현해야 하는 고리."
}
],
"viewBox": [
1080,
500
],
"legend": {
"mode": "auto",
"entries": {
"emphasis": {
"label": "주 경로"
},
"security": {
"label": "등급 통제"
},
"database": {
"label": "저장소"
},
"default": {
"label": "데이터 흐름"
}
}
}
},
"stages": [
{
"label": "수집"
},
{
"label": "경계 검사"
},
{
"label": "정규화 · 채점"
},
{
"label": "영속화"
},
{
"label": "소비"
}
],
"nodes": [
{
"id": "vision",
"type": "external",
"label": "Cloud Vision",
"sublabel": "웹 탐지 · 엔티티",
"tag": "match",
"brand": "google-cloud",
"stage": 0,
"row": 0
},
{
"id": "cse",
"type": "external",
"label": "Google 맞춤 검색",
"sublabel": "이미지 · 웹문서",
"tag": "match=page",
"stage": 0,
"row": 1
},
{
"id": "naver",
"type": "external",
"label": "네이버 검색",
"sublabel": "블로그 · 웹문서",
"tag": "promoted",
"stage": 0,
"row": 2
},
{
"id": "knowledge",
"type": "database",
"label": "지식DB · 신뢰 출처",
"sublabel": "지문 · 자사 도메인",
"tag": "내부",
"stage": 2,
"row": 2
},
{
"id": "policy",
"type": "security",
"label": "데이터 등급 검사",
"sublabel": "payload 허용 목록",
"tag": "SEARCH_EVIDENCE",
"stage": 1,
"row": 1
},
{
"id": "normalizer",
"type": "backend",
"label": "증거 정규화",
"sublabel": "Evidence 레코드",
"tag": "source",
"stage": 2,
"row": 0
},
{
"id": "scorer",
"type": "backend",
"label": "RiskScorer",
"sublabel": "제공자별 풀 · 버킷",
"tag": "v4",
"stage": 2,
"row": 1
},
{
"id": "payload",
"type": "backend",
"label": "_evidence_payload",
"sublabel": "도메인 → payload",
"tag": "host 해석",
"stage": 3,
"row": 0
},
{
"id": "sqlite",
"type": "database",
"label": "evidence 테이블",
"sublabel": "payload JSON · WAL",
"tag": "cascade",
"stage": 3,
"row": 1
},
{
"id": "restore",
"type": "backend",
"label": "증거 복원",
"sublabel": "payload → 도메인",
"tag": "복원",
"stage": 3,
"row": 2
},
{
"id": "console",
"type": "frontend",
"label": "운영자 콘솔",
"sublabel": "증거 카드 · host 칩",
"tag": "판정",
"stage": 4,
"row": 0
},
{
"id": "llm",
"type": "backend",
"label": "LLM 증거 판독",
"sublabel": "상위 12행 화이트리스트",
"tag": "ko-v4",
"stage": 4,
"row": 1
}
],
"flows": [
{
"id": "vision-payload",
"from": "vision",
"to": "policy",
"label": "웹 탐지 결과",
"classification": "외부 응답",
"route": "top-channel"
},
{
"id": "cse-payload",
"from": "cse",
"to": "policy",
"label": "검색 결과",
"classification": "외부 응답",
"route": "straight"
},
{
"id": "naver-payload",
"from": "naver",
"to": "policy",
"label": "블로그 · 웹문서",
"classification": "외부 응답",
"route": "bottom-channel"
},
{
"id": "allowed-fields",
"from": "policy",
"to": "normalizer",
"label": "허용 필드만 통과",
"classification": "등급 통제",
"variant": "security"
},
{
"id": "evidence-record",
"from": "normalizer",
"to": "scorer",
"label": "채점 입력 신호",
"classification": "주 경로",
"variant": "emphasis",
"labelDy": 36
},
{
"id": "fingerprint-match",
"from": "knowledge",
"to": "scorer",
"label": "지문 유사도 0.9+ → 80점",
"classification": "풀링 제외",
"labelDy": -20
},
{
"id": "score-band",
"from": "scorer",
"to": "payload",
"label": "점수 · 밴드 · 사유",
"classification": "주 경로",
"variant": "emphasis"
},
{
"id": "serialize",
"from": "payload",
"to": "sqlite",
"label": "payload JSON · host",
"classification": "주 경로",
"variant": "emphasis",
"labelDy": 36
},
{
"id": "reload-restore",
"from": "sqlite",
"to": "restore",
"label": "리로드 · 판정 시 복원",
"classification": "읽기 경로",
"labelDy": 36
},
{
"id": "roundtrip-invariant",
"from": "restore",
"to": "scorer",
"label": "원 점수 재현",
"classification": "불변식",
"variant": "emphasis"
},
{
"id": "bootstrap-read",
"from": "sqlite",
"to": "console",
"label": "bootstrap 조회",
"classification": "읽기 경로"
},
{
"id": "evidence-reading",
"from": "restore",
"to": "llm",
"label": "증거 판독 요청",
"classification": "읽기 경로"
}
],
"cards": [
{
"dot": "emerald",
"title": "주 경로",
"items": [
"외부 응답은 데이터 등급 검사를 통과한 필드만 Evidence 가 된다",
"RiskScorer v4 는 풀과 dedup 버킷을 제공자별로 나눈다 (presence 60 / entity 20)",
"점수 · 밴드 · 사유는 payload 로 직렬화되어 evidence 테이블에 남는다",
"신뢰 출처(자사·계약처 도메인)에서 발견된 행은 0점이다 — 행 단위 제외라 스크래퍼 게시는 그대로 센다"
]
},
{
"dot": "rose",
"title": "라운드트립 불변식",
"items": [
"_evidence_payload 로 직렬화하고 _domain_evidence_from_ui 로 복원한다",
"복원된 증거를 다시 채점하면 원 점수가 재현되어야 한다",
"result_url → url 별칭이 0점을 45점으로 바꾼 사고가 있었다",
"host 는 저장 시 해석하고 복원 시 우선 반환한다 — API 이름으로 되돌아가지 않는다"
]
},
{
"dot": "orange",
"title": "소비 경로",
"items": [
"콘솔은 영속화된 payload 를 읽는다 — 호스트 칩은 20ch 로 잘리고 전체는 툴팁에 있다",
"LLM 은 복원된 증거 상위 12행만 본다 — 인용 없는 claim 은 폐기된다",
"지식DB 지문 매칭은 풀링 대상이 아니며, 라벨만으로는 닿지 않는 high 승격 경로다"
]
}
]
}