← 미리디 기술 사전 / Visual Summary

ALGORITHM CLASS2026-09-13 로컬 코드 대조

comp-frame 알고리즘
fallback 흐름과 의문점

글을 담을 디자인을 찾는 과정부터
“왜 이 반복과 종료 조건이 이상할까?”에 답하기까지.

iui 5d807e2dwiki 013fff13Frame v3핵심 회귀 470개 · 재현 9개
§0

수업 지도: 세 종류의 fallback을 구분하자

comp-frame은 “내 글을 이미 있는 디자인의 어느 칸에 넣을까?”를 계산합니다. 예를 들어 세 단계의 설명을 담으려면, 세 장의 카드가 있고 각 카드에 제목과 본문을 넣을 수 있는 디자인이 필요합니다. 코드는 먼저 칸 배정을 연습하고, 사용할 수 있는 후보를 추린 뒤 순위를 매깁니다.

① 입력 읽기YAML/JSON → 규약 검사
② 표현 정하기중첩 N 단계 → 카테고리 Tier
③ 후보 찾기Query Frame → Stage 0·1·2
④ 대치 연습글 배정 → 탈락 검사 → 벌점
⑤ 결과 만들기순위·중복 제거 → binding
⑥ 화면 확인실제 디자인 로딩·대치·렌더
이름무엇을 바꾸나짧은 비유
Tier 1·2·3컴포넌트의 카테고리. 각 Tier 안에 후보 종류가 있다.계단 그림이 없으면 목록 디자인도 찾는다.
Stage 0·1·2같은 카테고리 안의 슬롯 역할 차이.제목+본문에 수치 칸까지 있는 디자인도 살핀다.
N1~N5입력의 중첩 컴포넌트 구조와 각 노드의 카테고리.큰 상자 안 작은 상자들을 유지할지, 꺼낼지, 글로 풀지 정한다.

이번 수업에서 도달할 목표

“반복이 이상하다”에서 끝내지 않고 ① 무엇을 반복하고 ② 어떤 값이 변하며 ③ 어디서 멈추고 ④ 어떤 후보를 놓치는지를 설명해 봅시다. 해결된 문제, 재현된 결함, 의도된 절충을 구분합니다.

§1

입력과 출력: 글을 칸에 넣는 문제

입력은 VisualSummary 문서입니다. title은 문서 제목, components는 디자인으로 표현할 내용 덩어리들의 목록입니다. 화면은 YAML과 JSON을 받으며 단일 Component도 문서로 감싸서 처리합니다. 전체 문서는 version과 올바른 결합 type 등 규약 검사를 통과해야 합니다.

version: "0.5"
title: "주문 진행 과정"
components:
  - type: "ProcessFlow.Steps"
    structure:
      entities:
        - label: "견적 제출"
          items: ["수량과 납기를 적습니다."]
        - label: "주문 확인"
          items: ["금액과 일정을 확인합니다."]
        - label: "제작 시작"
          items: ["확인된 주문을 제작합니다."]

여기에는 컴포넌트 1개, 항목 3개, 항목마다 제목 1개와 본문 1개가 있습니다. 컴포넌트 3개가 아니라, 하나의 컴포넌트 안에 카드 3개가 필요한 것입니다.

출력뜻예
FrameSearchResult[]후보별 디자인 주소와 평가 결과do_id, node_id, tier, cost
binding어떤 시트 노드에 어떤 글을 넣는지sheet_id: title-1 → “견적 제출”
blank / preserve입력 글이 배정되지 않은 슬롯의 처리 분류비울 대상으로 분류 / 원문 보존
projection / matched_category어떤 카테고리·변환으로 이 결과를 얻었는지Steps → List, P1·P2
meta조회와 탈락을 추적할 수치조회 행 수, 용량·내용 배제, 오류

검색 결과는 아직 완성된 그림이 아닙니다. 화면이 이 결과를 받아 원본 디자인을 로딩하고 binding의 글을 넣어 썸네일을 만듭니다. 그래서 “검색 통과”와 “실제 이미지에서 읽기 좋음”은 별도로 확인해야 합니다.

L1·L2·L3와 문서 중복 제거

L1은 단일 컴포넌트, L2는 최상위 컴포넌트 여럿의 병치, L3는 entity.components[] 안에 다른 컴포넌트가 있는 중첩입니다. 프리셋의 여러 레벨이 정규화 후 같은 문서이면 검색은 한 번만 하고 L2·L3처럼 배지를 합칩니다. 직접 입력은 별도 레벨 하나로 취급합니다.

최상위 컴포넌트끼리는 독립적으로 검색하며 기본 동시 실행 수는 2입니다. 현재 flattenComponents는 보기·주소 추적에도 쓰이지만, 실제 L3 검색은 먼저 searchNestedComponent를 거칩니다. 처음부터 모든 자식을 독립 검색한다는 옛 설명은 현재 실행 경로와 다릅니다.

코드 근거 · 입력 파싱 · 문서별 검색 · 결과 구조

§2

Frame: 내용과 디자인이 만나는 공통 표

Frame은 “칸을 기록한 표”라고 생각하면 됩니다. 입력 쪽은 각 칸에 넣을 글을 적고, 디자인 쪽은 그 글을 받을 실제 노드 주소와 용량을 적습니다. 같은 모양의 표를 쓰기 때문에 서로 비교할 수 있습니다.

단위입력 쪽디자인 쪽
Frame컴포넌트 전체의 요구디자인 전체 또는 선택된 경계 하나
Unit항목 하나: 견적 제출반복 카드 하나
Slot제목·수치·본문에 들어갈 글실제 Text 노드, 용량, 별칭
NodeRef보통 없음rlscId: 구조 주소, sheetId: 실제 시트 주소
Cap글 길이로 수요 계산charsPerLine, lines, chars
satellites페이지 제목항목 바깥 제목·부제·설명 슬롯
dataset표를 채울 문자열 등표·차트의 grid 노드
nested / isForest중첩 경계와 묶음 요구대응하는 중첩 경계의 Frame
params / relations / decoration방향·관계·장식 선호후보가 가진 속성·관계·장식

입력 Frame은 그때 만들고, 디자인 Frame은 미리 만들어 둡니다

buildQueryFrames는 검색할 때 입력을 복제하고 관계 ID를 해석한 뒤 카테고리별 Frame을 만듭니다. 관계가 존재하지 않는 항목을 가리키면 실패를 돌려줍니다. buildIisFrame은 I.I.S.가 인식한 항목·필드를 실제 RLSC 노드에 연결하고, 적절한 I.I.S. 구조가 없으면 로더가 buildRuleFrame으로 반복 모양을 추정합니다.

디자인 Frame을 만들 때의 보정

I.I.S.가 반복 항목을 빠뜨렸고 규칙 검출과 모순되지 않으면 누락 항목을 보완합니다. 서로 충돌하면 억지로 합치지 않고 unitMismatch로 기록합니다. 위성 제목은 반복 항목 밖의 헤더에서 찾습니다. 그림 같은 비텍스트 말단은 텍스트 슬롯에서 제외하고, 컨테이너를 가리키면 하위 Text로 펼칩니다. 표 셀의 글은 표 전체 대치와 중복해서 배정하지 않습니다.

최신 기준은 Frame 버전 3

버전 2에서 중첩·장식 정보가 추가됐고, 현재 FRAME_VERSION = 3에는 슬롯의 aliases가 있습니다. 예를 들어 같은 물리적 칸을 한 카테고리는 value, 다른 카테고리는 emphasis라고 부를 수 있습니다. 한 노드에 두 번 대치하지 않도록 대표 슬롯 하나와 별칭을 저장합니다. 별칭은 단수 필드끼리만 허용하고 items/values에는 붙이지 않습니다.

DB 테이블 이름 comp_frames와 Frame 직렬화 버전 3은 서로 다른 이름입니다. 코드가 3이라고 기존 DB 행까지 모두 3으로 갱신됐다고 단정할 수는 없습니다.

코드 근거 · Frame 버전·타입 · I.I.S. Frame · 규칙 Frame · 별칭과 중복 노드

§3

Tier와 투영: 어떤 종류를 찾아볼까

단계 설명을 Steps로 표현하고 싶어도, 공급된 디자인 중 적당한 Steps가 없을 수 있습니다. 이때 규약이 허용하는 다른 카테고리를 차례로 찾습니다. 카테고리가 내용을 받아들일 수 있는지는 establish, 실제 디자인에 글이 들어가는지는 나중의 배정·용량 검사가 판단합니다.

Tier카테고리 선택주의
1요청한 type. 성립 조건을 통과한 것.화면 규약은 결합 type을 요구한다. alternatives는 검색에서 사용하지 않는다.
2원래 요청 카테고리의 fallback 행을 왼쪽부터. 각각 투영 후 성립 검사.A→B→C라고 표시해도 C는 원본 A에서 변환한다. B의 fallback 행으로 갈아타지 않는다.
3항목 수·문장 수로 정한 종단 하나. 앞 Tier와 중복이면 생략.List / LongFormTextLayout / HighlightedMessage를 전부 조회하는 것이 아니다.

예를 들어 Steps의 행은 Timeline → Staircase → List입니다. 입력이 17항목이면 상한 15인 Timeline과 상한 8인 Staircase는 성립하지 않아 건너뜁니다. List가 이미 Tier 2에 들어갔다면 Tier 3에서 또 넣지 않습니다.

Tier 3는 어떻게 하나를 고르나

terminalCategory는 measure를 텍스트 항목으로 구체화한 뒤 개수를 셉니다. 항목이 1개가 아니면 List, 1개이고 본문이 여러 문장이면 LongFormTextLayout, 그 외에는 HighlightedMessage를 고릅니다. 그 다음 buildTiersFor가 성립 여부를 별도로 확인합니다. 빈 입력에 결과를 만들어 준다는 뜻은 아닙니다. 문장 구분에는 줄바꿈·문장부호를 사용하며 이 구체적 구분법은 구현 선택입니다.

