id: D2
version: 10
bundle: replace
name: 질의 글이 결과에 없음
gold: false
status: fix
unit: slot
sample:
  conditions:
  - O
  - O_v10
  - a1
  - a
  - c
  scope: top10
question: |
  대상 질의 글(target)이 이 장의 결과 글에 있는가. 결과 글 = node_text_map_union 의 글(대치 뒤 글)과 result_thumbs_pages 에 보이는 글이다. query_yaml 에 적혀 있다는 것은 「보임」의 근거가 아니다.
  - visible: 어떤 노드 글 하나가 대상 글과 같다(공백, 대소문자 차이는 같음). 글머리 번호(「14.」「①」「01」)를 떼고 같아도 같다(번호는 marker 칸으로 갈 수 있다).
    예: 대상 글과 글자가 같은 노드가 하나라도 있으면 visible 이다. 비슷한 다른 글이 함께 있어도, 그림에서 잘 안 보여도 node_text_map_union 에 같은 글이 있으면 visible 이다.
  - merged: 같은 노드는 없지만 어떤 노드 글 안에 대상 글이 「* 」 불릿 한 줄로, 「이름: 값」 꼴로, 또는 부분 문자열(4자 이상)로 들어 있다. 쉼표, 가운뎃점(·), 쌍반점, 빗금으로 항목을 이어 붙인 줄은 그 조각 하나가 대상 글과 같으면 길이와 상관없이 merged 다.
    예: 대상 글 「보행」, 노드 글 「* 개인위생, 보행, 계단 오르내리기」 이면 merged 다.
    예: 여러 줄 노드 글의 불릿 한 줄(「* 」 뒤)이 대상 글과 같으면 merged 다(없어진 것이 아니다). 노드 글을 줄마다 나눠 모든 줄을 대상 글과 견준다.
    예: 노드 글 한 줄(또는 쉼표 · 가운뎃점 · 쌍반점으로 이은 줄의 한 조각)이 「period: 3월」 처럼 「이름: 값」 꼴이고 값이 대상 글 「3월」 과 같으면 merged 다(길이와 상관없음). 「항목, 항목, period: 9월」 의 「9월」 도 merged 다.
    예: 표(마크다운 표 글)의 칸 하나가 대상 글과 같으면 merged 다(머리 칸의 「(단위)」 는 떼고 견준다). 대상 글이 「2033 감축률: 105.9% (100%)」 처럼 「이름: 값」 이고, 첫 칸이 그 항목 label 인 행의 「2033 감축률」 열 칸이 105.9 이면 merged 다.
  - title_no_slot: 대상 필드가 title 인데 이 장에 제목 자리(binding 의 field title)가 없어 제목이 들어가지 않았다. 결함이 아니다(제목 자리 판정은 D4 몫).
    예: 대상 필드가 title 이고 binding 에 field title 이 하나도 없는 템플릿이면, 같거나 포함하는 글이 없을 때 absent 가 아니라 title_no_slot 이다.
  - absent: 그 밖. 글이 전혀 없거나 뜻이 바뀐 다른 글만 있다. 위 세 경우를 모두 확인한 뒤에만 고른다.
  나눠 담기면(한 YAML 몫이 여러 쪽에 걸친 경우 포함) node_text_map_union 은 「쪽 i/N」 별로 글을 나누어 담고 result_thumbs_pages 는 쪽 그림을 쪽 순서대로 담는다. 어느 쪽에 있든 그 전부에서 찾는다.
inputs:
- query_yaml
- binding
- node_text_map_union
- result_thumbs_pages
- spec_excerpt:
  - contract-601
  - cap-286
answers:
  kind: categorical
  options:
  - key: visible
    label: 보임(대상 글과 글자가 같은 노드가 있음)
  - key: merged
    label: '합쳐져 보임(불릿 한 줄이 대상 글과 같음, 「이름: 값」, 부분 문자열)'
  - key: title_no_slot
    label: 문서 제목인데 제목 자리가 없음(binding 에 field title 없음, 결함 아님)
  - key: absent
    label: 없음(위 셋이 모두 아님)
defect:
  bad:
  - absent
aggregate: ratio
truth:
  kind: rule
  rule: query_text_presence
allowed:
- '넘치는 항목이 「* 」 불릿으로 한 자리에 합쳐지는 것, 자리 없는 필드가 items 에 「이름: 값」으로 붙는 것은 허용이다(merged).'
- 'entities 와 표(matrix)가 함께 있는 장에서 entities 글이 표 칸(머리 칸, 행 칸)에 실제로 들어간 것은 있음이다(merged). 표에도 없으면 그대로 absent 다.'
- 값과 단위가 한 글로 합쳐지는 것, 표 머리글에 「(단위)」가 붙는 것은 같음이다(visible).
- 문서 제목은 제목 자리가 있을 때만 들어간다. 자리가 없어 빠진 것은 결함이 아니다(title_no_slot).
sources:
- design/content-binding-contract.md 3.7.3(텍스트 전량 보존)
- 21-replace-cards.md §0.1(제목 규칙, 유저 규칙 10/19 자리가 없으면 결함 아님)
threshold:
  basis: a1
  value: null
