# 설계서: 벡터 검색 VPD effective SQL trace (#570)

> **상태**: Approved
> **작성**: [AI] Architect · **최종수정**: 2026-06-30
> **추적성** — Redmine: #570 · 선행 기능: #567, #569
> · 구현 파일: `OrdsProbeService`, `probe-result.html`, `29_agent_ords_vector_search_ords.sql`
> · 테스트: `GuidedFlowTemplateTest`, `OrdsProbeServiceTest`, `mvn test`

## 1. 목적

벡터 검색 권한 검증에서도 `set_vpd_context` 이후 Oracle VPD가 추가한 행 조건과 벡터 검색 기본 SQL을 한 화면에서 확인한다. 검색 결과의 `SCORE`만 보여주는 것이 아니라 다음과 같은 재현용 effective SQL을 제공한다.

```sql
SELECT chunk_id, document_id, chunk_no, title, chunk_text, source_uri, tech_tag, score
FROM (
  SELECT d.chunk_id, ..., VECTOR_DISTANCE(d.embedding, TO_VECTOR(:embedding), COSINE) AS score
  FROM ADMIN.CB_VECTOR_SEARCH_DOCUMENTS d
  WHERE d.embedding IS NOT NULL
    AND (<VPD predicate>)
  ORDER BY score
) ranked_chunks
WHERE ROWNUM <= LEAST(GREATEST(NVL(:row_limit, 10), 1), 100)
```

실제 Oracle 실행은 보호 뷰에 부착된 DBMS_RLS가 predicate를 자동 주입한다. 화면의 SQL은 Bearer/임베딩 원문을 치환하지 않고 bind placeholder를 유지하는 진단용 표현이다.

## 2. 범위

- **포함**
  - 벡터 ORDS Handler trace에 `AND (<predicate>)`가 들어간 effective SQL 생성.
  - ORDS가 trace를 반환하지 않는 구버전 Handler를 위한 백오피스 same-context fallback.
  - `/probe`의 기존 `토큰 적용 후 SQL` 영역 재사용.
  - 벡터 결과에 VPD predicate와 effective SQL이 함께 표시되는 템플릿/운영 smoke 테스트.
- **제외**
  - Oracle optimizer 실행계획, `V$SQL`, `DBMS_XPLAN` 조회.
  - 실제 embedding 숫자 배열이나 Bearer 원문의 SQL 문자열 치환.
  - 벡터 거리 계산, VPD 정책, 권한 우선순위 자체의 변경.

## 3. 인수조건

- [ ] 벡터 검색 결과에 `토큰 적용 후 SQL`이 표시된다.
- [ ] SQL에 `FROM ADMIN.CB_VECTOR_SEARCH_DOCUMENTS`, `VECTOR_DISTANCE`, `WHERE d.embedding IS NOT NULL`, `AND (<VPD predicate>)`, `ORDER BY score`, row limit이 포함된다.
- [ ] ORDS trace가 있으면 그 값을 사용하고, 없으면 같은 Bearer context의 predicate fallback으로 결과를 보강한다.
- [ ] fallback 실패는 검색 결과를 실패로 바꾸지 않으며, 기존 trace 미지원 안내를 유지한다.
- [ ] SQL에는 Bearer 원문·임베딩 숫자·context 값이 포함되지 않는다.
- [ ] 기존 비벡터 객체의 SQL trace와 권한 결과 흐름은 회귀하지 않는다.
- [ ] 전체 Maven 테스트와 실제 vector `/probe` smoke가 통과한다.

## 4. 처리 흐름

```text
[ORDS vector response]
   ├─ effective_sql 있음 ───────▶ ProbeResult SQL trace 표시
   └─ trace 없음
        └─ same DB connection: set_user_by_bearer
             → cb_agent_doc_vpd_filter
             → vector effective SQL 조합
             → clear_user (finally)
```

`OrdsProbeService`는 객체명이 `CB_VECTOR_SEARCH_DOCUMENTS`인지 whitelist 상수로 판정한다. 일반 객체에는 기존 컬럼 기반 SQL 조합을 적용하고, 벡터 객체에는 `VECTOR_DISTANCE`와 bind placeholder를 포함한 전용 SQL builder를 적용한다.

## 5. 함수 명세

| 함수 | 책임 | 시그니처 | 실패 계약 |
|---|---|---|---|
| `addVectorSqlTrace` | predicate를 벡터 검색 effective SQL에 결합 | `ProbeResult addVectorSqlTrace(ProbeResult, String, ProtectedObject)` | predicate/컬럼 조회 실패 시 원 결과 |
| `vectorEffectiveSql` | 벡터 Handler의 SQL 구조와 VPD 조건을 조합 | `String vectorEffectiveSql(String)` | 입력 predicate는 DB 함수 반환값만 사용 |
| `findVpdPredicate` | 동일 토큰 context에서 기본 VPD predicate 조회 | 기존 private 함수 | 예외 시 null, 반드시 context cleanup |
| vector Handler trace block | ORDS 응답에 predicate와 effective SQL 출력 | SQL PL/SQL source | trace 실패가 검색 결과를 실패로 바꾸지 않음 |

## 6. 보안 및 표현 규칙

- VPD predicate는 `ADMIN.CB_AGENT_DOC_VPD_FILTER`가 현재 토큰 context에서 반환한 문자열만 사용한다. 사용자 입력을 SQL 조각으로 받지 않는다.
- `:embedding`, `:row_limit` placeholder를 사용한다. 실제 embedding 배열은 SQL trace에 포함하지 않는다.
- 응답의 technical detail request payload에는 기존처럼 서버 생성 embedding이 표시될 수 있지만 effective SQL에는 표시하지 않는다.
- `set_user_by_bearer`와 `clear_user`는 같은 pooled connection에서 실행하고 cleanup은 `finally`로 고정한다.

## 7. 검증

- 단위/템플릿: 벡터 SQL에 `VECTOR_DISTANCE`, `AND (predicate)`, row limit이 포함되는지 확인.
- 전체 테스트: `mvn test`.
- 운영: 평문 `Oracle VPD에서 ORDS 권한을 적용하는 방법`, `limit=5`, `agent_hr` 임시 세션으로 `/probe` 실행 후 결과에서 `SCORE`와 SQL trace를 함께 확인한다.