투영 P1~P7은 “다른 종류에서도 읽히게 내용의 자리를 바꾸기”입니다

규칙쉬운 설명
P1도착 카테고리가 읽는 공통 내용을 유지한다.
P2도착지가 사용하지 않는 표현 옵션 params는 제거한다.
P3도착지가 못 읽는 내용 필드는 items로 옮긴다. 지원하지 않는 자식 항목도 글로 푼다.
P4표의 각 행을 항목으로 바꾼다. 첫 열 값은 label, 나머지 열은 “열 제목: 값·단위”로 옮긴다.
P5measure를 못 읽는 곳에서는 숫자·단위를 텍스트 항목으로 옮긴다.
P6항목을 표의 행으로 만든다. 앞서 옮긴 본문도 표 안에 포함한다.
P7도착지가 표현하지 못하는 관계의 desc를 첫 참가자 본문으로 옮긴다.

P8 폐기와 “접기”를 혼동하지 않기

최상위 항목을 상한에 맞게 합치는 P8은 폐기됐습니다. 17항목을 15항목으로 합쳐 Timeline을 성립시키지 않습니다. 디자인의 최상위 Unit 수도 입력 이상이어야 합니다. 반면 한 항목의 문장을 마지막 본문 칸에 합치거나, 자식 내용을 본문으로 푸는 처리는 남아 있습니다. 이 중 배정 단계의 자식 접기에 남은 손실은 문제 F05에서 다룹니다.

현재 보정은 summary-projection.ts와 summary-content.ts에서 하며 벤더 eregion 코드는 그대로 둡니다. 현재 관계 변환은 desc만 남깁니다. “관계 종류·참가자도 함께 남긴다”는 일부 과거 문서와 주석은 최신 relationLines 본문과 다릅니다. 표 첫 열의 제목도 P4 텍스트 변환에는 남지 않습니다. 따라서 투영은 모든 의미를 무손실 보장하는 변환이 아닙니다.

기존 규약 문구의 충돌도 남겨 둡니다

고정 wiki의 schema-v0.5.md 678행에는 Gauge→HighlightedMessage에서 P8로 접는다는 옛 예시가 남아 있습니다. 그러나 명시적인 P8 폐기 결정과 현재 구현은 상한 초과 후보를 접어 성립시키지 않습니다. 입력의 카테고리 성립 상한과, 이미 존재하는 디자인을 인식하는 범위도 구분해야 합니다.

코드 근거 · 남은 P8 문장 · 입력 상한과 디자인 인식

코드 근거 · Tier 생성 · 종단 선택 · 자체 투영 보정 · 표 변환 · 관계 desc · 정본 P1~P7·P8 폐기

§4

Stage와 사전 필터: 어떤 칸이 있는가

카테고리를 정했으면 후보 DB에서 대략 맞는 디자인을 가져옵니다. 모든 디자인을 렌더해 볼 수 없으므로, 먼저 값싼 조건으로 줄입니다. 이 필터를 통과한 후보만 정밀한 대치 검사를 받습니다.

조건현재 확인하는 것
카테고리행의 카테고리에 지금 찾는 종류가 포함되는가. 뿌리 없는 forest 검색은 바깥 카테고리를 비워 둔다.
중첩 카테고리nested_categories에 요구 종류가 있는가. 정확한 경계 짝은 이후 pairNested로 다시 확인한다.
모양 비트역할의 유무가 Stage의 허용 범위에 들어오는가.
최상위 Unit 수후보의 수 ≥ 입력의 수. 일반 질의는 최소 1, matrix·forest는 0도 가능.
dataset 종류Query Frame과 후보 Frame의 종류가 같은가. 현재 measure 입력은 텍스트 Unit으로 구체화되어 일반적으로 none 질의가 된다. matrix는 grid 경로로 간다.
label 용량항목 제목의 줄 수·가장 긴 줄 길이로 만든 최소 기준. 본문·수치는 배정 후 검사한다.
GC 통과 옵션외부 검사 통과 행으로만 좁힌다. 기본은 꺼짐. 이번 입력에 대한 대치 통과 판정과는 다르다.
Stage 0

정확히 0비트 차이
제목 + 본문

Stage 1

정확히 1비트 차이
제목 + 본문 + 수치

Stage 2

정확히 2비트 차이
제목 + 본문 + 수치 + 기간

비트는 스위치처럼 “그 역할이 어딘가에 있음/없음”만 기록합니다. 카드마다 칸 수나 위치·크기가 같은지는 모릅니다. 역할이 추가된 경우뿐 아니라 빠진 경우도 비트 차이에 포함됩니다. 한 카테고리에서 Stage 0·1·2는 서로 겹치지 않습니다.

20개 비트와 제목 사전 필터 수식

내용 필드 13개, children, 위성 제목·부제·설명이 0~16번입니다. 이 17개 비트만 완화합니다. dataset 비트 17~18과 추가 grid 비트 19는 완화하지 않습니다. marker는 비트 비교에서 빠집니다.

m = overflow_multiplier (기본 1)
label_lines ≥ ceil(제목들의 최대 명시적 줄 수 / m)
label_cpl ≥ ceil(제목들의 최대 한 줄 길이 / m / 2)

조회 용량이 NULL이면 제외하고 0이면 미상으로 통과합니다. 이 “절반” 기준은 필요한 조건을 완벽하게 나타내지 못합니다. 20자는 8자×3줄에 들어가지만 cpl≥10을 요구해 빠집니다. F04의 재현 결과를 보세요.

코드 근거 · label 하한 · Stage 분리 · 필터 구성 · 허용 비트 · measure·matrix Frame

§5

후보 수집 loop: 무엇을 세고 언제 멈추나

searchFrames 안에는 Tier → 카테고리 → Stage → 페이지 순서로 반복이 겹쳐 있습니다. “반복문이 있다”는 사실보다, 각 반복이 어떤 일을 하고 무엇을 세는지가 중요합니다.

Tier 1 → 2 → 3
그 Tier의 카테고리를 왼쪽부터
Stage 0 → 1 → 2
현재 조건의 다음 페이지

가져오기 → Query Frame 연결 → 배정·검사 → 통과한 행의 주소를 Set에 추가

값기본/정의어디에 쓰나
min_candidates500검색 전체의 통과 행 목표. 보장된 반환 개수가 아니다.
tier_targets[50, 50]Tier 처리가 끝난 뒤 누적 통과 수가 문턱 이상이면 하위 Tier를 생략한다.
top_n50최종 순위·Frame 중복 제거 후 반환 상한.
admittedCount통과한 do_id|node_id의 수반복의 중단 판단. Frame fingerprint 중복은 아직 포함한다.
scannedForCategory현재 카테고리에서 읽은 행 수실패가 계속돼도 조회량이 끝없이 늘지 않게 제한한다.
CATEGORY_SCAN_MULTIPLIER4카테고리의 배정량 ×4까지만 훑는다. 실제 공급 수보다 많이 읽지는 않는다.
FETCH_PAGE_SIZE1,000한 번에 요청할 최대 행 수.

한 페이지를 가져올 때 실제로 하는 일

  1. 각 카테고리에서 Stage 0~2의 합집합을 count()로 센다. 이것은 정밀 검사 전 공급 수다.
  2. 카테고리를 순서대로 처리한다. 현재 코드는 균등 배분하지 않는다. Tier 시작 때의 남은 목표로 카테고리 배정량을 정한다.
  3. 페이지 요청량은 min(남은 스캔 예산, 남은 통과 목표, 1000)이다. 가져온 만큼 offset과 스캔 수를 증가시킨다.
  4. 행 주소로 중복을 제거하고 그 행을 통과시킨 QueryFrame을 matchedQueries에 기록한다. 한 행이 여러 카테고리에 있어도, 실제로 통과한 질의로 채점한다.
  5. 그 페이지의 아직 승인되지 않은 행을 rankCandidates(..., dedup:false)로 검사한다. 배정·내용·용량·속성 조건을 통과한 행 주소만 admittedKeys에 넣는다.
  6. 전부 탈락했다면 다음 페이지 또는 Stage·카테고리·Tier로 계속 간다. 마지막에는 모은 전체 행을 다시 평가하고 정렬·fingerprint 중복 제거·top_n 절단을 한다.
조건어디서 나가나의미
누적 통과 수 ≥ min_candidates다음 Stage·카테고리·Tier를 멈춤목표만큼 승인했다.
카테고리 스캔 수 ≥ scanBudget그 카테고리의 Stage 반복 종료이 카테고리에 쓸 조회량을 다 썼다.
페이지가 요청보다 적게 옴현재 Stage의 페이지 반복만 종료그 조건의 공급이 끝났다. 다음 Stage는 볼 수 있다.
Tier 처리 후 누적 통과 수 ≥ 해당 문턱Tier 반복 전체 종료최대 500 목표를 못 채워도 충분하다고 판단한다.
모든 Tier·카테고리·Stage 소진최종 평가로 이동0개도 정상 결과일 수 있다.

옛 “미보충” 문제는 해결됐습니다

과거에는 Tier 1에서 50행을 읽었다는 이유로 중단하고, 나중에 전부 탈락해도 Tier 2를 보지 않았습니다. 현재는 그 50행이 모두 탈락하면 통과 수가 0이므로 계속 찾습니다. 다만 스캔 상한, fingerprint 중복 제거, 화면 사후 필터 때문에 결과가 부족해지는 다른 경로는 남아 있습니다.

작은 사례를 한 단계씩 따라가기

분기 이해용 고정 시나리오입니다. F01~F03은 현재 검색 함수를 직접 호출한 재현과 대응합니다. 실제 DB 요청을 실행하지 않습니다.