model:
  default: gpt-6-luna
  current: gpt-6-luna
reps: 5
observe_only: false
purpose: "질의 글 하나가 대치 결과 어디에도 없는 일(같은 글로도, 불릿 한 줄이나 「이름: 값」으로도 없음)을 잡는다. 텍스트 전량 보존은 대치 계약이다(contract-601, content-binding-contract 3.7.3). 대치 링크의 책임이고 비교 대상은 질의 글이며, 나눠 담기면 같은 항목의 모든 쪽을 합쳐 찾는다(D2 v3, v5, 기본품질 18). 제목 자리가 없는 장에 문서 제목이 없는 것은 결함이 아니고(user-title-1019), 엉뚱한 자리에 든 것은 D3, 생성에서 이미 빠진 글은 G7 몫이다."
changelog:
- 'v2 (2026-10-20): 거짓 양성 524 건 중 522 건이 나눠 담기의 다른 쪽에 있는 글을 이 쪽 그림만 보고 absent 로 답한 것(b, 꾸러미가 쪽 하나뿐). 결함 685 건 중 102 건은 제목 자리가 없는 장의 문서 제목을 absent 로 센 것(유저 규칙상 결함 아님). 답에 title_no_slot 을 더하고 binding 을 넣어 제목 자리 유무를 보게 했다. visible 과 merged 의 경계(노드 글 하나와 같음 대 노드 글 안에 포함)를 정의했다. 쪽 합집합 원천은 needed.'
- 'v3 (2026-10-20): 나눠 담기 쪽 합집합. 원천 node_text_map 을 node_text_map_union(쪽별 글, 쪽 경계 표시)으로, result_thumb 를 result_thumbs_pages(쪽 그림 전부)로 바꿨다. 쪽 하나만 보여 absent 로 답하던 거짓 양성 대응.'
- 'v4 (2026-10-20): 규칙 정답은 present 인데 평가기가 absent 라 답한 셀 75 건 가운데 표본을 보니 전부 규칙이 맞았다. 놓친 꼴은 불릿 한 줄 안에 대상 글이 그대로 있음, 노드 글이 대상 글과 정확히 같음, 제목 자리가 없는데 title_no_slot 을 안 고름. 질문과 답 설명에 세 꼴의 예시를 한 줄씩 더했다(의미와 입력은 그대로).'
- 'v5 (2026-10-22): 규칙의 쪽 묶음 수정. 순위 2 이상 항목의 행 키는 `<md5>#<쪽>#r<순위>` 인데 규칙이 끝 숫자를 쪽으로 읽어 같은 항목의 쪽들을 하나로 묶지 못하고, 다른 쪽에 들어간 글을 absent 로 셌다. 쪽 번호와 순위를 가려 읽도록 고쳤다(`rules/_util.py` 의 `page_of_key`). 질문과 입력 종류는 그대로이고 규칙 정답이 바뀐다. 쪽 합집합 입력도 같은 묶음 함수를 쓰므로 순위 2 이상 나눠 담기 항목에서 쪽이 더 모인다. 확인 표본 D2 결함 9,948 건 가운데 70.4% 가 이 원인이었다. 글머리 번호가 순번 표식으로 간 경우와 4자 미만 짧은 글은 이번 수정 밖이다.'
- 'purpose 추가(10/24)'
- 'v6 (2026-10-26): 유저 규칙 검수(20 단위, 규칙이 틀림 4, 넷 다 규칙 답 absent)를 반영해 규칙을 고쳤다. (a) 쉼표, 가운뎃점 등으로 합친 줄은 조각이 질의 글과 같으면 길이 하한 없이 merged(4자 하한에 걸린 2 단위). (b) 글머리 번호 접두(「14.」「①」「01」)를 양쪽에서 떼고도 비교(번호가 marker 칸으로 간 1 단위). (c) row_level 보정: slot 번째 L2 칸으로 골랐어도 장 글 줄이 L1 문서 슬롯과 더 많이 맞으면 L1 나눠 담기 쪽으로 읽는다(d2-decision-1026 rowlevel3 기준, 1 단위. 같은 함수를 쓰는 D3, D6, R5 의 단위 열거도 바뀐다). (d) label 자리가 없는 템플릿 예외(label_no_slot)는 유저 미결이라 플래그 VS_EVAL_D2_LABEL_NO_SLOT 로만 켜고 기본은 꺼짐(absent). 질문은 (a)(b) 예시를 더했고 답 종류는 그대로다. 규칙 정답이 바뀌므로 규칙 설계 검증 기록은 v6 재검수로 새로 세운다.'
- 'v7 (2026-10-27): 질의 문서 고르기(row_level) 측정 오류 수정. L1, L2 가 둘 다 있는 질의에서 결과가 L1 을 나눠 담았는데 binding 점수가 다른 L2 칸(l2other)을 골라 생성기가 바꾼 L2 문구를 찾던 행(v6 결함 442 단위, 84 장)을 L1 으로 읽는다. 보정을 l2, unknown, l2other 셋 다에 걸고, 근거는 장 글(binding 과 nodeTextMap, 표는 칸 단위) 가운데 L1 문서에만 있는 글과 고른 L2 칸에만 있는 글의 수로 센다(제목, 두 문서 공통 글은 뺌). L1 쪽이 많고 근거가 두 줄 이상이거나 10자 이상 문장 한 줄이면 L1, 같은 항목의 다른 쪽이 L1 이면 그 쪽도 L1. 짧은 줄 하나뿐, 동점, 근거 없음은 고르지 않고 표시만 한다. 판별 기준은 76-d2-v7-row-level.md, 비교용 v6 동작은 VS_EVAL_ROW_LEVEL_V6=1. 질문, 답 종류, 매칭 규칙은 그대로다. 2,000 운영 결함 8,040(2.66%) → 7,510(2.49%).'
- 'v8 (2026-10-27): 유저 v7 규칙 검수(20 단위, 결함 쪽 10 가운데 「규칙이 틀림」 5, 다섯 다 규칙 답 absent)를 반영해 「질의 글이 결과 어디에든 있으면 absent 가 아니다」를 더 정확히 재도록 고쳤다. 예외 조항은 없다. (a) 행 수준 물려받기: 같은 항목의 L2 칸 번호 밖 쪽(plain)도 L1 근거로 쓴다(2 단위). (b) 같은 몫 쪽 묶기: 같은 항목의 쪽들이 같은 L2 컴포넌트 하나를 골랐으면 그 몫을 나눠 담은 쪽으로 묶는다(검수 밖, 남은 결함 표본에서 찾음). (c) 「이름: 값」 줄의 값 · 이름 조각(1 단위). (d) 마크다운 표의 칸 글(1 단위). (e) 「이름: 값」 질의 글을 표의 행(항목 label) · 열(이름) 칸 값으로 찾음, 값 뒤 괄호 덧말은 떼고 견줌(1 단위). (a)(b) 는 rules/_util.py · sources.py 를 함께 쓰는 D3, D6, R5 의 단위 열거와 쪽 묶기도 바꾼다. 비교용 v7 동작은 VS_EVAL_D2_V7=1. 2,000 운영 결함 7,510(2.49%) → 6,498(2.15%), D3 2,329 → 2,302(77 문서).'
- 'v9 (2026-10-27): 장의 판(L1 문서 · L2 칸)을 binding 점수로 추정하지 않고 사이드카(page_yaml, page_record)의 method · levels 로 정한다(81 문서). method l2 면 L2 의 그 칸(칸 번호 = L2 컴포넌트 순번), 그 밖(single · list · table · unknown, levels L1)이면 L1 문서. 쪽 묶기(is_threaded)도 같은 정보로: 사이드카 l2 는 한 장 = 한 칸이라 묶지 않고, L1 나눠 담기는 같은 항목의 모든 쪽을 묶는다. 사이드카가 없는 장만 v8 추정으로 떨어진다. 매칭 규칙 · 질문 · 답 종류는 그대로다. 비교용 v8 동작은 VS_EVAL_D2_V8=1. 2,000 운영 결함 6,498(2.15%) → 6,509(2.15%): L2 칸을 L1 으로 읽던 장 −55, L1 리스트 나눠 담기를 L2 칸으로 읽던 장 −77, L1 표 나눠 담기(공존 장 대부분) +143. D3 2,302 → 2,046, D6 변화 없음.'
- 'v10 (2026-10-27): 유저 D2 v9 검수(20 단위, 규칙이 틀림 2)를 반영해 「이름: 값」 일치(kv)를 줄 전체뿐 아니라 쉼표 · 가운뎃점 · 쌍반점으로 나눈 조각마다도 본다(빗금은 날짜를 깨므로 구분자가 아니다). 넘친 항목을 쉼표로 잇고 끝에 「period: 9월」 을 단 줄은 이름 부분이 40자를 넘어 v9 에서 absent 였다. 예외 조항이 아니라 글이 실제로 있는지를 더 정확히 보는 수정이다. 비교용 v9 일치는 VS_EVAL_D2_V9=1. 2,000 운영 결함 6,509 → 6,505(질의 1개, 4 단위 absent → merged). 판 고르기(v9)와 D3 · D6 은 그대로다.'
