POSA_Copyrighter/docs/INDEX.md
changukyu 4e8e4b3181 feat: 선례 승계 — 재제출을 다시 심사하지 않는다
8/8 실효성 평가의 결론은 "검색·기록 노동은 줄여주나 심사 건수는 전혀 못 줄인다"
였다. 이 커밋은 그 축을 직접 건드리는 첫 기능이다.

중복 탐지는 이 도구에서 실증으로 검증된 유일한 판별 기능이다 — 재저장(JPEG q90)
/80%축소/50%축소/밝기+10% 변형 24건 중 24건 그룹핑, 같은 24건에서 SHA-256
완전일치는 0건. 그런데 그 결과를 쓰는 곳이 없었다. 서버는 store_duplicates.py
에서 priorDecisions 와 conflicting 을 계산해 내려보내는데, 콘솔은 그것을 큐
배지의 title 속성에만 넣었다. 마우스를 올린 사람만 "이거 지난주에 반려한
이미지"임을 알 수 있었고, 재제출은 처음부터 다시 심사됐다.

서버는 건드리지 않았다. 자리만 옮겼다.

  큐 배지        "동일 이미지 3건 · 선례 반려" (title 이 아니라 본문에)
  판정 패널      결정 메모 바로 위에 선례 배너 + [선례 승계] 1타