코드 근거 · 반복 진입·count · 카테고리·Stage·페이지 · 승인 수 갱신 · Tier 문턱 · 최종 재평가

§6

N1~N5: 중첩 구조의 fallback 수업

큰 Steps 상자 안에 작은 BigNumber 카드가 있다고 합시다. 처음부터 두 개를 따로 찾으면 “수치가 어느 단계에 속하는지”라는 배치 정보가 사라질 수 있습니다. 그래서 현재는 전체 중첩을 지킬 수 있는지부터 확인합니다.

단계실제 동작다음으로 넘어가는 조건
N1
구조·종류 그대로
전체 트리 또는 형제 forest를 그대로 검색. exactType:true로 카테고리 Tier 1만 사용.반환 후보가 0개일 때 N2.
N2
구조 고정, 종류 변경
노드마다 원래 fallback 행의 변형을 만든다. 성립하고 중첩 topology를 유지하는 조합만 시도.첫 성공 조합에서 반환. 전부 실패한 뒤에만 부모 벗기기.
N3
부모 한 층 벗기기
부모의 내용을 첫 승격 자식에 옮기고, 연속 형제를 큰 묶음부터 검색. 묶음마다 N1/N2를 다시 시도.선택한 분할의 모든 조각에 후보가 있어야 성공.
N4
다시 벗기기
단일 조각이 아직 중첩이면 같은 절차를 재귀로 반복.성공한 조각 반환 또는 그 조각의 N5.
N5
내용 평탄화
항목·하위 내용을 들여쓴 글로 만들고 종단 카테고리로 검색.검색 결과를 그대로 반환. 0개도 가능.

여기서 exactType은 “Stage도 0만”이라는 뜻이 아닙니다. 카테고리 Tier만 1로 제한하며, 같은 카테고리 안의 Stage 0·1·2와 용량·내용 검사는 여전히 실행됩니다. 또한 N 단계는 트리 전체가 한 번에 N1→N2→N3→N4→N5로 한 줄 이동하는 모습만 있는 것이 아닙니다. 벗겨진 한 조각이 다시 N1/N2로 성공하거나, 다른 조각보다 먼저 N5에 도달할 수 있습니다.

N2의 조합 순서를 손으로 써 보기

부모와 자식에 원형 0, 첫 대안 1, 둘째 대안 2가 있다고 합시다. N1은 (0,0)입니다. N2는 강등 칸수의 합이 작은 순서이며, 동점에서는 더 깊은 노드를 먼저 내립니다.

(부모 0, 자식 1)(1, 0)(0, 2)(1, 1)(2, 0)…

중간 카테고리가 성립하지 않아 빠져도 원래 행에서의 칸 거리는 유지합니다. 각 조합의 투영은 원본 노드에서 출발합니다. 바뀐 카테고리의 fallback을 다시 따라가며 무한히 돌아가는 방식이 아닙니다.

왜 유한한 반복도 오래 걸릴까?

624

모든 노드의 선택지 수가 같다고 가정한 설명용 상한: mⁿ−1. 실제로는 노드별 선택지 수의 곱−1이며 성립·topology 검사와 조기 성공으로 줄어듭니다. N3/N4에서 다시 시도하는 묶음은 이 수에 포함하지 않았습니다.

부모를 벗길 때도 규칙이 있습니다

종료·캐시·취소를 정확히 설명하기

semanticVariants는 모든 조합을 메모리에 쌓지 않고 하나씩 생성합니다. 총 강등 합은 유한한 suffixMax까지 증가하고, 조합 재귀의 position도 증가하므로 유한한 입력에서 끝납니다. N3/N4는 부모를 벗겨 중첩 깊이가 줄고, 형제 분할 재귀는 남은 형제 수가 줄어듭니다. N5는 검색 결과를 돌려주고 끝납니다.

이는 각 검색 요청이 결국 응답하거나 취소된다는 전제의 종료 설명입니다. 응답하지 않는 외부 요청까지 이 함수가 해결하지는 않습니다. N2에는 현재 216회·전체 600회 같은 횟수 제한이 없습니다. 16ms마다 이벤트 루프에 제어권을 돌려 취소 클릭을 처리할 수 있게 하지만, 탐색량을 줄이는 장치는 아닙니다.

attempt는 동일 forest와 exactType의 일반 시도를 캐시합니다. N2의 개별 변형은 조합 수만큼 메모리를 먹지 않도록 캐시하지 않습니다. 대신 preservedCache가 원래 형제 묶음의 N1/N2 전체 검색 결과를 재사용합니다. 캐시는 최상위 컴포넌트 검색 한 번의 범위입니다.

“N5는 성립한다”와 “DB에 후보가 있다”는 별개

평탄화한 내용을 표현할 카테고리를 정할 수 있어도, 필요한 칸·용량을 가진 실제 디자인이 없으면 결과는 비어 있습니다. 최신 코드의 조건은 results.length > 0입니다. 규약의 “빈 결과가 나오지 않는다”는 문장을 실제 공급 보장으로 읽으면 디버깅을 잘못하게 됩니다.

코드 근거 · N2 선택지 · 조합 생성 · 부모 내용 이전 · N1/N2·첫 성공 · N3~N5 재귀 · exactType의 Tier 제한 · N 단계 규약

§7

대치 예행연습과 용량 검사

align은 첫 항목을 첫 카드에, 둘째 항목을 둘째 카드에 배정합니다. 모든 배치 조합을 탐색해 최적의 자리를 찾는 함수는 아닙니다. 같은 이름 → 별칭 → 다른 텍스트 칸으로 이동 순서로 글을 넣고, 그 결과를 costOf가 검사합니다.

상황현재 동작
같은 역할이 있음직접 배정한다. one은 단일 칸, many는 문서 순서의 여러 칸이다.
같은 이름은 없고 별칭이 있음이미 채워지지 않은 단수 슬롯의 aliases를 찾는다. 성공한 필드를 기록해 뒤의 이동 단계가 또 넣지 않게 한다. marker는 별칭 받는 칸에서 제외한다.
전용 필드가 없음본문 items로 옮기거나 label, 그 밖의 단수 텍스트 슬롯을 사용한다. 역할이 바뀐 이동을 기록한다.
본문·값 목록이 슬롯보다 많음초과 내용을 마지막 칸에 줄바꿈 등으로 이어 붙인다. 합친 뒤 길이로 용량을 검사한다.
디자인에 최상위 카드가 더 많음초과 카드를 blank로 분류한다. 입력보다 카드가 적으면 앞 필터·rank에서 배제한다.
Unit.children 칸이 부족함초과 자식을 부모 본문으로 접는다. 이 경로는 P3/N5와 다른 함수이며, 필드 누락이 남아 있다.
옮길 텍스트 슬롯이 전혀 없음droppedTexts와 contentLoss에 기록한다. 현재 rank는 contentLoss>0 후보를 배제한다.
번호 칸이 있음순서형 카테고리의 marker에 01, 02…를 넣는다.
입력 없는 칸이 남음원문 지도와 짧은 토큰 보존 규칙에 해당하면 preserve, 나머지는 blank. 위성 제목·부제·설명은 별도 규칙이다.

제목 슬롯이 있으면 페이지 제목을 넣습니다. 제목 입력이 없으면 원래 제목을 보존하고, 부제·설명 위성은 보존합니다. 제목을 받을 슬롯이 없으면 titleDropped 벌점 1이며 contentLoss와는 다른 판정입니다. 화면의 경계 밖 제목 구제는 다음 절에서 따로 설명합니다.

용량은 “합친 글이 몇 줄인가?”로 검사합니다

한 줄 20자 · 최대 3줄 · 총 60자

·

줄바꿈 없는 73자는 한 줄 20자 기준으로 4줄입니다. 1.0배이면 4>3 또는 73>60이므로 탈락합니다. 1.5배에서는 4≤4.5이고 73≤90이므로 통과하며 용량 벌점 약 5.01점을 받습니다. 허용 배수는 검사 기준이며 실제 폰트 크기를 바꾸지 않습니다.

수식과 검사의 한계
예상 줄 수 = 명시적 각 줄에 대해 max(1, ceil(UTF-16 길이 / 한 줄 용량))의 합
탈락 = 예상 줄 수 > cap.lines × m  또는  글자 수 > cap.chars × m
줄 벌점 = 4 × Σ sqrt(max(0, 예상 줄 수 − cap.lines))
글자 벌점 = 2 × Σ clamp((글자 수 / cap.chars − 1) / 0.43, 0, 1)

기본 1.0배에서 정상 용량을 가진 통과 후보는 넘침 벌점이 0입니다. 완화했을 때 넘치는 후보끼리 순위를 나누는 데 이 벌점이 쓰입니다. 길이는 UTF-16 단위이므로 이모지·실제 글꼴 폭·실제 줄바꿈을 완벽히 재현하지 않습니다.

용량이 없거나 charsPerLine·lines·chars 중 하나라도 0 이하이면 하드 용량 검사를 건너뜁니다. capUnknown 벌점은 완전히 같은 조건이 아니라 cap 자체가 없거나 charsPerLine≤0인 경우를 셉니다. 표·차트 grid는 텍스트 용량 모델에서 제외합니다. 실제 겹침·잘림·표 셀 가독성은 이 검사에 포함되지 않습니다.

코드 근거 · 항목 배정 · 별칭 단계 · 위성 처리 · 내용 손실 배제 · 용량 게이트

§8

벌점 21개와 순위 계산

벌점은 발생량 × 가중치를 더한 값이며 낮을수록 좋습니다. 빈 카드 1개가 10점, 다른 역할로 옮긴 필드 2건이 6점이면 두 항목의 합은 16점입니다. 그렇다고 최종 순위가 항상 총점 하나로 결정되지는 않습니다.

