intel_bronze_sink 노드 QA 가이드 — Bronze 적재 + MCP 자동 등록
이 문서는 Pipeline Studio의 intel_bronze_sink 노드(Intel 셀프서비스 수집 Slice C, #2289)를 QA가 화면에서 단계별로 검증할 수 있도록 실제 prod(gend.genon.ai)의 finance-invest 워크스페이스 화면과 함께 정리한 것입니다.
개요
intel_bronze_sink는 upstream(예: rest_source)의 records[]를 받아 "PS에서 만들면 즉시 조회 가능한 MCP 인텔 도구" 루프를 닫는 종단(sink) 노드입니다:
- Bronze 적재 — 공유 테이블
iceberg.bronze.intel_<domain>_raw에(workspace_id, content_hash)dedup append (재실행 중복 방지, 불변식 I4). - MCP 자동 등록 — 적재 후
WorkspaceMcpTool을 자동 등록해, 워크스페이스가 MCPtools/list에서 바로 조회 도구로 사용.
★ 워크스페이스 격리 (cross-ws 누출 차단, I5)
bronze는 전 워크스페이스가 공유하는 단일 물리 테이블이고 행은 workspace_id 컬럼으로만 구분됩니다. 따라서 자동 등록되는 MCP 도구는 서버가 강제 주입하는 ws-펜스(query_spec.ws_fenced_col)로만 자기 워크스페이스 행을 조회합니다 — 이 펜스는 호출자가 변경할 수 없고(필터가 아님), 펜스 없는 공유-테이블 도구는 dispatch에서 **거부(fail-closed)**됩니다. 또한 ws-펜스 도구는 마켓플레이스 publish가 금지됩니다(publisher private 행 누출 방지).
신원: 적재 워크스페이스는
run_id → PipelineStudioRun바인딩에서 서버사이드로 파생되며, 노드 config의 workspace_id는 신뢰하지 않습니다(D10).현재 상태: 작성·실행 모두 prod 라이브입니다. egress-proxy 는 2026-06-25 전체 활성화됐고 (Epic #2286), rest_source → intel_bronze_sink 풀체인 E2E 가 prod 에서 검증됐습니다 — 본 가이드의 절차만으로 실제 적재·MCP 조회까지 동작합니다.
1. 팔레트에서 intel_bronze_sink 선택
Pipeline Studio에서 새 파이프라인을 만들면 빌더가 열립니다. 좌측 노드 팔레트에 싱크 (Intel Bronze + MCP) 항목이 있습니다.

2. 캔버스에 드래그&드롭
**싱크 (Intel Bronze + MCP)**를 캔버스로 끌어다 놓으면 intel_bronze_sink 노드가 생성됩니다. (종단 노드 — records를 입력으로 받습니다.)

3. config 폼
노드를 클릭하면 우측에 설정 폼이 열립니다.

| 필드 | 설명 |
|---|---|
| source | 출처 라벨 (예: dart) |
| domain | bronze 테이블 iceberg.bronze.intel_<domain>_raw의 일부 — 안전 식별자만(예: filings) |
| external_id_path | payload에서 외부 ID를 뽑을 path (예: $.rcept_no). 미설정 시 content_hash 사용 |
| 중복·변경 정책 (write_mode) | 같은 external_id의 내용이 달라졌을 때 어떻게 적재할지. 버전 누적(기본) = 새 버전 행 추가(이력 보존), 최신으로 교체 = 새 행 적재 후 구버전 행 제거(external_id 당 최신 1행 수렴, 이력 미보존). 내용이 같으면 어느 모드든 중복 스킵 |
| 검색 필드 (search_fields) | 이름 → payload JSON 경로 맵 (예: law_name → $.법령명한글). 자동 등록되는 MCP 도구에 <이름>_like 부분일치 검색 인자(선택 인자)가 추가됩니다. 이름은 snake_case, 경로는 $.필드(.하위) 형식만 허용 |
| MCP 기본 최신행만 (latest_only, 고급) | 기본 켬 — 버전 누적 테이블에서 external_id 당 최신 1행만 기본 반환하고, 호출 시 all_versions=true 인자로 전체 버전을 조회합니다 (#2529). 이미 등록된 도구는 이 값을 명시적으로 바꿔 저장했을 때만 변경됩니다 — 설정을 건드리지 않으면 기존 도구의 조회 의미(publish/구독 포함)가 정기 실행만으로 바뀌지 않습니다 |
| 검색 인덱싱 (search_index_*, 그룹) | 켬(opt-in) 시 적재 레코드를 청킹→임베딩→Weaviate 인덱싱하고 search_<domain> MCP 검색 도구(시맨틱/하이브리드/키워드)를 자동 등록합니다 (#2594). search_text_paths(payload JSON 경로 목록, 필수)·청크 크기/오버랩·임베딩 프로바이더(선택). 인덱싱 실패는 실행을 죽이지 않고 실행 요약에 오류로 표기(fail-soft — bronze 원장은 이미 커밋) |
| MCP 도구 | 적재 후 자동 등록될 워크스페이스 MCP 조회 도구. tool_name + description 분리 입력(#2323 — raw JSON 직접 입력 아님; 두 칸을 채우면 {tool_name, description}으로 자동 조립). ws-펜스는 서버가 강제 |
| silver 매핑 (JSON, 선택) | silver canonical 매핑(선택) |
4. config 입력 예시
source/domain을 채우고, MCP 도구는 tool_name(예: query_intel_my) + description 두 칸에 입력합니다.

MCP 도구 입력(#2323): 과거엔
{"tool_name":...,"description":...}raw JSON을 직접 입력했으나, 이제 tool_name / description 분리 텍스트 입력입니다. 따옴표·중괄호 실수 없이 두 칸만 채우면 서버 계약({tool_name, description})으로 자동 조립됩니다.

중복·변경 정책 + 검색 필드 (PR-1 #2589) — 최신으로 교체를 선택하고 검색 필드에 law_name → $.법령명한글을 입력한 모습:

고급 설정 → MCP 기본 최신행만 (latest_only) — 접이식 고급 섹션을 열면 최신행 노출 설정이 보입니다:

확인 포인트(QA)
- 적재 후 워크스페이스 MCP
tools/list에tool_name이 출현하고, 그 도구는 자기 워크스페이스 bronze 행만 반환합니다(cross-ws 누출 없음).domain은 안전 식별자가 아니면 422로 거부됩니다(SQL injection 방지).- 같은
(workspace_id, content_hash)는 재적재 시 skip됩니다(중복 방지).- 공유 bronze 테이블 대상 MCP 도구를 ws-펜스 없이 만들려 하면 차단됩니다(I5).
- 검색 필드를 등록했다면 MCP 도구 inputSchema에
<이름>_like인자가 나타나고, 부분일치 값으로 호출하면 해당 payload 필드 기준으로 필터링됩니다. 도구 설명문에는 실제 대상 테이블 FQN이 표시됩니다(#2544).- 최신으로 교체 모드에서 같은
external_id의 내용을 바꿔 재적재하면 실행 요약에N건 최신으로 교체가 표시되고, 테이블에는 최신 1행만 남습니다.
5. 실행 결과 확인
실행이 끝나면 실행 탭에서 해당 실행을 펼치면 적재 결과 패널에
Bronze N행 적재 · M건 스킵(중복) → <테이블> 요약과 등록된 MCP 도구,
적재 레코드 샘플이 표시됩니다. 최신으로 교체 모드로 기존 행이 대체된 경우
· K건 최신으로 교체가 요약에 덧붙습니다.
(재실행으로 전부 중복 스킵된 경우
"신규 없음 — 전부 중복 스킵" 으로 표시됩니다 — 실패가 아닙니다.)
SQL 로 직접 확인하려면:
SELECT count(*), max(fetched_at) FROM iceberg.bronze.intel_<domain>_raw;
보안·무결성 요약 (참고)
| 상황 | 동작 |
|---|---|
| 자기 워크스페이스 도구 조회 | 서버 강제 ws-펜스 → 자기 행만 |
| 펜스 없는 공유-테이블 도구 dispatch | 거부(fail-closed) |
| ws-펜스 도구 마켓플레이스 publish | 거부(422) — publisher private 누출 방지 |
| 동일 (ws, content_hash) 재적재 | skip(중복 방지, I4) |
최신으로 교체 모드 재적재 | 내용이 달라진 external_id의 구버전 행만 교체(무변경 행 무접촉). INSERT 후 DELETE 순서라 부분 실패 시에도 원장(bronze) 유실이 없습니다 — 최악은 구버전 행 잔존(MCP 최신행 윈도우가 가림, 다음 변경 적재 시 수렴). DELETE 도 ws-펜스 내에서만 |
최신으로 교체 동시 실행 | 같은 external_id 를 동시에 적재하는 두 실행이 겹치면 일시적으로 2행이 남을 수 있으나(유실·덮어쓰기 없음) 최신행 윈도우가 가리고 이후 수렴합니다 |
search_<domain> 검색 도구 | Weaviate 공유 컬렉션(intel_<domain>)을 서버 강제 workspace_id 펜스로만 조회(I5) — 검색어는 GraphQL 리터럴로 이스케이프(인젝션 차단), 결과는 HMAC 서명 검증 후 반환. publish 금지(ws-펜스 도구 게이트) |
| 검색 인덱스 버전 | write_mode 와 무관하게 external_id 당 최신판만 인덱싱(이력 검색은 비목표 — 원장은 bronze). 최신판의 텍스트 경로가 비면 기존 청크도 제거(delete-only — stale 검색 결과 방지) |
| 검색 필드 이름/경로 | snake_case + $.필드 형식만 허용 — 인용부호·괄호·와일드카드 422(injection 차단), 저장 스펙 위·변조 시 실행 시점에도 fail-closed |
| malformed sink_config | bronze 적재 전 422(부분 적재 없음) |
자동 검증
이 가이드의 단계는 ui/tests/intel-bronze-sink-e2e.spec.ts(Playwright)로 자동 검증되며, QA_CAPTURE=1로 실행하면 위 스크린샷이 재생성됩니다.
E2E_BASE_URL=https://gend.genon.ai E2E_USERNAME=... E2E_PASSWORD=... \
QA_CAPTURE=1 pnpm exec playwright test intel-bronze-sink