승계는 별도 판정 경로를 만들지 않는다. 메모를 채워 기존 setDecision 을 그대로
타므로 반려 메모 필수 검사 · 판정 시점 스냅샷 · 감사 이벤트가 유지되고, 승계
사실은 메모로 감사에 남는다("선례 승계: 동일 이미지 SUB-OLD1, SUB-OLD2 와 같은
판정").

판정 불일치는 승계 대상이 아니다. 같은 이미지에 서로 다른 판정이 있다는 것은
자동 처리할 상황이 아니라 사람이 봐야 하는 신호이므로, conflicting 이면 버튼을
아예 내지 않고 색을 갈라 표시한다.

실렌더 확인(Playwright 1440x900, 실제 서버 + 부트스트랩 스텁):
세 상태(승계 가능 / 판정 불일치 / 선례 없음)의 배너 문구와 버튼 유무가 의도대로,
승계 클릭 시 POST 본문이 위 메모 그대로, 콘솔 에러 0, 가로 오버플로 없음.

검증: ruff clean, pytest 622 passed (정적 3건 추가).

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

18 KiB
Raw Blame History

Project INDEX

  • 2026-09-21 · 선례 승계 — 재제출을 다시 심사하지 않게 한다. 8/8 실효성 평가의 미해결 결론("검색·기록 노동은 줄여주나 심사 건수는 못 줄인다")을 직접 겨냥한 첫 기능이다. 중복 탐지는 이 도구에서 실증으로 검증된 유일한 판별 기능인데(재저장·80%/50%축소·밝기 변형 24/24 그룹핑, 같은 24건 SHA-256 일치 0건), 서버가 계산해 내려보내던 priorDecisions·conflicting 이 큐 배지의 title 속성에만 있었다 — 마우스를 올린 사람만 보는 자리라 아무것도 막지 못했다. 서버 변경 없이 콘솔만 고쳤다: 배지 본문에 선례 표시, 판정 패널(결정 메모 바로 위)에 선례 배너 + 선례 승계 1타. 승계는 별도 경로를 만들지 않고 메모를 채워 기존 setDecision 을 타므로 반려 메모 필수·판정 스냅샷·감사 이벤트가 그대로 유지된다. 판정 불일치(conflicting)면 승계를 제안하지 않는다 — 그때가 사람이 봐야 하는 상황이다. 실렌더 확인(Playwright, 1440×900): 세 상태(승계 가능/불일치/선례 없음) 배너·버튼 유무가 의도대로였고 승계 클릭 시 {"decision":"rejected","memo":"선례 승계: 동일 이미지 SUB-OLD1, SUB-OLD2 와 같은 판정"} 전송, 콘솔 에러 0. ruff clean · pytest 622 passed(정적 3건 추가)

  • 2026-09-21 · 다이어그램 용도를 내부 문서로 확정하고 그 기준으로 부채를 재판정. 한글 폰트 미번들·영어 뷰어 UI 는 archify 한계라 spec 으로 못 고치는데, 사내 머신에는 한글 폰트가 있으므로 low 로 내렸다(인수물로 승격하면 둘이 먼저 blocker — PROJECT_MAP 다이어그램 절에 승격 조건으로 명시). 이어서 코드↔그림 리터럴 드리프트 게이트 tests/test_diagram_facts.py 19건 신설 — 그림에 하드카피된 코드 유래 값(SCORER_VERSION · SCHEMA_VERSION · 믹스인 8개 · app-*.js 15개 · 바디 10MB · 인증 10회/60초 · 프롬프트 12행 · 풀 상한 60/20 · 기본 모델 · 런타임 의존성 3종)을 실제 코드 상수와 대조하고, 상수가 아닌 "지문 유사도 0.9+ → 80점" 은 실제로 채점해 확인한다. SCORER_VERSION v3→v4 와 MAX_PROMPT_EVIDENCE 12→16 을 실제로 넣어 영향받는 세 다이어그램 전부에서 차단됨을 실증. 발견 가능성도 정리 — README 문서 색인에 등재, docs/diagrams/README.md 신설(폴더 안에 '직접 수정 금지'·재생성 명령·CSP 주의). ruff clean · pytest 619 passed(사실 게이트 +19)

  • 2026-09-21 · 다이어그램 감사 후 드리프트 게이트 신설. 에이전트 6축 감사가 주간 한도로 절반(2축)만 완주했고 검증 단계도 죽어, 완주분 15건을 저널에서 복구한 뒤 결정적 주장은 직접 재검증했다. 확정된 구멍 — 그림 4종의 재생성 절차가 문서대로는 실행 불가(archify 실행파일이 PATH 에 없음), 소스↔산출물 동기화를 보는 장치 0개, 사이드카 24개가 개발 머신 절대경로를 담은 채 미추적·비ignore, 임베드 폰트에 한글 구간 0건(U+AC00 매치 0 · 폴백은 중국어 폰트뿐). 실수정: scripts/rebuild-diagrams.ps1(validate→deliver→visual-check→manifest, 실행 확인)과 scripts/update_diagram_manifest.py, 수신증 docs/diagrams/manifest.json, 게이트 tests/test_diagram_sync.py 14건(HTML 직접 수정·spec 만 수정 두 시나리오 모두 실제로 차단됨을 실증), .gitignore 에 사이드카 제외(미추적 24→0), .gitattributes 에 linguist-generated -diff merge=binary. 재생성해도 4종 sha256 불변 — 바이트 결정성 재확인. 한글 폰트·영어 뷰어 UI·architecture 좌표 하드코딩·lifecycle 손튜닝 8개소는 PROJECT_MAP 부채 표에 등재. ruff clean · pytest 600 passed(게이트 +14)

  • 2026-09-19 · 다이어그램 4종으로 확장 — system-architecture(폐쇄망 경계·SSRF 가드 앞 호출 게이트), operator-review-workflow(4레인, 비상 차단 시 심사 계속 경로), submission-lifecycle(분석 실패·보류가 분석으로 복귀하는 두 고리)를 신설하고 기존 evidence-dataflow 포함 4종의 범례 항목을 한글화했다(렌더러 기본값이 "User UI / Agent logic / policy·PII" 같은 타 도메인 문구였다). 뷰어 크롬은 영어로 남는다 — locale enum 이 en/zh-CN 뿐이고 템플릿이 <html lang="en"> 을 하드코딩하므로 Light/Dark·Present·Export·범례 제목("Legend")은 저자가 바꿀 수 없다. 9/21 감사에서 확인. 작성 중 내린 고도 판단: 아키텍처에서는 analyzer/scorer 를 한 컴포넌트로 합쳤고(세부는 dataflow 담당), 라이프사이클에서 "재분석 요청"은 decisionStatus 가 아닌 운영자 액션이라 상태에서 제외해 복귀 엣지를 하나로 줄였다. 4종 모두 archify showcase 통과(아티팩트 검사 9/9 · 합성 오류 0 · 경고 0) + visual-check 통과(1440×900 · 2048×1320 각 Light/Dark, 오버플로 0). 수신증 — dataflow html a62f0f5c / architecture f5a4b6e1 / workflow 402914a3 / lifecycle 62e934a3

  • 2026-09-19 · docs/diagrams/evidence-dataflow.html 신설 — 증거 데이터 흐름(수집 → 경계 검사 → 정규화·채점 → 영속화 → 소비) 자체 완결 다이어그램. 9/18 리뷰 수정의 불변식을 그림으로 고정한다: 제공자별 풀·버킷(RiskScorer v3), 라운드트립이 원 점수를 재현(_evidence_payload ↔ _domain_evidence_from_ui), host 는 저장 시 해석·복원 시 우선 반환, 지식DB 지문 매칭이 풀링 밖 유일한 high 승격 경로. 프로덕션 LLM 경로가 영속화 payload 를 복원해 쓴다는 사실(store_operations.py:487, EvidenceEnricher 는 테스트 전용)도 반영. archify showcase 검증 통과(아티팩트 검사 9/9 · 합성 오류 0 · 경고 0), 브라우저 증거 통과(1440×900 · 2048×1320 각 Light/Dark 4컷, 오버플로 0, 최소 투영 텍스트 6.71px ≥ 6px). spec sha256 42c334cd · html sha256 268f3352 (822,655 B). CDN·원격 fetch 없음 — 폐쇄망 규칙 준수

  • 2026-09-18 · /code-review 15건 전수 처리 (헤드라인 1건은 반증). 반증: "CSE 웹 증거가 라운드트립 후 0→45점" — 리뷰가 match 키 없는 합성 Evidence 로 재현한 것이고, 실제 CSE 웹 결과는 google_custom_search.py:301 에서 match="page" 를 달고 오며 matchType 이 충실히 왕복한다(신선/복구 모두 35점). 직렬화 불변식 위반 없음. 대신 그 조사에서 리뷰가 놓친 라이브 버그가 나왔다: counted_web_buckets 가 제공자를 안 가려 Vision 이 match="page" 를 먼저 보고하면 CSE 웹 히트가 점수도 사유도 없이 통째로 버려졌다. 실수정 — 점수 v2 → v3(풀·버킷을 제공자별로: Vision 자기 상관 뷰 4개는 60/medium 유지, Vision full + CSE page 는 45+35=80/high 복원 · 도달 불가였던 category 탈출구 제거 + 미등록 유명인 미탐은 의도된 트레이드임을 명시, 승격 경로는 지식DB/FINGERPRINT), 저장·복구 5종(_result_host 가 자기 host 를 안 읽어 재직렬화 시 API 이름으로 퇴행하던 잠재 버그 + 점 없는 토큰 호스트 거부 · 복구가 남긴 고아 faceCrops 참조를 재생성/정리 · assetMissing 해제 경로 신설로 두 번째 소실도 감사에 남김 · 플래그+감사를 한 트랜잭션으로 · 스코어러 마이그레이션 밴드 변경에 scoredVersion 스탬프 + 감사 1회), 콘솔 4종(긴 CDN 호스트가 제목을 세로 컬럼으로 만든 flex 버그 — 실측 360px 51×95px→246×19px, 1280px 9×380px→205×19px 로 폰 전용이 아니었음 · 20ch 로 잘린 호스트를 툴팁에 · bloggerLink 폴백 누락 · 보존 케이스 설명 표시), PROMPT_VERSION ko-v4-structured-host(실모델 프로브 qwen2.5:7b — grounded 3/dropped 0/verified True, 반향 없음). 테스트 +14건. ruff clean · pytest 586 passed. 발견된 기존 결함 1건은 미수정 기록: 로컬 ollama 가 떠 있으면 test_http_app.py 3건이 실호출 타임아웃으로 실패한다(기본 생성 store 가 127.0.0.1:11434 기본값에 붙음 — clean HEAD 에서도 동일). 커밋 b0aa4c5 / 4ba83eb / e38dad8

  • 2026-08-09 · P1 2차 — 게시 호스트 복구. P1 3번의 전제("호스트는 저장돼 있고 점수만 안 쓴다")가 틀렸다: CSE 가 실호스트를 data["domain"] 에 넣는데 store_serialization.py:298 이 provider 를 우선해 저장 시점에 덮어썼고, Vision·Naver 는 URL 만 준다. 결과적으로 LLM 프롬프트 12줄이 전부 domain=google 이라 "어디에 떠 있나"를 모델도 운영자도 못 봤다. domain 은 provider 커버리지·CSE 시그니처 매칭의 키라 재사용 불가 → host 별도 키 신설(_result_host: CSE displayLink 또는 URL 파싱, www 제거·소문자). 점수 무영향·_evidence_id 무변화(도메인 객체 해싱이라 payload 키 추가가 id 를 안 바꿈). PROMPT_DATA_FIELDS 의 domain→host, 콘솔 증거 카드에 monospace host-chip(레거시 행은 evidenceHost() 가 저장 URL 에서 파생 — 마이그레이션 불요). 실렌더 검증(실 DB, 칩 82개 전부 유효 호스트, 콘솔 에러 0)에서만 드러난 결함 2건 수정: 긴 CDN 호스트가 제목을 한 글자씩 세로로 깨뜨림 → 칩 20ch 상한 + 제목 flex:1 1 auto, 이후 짧은 호스트까지 잘림 → 칩 flex:0 0 auto 고정. PROVENANCE 배점은 보류(카테고리가 2종뿐이라 라벨이 사실상 "geometry AND 자막"이고, "새 신호는 0점 출시 후 상관 확인" 결정과 충돌 — 한계를 provenance.py 상수 옆에 기록). pytest 574 passed(착수 전 570)

  • 2026-08-09 · P1 1차 — 판별력 복구를 위한 신호 풀 도입, SCORER_VERSION v1 → v2 — 포화 동인이 둘이었다: category 없는 raw Vision 라벨이 이름별 버킷으로 무한 누적(WEB_ENTITY_MAX_POINTS=20, medium 미만으로 캡)되고, full/partial/page/visual 이 하나의 사실을 4개 상관된 뷰로 보고하는데 합산돼 125→100 포화(WEB_PRESENCE_MAX_POINTS=60, high 미만으로 캡). category(character/celebrity/work) 엔티티는 권리 분류이므로 풀에서 제외하고 +45 유지. 원칙: 웹에 존재한다는 사실만으로는 high 가 되지 않고, 두 번째 종류의 신호가 필요하다. 224조합 재측정 — 웹 신호만으로 high 가 되는 조합 2/7 → 0/7, 100점 포화 66.5%→51.3%(전체 high 비율 82.6%→76.3%은 격자가 균등샘플이라 대리값이 아님을 명기). 웹에 없는 오리지널·cleared 자산이 100/high → 20/low 로 교정. 라운드트립 버킷 보존 테스트는 캡에 가려지지 않도록 저신뢰도로 재작성. pytest 570 passed(착수 전 565) → 평가 리포트 6절

  • 2026-08-08 · 기능 실효성 평가(6축 조사 + 축별 적대적 반증, 에이전트 12) 후 P0 4종 수정 — 결론은 "검색·기록 노동은 줄여주나 심사 건수는 못 줄인다"(신호조합 224개 전수 시 high 77.7%·low 3.6%, 지배 동인은 match 스택이 아니라 web entity 누적 — 이미지 매칭 0건이어도 entity 3개면 100/high, 웹에 없는 오리지널도 66/medium). 실수정: 폴더 정리가 판정 기록을 지우던 경로 차단(판정 완료 가드 + assetMissing 1회 마킹; 실증으로 export 1행→0행 확인됨), 비상 차단 스위치 실배선(_external_calls_blocked 신설 → 자동 Naver/CSE/Vision/얼굴크롭 5개 경로; 이전엔 눌러도 외부 호출 5회 동일), 생체 크롭의 보존기간 초과 생존 차단(스냅샷 제외 + 레거시 아카이브 복구 스킵 — 복구가 mtime을 리셋해 90일을 재시작시켰음), 오프라인 설치 문서의 계약 위반 모델 정정(0.5b→7b + ollama 바이너리·GPU 전제·거짓 disable 서술). DB 6건은 첫 커밋보다 2주 앞선 구빌드 스냅샷이라 검증 코퍼스가 아님을 확인. pytest 565 passed(착수 전 562), 린트 클린 → docs/reviews/2026-08-08-utility-assessment.md

  • 2026-08-08 · 프로젝트 분석 후 인프라·구조·보안 정비 — 원격 백업 복구(20커밋이 로컬에만 있었음: main 2 + 작업브랜치 18 → Forgejo push), 단일 verify 게이트 신설(verify.ps1 + pytest.ini + ruff.toml, ruff 0.12.0 dev 핀; 린트 18건 정리), app.js 5,428줄 → app-*.js 15개 분할(순수 라인범위 추출로 바이트 단위 라운드트립 검증, 로드 순서를 정적 테스트로 고정), 보안 2종 실수정(SSRF DNS-rebinding TOCTOU — 단일 DNS 해석 후 그 답변으로만 연결하는 _guarded_create_connection; 실패 인증 스로틀 — 자격증명 제시 실패만 10회/60초, 429+Retry-After), 7/11 체크리스트 재확인(6건은 이미 수정돼 있던 낡은 항목, Batch 8 은 Batch 6 과 중복이라 정리), CLAUDE.md·docs/PROJECT_MAP.md 신설. E2E 플레이크(업로드 대기 10초 → UPLOAD_ANALYSIS_TIMEOUT_MS 30초) 해소. pytest 562 passed(착수 전 533/1 failed), 린트 클린. 실렌더 확인: 큐·케이스 심사 정상 렌더, 스크립트 15개 전부 200, 새로고침 후 콘솔 메시지 0

  • 2026-07-24 · 멀티에이전트 프로젝트 점검(에이전트 109, 적대적 검증 포함) — pytest 377/379, 런타임 스모크 9/9 통과, 신규 CONFIRMED 43건(HIGH 7) + 7/11 체크리스트 중 3건 실수정 확인 + 기능 제안 상위 5 선정 → docs/reviews/2026-07-24-project-review.md

  • 2026-07-26 · 운영자 콘솔 실렌더 검증 + 결함 5종 수정 (d20e6d6) — 서버 기동 불가(cp949에서 em-dash UnicodeEncodeError로 프로세스 사망, 납품 환경 치명) · 요약이 모델이 못 본 78건을 "연결 근거"로 주장(B단계가 절반만 막았음) · grounded/droppedClaims 미영속화 · app.js가 서버 그룹 분류를 자체 매핑으로 덮어씀 · 기본 모델이 클라이언트/배선에서 불일치(미설치 모델 지목). 실렌더 확인: 출처 표기 그룹 자체 섹션 렌더, [E1,E2...] 인용 2단 요약, sourceIds 78→10, qwen2.5:7b 6.0초. pytest 534 passed

  • 2026-07-25 · C단계: 출처 신호 2종 (5a9fcc0) — EXIF/IPTC 권리 표기 추출(화이트리스트 6필드, GPS·시리얼·Make/Model 미판독) + 방송캡처 포렌식(레터박스·자막밴드·프레임크기, 독립 카테고리 2개 이상). 하나의 EvidenceSource.PROVENANCE·하나의 GUI 그룹으로 배관 12곳 비용 1회 지불. 둘 다 0점 라벨(캘리브레이션 전). 실측: 실제 이미지 6장에서 캡처 오탐 0·권리메타 히트 0(정밀도 확인, 가치는 이 코퍼스에서 미입증). XMP/C2PA는 defusedxml 미반입으로 제외. pytest 531 passed

  • 2026-07-25 · 실모델 프로브로 형식 예시 반향 결함 발견·차단 (6bbaaf6) — qwen2.5:0.5b가 프롬프트의 형식 예시를 그대로 출력하며 실제 라벨 12개를 전부 인용해 집합 포함 검사를 통과. 가짜 transport 테스트로는 불가능한 발견. 기본 모델을 실측으로 qwen2.5:7b 확정(0.5b 55.7s 계약위반 / 7b 8.8s 준수 / qwen3:8b 35.7s 준수)

  • 2026-07-25 · B단계: LLM을 요약기에서 증거 판독기로 (6be263a) — 입력 화이트리스트 9필드+상위 12건 상한(promotion_reason 제외), format=json 구조화 인용 + 라벨 집합 포함 검사로 미인용 claim 폐기, 기본 모델 0.5B→3B 및 num_ctx/num_predict/keep_alive/timeout 노출, 시드 LLM 호출을 _write_lock 밖으로(시드당 20건 상한). 잠금 이동이 만든 provider 커버리지 회귀(요약 존재하는데 not_run 보고)를 나레이션 후 재계산으로 수정. pytest 515 passed

  • 2026-07-25 · 실사용 투입 전 T0 4종 + 임베딩 정책 개정 구현 — (T0-1) initialRiskScore/initialRiskBand/scorerVersion 각인, (T0-2) YuNet 얼굴검출 교체 + 인물 등급(identifiable/background) 도입 및 라운드트립 보존, (T0-3) 판정 시점 피처 스냅샷(라벨 순환 차단), (T0-4) 모델·프롬프트 버전 + latency_ms 스탬프. Scene Embedding Policy 신설로 임베딩 금지 범위를 생체 식별로 축소(얼굴 임베딩 금지는 landmark·descriptor 추가로 강화). YuNet 가중치는 models/(gitignore) + offline-install.md에 sha256 반입 절차. pytest 502 passed(착수 전 463). 실측: 6장 기준 검출 378ms(YuNet) vs 654ms(Haar), 2장에서 등급 판정이 갈림

  • 2026-07-25 · AI 기능 확장 브레인스토밍(에이전트 14: 5렌즈 발산 30건 → 적대적 실현가능성 검증 6건 REFUTED → 심사 3인 채점) — 1위 「LLM 예산·계측·입력 경계」 7.90(만장일치). 검증 중 실측으로 확인: 판정 라벨 0건·operatorStatus 292행 전부 None·밴드 high 4/medium 2/low 0(4건 100점 포화)·_perceptual_hash는 pHash가 아닌 8x8 평균해시. 문서의 WAL 미설정 주장은 검증 결과 오류로 정정(이미 적용됨) → docs/brainstorms/2026-07-25-ai-capability-expansion-brainstorm.md

  • 2026-07-24 · 위 점검의 전체 remediation + 신규 기능 5종 구현 — HIGH 7·MEDIUM 15·LOW 21 및 F1~F5(키보드 심사·일괄 판정/메모 프리셋·지문 중복 인덱스·판정 내보내기·백업 복구) 완료. cv2 환경 드리프트 복구(OpenCV 5.0.0 제거). pytest 457 passed(착수 전 377/2 failed), 실서버 스모크 및 백업 복구 왕복 검증. GUI 스펙의 "일괄 승인/반려 금지(v1)" 제약은 가드레일 조건부로 개정 이력 남기고 해제 → docs/reviews/2026-07-24-implementation-checklist.md