현재 항목기본 가중치무엇을 세나
빈 항목 unitBlank15비운 최상위·자식 Unit 수.
자리 이동 fieldMove3다른 역할로 옮긴 필드 건수. 별칭으로 직접 배정된 것은 이동으로 세지 않는다.
본문·값 초과 itemOverflow2many 목록의 준비된 칸 수를 넘은 항목 수.
빈 본문·값 칸 itemBlank15many 목록에 남은 칸 수.
줄 넘침 capOverflow4각 칸의 초과 줄 수 제곱근을 합산. 1줄 초과 4점, 4줄 초과 8점.
글자 넘침 capChars2용량 100%까지 0, 100~143% 비례 증가, 143% 이상 칸당 2점.
용량 미상 capUnknown2cap이 없거나 charsPerLine≤0인 배정 텍스트 칸 수. grid 제외.
관계 누락 relationGap3후보에 없는 관계 유형을 요구한 관계 수. 연결 대상·전체 연결 모양의 동일성을 증명하지 않는다.
옵션 충돌 paramConflict5정책 처리 후 남은 속성 충돌 수. 후보에 속성 자체가 없으면 비교 불가로 충돌을 세지 않을 수 있다.
구조 출처 provenance0규칙 Frame 또는 unitMismatch인 I.I.S. Frame이면 원시값 1. 기본 가중치에서는 영향 없음.
제목 탈락 titleDropped1페이지 제목을 위성 슬롯에 넣지 못함. 화면이 나중에 구제해도 검색 비용은 그대로.
추가 표·차트 extraGrids10대표 grid 외 추가 grid 수. 앞의 하드 비트 필터에서 먼저 제외될 수도 있다.
내용 손실 contentLoss10비용 정의는 남아 있지만 일반 rank 결과에서는 contentLoss>0을 배제하므로 가중치가 순위를 바꾸지 않는다. costOf 직접 호출용으로는 유효.
경계 밖 글 outsideText10저장된 경계 밖 Text 노드 수. 실제 대치 후 남은 글의 중요도·면적까지 평가하지 않는다.
경계 안 미배정 글 insideResidue10경계 안에 있으나 Frame 슬롯에 연결되지 않은 Text 노드 수.
Tier 2 tier2Penalty10tier_penalty 모드에서만 추가.
Tier 3 tier3Penalty20tier_penalty 모드에서만 추가.
글꼴 위계 fontHierarchy0최대 글꼴 / 나머지 평균의 비를 이용. 비가 1에 가까울수록 벌점이 크다. 데이터가 없으면 0.
빈 필드 칸 fieldBlank5슬롯은 있는데 채울 글이 없어 비운 필드 수. 121,851 후보 중 3.3%에서만 발화한다.
경계 밖 제목 구제 titleOutsideBonus3유일하게 값이 음수인 항목이다 — 경계 밖에 제목을 넣으면 raw가 −1이라 비용을 깎는다. 그래서 총 비용이 음수가 될 수 있다.
글꼴 축소 예측 fontShrink5렌더 전에 글꼴이 줄어들지를 예측한다. capChars·capOverflow와 별개 항목이고, 재적재 전 옛 Frame은 0이라 비용이 안 바뀐다.
새 글꼴 위계 항목과 기본값 해석

fontHierarchy의 원시값은 π/2 − atan(max(1, 최대/나머지평균) − 1)입니다. 비가 1이면 약 1.57점, 2이면 약 0.79점입니다. 글자 수·내용 보존의 검사가 아니라 원래 디자인의 제목/본문 크기 구분 신호입니다. 주석에서는 tie-breaker라고 부르지만 실제로는 총비용에 더해져 작은 비용 차이를 뒤집을 수도 있습니다.

18개 값은 현재 코드의 기본값입니다. 이 작업은 가중치를 학습하거나 사람의 선호와 비교하지 않았습니다. 예전 문서의 “16개/17개 모두 동일한 튜닝 전 상태”라는 표현 대신, 현재 항목·기본값과 검증 범위를 분리했습니다. comp-sign보다 품질이 좋다는 결론도 이 분석만으로는 낼 수 없습니다.

후보 하나의 순위는 사전식으로 비교합니다

모드먼저 비교하는 키 → 다음 키예
tier_pool 기본Tier → 같은 Tier의 fallback 순서 → 장식 선호 → 비용 → 동점 처리Tier 1이 30점, Tier 2가 0점이어도 Tier 1이 먼저.
tier_penalty장식 선호 → Tier 벌점이 포함된 비용 → 동점 처리장식 선호가 같다면 Tier 1 30점보다 Tier 2 0+10점이 먼저.

장식은 점수를 더하지 않고 preferred → neutral → avoided 순서로 비교합니다. 기본 모드에서는 같은 fallback 위치 안에서 적용합니다. 코드상 tier_penalty에도 장식 비교가 비용보다 먼저 있으므로 “총점만으로 정렬”이라고 설명하면 틀립니다. 장식 축의 순서는 ornament, background이며 중첩도 비교 대상입니다.

동점은 template_idx 내림차순(NULL 마지막) → 디자인 ID 내림차순 → 노드 ID 오름차순입니다. 정렬 후 frame_fingerprint가 같은 결과를 합치고 top_n까지만 반환합니다. fingerprint가 NULL인 행은 이 중복 제거에서 합치지 않습니다.

한 행이 여러 카테고리에 걸렸을 때

현재 rankCandidates는 실제 조회 필터를 통과한 Query Frame들을 Tier 순으로 보고 처음 성공한 해석을 채택합니다. 같은 행의 모든 해석 중 최저 비용을 찾지는 않습니다. 배제되거나 계산 오류가 나면 다음 해석을 계속 보므로, 한 후보의 오류가 검색 전체를 중단시키지는 않습니다.

코드 근거 · 18개 기본값 · 글꼴 위계 · 실제 정렬 순서 · 해석별 시도·첫 성공 · 중복 제거·top_n · 장식 순서

§9

화면에서 실제로 보이는 결과

계산 결과와 그림 사이에는 화면의 처리가 한 번 더 있습니다. 이 층을 빼면 “blank인데 왜 글이 보이지?” 또는 “제목이 보이는데 왜 제목 탈락 벌점이 있지?”라는 질문에 답할 수 없습니다.

검색 결과 분류실제 화면의 대치
bindingsheet_id를 키로 실제 입력 글을 넣는다. sheet_id가 null이면 이 지도에서는 건너뛴다.
blank현재 검토 화면은 완전한 공백 대신 임시 문구로 채운다.
inside_unbound_text역할·길이에 맞는 임시 문구로 채운다.
preserve지도에 쓰지 않아 원래 글을 유지한다. 유닛의 짧은 토큰 보존은 검색 호출의 원문 지도 제공 여부에 영향을 받는다.
outside_text기본적으로 원문 그대로 둔다. 제목 구제 노드 하나만 예외다.
페이지 제목 구제title binding이 없으면 경계 밖 Title 역할을 우선하고, 위쪽·왼쪽·큰 글꼴을 가중 비교해 한 노드를 고른다.

화면의 제목 구제는 같은 썸네일에 제목을 두 번 쓰지 않도록 이미 title binding이 있으면 생략합니다. 구제된 제목을 포함해 검색 점수를 다시 계산하거나 새 용량 게이트를 실행하지는 않습니다. forest Query Frame은 현재 위성 제목을 만들지 않는 경로도 있으므로, 제목이 각 단계에 실제로 남는지는 pageTitle → satellites.title → binding → 화면 지도를 따로 추적해야 합니다.

여러 조각이 나오면 한 페이지 후보 카드로 묶습니다

Steps
12점
+BigNumber
3점
+List
7.5점
=그룹
22.5점

합산 방법을 보여 주는 계산 예시입니다.

조각이 하나면 결과마다 단일 카드를, 둘 이상이면 현재 선택한 후보들의 비용 합을 가진 그룹 카드 하나를 만듭니다. 그룹 Tier는 선택 결과 중 가장 큰 값입니다. 대안 선택을 바꾸면 비용·Tier를 다시 합쳐 목록을 정렬합니다. 가능한 모든 조합의 페이지를 자동 생성하는 것은 아닙니다.

색상·크기·간격의 조화는 이 비용 합에 포함되지 않습니다. 색상 대치와 선택적 재배치는 렌더 쪽 작업이며 이후 검색 점수를 다시 매기지 않습니다. N3/N4 조각을 새로운 한 장의 레이아웃으로 배치해 주는 엔진과, 화면에서 결과들을 그룹 카드로 보여 주는 것은 구분해야 합니다.

페이지 비교와 빈 칸

기본 모드는 그룹/단일 결과의 Tier를 먼저 비교하고, 같은 컴포넌트의 단일 대안 사이에는 fallback 순서·장식을 비교한 다음 비용을 봅니다. 나머지는 비용 → 레벨 → 자체 순위입니다. 이 조건부 비교에 F06의 순환이 남아 있습니다.

빈 슬롯의 비용은 0이며 그룹 Tier 계산에서도 빠집니다. 전부 비면 Tier가 Infinity지만, 일부만 비면 낮은 점수의 불완전 그룹이 위로 올 수 있습니다. 특히 tier_penalty 모드에서는 Tier 자체를 정렬 키로 쓰지 않습니다. 빈 그룹 처리 한계는 F09를 보세요.

코드 근거 · 제목 중복 방지·구제 · 실제 텍스트 지도 · 경계 밖 제목 선택 · forest의 제목 경로 · 단일·그룹 조립 · 통합 순위 · 렌더·재배치

§10

어디가 이상한가: 재현과 반론까지

아래의 “재현됨”은 현재 로컬 코드의 함수를 직접 호출한 작은 사례에서 확인했다는 뜻입니다. 운영 DB에서 얼마나 자주 발생하는지까지 측정한 것은 아닙니다. 각 항목에서 “왜?”와 “반론”을 함께 읽으면, 이상해 보이는 모든 분기를 무조건 삭제하는 실수를 피할 수 있습니다.

항목핵심 질문판정
F01왜 2개를 찾고 1개만 보여 주나?중단 단위와 반환 단위가 다름
F02Tier 2인데 왜 Tier 1 문턱을 쓰나?빈 Tier + 서로 다른 목표에서 재현
F03후보가 없나, 조회를 멈췄나?의도된 예산 상한·누락 가능
F04왜 들어가는 제목이 검색에서 빠지나?사전 필터 반례
F05글이 사라졌는데 왜 손실 0인가?변환 전에 누락된 필드를 검사 못 함
F06왜 정렬 순서가 원을 그리나?쌍에 따라 기준이 달라짐
F07왜 조회 실패 뒤 표현을 바꾸나?오류와 공급 없음의 혼동
F08왜 999점에서 멈추나?규약의 첫 성공 정책
F09왜 빈 조각이 점수를 낮추나?그룹 완성 여부 미반영
F01재현됨 · 후보 수 기준 불일치

“충분히 찾았다”는데 최종 결과는 하나뿐

언제 발생하나
서로 다른 행 A₁·A₂가 같은 fingerprint를 가지고, 하위 Tier에는 다른 Frame B가 있다. 목표/중단 수 2, 반환 상한 2로 검색한다.
현재 결과
A₁·A₂가 승인돼 admittedCount=2에서 멈춘다. 마지막 fingerprint 중복 제거 후 결과 1개. B는 조회하지 않는다. 재현 R01.
왜 이상한가
멈출 때는 “서로 다른 행”을 세고, 보여 줄 때는 “서로 다른 Frame”으로 합친다. 성공의 단위가 앞뒤에서 다르다. 50개의 같은 Frame 행도 같은 문제를 만든다.
반론까지 생각하면
min_candidates가 원래 행 목표라면 코드의 산술 자체는 맞다. 그러나 “사용 가능한 다양한 결과를 충분히 찾는다”는 해석과는 맞지 않는다. 탈락 후 보충이 해결됐다고 이 문제가 같이 사라진 것은 아니다.
개선 방향
승인 행 수와 고유 Frame 수를 분리하고, 최종 반환 목표가 부족할 때 재조회할지 명시한다. dedup:false로 다양성 부족을 숨기는 것은 해결이 아니다.

코드 근거 · 승인 때 dedup:false · 승인 수로 중단 · 나중에 중복 제거

F02재현됨 · 옵션 경계 결함

빈 Tier가 있으면 종료 문턱이 다른 Tier에 붙는다

언제 발생하나
Tier 1이 없고 Tier 2·3만 있으며, tier_targets=[2,5], min_candidates=10이다. Tier 2에서 2개 통과하고 Tier 3에는 추가 후보가 있다.
현재 결과
tierTargetAt(..., tierIdx)가 압축된 배열의 첫 자리 0을 사용한다. 실제 Tier 2에 Tier 1 문턱 2가 붙어 Tier 3를 조회하지 않는다. 재현 R02. Timeline 17항목처럼 성립 실패로 Tier 1이 빠지는 실제 생성 경로도 확인했다.
왜 이상한가
Tier 번호는 2인데 배열 위치는 0이다. 식별 번호와 현재 배열 위치를 같은 값으로 취급했다. 옵션 계약은 Tier 1/2별 문턱인데 실행은 첫째/둘째 남은 Tier별 문턱이다.
반론까지 생각하면
현재 화면은 두 값을 동일하게 전달하므로 기본 [50,50]에서는 차이가 숨는다. 서로 다른 값을 주는 API/직접 호출에서 드러난다. 모든 사용자에게 기본 설정으로 발생한다고 말하면 과장이다.
개선 방향
실제 tier 번호로 문턱을 찾거나 {1: 목표, 2: 목표}로 표현한다. [1,2,3], [2,3], [3]과 서로 다른 문턱을 함께 검증한다.

코드 근거 · 빈 Tier 생략 · tierIdx로 문턱 선택 · 화면은 같은 값 두 개

F03재현됨 · 의도된 조회량 절충

다음 후보가 맞는데 스캔 상한 때문에 “없음”이 된다

언제 발생하나
min_candidates=1. 같은 카테고리에 정렬상 1~4번째는 용량 탈락, 5번째는 충분한 용량의 후보가 있다.
현재 결과
조회량 상한이 1×4=4라 4행만 훑고 결과 0. 다섯 번째 후보만 공급하면 정상 통과한다. 재현 R03. 기본 목표 500이면 공급이 충분한 카테고리의 상한은 최대 2,000행이다.
왜 이상한가
“이 카테고리에 쓸 만한 것이 없다”와 “배정된 조회량 안에서 못 찾았다”는 다른 사실이다. 바깥 N2가 이 둘을 구분하지 않으면 실제 적합 후보가 있어도 구조 변경 단계로 내려갈 수 있다.
반론까지 생각하면
상한은 실패 후보를 끝없이 훑어 UI가 느려지는 것을 막는 실제 목적이 있다. 무조건 제거하면 문제가 커진다. 다만 N2 전수 탐색과 결합해도 카테고리 내 공급을 전부 검사했다는 보장은 없다.
개선 방향
exhausted / scan_budget_exhausted / target_reached를 구분해 반환한다. 사용자가 더 찾거나, 남은 공급을 재개할 수 있도록 한다. 상한을 유지할지 확대할지는 재현율과 시간으로 판단한다.

코드 근거 · 스캔 상한 의도 · 상한·remaining · 후보 0이면 다음 표현

F04재현됨 · 사전 필터 누락

충분히 들어가는 제목을 검색 전에 잘라낸다

언제 발생하나
줄바꿈 없는 20자 label, 디자인은 한 줄 8자·3줄·총 24자, 허용 배수 1.
현재 결과
사전 필터는 cpl≥10을 요구해 제외한다. 하지만 실제 배정·채점에 직접 넣으면 3줄·20자로 용량을 통과한다. 재현 R04.
왜 이상한가
사전 필터는 빠른 검사이므로 뒤 검사에서 통과할 가능성이 있는 것을 보수적으로 남겨야 한다. 최대 한 줄 길이를 2로 나누는 규칙은 3줄 이상 수용 가능한 칸을 놓친다.
반론까지 생각하면
이 조건은 “확실히 못 들어가는 것만 제거”하려는 휴리스틱이었지만 항상 그런 성질을 가지지는 않는다. 실제 실패 빈도는 공급 DB 분포를 측정해야 알 수 있다.
개선 방향
행별 줄 수·총 용량을 고려한 필요조건으로 바꾸거나, 해당 cpl 하한을 완화하고 정밀 검사로 넘긴다. 어떤 수정이든 용량 통과 후보가 prefilter에 막히는 반례를 검사한다.

코드 근거 · 절반 cpl 하한 · 실제 용량 조건

F05재현됨 · 내용 누락

자식 내용이 사라졌는데 contentLoss는 0이다

언제 발생하나
ResumeCV 입력의 Unit.children에 label=자식, period=2099년, items=설명이 있고, 후보에는 자식 슬롯 없이 부모 label·items 슬롯만 있다.
현재 결과
초과 자식을 unitLikeForFold → foldText로 접는다. 이 보조 함수는 label·value·items만 꺼내 period가 최종 binding에서 사라지는데 contentLoss=0이며 searchFrames도 후보를 통과시킨다. 재현 R05.
왜 이상한가
contentLoss는 “넣으려다가 자리를 못 찾은 문자열”만 센다. 변환이 애초에 꺼내지 않은 필드는 검사 대상에 들어오지 않는다. 검사할 자료에서 먼저 지워진 손실은 검사기가 찾을 수 없다. 코드상 values·다른 단수 필드와 더 깊은 자식도 이 helper의 시야 밖이다.
반론까지 생각하면
P3/N5의 entityLines는 필드를 더 넓게 보존하도록 고쳐졌지만, 이곳은 별도의 alignment 내부 접기다. “projection을 고쳤으니 모든 접기가 안전하다”는 주장은 성립하지 않는다. 새로운 생성기가 안 쓰는 필드라도 기존 입력·직접 호출 경로는 남는다.
개선 방향
원본 필드별 기대값을 최종 binding과 대조하고, 자식 접기에도 공통 재귀 텍스트 변환 또는 동등한 전 필드 순회를 적용한다. contentLoss 가중치를 높이는 것만으로는 0인 손실을 잡을 수 없다.

코드 근거 · 세 필드만 읽는 helper · 초과 children 접기 · contentLoss 집계 · 0이면 배제 안 됨

F06재현됨 · 순위 일관성 결함

통합 정렬 기준이 원을 그린다

언제 발생하나
같은 컴포넌트의 A₀는 fallback 0·900점, A₁은 fallback 1·40점. 다른 컴포넌트 B는 100점이다. 모두 Tier 2, 장식 조건도 같다.
현재 결과
같은 컴포넌트끼리는 fallback으로 A₀<A₁. 다른 컴포넌트끼리는 비용으로 A₁<B, B<A₀. 세 쌍 비교와 입력 배열 순서에 따른 다른 정렬 결과를 재현했다. 재현 R06.
왜 이상한가
정렬은 A가 B보다 앞이고 B가 C보다 앞이면 A가 C보다 앞이라는 일관성이 필요하다. 이 비교 함수는 상대가 누구인지에 따라 우선 기준이 바뀌어 A₀ → A₁ → B → A₀라는 순환이 생긴다.
반론까지 생각하면
서로 다른 컴포넌트의 fallback 위치를 직접 비교하지 않으려는 수정 의도는 타당하다. 하지만 일부 쌍에만 다른 정렬 기준을 넣으면 전체 순서를 만들 수 없다는 별도 문제가 남는다.
개선 방향
컴포넌트 단위 묶음의 순위를 먼저 정하고 내부 순서를 보존하거나, 전체 후보에 공통으로 적용되는 키를 설계한다. “자기 fallback 순서 보존”과 “문서 전체 비용 순서”가 충돌할 때 어느 쪽을 우선하는지 정한다.

코드 근거 · 조건부 비교 함수

F07재현됨 · 오류와 빈 공급 혼동

DB 오류가 “후보 없음”이 되어 fallback이 계속 돈다

언제 발생하나
후보 검색에서 DB/네트워크 오류가 나고, 취소된 상태는 아니다.
현재 결과
화면의 searchOne은 예외를 잡아 results:[]와 오류 메타로 바꾼다. N loop는 meta.error를 구분하지 않고 results.length만 봐 N2 이후 시도를 계속한다. 항상 오류 응답을 주는 제어된 공급으로 반복을 재현했다. 재현 R07.
왜 이상한가
“조회했는데 맞는 디자인이 없음”은 표현 변경의 근거지만, “조회 자체에 실패함”은 그런 근거가 아니다. 계속 같은 장애를 만나면 요청과 오류 목록만 늘어날 수 있다.
반론까지 생각하면
다른 독립 컴포넌트의 결과를 살리기 위해 한 오류로 문서 전체를 중단하지 않는 의도는 좋다. 그것과 같은 컴포넌트의 실패한 조회를 다른 의미로 계속 반복하는 것은 별개다. 실제 장애 시 호출량을 측정한 결과는 아니다.
개선 방향
응답을 성공·후보 없음·실패·취소로 구분한다. 실패한 컴포넌트의 N 사다리는 명시적 오류로 멈추고 다른 최상위 컴포넌트는 계속할 수 있게 한다. 재시도가 필요하면 별도의 제한된 재시도 규칙을 둔다.

코드 근거 · 예외를 빈 응답으로 · results.length만 판정

F08재현됨 · 규약에 따른 선택과 성능 한계

첫 성공에서 멈추므로 더 싼 대안을 비교하지 않는다

언제 발생하나
N1 실패 후 첫 N2 변형에서 사용 가능한 후보가 나오며 그 비용은 999점이다. 뒤 변형에는 더 좋은 결과가 있을 수도 있다.
현재 결과
첫 성공 N2를 반환하고 후속 변형을 조회하지 않는다. 반대로 전부 실패하면 가능한 N2 조합을 모두 시도한다. 재현 R08은 2번째 호출에서 999점으로 종료하는 것을 확인한다.
왜 이상한가
최저 비용 검색이라고 생각하면 이상하지만, 실제 목표는 정해진 손실 순서에서 먼저 성립하는 표현 찾기다. 한쪽은 빨리 멈추고 반대쪽은 조합을 전부 훑는 비대칭 때문에 성공/실패 입력의 시간 차이가 커진다.
반론까지 생각하면
N1~N5는 규약상 후보가 나오면 멈춘다. 이것 자체를 버그라고 부르면 안 된다. 동일 강등 합·동일 깊이의 형제 tie는 뒤쪽 노드를 먼저 내리는 코드 선택이며, 해당 순서도 어느 첫 성공을 얻는지 영향을 준다.
개선 방향
기본 첫 성공 정책을 문서·화면에 분명히 표시한다. 조합 생략 없는 조회 재사용·병합·정확한 불가능 판정부터 검토한다. 일률적인 N2 216회 제한을 되살리면 이전에 해결한 탐색 누락을 다시 만든다.

코드 근거 · 깊이·노드 순서 · 첫 성공 반환 · 전체 조합 끝

F09재현됨 · 불완전 그룹 순위

빈 조각이 있는 페이지가 더 좋은 점수를 받는다

언제 발생하나
최상위 L2의 독립 컴포넌트 중 하나만 1점 후보를 얻고 다른 하나는 0개다. 비교할 완전한 단일 결과는 2점·같은 Tier다.
현재 결과
빈 슬롯 비용은 0, 그룹 Tier에서도 빈 슬롯을 뺀다. 불완전 그룹이 1점·Tier 1로 앞선다. 재현 R09.
왜 이상한가
낮은 합계가 내용 전체를 잘 담았기 때문인지, 못 찾은 내용이 합계에서 빠졌기 때문인지 구분되지 않는다. 항목을 많이 표현한 완전한 결과가 오히려 불리할 수 있다.
반론까지 생각하면
N3 분할 내부에는 모든 조각 성공 검사가 있다. 하지만 최상위 독립 L2 결과를 합치는 층은 별도이며, 여기서는 빈 슬롯도 가진 그룹을 만든다. 부분 결과를 보여 주는 것 자체보다 완성 결과와 같은 점수로 비교하는 것이 문제다.
개선 방향
완료 조각 수/전체 조각 수를 명시하고, 완전한 결과 우선 순서 또는 별도 부분 결과 영역을 둔다. 단순히 누락당 임의 벌점을 더하는 것보다 먼저 완성 여부의 의미를 정한다.

코드 근거 · 빈 슬롯 비용 0 · 빈 슬롯 포함 그룹 · 빈 슬롯 Tier 제외

§11

왜 이렇게 했나: 유지할 것과 바꿀 것

좋은 수정은 반복문 수를 줄이는 작업이 아닙니다. 같은 조건을 두 번 확인하는 이유가 있는지, 끝낼 근거가 맞는지, 생략한 후보의 의미가 무엇인지를 먼저 따져야 합니다.

현재 선택왜 필요한가판단
원래 카테고리의 자기 fallback 행만 사용도착지의 새 fallback을 계속 따라가며 우선순위가 변하는 것을 막는다.유지할 규칙
Tier·Stage를 별도로 둠표현 종류의 차이와 슬롯 역할의 차이를 구분한다.하나의 숫자로 합치지 않는다.
Stage 2에서 1비트 패턴 제외같은 카테고리에서 같은 행을 다시 조회하는 것을 막는다.필요한 중복 방지
검사 후 승인 수로 중단읽기만 한 후보가 탈락해도 다음 후보를 찾을 수 있다.해결된 동작 유지
matchedQueries 기록복수 태그 행을 통과하지도 않은 원래 카테고리로 잘못 승격시키지 않는다.필터와 채점 연결에 필요
별칭 배정 후 aliasPlacedFields 기록이미 넣은 필드를 이동 단계가 또 넣는 중복 방지. marker 제외도 덮어쓰기 방지.겉보기 중복 분기가 아니라 역할이 있음
N2 후 N3, Hierarchy는 N5공간 구조·소속 관계를 가급적 보존한다.규약 순서 유지
N2 지연 생성 + 묶음 캐시조합 전체 저장으로 메모리가 폭증하는 것을 줄인다.조회량·실행 시간까지 줄여 주지는 않음

불필요해 보이는 계산은 어디에 남았나

코드 주석도 현재 동작과 대조해야 합니다

documentSearch.ts 머리말의 “L3는 바로 평탄화”, search.ts 주변 문서의 “allocateSlots로 배분”, rank.ts의 “alternatives 우선순위”, summary-projection.ts의 “관계 종류·참가자까지 보존”은 현재 실행문과 맞지 않는 설명이 남은 사례입니다. 이 문서는 현재 실행문과 재현 결과로 설명하고, 규약 의도는 별도 근거로 표시합니다.

개선 순서 제안

  1. 내용 누락·오류 전파·정렬 순환처럼 결과의 신뢰성을 깨는 F05·F07·F06을 먼저 다룬다.
  2. 후보 발견과 종료의 의미를 맞춘다. F01·F02·F04와 스캔 소진 사유(F03)를 정리한다. 화면 사후 태그 필터가 결과를 비우고 코어를 보충시키지 않는 경로도 같이 본다.
  3. 완성도와 품질를 나눠 본다. 누락된 조각(F09), 핵심 숫자·단위·조건, 카드별 분량 균형, 관계·순서, 남은 원문의 시각적 영향, 실제 겹침·잘림을 평가한다.
  4. 합치기 때문에 길어진 문장이 itemOverflow·capOverflow·capChars에 이미 중복 반영되는지 보고 새 과밀도 벌점을 조정한다. 효과는 총점 하락보다 사용 가능한 결과 비율·원본 내용 보존·사람의 선택과 일치·검색 및 렌더 시간으로 검증한다.

코드 근거 · exactType 이전 전체 Tier 생성 · 성립용 투영 · Frame용 투영 · 최종 재채점 · 화면 사후 필터 · contentLoss 가중치 설명

§12

직접 설명해 보기와 디버깅 순서

“왜 이상한가?”에 답할 때는 입력 → 중간 상태 → 종료 조건 → 놓친 결과 순서로 말해 보세요. 단순히 “fallback이 너무 많다”보다 수정할 지점이 명확해집니다.

문제 1 · Stage 0 후보 50개가 모두 용량 초과다. Tier 2를 볼까?

현재는 봅니다. 승인 수가 0이므로 다른 공급·Stage·카테고리·Tier를 계속 시도합니다. 단, 카테고리 스캔 예산은 여전히 적용됩니다. 과거에는 읽은 수 50을 세어 멈췄습니다.

문제 2 · 50개가 모두 통과했는데 결과는 1개다. 가능한가?

가능합니다. 서로 다른 행 50개가 같은 fingerprint면 승인 단계는 50, 최종 중복 제거 뒤는 1입니다. 승인과 반환이 세는 대상이 다릅니다.

문제 3 · N1 ExactMatch는 모양 비트도 정확히 같다는 뜻인가?

아닙니다. exactType이 Tier 1만 남겨 카테고리 변환을 제한합니다. 그 안의 Stage 0~2는 그대로 돌고, 중첩 경계는 containment 검사로 확인합니다.

문제 4 · N2는 무한 루프인가?

유한하고 순환 없는 입력, 응답하는 공급이라는 전제에서는 유한합니다. 강등 합과 조합 인덱스에 끝이 있습니다. 하지만 노드별 선택지 수의 곱이 커서 현실적으로 오래 걸릴 수 있습니다. 지연 생성은 메모리를 아끼며 조합 수를 없애지는 않습니다.

문제 5 · contentLoss=0이면 원본 글이 전부 남았나?

그렇지 않습니다. 변환이 꺼내지 않은 필드(F05), 규약상 텍스트로 옮기지 않는 관계 종류·참가자, 별도 titleDropped 판정은 같은 검사에 들어오지 않습니다. 원본의 기대값과 최종 binding을 직접 비교해야 합니다.

문제 6 · [4] 다음 [1,3]이 없으니 버그인가?

그 사실만으로는 아닙니다. 규약 N-R2가 [4], [3,1], [2,2], [2,1,1], [1,1,1,1]이라는 큰 묶음 우선 정책을 정했습니다. 모든 연속 분할 중 최적을 찾는 목적과는 다릅니다.

디버깅은 이 순서로 기록합니다

증상먼저 볼 값확인할 질문
입력 단계에서 검색 안 됨parse 결과 kind, schema 오류, type·version문법 오류인가, 규약 위반인가?
원래 카테고리 후보 없음buildTiersFor 결과, establish, 투영 내용해당 Tier가 빠졌나? count가 0인가?
중첩에서 느림N stage, 노드별 선택지 수, searchCount, exactType·forestN2 조합인가? 같은 오류를 반복하나?
후보가 갑자기 없어짐Stage filter, cap_min, dataset_kind, nested_categoriesDB 전 필터가 가능한 후보를 잘랐나?
읽은 수와 결과 수 차이fetched_rows, candidate_count, 제외 수, fingerprint중복·탈락·상한 중 어디에서 줄었나?
글이 빠짐원본 필드 → projected → Query Frame → alignment → binding처음 사라지는 단계는 어디인가?
화면 글이 예상과 다름sheet_id, blank·preserve, inside/outside, 제목 구제코어 배정인가 화면 임시 문구인가?
순위가 이상함tier·fallback_order·decoration_match·cost·완성 조각 수후보 순위인가 그룹 순위인가? 세 쌍 비교가 일관적인가?

로그 숫자를 읽을 때 주의

meta.candidate_count는 승인 수가 아니라 수집된 고유 행 수입니다. per_tier.count도 해당 Tier에서 새로 수집한 행 수입니다. fetched_rows는 반복 조회까지 포함합니다. 현재 응답에는 admittedCount나 종료 사유가 따로 없으므로, “후보 50”만 보고 성공 50이라고 판단하면 안 됩니다.

문서 searchCount는 N2 등을 포함한 실제 searchOne 호출 수이며, 최종 카드 수가 아닙니다. tookMs는 여러 요청 시간의 합이므로 동시 실행 시 사용자가 기다린 벽시계 시간과 다릅니다. capacity·param·content 배제 수는 마지막 채점에서 남은 한 사유 기준이며, 구조 불일치 등 모든 탈락을 전부 설명하는 계수는 아닙니다.

코드 근거 · 응답 메타 · 구조 탈락·해석 시도 · 호출 수와 시간 합

§13

iui.comp_frames: 적재된 Frame 테이블

§2에서 Frame을 「내용과 디자인이 만나는 공통 표」로 배웠습니다. 그 Frame은 검색할 때 그 자리에서 만드는 것이 아니라 미리 만들어 테이블에 넣어 둔 것입니다. 검색이 읽는 색인이 바로 이 표입니다.

행 하나 = 컴포넌트 하나가 아닙니다. 행은 IIS가 나눈 경계 노드 하나마다 생깁니다. 그래서 한 디자인(design object)에 행이 여럿일 수 있고, 뒤에서 볼 「표·차트가 섞였는지」 판정이 가능해지는 것도 이 덕분입니다.

규모값
전체 행226,952
데이터 버전 2.5113,614행 · design object 96,538개
컬럼48개

1. 본체는 frame 한 칸입니다 (jsonb)

검색과 대치가 실제로 쓰는 구조는 전부 이 jsonb 안에 있습니다. 나머지 47개 컬럼은 거기서 뽑아 둔 사본이거나 부가 정보입니다.

키내용
units[]반복 단위(카드·단계 등) 목록. 단위마다 fields로 label·value·items·grid 슬롯을 가집니다
└ 슬롯의 nodesheetId·rlscId·rlscPath — 어느 시트 노드에 대치할지를 가리킵니다
└ 슬롯의 cap용량. chars·lines·charsPerLine. v2 슬롯에는 hardLimit, v5에는 boxWidth·boxHeight·fontSize가 더 붙습니다
paramstitle 유무 등 표현 선택
dataset표·차트 여부. kind가 matrix면 실제 grid를 감지한 것입니다
relations · categories단위 사이 관계 · 의미 분류
satellites제목·설명 위성 슬롯
decorations장식
provenanceiis 또는 rlsc-rule과 그 버전 — 이 Frame을 무엇이 만들었나

2. 검색 사전 필터용으로 펼친 컬럼

jsonb 안을 뒤지면 느리므로, §4의 사전 필터가 WHERE로 바로 거를 수 있게 밖으로 꺼내 둔 값들입니다. 원본은 어디까지나 frame이고 이 컬럼들은 사본입니다.

묶음컬럼
카테고리categories · categories_from
모양shape_bits · shape_key · unit_count · items_per_unit_min/max · children_depth
용량 하한cap_label_lines_min · cap_label_cpl_min · cap_value_* · cap_item_* · cap_sat_title_* · cap_sat_desc_*
용량 배열cap_lines_arr · cap_cpl_arr · cap_unknown_count
버전semantic_component_version · frame_version · stale

3. 식별과 중복 제거

frame_fingerprint · rlsc_fingerprint · unit_signature · design_object_uuid · template_idx · source. §9에서 본 같은 지문끼리 묶어 온전한 쪽을 대표로 세우는 처리가 frame_fingerprint를 씁니다.

4. 벌점 계산에 쓰는 부가 데이터

컬럼내용
outside_text · outside_text_count이 노드 경계 밖의 텍스트. outsideText 벌점과 제목 구제에 씁니다
inside_unbound_text · inside_unbound_count경계 안이지만 슬롯에 안 묶인 잔여. insideResidue 벌점에 씁니다
preserve_text_nodes원문을 그대로 둘 노드(번호·vs 등)
font_size_max · font_size_rest_avgfontHierarchy 재료. 지금 가중치가 0이라 순위에 닿지 않습니다
threading_check스레딩 검사 결과

5. 버전은 다섯 축으로 따로 돕니다

「버전」이 하나가 아닙니다. 무엇이 낡았는지 말하려면 어느 축의 버전인지를 같이 말해야 합니다.

축컬럼지금 값과 뜻
데이터 발행분semantic_component_version2.4 / 2.5 — 어느 발행분의 IIS 결과로 만들었나
Frame 스키마frame_version전부 5 — jsonb 구조 자체의 판
용량 측정법cap_sourcetext_capacity:v2. 226,952행 중 225,382행(99.3%)이 v2이고, v2 슬롯 cap에는 hardLimit이 붙습니다
IIS 추출iis_boundary_version · iis_property_version · iis_property_prompt_version경계·속성·프롬프트가 각각 따로 올라갑니다
시그니처signature_version구조 해시 계산법

stale은 「이 행이 낡았다」 표시이고, built_at은 적재 시각입니다. provenance는 iis인지 rlsc-rule인지를 적습니다 — 분류는 IIS에서 받아도 Frame 자체는 규칙으로 만든 행이 있습니다.

6. 함정 둘

함정 1 categories_from으로는 아무것도 구분하지 못합니다.

이 컬럼은 categories가 어디서 왔는지를 적는 메타이고 값은 iis·tags·none 셋입니다. 그런데 226,952행 전건이 iis입니다 — 적재기가 하드코딩하기 때문입니다. provenance가 rlsc-rule인 행(25,373행)도 분류는 IIS에서 받습니다. 지금은 정보가 없는 상수 컬럼입니다.

한 컴포넌트에 표·차트와 다른 유형이 섞였는지 보려면 그 컴포넌트의 행들을 모아 행마다 판정합니다. 기준은 둘이고, frame.dataset.kind === 'matrix' 쪽이 더 확실합니다 — 적재기가 시트에서 실제 grid를 감지했다는 뜻이기 때문입니다. categories의 이름(MagnitudeRanking_BarChart·Enumeration_ListingTable 등)은 보조로 봅니다.

함정 2 도형 속 글자는 이 표에 아예 없습니다.

이 표의 텍스트는 슬롯이든 outside_text든 inside_unbound_text든 전부 RLSC Text 노드에서만 옵니다. 그래서 도형에 들어 있는 글자(ExtendableShapeItem)는 2.5 기준 3,357개 컴포넌트에 8,418개가 있는데도 Frame 어디에도 안 잡힙니다.

즉 검색도 대치도 그 글자들의 존재를 모릅니다. 벌점에도 안 세고, 용량 계산에도 안 들어가고, 대치 대상도 아닙니다. 시트 JSON은 이 표가 아니라 public.design_objects.design_object_sheet_json에 따로 있습니다 — 그쪽을 읽어야 보입니다.

이 노드들을 대치 대상에 넣을지는 아직 정해지지 않았습니다(2026-10-02 기준). 「대치가 안 된다」가 아니라 「대상으로 보지 않는다」가 현재 상태입니다.

근거 규모·컬럼 구성·categories_from 전건 iis·ExtendableShapeItem 8,418개는 사용자가 2026-10-02에 2.5 전수를 직접 조회해 얻은 값이며 이 문서에서 DB로 재확인하지는 않았습니다. 전체 226,952행과 text_capacity:v2 225,382행(99.3%)·hardLimit은 저장소 문서(src/comp-frame/AGENTS.md)에서 교차 확인했습니다. categories_from·cap_source 타입은 packages/comp-frame-shared/src/types.ts에서 확인했습니다.

§14

출처·검증·기존 내용 정리 기록

2026-09-13 로컬 체크아웃 기준입니다. 구현 저장소는 /Users/miridih/Documents/miricanvas-iui, 기준 커밋은 5d807e2dda8ff678fde227a436d7eea762e356bc입니다. 이 작업에서 인용한 packages/comp-frame와 src/comp-frame는 HEAD 대비 변경이 없음을 확인했습니다. 저장소의 다른 변경(Cargo.lock)은 건드리지 않았습니다. 원격을 새로 받아 “원격 최신”을 확인한 것은 아닙니다.

규약 저장소는 로컬 mordor-wiki 013fff131c99bc737ec4fd93ed38b3545675ba19입니다. comp-frame의 정본 fixture MANIFEST도 같은 커밋을 가리킵니다. 구현과 규약이 다르면 현재 실행 결과와 규약의 의도를 나눠 적었습니다. 코드 링크는 모두 이 고정 커밋을 가리킵니다.

이번에 확인한 것결과
기존 핵심 회귀 테스트18파일, 470개 통과. search·filter·rank·align·cost·query·projection·규약 대조·nested·documentSearch·resultMaps 등.
문서 지적 재현9개 통과. F01~F09의 현재 동작을 고정한 사례. 결함이 고쳐졌다는 의미가 아니라 해당 동작이 재현됐다는 의미.
규약 기준45개 카테고리·130개 projection 경로 fixture 대조를 포함.
운영 범위실제 DB 전체 실패율·실제 디자인 썸네일 품질·LLM 생성 품질은 측정하지 않음. 문서 분석과 합성 입력 검증.
변경 범위이 HTML 수업자료를 업데이트. 검색·대치 소스코드나 DB는 수정하지 않음.
기존 문서의 내용은 어디로 갔나
기존 주제새 위치정리 내용
기존 §0 전체 흐름·§7 세 층§0·§1·§2·§9코어/화면/저장소 구분 유지, 실제 N 검색 경로 반영.
기존 §1 Frame§2Unit·Slot·용량·관계·params 유지. Frame v3, aliases, nested 추가.
기존 §2 입력 평탄화§1·§6입력·레벨 중복 제거 유지. L3 즉시 평탄화를 N1~N5로 교체.
기존 §3 Tier·P8§345종·alternatives 미사용·P8 폐기 유지. 종단 하나·원본 행·최신 관계 보존으로 구체화.
기존 §4 후보 필터·Stage§4·§520비트·label 반례·GC·조회 정렬 유지. 균등 배분과 미보충 설명은 현재 코드에 맞게 교체.
기존 §5 배정·73자 실습·17벌점§7·§8배정·보존·용량 실습 유지. 별칭·하드 content 배제·fontHierarchy를 반영해 18항목.
기존 §6 그룹·리랭킹§8·§9·F06·F09합산 예시·최대 Tier·동점·렌더 후 미재채점 유지. fallback·장식 우선·불완전 그룹 설명 보강.
기존 §8 개선 제안§10·§11내용·분량 균형·관계·잔여 글·이미지 가독성·중복 감점 제안 유지. 해결된 보충 문제와 남은 문제 분리.
기존 §9 출처·323개 테스트§14옛 검증 수치를 현재 검증으로 대체. 고정 커밋 링크를 다시 확인.
코드 위치 지도
층주요 함수·파일
화면 입력·조율parseVisualSummaryInput → dedupeLevelDocs → searchDocumentLevels → searchNestedComponent → useFrameSearch의 searchOne
검색 코어buildTiersFor → buildQueryFrames → buildCandidateFilter → searchFrames → rankCandidates
배정·검사align → costOf, pairNested, projectStructure, entityLines / relationLines
사전 저장buildIisFrame / buildRuleFrame → frameToRow → iui.comp_frames 또는 선택 테이블
화면 대치·출력useResultAssets → resultMaps → FrameThumbnail. 그룹은 documentSearch / FrameGroupCard
독립성실행 코어와 화면은 comp-sign·comp-match 직접 import 없이 forked 사본을 사용. no-legacy-imports 테스트가 검사. 색상 엔진은 color-mapper.
고정 커밋 코드·규약 근거 72곳
저장소파일·줄
miricanvas-iuisrc/comp-frame/parseVisualSummaryInput.ts:103
miricanvas-iuisrc/comp-frame/documentSearch.ts:341
miricanvas-iuipackages/comp-frame/src/types.ts:122
miricanvas-iuipackages/comp-frame/src/frame.ts:15
miricanvas-iuipackages/comp-frame/src/component-frame.ts:1010
miricanvas-iuipackages/comp-frame/src/component-frame.ts:1508
miricanvas-iuipackages/comp-frame/src/component-frame.ts:379
mordor-wikiprojects/mordor/visual-summary/spec/schema-v0.5.md:678
mordor-wikiprojects/mordor/visual-summary/spec/capability-table.md:72
miricanvas-iuipackages/comp-frame/src/query-frame.ts:612
miricanvas-iuipackages/comp-frame/src/summary-content.ts:245
miricanvas-iuipackages/comp-frame/src/summary-projection.ts:14
miricanvas-iuipackages/comp-frame/src/summary-content.ts:118
miricanvas-iuipackages/comp-frame/src/summary-content.ts:136
mordor-wikiprojects/mordor/visual-summary/spec/capability-table.md:278
miricanvas-iuipackages/comp-frame/src/filter.ts:75
miricanvas-iuipackages/comp-frame/src/filter.ts:103
miricanvas-iuipackages/comp-frame/src/filter.ts:116
miricanvas-iuipackages/comp-frame/src/shape.ts:92
miricanvas-iuipackages/comp-frame/src/query-frame.ts:312
miricanvas-iuipackages/comp-frame/src/search.ts:174
miricanvas-iuipackages/comp-frame/src/search.ts:200
miricanvas-iuipackages/comp-frame/src/search.ts:240
miricanvas-iuipackages/comp-frame/src/search.ts:269
miricanvas-iuipackages/comp-frame/src/search.ts:282
miricanvas-iuisrc/comp-frame/nestedSearch.ts:82
miricanvas-iuisrc/comp-frame/nestedSearch.ts:114
miricanvas-iuisrc/comp-frame/nestedSearch.ts:192
miricanvas-iuisrc/comp-frame/nestedSearch.ts:250
miricanvas-iuisrc/comp-frame/nestedSearch.ts:273
miricanvas-iuisrc/comp-frame/useFrameSearch.ts:205
mordor-wikiprojects/mordor/visual-summary/spec/capability-table.md:444
miricanvas-iuipackages/comp-frame/src/align.ts:248
miricanvas-iuipackages/comp-frame/src/align.ts:397
miricanvas-iuipackages/comp-frame/src/align.ts:663
miricanvas-iuipackages/comp-frame/src/rank.ts:235
miricanvas-iuipackages/comp-frame/src/cost.ts:355
miricanvas-iuipackages/comp-frame/src/cost.ts:117
miricanvas-iuipackages/comp-frame/src/cost.ts:399
miricanvas-iuipackages/comp-frame/src/rank.ts:80
miricanvas-iuipackages/comp-frame/src/rank.ts:172
miricanvas-iuipackages/comp-frame/src/rank.ts:310
miricanvas-iuipackages/comp-frame/src/decoration.ts:47
miricanvas-iuisrc/comp-frame/resultMaps.ts:125
miricanvas-iuisrc/comp-frame/resultMaps.ts:191
miricanvas-iuipackages/comp-frame/src/titleCandidate.ts:1
miricanvas-iuipackages/comp-frame/src/query-frame.ts:400
miricanvas-iuisrc/comp-frame/documentSearch.ts:390
miricanvas-iuisrc/comp-frame/documentSearch.ts:479
miricanvas-iuisrc/comp-frame/FrameThumbnail.tsx:1
miricanvas-iuipackages/comp-frame/src/search.ts:270
miricanvas-iuipackages/comp-frame/src/query-frame.ts:673
miricanvas-iuisrc/comp-frame/frameSearchOptions.ts:65
miricanvas-iuipackages/comp-frame/src/search.ts:30
miricanvas-iuipackages/comp-frame/src/search.ts:210
miricanvas-iuisrc/comp-frame/nestedSearch.ts:255
miricanvas-iuipackages/comp-frame/src/align.ts:149
miricanvas-iuipackages/comp-frame/src/align.ts:269
miricanvas-iuipackages/comp-frame/src/align.ts:822
miricanvas-iuisrc/comp-frame/useFrameSearch.ts:214
miricanvas-iuisrc/comp-frame/nestedSearch.ts:124
miricanvas-iuisrc/comp-frame/nestedSearch.ts:165
miricanvas-iuisrc/comp-frame/documentSearch.ts:306
miricanvas-iuisrc/comp-frame/documentSearch.ts:406
miricanvas-iuisrc/comp-frame/documentSearch.ts:448
miricanvas-iuipackages/comp-frame/src/query-frame.ts:637
miricanvas-iuipackages/comp-frame/src/query-frame.ts:514
miricanvas-iuisrc/comp-frame/useFrameSearch.ts:233
miricanvas-iuipackages/comp-frame/src/cost.ts:130
miricanvas-iuipackages/comp-frame/src/search.ts:319
miricanvas-iuipackages/comp-frame/src/rank.ts:160
miricanvas-iuisrc/comp-frame/documentSearch.ts:364

작성 2026-09-08 · 기존 판 2026-09-12 · 전체 대조 및 수업자료 개정 2026-09-13. 과거 문서에 기록된 온라인 측정값을 이번 작업의 측정값으로 옮기지 않았습니다.