← 미리디 기술 사전 / Visual Summary

DEFECT MAP2026-09-17 갱신

Visual Summary 결함 지도

결함마다 얼마나 자주 터지는지와 어느 저장소에서 고쳐야 하는지를 붙였습니다. 모든 숫자는 defect-census 한 번의 실행에서 나옵니다 — 분모도 창(window)도 정의가 하나입니다.

분모 391 / 조각 403 창 top 10 실제 결과 17,520 · 기록 3,799 색인 112,227행 측정 판 preset-report-2026-09-16 iui ce154bec3 문서 갱신 2026-09-17
00

숫자는 어디서 오나

앞선 판들에서 같은 결함의 %가 달라진 적이 있다. 원인은 계산이 아니라 정의를 고정하지 않은 것이었다 — 한 번은 레벨을 안 합친 컴포넌트 505를 분모로 썼고, 한 번은 색인 점유율을 발생률처럼 적었다. 지금은 census.json 하나가 모든 숫자를 만들고 이 페이지는 그것만 옮긴다.

tsx scripts/comp-frame/defect-census.ts \
  --report eval-out/comp-frames/preset-report-2026-09-16 \
  --rowflags <snapshot 에서 뽑은 행 속성> --index <카테고리 통계>
→ census.json  (metrics 37 · clean_first · groups · documents · dedupe · ranking · shares)
분모 결과가 나온 컴포넌트 391. 프리셋 134건을 화면과 같은 순서(dedupeLevelDocs → flattenComponents)로 펴면 조각이 403개고, 결과를 1건 이상 받은 것이 391개다. 나머지 12개는 셀 대상이 없다.
창 top 10. preset-report 는 top_n(50)까지 세지만 본문은 top_detail(10)개만 적는다. 실제 결과는 17,520건인데 기록된 건 3,799건이다. 결과를 들여다보는 지표는 전부 이 10개 창 안에서만 참이다 — 앞 판에서 "top 50"이라 적은 건 틀렸다.
결과 돌려받은 목록만 보고 판정. 「미대치」는 breakdown 의 다섯 키(unitBlank·itemBlank·fieldBlank·insideResidue·outsideText) 중 하나라도 0보다 크면 참이다. 이 방식의 값이 2026-09-15 실측과 자리까지 일치한다.
쿼리 입력 문서만 보고 판정. 실제 buildTiersFor·buildQueryFrames 에 태워 확인한다.
조인 결과의 (do_id, node_id) 로 색인 행 속성을 찾아 판정. 색인 점유율이 아니라 실제로 1위(또는 창)에 온 비율이다.
census 스크립트는 아직 저장소에 없다. 지금은 스크래치패드에서 돈다. 이걸 scripts/comp-frame/defect-census.ts 로 들이면 숫자가 대화가 아니라 커밋에 묶인다 — 들이기 전까지는 이 페이지의 값을 다시 재려면 스크립트부터 다시 지어야 한다.
01

어디서 고치나 — 저장소 셋의 경계

경계는 파일 경로로 기계적으로 갈린다. 추측할 필요가 없다.

miricanvas-iui 이 저장소. src/** · scripts/** · packages/comp-frame-index/** · packages/comp-frame-shared/src/** — 단 eregion/ 제외.
주의 하나 — packages/comp-frame-shared/src/forked/ 는 이름이 fork 지만 상류가 aippt 가 아니라 comp-sign 이다(placeholders.ts 머리에 "Forked from the comp-sign package … @ b0097674"). 여기서 고치고 parity 테스트만 맞추면 된다.
aippt-prisonbreak 상류. packages/comp-frame-shared/src/eregion/visual-summary/** 의 .ts 30개가 aippt src/lib/visual-summary/ 를 그대로 베낀 사본이다(VENDOR.json, eregionCommit 3d5a05d2f). AGENTS.md:87-88 — "Never patch a vendored file to match the spec — fix aippt and re-run scripts/comp-frame/sync-eregion.ts".
해당: establish.ts · projection.ts · assignIds.ts · capability.ts · audit.ts · binding.ts · fallback.ts · taxonomy.ts · iis/propertyMatch.ts · iis/nodeBinding.ts · generator/definitions.ts · generator/vocabulary.ts 등. 실서비스 생성기 프롬프트도 aippt(generator/prompt.ts)에 있고 이 저장소 generate/prompts/ 는 우리가 떼어 온 사본이다.
mordor-wiki 정본. spec/schema-v0.5.md · spec/capability-table.md · spec/schema/capability.json. 동기화 지점은 packages/comp-frame-shared/tests/spec/MANIFEST.json(wikiCommit 013fff131, sync-spec-fixtures.ts). 규칙 자체가 정본이 정한 것이거나 정본이 침묵해서 생긴 결함이면 정본 변경 요청이 먼저다.
같은 함수라도 갈린다. p3Text(packages/comp-frame-shared/src/text.ts:68)가 만드는 "<field>: <value>" 표기는 정본 §5.1 이 정한 것이다. 그런데 items: 누출이 쓰는 items→목적지 없음 경로는 align.ts:519-522 가 스스로 "§5.1 에 명시되지 않은 설계 결정" 이라고 적어 뒀다. 그래서 period:·value: 접두는 mordor-wiki 건이고 items: 는 우리 건이다.
02

한눈에

1위가 검증 안 된 추출
43.2%
169/391. 벌점이 0이라 대가 없이 올라온다.
1위가 미대치
24.3%
95/391. 임시 문구가 남은 카드가 맨 앞이다.
tier 1 풀이 얕음
39.1%
153/391 이 500행 미만 풀에서 고른다.
전면 중단
0%
파싱·쿼리 빌드·tier 구성 실패가 한 건도 없다.
03

이슈 전체 — 결과가 나온 컴포넌트 391 대비

이슈고칠 곳기준건수391 대비
template_idx 가 NULL 이라 타이브레이커가 무력scripts/build-comp-frames.ts · rank.ts:119iui조인391100.0%
검증 안 된 추출이 top 10 안에cost.ts:81iui조인24863.4%
top 10 안에 미대치 자리types.ts:449iui결과24662.9%
쿼리에 items 가 있음결함이 아니라 노출 범위다노출쿼리19750.4%
검증 안 된 추출이 1위cost.ts:81, 456-463iui조인16943.2%
병치 — 묶음 카드가 된다결함이 아니라 노출 범위다노출쿼리15740.2%
tier 1 풀이 500행 미만build-comp-frames.ts · 프롬프트iui aippt쿼리15339.1%
tier 1 풀이 200행 미만같음iui aippt쿼리12331.5%
열에 role 을 적음 — B-37 사정권결함이 아니라 노출 범위다노출쿼리12130.9%
1위가 미대치types.ts:449 · rank.ts:101iui결과9524.3%
Title 잔여+제목 없음 — top 10 안에resultMaps.ts:231iui조인8521.7%
비내용 잔여가 있는 행 — top 10 안에resultMaps.ts:221iui조인7920.2%
온전한 후보가 top 10 안에 0개—iui결과5313.6%
entities + matrix 동봉결함이 아니라 노출 범위다노출쿼리3910.0%
Marker 잔여가 있는 행 — top 10 안에resultMaps.ts:221iui조인369.2%
matrix 표 쿼리 — 유닛이 전부 blankquery-frame.ts:319 · align.ts:688iui wiki쿼리348.7%
tier 1 이 통째로 빔 (B-37 26 + 개수 7)query-frame.ts:621, 648, 668aippt wiki쿼리338.4%
순번 카테고리를 씀 — 규칙 (d) 대상결함이 아니라 노출 범위다노출쿼리317.9%
items: 누출 — top 10 안에align.ts:526, 530iui조인266.6%
그중 축이 달라 중복이 아닌 것 (유닛만 부푼다)summary-projection.ts:62iui쿼리287.2%
B-37 위반 — role 숫자 열에 문자열eregion/…/establish.ts:142-188aippt쿼리266.6%
경계 밖 Title 없는 부분 매치 — top 10 안에titleCandidate.ts:245iui조인246.1%
tier 1 카테고리의 dataset kind 공급이 0filter.ts:175iui쿼리225.6%
제목은 버리고 Title 잔여엔 「제목 입력」 — 1위resultMaps.ts:231iui조인215.4%
relation of 를 씀결함이 아니라 노출 범위다노출쿼리174.3%
비내용 잔여가 있는 행이 1위resultMaps.ts:221iui조인174.3%
items: 누출 — 1위align.ts:526, 530iui조인143.6%
marker 슬롯을 가진 행 — top 10 안에align.ts:567iui조인71.8%
그중 진짜 중복 — 같은 내용이 두 번 (PR #1070)summary-projection.ts:62 · summary-content.ts:150iui쿼리112.8%
Funnel 을 씀summary-projection.ts:62iui쿼리61.5%
Cycle 을 씀v2/system.md · aippt prompt.tsaippt iui쿼리51.3%
개수 조건 미달로 성립 실패 (NestedScope 7건)eregion/…/establish.ts:191aippt wiki쿼리71.8%
Pyramid 에 apex 생략 — 순서 역전rank.ts:240, 373iui쿼리51.3%
QnA 카드를 씀resultMaps.ts:221iui쿼리30.8%
경계 밖 Title 없는 부분 매치 — 1위titleCandidate.ts:245iui조인30.8%
Marker 잔여가 있는 행이 1위resultMaps.ts:221iui조인10.3%
marker 슬롯을 가진 행이 1위 — 규칙 (d) 가 실제로 도는 경우align.ts:567iui조인00.0%
쿼리 빌드 실패 / tier 구성 실패query-frame.ts:451 · search.ts:138iui쿼리00.0%
04

391로 환산할 수 없는 것

이슈고칠 곳분모건수발생률
장식 정렬 키가 전 행 동일값component-frame.ts:1198 · decoration.ts:9iui색인 112,227 ✻112,227100%
용량 소프트 벌점 둘이 항상 0cost.ts:286, 344iui설정—100%
규칙 (e) 텍스트 보존이 런타임에서 죽음align.ts:617 · search.tsiui런타임—100%
레벨 문서를 합칠 때 제목을 잃는다documentSearch.ts:158iui합쳐진 68그룹2536.8%
문서 병합 목록의 1위가 미대치documentSearch.ts:664iui문서 1324332.6%
열 메타만 달라 같은 문서가 갈림documentSearch.ts:263iui갈린 268쌍 ✻166.0%
빈 슬롯이 0점 — 컴포넌트를 잃은 묶음이 1등documentSearch.ts:497, 663iui묶음 5723.5%
두 슬롯이 같은 결과를 골라 카드 키가 겹침FrameGroupCard.tsx:369iui묶음 5723.5%
fallback_order 가 비용을 압도rank.ts:106iui wiki인접 쌍 3,347411.2%
중첩 경계를 가진 색인 행filter.ts:131iui색인 112,227 ✻1540.14%
중첩 컴포넌트 — 사다리를 타는 입력nestedSearch.ts:216iui조각 40300%
✻ 표시한 셋만 census 밖이다. 나머지는 전부 census.json 에서 나온다 — 묶음(groups) · 문서(documents) · 제목 손실(dedupe) · 비용 역전(ranking). ✻ 셋은 스냅샷 집계와 fuzzy 비교라 census 가 아직 안 세고, 들이려면 스크립트에 한 함수씩 더 붙이면 된다.
빈도를 아예 못 잰 이슈가 열넷 더 있다. 화면·비동기 경로 여덟(큐 리셋 고아 카드, REQUEST 2회 전송, 자산 캐시 미충전, 미대치 표시 위치 어긋남, 검색 실패 침묵, LOADED 10초 초과, 형제 축소가 임시 문구를 못 봄, 별칭이 진짜 텍스트를 가림)과, 프리셋에 중첩이 0건이라 코퍼스로는 영영 못 재는 것 여섯 (peel 오귀속, 영문 키 누출, N2·묶음이 늘 tier 1, 보기 모드 반쯤 죽음, 첫 완주 분할 우선, ORDERED_PREFIXES 에 Cycle 누락). 전부 iui 다.
05

색인 점유율은 왜 못 믿나

같은 속성을 세 지점에서 셌다 — 색인 112,227행, 기록된 창의 결과 3,799건, 1위 391건.

행 속성색인창(top 10)1위창→1위
검증 안 된 추출 (rlsc-rule · unitMismatch)20.1%38.2%43.2%×1.13
첫 유닛에 items 슬롯이 없음11.8%36.6%39.1%×1.07
Title 잔여가 있고 제목 위성이 없음6.2%3.1%5.4%×1.74
비내용 잔여가 있음11.7%3.1%4.3%×1.39
경계 밖에 Title 역할이 없는 부분 매치5.1%0.7%0.8%×1.14
Marker 잔여가 있음11.0%1.6%0.3%×0.19
marker 슬롯을 가짐 (규칙 d 대상)1.1%0.2%0.0%×0
색인 → 창의 변화는 하드 필터와 용량 게이트가 만들고, 창 → 1위가 랭킹의 몫이다. 후자는 전부 ×1.1~×1.7 수준이다 — 랭킹은 크게 비뚤지 않고, 들어오는 후보 자체가 비뚤다. Marker 잔여는 색인에서 11.0%인데 1위에는 0.3%밖에 안 온다. 색인 점유율을 발생률로 읽으면 안 된다.
06

미대치 상위 노출 — 두 자리 중 무엇을 켤까

clean_first 는 「대치하고도 저자 글이 아닌 자리가 남는가」를 정렬 키로 만든다. within_tier 는 tier 뒤에, above_tier 는 tier 앞에 꽂는다. 기본값은 아직 'off' 다.

설정1위 미대치1위 교체tier 하락새 1위 비용
off — 지금24.3%———
within_tier — tier 뒤19.2%20건 (5.1%)0건중앙값 −119
above_tier — tier 앞13.6%42건 (10.7%)22건 (5.6%)중앙값 −36
above_tier 가 창 안에서의 바닥이다. 13.6%는 「온전한 후보가 top 10 안에 0개인 검색」 비율(53/391)과 같다. 대가는 tier 1 → 2 강등 22건인데, 교체 42건 중 38건은 새 1위가 오히려 더 싸다(최대 −201). 고칠 곳은 iui packages/comp-frame-shared/src/types.ts:449 한 줄이다.
이 시뮬레이션은 기록된 top 10 안에서만 재배열한 것이라 개선폭의 하한이다. 실제 검색은 50개를 정렬한 뒤 자르므로 11~50위의 온전한 후보도 끌어올린다. 2026-09-15 무제한 수집본 기준 within_tier 55.0% · above_tier 37.3%(top 10 오염)였다.
07

각 결함 — 무엇이 보이고 어디를 고치나

엔트리마다 셋을 둔다 — 왼쪽 본문은 무엇이 어떻게 잘못되는지, 그 아래 굵은 줄은 어느 저장소의 어느 파일·줄을 고치는지, 오른쪽 그림은 결과 카드 썸네일에 어떻게 보이는지다. 붉은 표시가 결함이다.

검증 안 된 추출이 벌점 없이 1위에 온다

1위 43.2% · top10 63.4%miricanvas-iui

cost.ts:456-463 이 unitMismatch 에 새 가중치를 안 넣은 근거로 "기존 provenance 가중치가 이미 벌한다"고 적어 뒀다. 그런데 그 가중치가 cost.ts:81 에서 0이다.

fontHierarchy: 0 에는 "2026-09-14: 1 → 0" 이라는 날짜와 근거가 붙어 있는데 provenance: 0 에는 아무것도 없다. git log -S 로 따라가니 최초 커밋 e82e02846 부터 0이다 — 처음부터 안 켠 것이다.

늘어나는 구간이 색인(20.1%) → 창(38.2%) 이라 랭킹 탓이 아니라 하드 필터가 이런 행을 잘 통과시키는 것이다. 규칙 기반 추출은 프레임이 단순해 정렬이 잘 맞고 빈 슬롯이 적다.

고칠 곳 — src/comp-frame/cost.ts:81 값 하나. 벤더도 정본도 아니다. 숫자는 placeholder-sweep-collect 로 raw 를 한 번 모은 뒤 DB 없이 곱셈으로 쓸어 정한다. 함께 갱신: cost.test.ts, oracle/golden/align/*.json.
세 지점의 점유율
색인 20.1%
창 38.2%
1위 43.2%
벌점은 0이다

임시 문구가 남은 카드가 1위에 온다

1위 24.3% · top10 62.9%miricanvas-iui

대치하고도 저자 글이 아닌 자리가 셋 남는다 — 빈 슬롯, 경계 안 잔여(둘 다 임시 문구로 채움), 경계 밖 잔여(컴포넌트 원문이 그대로). 셋의 합이 unauthored_count 다.

기본 가중치만으로는 천장이다. cost.ts:47-67 이 "더 올려도 성적이 한 칸도 안 움직인다"고 실측으로 못 박았다. tier_pool 에서 tier 가 첫 키라, tier 1 풀에 온전한 후보가 없으면 가중치는 풀 안 순서만 바꾼다.

13.6%(53건)는 온전한 후보가 창 안에 아예 없다 — 어떤 정렬로도 못 고친다. 얕은 풀과 이어진다.

고칠 곳 — packages/comp-frame-shared/src/types.ts:449 의 clean_first 기본값 한 줄. 정렬 키는 src/comp-frame/rank.ts:101-110, 병합 목록은 documentSearch.ts:664 로 이미 배선돼 있다. 함께 갱신: rank.test.ts 정렬 describe.
카드에 보이는 것 · 1등
2026 사업 로드맵
1시장 조사 완료
2내용 입력
3내용 입력

B-37 — 열 메타데이터 한 글자가 차트·표 후보를 지운다

6.6% (26/391)aippt-prisonbreak

B-37 은 열의 role 과 셀 타입이 맞는지를 본다. 양방향이다 — value·x·y·size 열은 number 또는 null 을, category 열은 string 을 요구한다. 하나라도 어긋나면 그 카테고리의 성립 판정이 통째로 깨진다.

role 을 쓰는 게 121건(30.9%)이고 그중 26건(6.6%)이 위반이다. 위반하면 예외 없이 tier 1 이 사라진다 — tier 1 소실 33건 중 26건(79%)이 이 경로다.

26건을 원문으로 다 열어 봤더니 성격이 넷으로 갈린다. 고치는 방법이 서로 다르다.

A. 연도 축에 문자열 — 12건 (46%)
role: x 인 연도 열에 "2023년"·"2021" 처럼 문자열이 들었다. csv-19·21·26·52·54.
데이터는 멀쩡하고 표기만 문제다. 축 라벨로는 "2023년" 이 오히려 자연스럽다.

B. 서술 열에 role: value — 11건 (42%)
주요 지원 내용·교육부·혜택 같은 서술 열 전체에 value 를 붙였다. csv-4·5·8·20·32·65·7.
csv-8 은 4개 열 16셀이 전부 문장이다. role 을 잘못 붙인 것이지 셀이 틀린 게 아니다.

C. category 열에 빈 칸 — 2건
csv-14 세부유형(category) 에 null, csv-51 내용(category) 에 null.
처음 24건으로 셌을 때 놓친 둘이 이것이다 — 숫자 role 만 검사했는데 B-37 은 category 열도 본다.

D. YAML 이 깨진 것 — 1건
csv-49 의 행이 ["기타(미혼", "비혼", "별거 등)", 5.4] 다. 원문은 "기타(미혼, 비혼, 별거 등)" 한 칸이었을 텐데 따옴표 없이 쉼표가 들어가 3칸으로 쪼개졌다.
여기서는 B-37 이 제 일을 했다 — 진짜 깨진 데이터를 잡아냈다.

검사 자체는 aippt — checkCellTypesByRole 이 벤더 packages/comp-frame-shared/src/eregion/visual-summary/establish.ts:142-188 에 있고 VENDOR.json 의 30개 .ts 중 하나다. AGENTS.md:87-88 이 패치를 금한다. 다만 검사를 느슨하게 하는 건 답이 아니다 — D 를 놓치게 된다.
A·B 는 생성기가 만든다 — 실서비스 프롬프트 aippt src/lib/visual-summary/generator/prompt.ts 에 「role: x 인 축 열의 셀은 숫자로 적는다(연도는 2023, "2023년" 이 아니다)」와 「서술 열에는 role 을 붙이지 않는다」 두 줄을 더하면 23건(88%)이 사라진다.
완화는 iui — src/comp-frame/useFrameSearch.ts 의 searchOne 앞에 보정 패스를 두고, 사유 문자열이 가리키는 그 열의 role 만 지워 재판정한다. A·B·C 에는 통하고 D 에는 통하면 안 된다 — 행 길이가 열 수와 다르면 건너뛰는 가드가 필요하다. 40줄 안팎.
실제 위반 · csv-19 (A)
columns:
  - label: 연도
    role: x
  - label: 목표인원
    role: y
rows:
  - ["2023년", 800, 367]
  - ["2024년", 540, 466]
→ tier 1 LineAreaChart 소실
1위 ComparisonTable tier 2 cost 201
실제 위반 · csv-49 (D)
  - ["이혼", 84.2]
  - ["사별", 10.4]
  - ["기타(미혼", "비혼", "별거 등)", 5.4]
따옴표가 빠져 한 칸이 세 칸이 됐다
이건 B-37 이 옳게 잡은 것

tier 1 이 비면 표를 요청해도 목록이 나온다

8.4% (33/391)aipptwikiiui

tier 1 은 요청한 type 하나만 본다(alternatives 도 안 읽는다). 그 카테고리가 성립 판정을 못 넘으면 tier 1 이 통째로 비고 tier 2 의 fallback 행으로 내려간다.

33건이 실제로 무엇을 받았는지 세어 봤다. 1위가 Enumeration_List 인 게 28건(85%), ComparisonTable 4건, Versus 1건이고 33건 전부 tier 2 이상이다. 표·차트를 요청했는데 목록 카드가 오는 게 과장이 아니라 다수다.

비용도 같이 뛴다. csv-19 는 LineAreaChart 를 요청했는데 ComparisonTable 이 cost 201 로 1위다 — tier 1 이 살아 있었으면 나오지 않았을 값이다.

사유는 둘뿐이고 겹치지 않는다.

① B-37 셀 타입 위반 — 26건 (79%)
아래 항목에 성격 넷으로 갈라 적었다.

② 개수 미달 — 7건 (21%), 전부 ScopeCoverage.NestedScope
사유가 전부 "개수 미달: 1 < 2 (entities)" 다. 원문을 보니 9건 모두 entities 를 하나만 두고 포함 관계를 children 중첩으로 적었다.

이게 왜 탈락인지가 중요하다. 정본이 그렇게 정했다. capability.ts:300-305 의 주석이 근거까지 적어 뒀다 — B-34(2026-09-04)로 「NestedScope 는 동심원이라 children 사슬로 적으면 단일 사슬 HierarchicalTree 와 데이터상 같은 모양이 되어 버린다」며 평평한 entities ≥ 2 로 되돌렸다. 규칙이 맞고 생성기가 안 지킨 것이다.

② 는 이미 고쳤을 가능성이 크다 — 이 저장소 V2 프롬프트(generate/prompts/v2/system.md)는 35-36행과 248행에서 두 번 "ScopeCoverage.NestedScope 는 children 을 쓰지 않는다 — entities 배열 순서와 direction 으로 겹을 표현한다" 고 가르친다. 그런데 V1 에는 그 문장이 없다(diff 로 확인). 코퍼스는 V1 산출물이라 이 7건은 옛 판의 흔적일 수 있다. 확인하려면 NestedScope 3 프리셋만 V2 로 재생성해 보면 된다 — 몇 십 센트다.
단 실서비스는 별개다 — 우리 V1 은 aippt generator/prompt.ts 를 벤더링 시점(3d5a05d2f)에 바이트째 베낀 것이다. aippt 가 그 뒤 이 규칙을 넣었는지는 이 저장소에서 알 수 없다. 안 넣었으면 실서비스는 계속 children 을 낸다.
iui 는 사유를 버리는 쪽이다 — src/comp-frame/query-frame.ts:621, 648, 668 이 establish 의 eligible 만 보고 reasons 를 버린다. 사유 문자열은 "B-37 셀 타입 위반: 열 \"연도\"(role x) 의 셀 \"2023년\" 은 number 또는 null 이어야 한다" 처럼 이미 자리와 값까지 다 적혀 있는데 화면까지 오지 않는다. meta.error 침묵과 같은 뿌리다.
33건이 실제로 받은 1위
Enumeration_List 28
ComparisonTable 4
Versus 1
33/33 전부 tier 2 이상
실제 사례 · csv-72
type: ScopeCoverage.NestedScope
entities:
  - label: 개인정보 전체
    children:
      - label: 민감정보
        children:
          - label: 고유식별정보
최상위 entities 는 1개 → "1 < 2" 탈락
정본은 평평하게 3개를 요구한다

items: 접두가 본문에 새어 나온다

1위 3.6% · top10 6.6%miricanvas-iui

쿼리 유닛에는 items 가 있는데 매치된 컴포넌트에 items 슬롯이 없으면, items 를 쉼표로 이어 붙인 뒤 "items: …" 를 만들어 label 슬롯 뒤에 줄바꿈으로 붙인다. 아무도 접두를 벗기지 않는다.

색인 점유율(11.8%)보다 실제 노출이 낮다. 쿼리에 items 가 있는 게 197건(50.4%)인데, 그중 1위 행에 items 슬롯이 없는 경우가 14건(3.6%)이다. fieldMove 벌점이 items 슬롯 있는 쪽으로 밀기 때문이다.

고칠 곳은 iui — 그리고 정본 문제가 아니다. p3Text 는 packages/comp-frame-shared/src/text.ts:68 로 벤더가 아니고, 이 items 경로는 src/comp-frame/align.ts:519-522 가 스스로 "§5.1 에 명시되지 않은 설계 결정" 이라고 적어 뒀다. align.ts:526, 530 두 줄에서 p3Text 를 빼면 된다. 함께 갱신: align.test.ts:762, oracle/golden/align.
형제는 mordor-wiki — 같은 p3Text 로 만드는 period:·value:·emphasis: 접두는 text.ts:67 주석대로 정본 §5.1 의 P3 이동 표기다. 그건 정본을 먼저 바꿔야 한다.
카드에 보이는 것
분기별 매출 성장
1국내 시장
items: 서울, 부산, 대구
2해외 시장
items: 도쿄, 상하이

표를 채우고 표 밖 글자를 전부 지운다

쿼리 8.7% · ListingTable 1위 미대치 71.4%iuiwiki

ListingTable·ComparisonTable 을 matrix 로 적으면 "matrix 가 행 텍스트를 통째로 소유한다"며 쿼리 units 를 비운다. 그러면 매치된 컴포넌트의 모든 유닛이 blank 로 가고, 표 옆 제목·목록이 전부 임시 문구가 된다.

8.7%가 작아 보이지만 착시다. ListingTable 485행 중 matrix 는 57행뿐이고 그 57행 중 56행(98.2%)이 텍스트 유닛을 갖고 있다. 그래서 ListingTable 검색의 1위 미대치율이 71.4%다 — 전체 평균의 세 배다.

완화는 iui — src/comp-frame/resultMaps.ts 에서 blankReason: 'unit' 인 자리는 임시 문구 대신 원문을 남긴다. 한 줄급이고 골든도 안 건드린다. 대신 컴포넌트 원문이 남는다.
근본은 mordor-wiki — "matrix 쿼리는 units 를 비운다"가 투영 규칙이다(query-frame.ts:319-325, align.ts:688-693 규칙 a). matrix 가 label 열을 유닛으로도 남기게 하려면 정본이 그 자리를 정해 줘야 한다. 지금은 정본 침묵이다.
카드에 보이는 것
제목 입력
성과 항목건수 언론보도18 협력 확대7
내용 입력 · 내용 입력

고를 후보 자체가 없다

500행 미만 39.1% · 200행 미만 31.5%iuiaippt

색인 공급이 극단적으로 치우쳐 있다. P0 13종 중 넷이 세 자리 수다.

List 34,607 · LongForm 33,169 · HighlightedMessage 10,051 · Steps 3,008 · Timeline 1,553 · Versus 986 · Transformation 730 · ListingTable 485 · ComparisonTable 161 · Cycle 138 · SWOT 131 · Staircase 94

그런데 프롬프트는 "넓은 것과 좁은 것이 둘 다 맞으면 좁은 쪽이다"라고 시킨다. 정본이 시키는 방향이지만, 효과는 tier 1 을 34,607행 풀에서 94행 풀로 옮기는 것이다.

색인은 iui — scripts/build-comp-frames.ts 가 적재한다. 얕은 카테고리를 채우려면 추출 범위를 넓히거나 재적재한다. 재적재는 배포 뒤에 한다.
생성기는 aippt — 실서비스 프롬프트는 aippt src/lib/visual-summary/generator/prompt.ts 다. 이 저장소 src/comp-frame/generate/prompts/v2/system.md 는 우리가 떼어 온 사본이라, 여기서 고쳐도 실서비스엔 안 간다. 여기서 효과를 재고 aippt 로 넘기는 순서다.
카드에 보이는 것
결과 3장
A A′ A″
같은 템플릿의 변형만 나온다

Q·A 글리프와 번호가 「내용」으로 덮인다

1위 0.3% · top10 9.2%miricanvas-iui

IIS 가 글리프 노드를 슬롯으로 안 잡아서 경계 안 잔여로 떨어진다. 화면은 잔여를 임시 문구로 채우는데, 임시 문구 표가 Marker 를 모르는 역할로 보아 1~2자 자리에 "내용" 을 넣는다.

앞서 이 결함을 크게 잡았던 건 틀렸다. 색인 점유율은 11.0%지만 창에는 1.6%만 들어오고 1위에 온 검색은 1건(0.3%)이다. insideResidue 벌점 10이 이미 잘 밀어낸다. 비내용 잔여 전체로 넓혀도 1위 17건(4.3%), 창 79건(20.2%)이다.

화면 수정은 iui — src/comp-frame/resultMaps.ts:221-224 에서 역할이 Marker 인 잔여를 맵에 안 넣으면 원문이 남는다. 임시 문구 표는 packages/comp-frame-shared/src/forked/placeholders.ts 인데 aippt 가 아니라 comp-sign 에서 포크한 자체 사본이라 여기서 고쳐도 된다(parity 테스트만 맞춘다).
근본도 iui — 색인이 Marker 를 marker 슬롯으로 적재해야 한다(packages/comp-frame-index/src/frame/component-frame.ts:1154-1157). 재적재가 따르고 배포 뒤에 한다. 우선순위는 낮다.
카드에 보이는 것
자주 묻는 질문
내용환불은 언제까지 되나요?
내용구매 후 7일 이내입니다.
1위에는 거의 안 온다

제목이 엉뚱한 자리로 간다

1위 5.4% · 창 21.7%miricanvas-iui

제목 처리에서 반대 방향의 실패가 둘 있다 — 제목을 넣을 자리가 있는데 버리는 것과 제목을 넣으면 안 될 자리에 넣는 것이다.

① 버리는 쪽 (1위 5.4% · 창 21.7%). 제목 위성이 없는 컴포넌트에서 쿼리 제목은 titleDropped 로 사라진다. 그런데 같은 경계 안에 RLSC 역할이 Title 인 잔여 노드가 있으면 거기엔 임시 문구가 들어간다. 화면은 "제목 자리가 있는데 임시 문구를 넣고 진짜 제목은 버렸다" 가 된다. 색인에서 이런 행이 5,694개(5.1%)이고 1위에 온 검색이 21건이다.

② 넣는 쪽 (1위 0.8% · 창 6.1%). 경계 밖에 Title 역할 노드가 하나도 없으면 outside_text 전체가 제목 후보가 된다. 역할 제한이 없어서 위·왼쪽·큰 글꼴 가중합으로 뽑으면 Marker(크고 위에 있는 번호)가 이기기 쉽다. 부분 매치 52,882행 중 Title 역할이 0개인 행이 5,572개이고, 그중 후보 풀이 비내용 역할로만 된 행이 2,654개, 풀 크기가 1이라 기하 계산도 안 거친 행이 4,133개다.

② 는 작다 — src/comp-frame/titleCandidate.ts:245-250 의 폴백 풀에서 비내용 역할(Marker·Decoration·Separator·Annotation·Background)을 빼고 Description·Subtitle·Highlight 순으로 우선순위를 둔다. 벤더도 정본도 안 걸린다.
① 은 정책 결정이 먼저다 — src/comp-frame/resultMaps.ts:231-239 의 outsideTitleTarget 이 outside_text 만 본다. 경계 안의 Title 잔여도 후보에 넣으면 되는데, 사용자 결정이 "경계 밖"이었다. 그 결정을 바꿀지부터 정해야 한다. 임시 문구를 넣는 자리는 :221-224 다.
카드에 보이는 것 · 두 방향
① 제목을 버린다
제목 입력
② 제목을 번호 원에 넣는다
2026 상반기 마케팅 성과 보고
쿼리 제목은 "2026 전략" 이었다

같은 내용이 위아래로 두 번 들어간다

진짜 중복 2.8% (11/391)miricanvas-iui

컴포넌트가 entities 와 dataset.matrix 를 동시에 들고 있을 때, tier 2 투영이 matrix 행을 entity 로 바꿔 라벨 중복 제거 없이 뒤에 붙인다. 유닛 4개가 8개가 된다.

앞 판에서 39건(10.0%)이라 적은 건 과대였다. 39건을 라벨로 대조해 보니 둘로 깨끗이 갈린다 — 부분 겹침은 0건이다.

① 진짜 중복 — 11건 (2.8%)
entities 와 matrix 행의 라벨이 순서까지 완전히 같다. csv-89 Funnel(4개), csv-68 BarChart(3개), csv-15 StackedBarChart(4개) 등.
앞 절반은 라벨만, 뒤 절반은 라벨+수치라 화면에 같은 항목이 두 줄씩 뜬다.

② 축이 달라 중복이 아닌 것 — 28건 (7.2%)
라벨이 하나도 안 겹친다. csv-54 는 entity 가 지표(운영 인지도…)이고 행이 연도(2023년…)다. csv-7 L3 는 entity 가 회사(농심·오뚜기), 행이 지표(매출·연평균 성장률) — 전치 관계다.
이어 붙이는 게 틀린 건 아니지만 유닛 수가 부푼다. 28건 중 3건은 합친 수가 도착 카테고리의 색인 최대 유닛을 넘는다 — csv-6 은 11 > 10, csv-48·50 은 5 > 4 라 후보가 깎인다.

벤더는 제대로 하고 있다. eregion/…/projection.ts:201 의 P4 는 label 이 겹치는 행을 뺀다. 우리 래퍼가 그 앞에서 delete prepared.dataset 을 해 버려 벤더 P4 가 아예 돌지 않는다.

PR #1070 이 ① 을 정확히 덮는다 — 11건 전부. foldMatrixIntoEntities() 하나를 summary-content.ts 에 두고 세 호출부가 쓰게 한다. 라벨 목록이 완전히 같을 때만 셀을 items 로 접고, 아니면 종전대로 이어 붙인다. 부분 겹침이 0건이라 그 엄격한 조건이 실측상 하나도 놓치지 않는다. 벤더로 되돌리는 것(겹치는 행 버리기)은 수치를 통째로 잃어 답이 아니라는 판단도 PR 본문에 적혀 있다.
다만 아직 머지되지 않았고 rebase 가 필요하다. PR 은 OPEN 이고 2026-09-15T10:59Z 에 만들어진 뒤 갱신이 없다. 고치는 파일이 packages/comp-frame/src/summary-content.ts·summary-projection.ts 인데 그 디렉터리는 2026-09-15 이관(D-8/M0-a)으로 사라졌다 — 지금 자리는 src/comp-frame/ 다. 세 파일 다 옮겨 다시 올려야 한다.
② 는 PR 밖이고, 결함인지부터 정해야 한다. 축이 다른 둘을 이어 붙이는 게 맞는지(정본 침묵), 아니면 matrix 를 grid 슬롯으로 남겨야 하는지의 문제다. 유닛 부풀림 3건만 보면 공급 쪽 이야기로 넘어간다.
① 진짜 중복 · csv-89 Funnel
방문
가입
방문 · 인원: 500,000명
가입 · 인원: 120,000명
라벨이 순서까지 같다 → PR #1070 이 접는다
② 축이 다름 · csv-54
entities: 운영 인지도 / 운영 효과성 / 운영 만족도
rows:     2023년 / 2024년 / 2025년
겹치는 라벨 0개 — 중복이 아니다
다만 3+3=6 유닛이 된다

1등이 엉망인데 2등이 멀쩡하다

인접 쌍 1.2% · 검색 4.9%iuiwiki

정렬 키에서 fallback_order — 그 tier 안에서 쿼리 프레임이 몇 번째 칸인가 — 가 cost 보다 앞이다. 같은 tier 안에서 비용이 훨씬 비싼 후보가 1등이 된다.

같은 tier 인접 쌍 3,347개 중 41개에서 앞선 것이 더 비싸고 41개 전부 매치된 카테고리가 다르다. 최대 역전 +435: ComparisonTable 쿼리에서 cost 440짜리가 cost 5짜리를 이긴다.

키 순서는 iui — src/comp-frame/rank.ts:106-118. 다만 이 순서는 정본의 "근접도 순서"를 해석한 것이다.
판단은 mordor-wiki — docs/visual-summary-frame-plan.md:315-352 가 "규약 4절은 상한을 없애면서 '근접도 순서만 지키면' 이라 했는데 tier 2 안에서는 fallback 행의 칸 위치가 정렬 키가 아니다 — 미결" 이라고 적어 뒀다. 근접도가 비용을 얼마나 이겨야 하는지 정본이 말해야 한다.
비용 역전 상위
+435 ListingTable ▸ Versus
+244 Steps ▸ List
+232 Steps ▸ List
+201 ComparisonTable ▸ List

빈 칸이 0점이라 컴포넌트를 잃은 묶음이 1등이 된다

묶음 3.5%miricanvas-iui

묶음 점수는 슬롯 비용의 합인데, 결과가 0건인 슬롯은 비용 0이다. tier 셈에서도 빠지고 「온전한가」 판정에서도 온전하다고 본다. 빈 칸이 채운 칸보다 유리하다.

프리셋 #9(「미식축구 vs 럭비」)의 L2 묶음은 슬롯 3개 중 핵심 ComparisonTable 이 결과 0건인데 점수 6.00 · tier 1 로 1등이다. 표를 온전히 맞춘 L1 단일 카드는 비용 201 로 3등이다. 슬롯 2개 이상 묶음 57개 중 2개가 이 모양이고 둘 다 1·2등을 먹었다.

고칠 곳 — src/comp-frame/documentSearch.ts:497-499(slotScore), :645-651(entryTier), :663-669(entryIsClean). 빈 슬롯에 벌점 상수를 주거나, 슬롯 하나만 비어도 entryIsClean 을 거짓으로 둔다. 문서 층은 Rust 포팅 대상도 아니라 골든이 안 걸린다. 반나절.
카드에 보이는 것 · 1등
결과
없음
✓ ✓
점수 6.00 · tier 1 로 1등

순위 타이브레이커가 전 행 NULL 이다

100%miricanvas-iui

정렬에 두 번 쓰이는 template_idx 가 색인 112,227행 전부 NULL 이다. 적재기에 그 컬럼을 쓰는 코드가 없다 — 채우는 건 build-comp-signs.ts 와 build-post-replace-relayout.ts 뿐이고 build-comp-frames.ts 에는 한 줄도 없다.

fetch 순서의 첫 키가 무력해 실질 design_object_id DESC 다. 타이브레이커도 무력해 비용이 같으면 do_id 큰 것이 1등이다. 랭킹 블루프린트가 List 오탐 가설로 세운 "template_idx DESC 가 1위를 정한다"는 틀렸다.

고칠 곳 — 채우려면 scripts/build-comp-frames.ts 가 layouts.template_idx 를 조인해 넣는다(build-comp-signs.ts 에 같은 조인이 있다). 재적재가 따른다. 안 채울 거면 src/comp-frame/candidateSource.ts:256-258 과 rank.ts:119-127 에서 그 키를 빼고 의도한 타이브레이커로 갈아 끼우는 게 정직하다.
실제 정렬 키
tier
fallback_order
decoration — 전 행 동일
cost
template_idx — 전 행 NULL
design_object_id DESC ← 여기서 갈린다

장식 선호를 적어도 순서가 안 바뀐다

색인 100%miricanvas-iui

frame.decorations 가 색인 112,227행 전부 {ornament:false, background:false} 다. 예외가 0이다.

적재기가 detectDecoration 을 부르긴 하고 역할 표기도 맞다 — Element.Decoration 이 실제 표기라는 걸 boundaryPrompt.ts:155 가 실측 사례로 인용한다. 문제는 그 함수가 경계 서브트리 안만 훑는데 장식·배경은 그 밖에 있다는 것이다.

그래서 rank.ts:116 과 documentSearch.ts:728 의 compareDecoration 은 항상 0을 돌려준다. Visual Summary 가 decoration 선호를 적어도 순서가 한 칸도 안 바뀐다.

고칠 곳 — packages/comp-frame-index/src/frame/component-frame.ts:1198, 1572 가 detectDecoration(boundary) 를 부르는 범위를 넓힌다. 탐지 함수는 packages/comp-frame-shared/src/decoration.ts:9 로 둘 다 벤더 밖이다. 재적재가 따르고 배포 뒤에 한다.
정렬 키에서 하는 일
쿼리: decoration.ornament = prefer
후보 A: ornament false → avoided
후보 B: ornament false → avoided
전부 같은 판정 → 순서 안 바뀜

글이 꽉 찬 후보와 여유 있는 후보를 구분 못 한다

기본 설정 100%miricanvas-iui

capOverflow(가중치 4)와 capChars(2)가 overflow_multiplier 기본 1.0에서 항상 0이다.

논리적으로 확실하다. capOverflow 가 0이 아니려면 lines > cap.lines(cost.ts:286-288) 여야 하는데, 그 조건이 용량 게이트의 배제 조건(cost.ts:344)과 정확히 같다. 게이트를 통과한 후보는 정의상 이 항목이 0이다. capChars 도 softAt = 1.0 이라 같은 처지다.

결과적으로 글이 상자에 빡빡하게 들어가는 후보와 여유 있게 들어가는 후보가 같은 점수를 받는다.

고칠 곳 — src/comp-frame/cost.ts:286-288, 344 에서 게이트 배수(예: 1.2)와 소프트 임계(1.0)를 분리한다. 다만 2026-09-09 「조금이라도 넘기면 탈락」 결정과 충돌하므로 제품 결정이 먼저다. 임계 원본은 벤더 audit.ts:366 의 DEFAULT_AUDIT_OPTIONS.overflow 지만, 게이트 배수는 우리 옵션이라 벤더는 안 건드린다.
지금 구분 못 하는 둘
분기별 매출 성장률 추이 분석 보고
매출 추이
같은 점수를 받는다

규칙 (e) 텍스트 보존이 런타임에서 죽어 있다

런타임 100%miricanvas-iui

src/comp-frame/align.ts:617-621 의 규칙 (e)는 ctx.preserveTexts 가 있어야 짧은 원문(단위·기호 같은 것)을 보존한다. 그런데 저장소 전체에서 이걸 채우는 곳이 scripts/frame-oracle/dump-frame-goldens.ts 하나뿐이다.

search.ts·candidateSource.ts·useFrameSearch.ts 어디도 안 넘긴다. 골든을 뜰 때만 살아 있고 화면에서는 한 번도 안 돈다. 그래서 골든은 통과하는데 실제 대치는 다르게 동작한다.

QnA 의 marker 슬롯 3건이 blank 로 떨어지는 것도 이 경로다 — 보존 규칙이 돌았으면 살았을 자리다.

고칠 곳 — src/comp-frame/rank.ts 가 costOf·align 을 부를 때 preserveTexts 를 채워 넘긴다. 무엇을 넣을지는 dump-frame-goldens.ts 가 이미 하고 있으니 그대로 베끼면 된다. 골든 재덤프가 따른다(지금 골든은 보존이 도는 전제로 떠 있다).
preserveTexts 를 채우는 곳
dump-frame-goldens.ts ✓
search.ts ✗
candidateSource.ts ✗
useFrameSearch.ts ✗
골든만 통과하고 화면은 다르게 돈다

규칙 (d) 순번 채우기가 채울 자리가 없다

노출 7.9% · 1위 0.0%miricanvas-iui

순번 카테고리(Steps·Staircase·Timeline)를 쓰는 검색이 31건(7.9%)인데, marker 슬롯을 가진 행이 1위에 온 검색은 0건이고 창 안에도 7건(1.8%)뿐이다. 규칙 (d)가 실제로 도는 일이 거의 없다.

색인 쪽을 보면 이유가 보인다. marker 슬롯을 가진 행이 1,282개(1.14%)뿐이고 ProcessFlow_Steps 3,008행 중에는 2개다. 반면 Marker 역할의 잔여는 33,193개다 — 마커 텍스트는 널려 있는데 IIS 가 슬롯으로 안 잡는다.

부수로 src/comp-frame/orderedCategories.ts:18-21 의 접두 목록(ProcessFlow_·Progression_·TimelineSchedule_)에 Cycle_ 이 빠져 있다. 주석은 벤더 reads.content 에 order 계열 필드가 없다는 걸 근거로 셋이면 끝이라 적었는데, 그건 Cycle 이 순서를 갖느냐와 다른 질문이다. 다만 위 숫자 때문에 실효 반경이 거의 0이다.

근본은 색인 — packages/comp-frame-index/src/frame/component-frame.ts:1154-1157 이 Marker 를 orphanOtherTexts 로 세기만 하고 슬롯에 안 넣는다. 이걸 marker 슬롯으로 적재하면 규칙 (d)도 살고 Marker 덮임도 같이 없어진다. 재적재가 따르고 배포 뒤에 한다. Cycle_ 추가는 10분이지만 그것만으로는 아무것도 안 바뀐다.
마커는 있는데 슬롯이 없다
Marker 역할의 잔여
33,193개
marker 슬롯
2,393개 / 1,282행 (1.14%)
Steps 3,008행 중 슬롯 있는 건 2개

카테고리는 맞는데 그 모양의 행이 하나도 없다

5.6% (22/391)miricanvas-iui

얕은 풀과 다른 문제다. tier 1 카테고리는 성립했는데, filter.ts:175 의 dataset_kind 하드 필터를 통과하는 행이 그 카테고리에 0개인 경우다. 22건(5.6%)이다.

ListingTable 이 전형이다 — 색인 485행 중 matrix 인 건 57행뿐이고 나머지 428행은 텍스트로 그린 표라 dataset: none 이다. matrix 쿼리는 그 428행을 영영 못 본다. 반대로 entities 형 쿼리는 57행을 못 본다.

그래서 tier 1 이 성립해도 결과가 tier 2 에서만 나온다. 배지는 tier 2 인데 사용자는 왜인지 모른다.

고칠 곳은 둘 — ① 색인 적재(scripts/build-comp-frames.ts)가 텍스트 표에서도 grid 를 뽑아 dataset: matrix 로 올린다. ② 또는 src/comp-frame/filter.ts:175 의 dataset_kind 를 하드 필터에서 빼고 cost 로 내린다. ②는 matrix 표 쿼리 결함과 얽히니 함께 결정해야 한다.
ListingTable 485행의 구성
dataset: none — 텍스트로 그린 표
428행 · matrix 쿼리가 못 본다
dataset: matrix
57행

피라미드 꼭대기와 바닥이 바뀐다

쿼리 1.3% · 색인 80행 중 78miricanvas-iui

뒤집으라는 신호는 나오는데 적용하는 코드가 없다. 벤더 iis/propertyMatch.ts 가 reverse: true 를 제대로 내는데, rank.ts:240 은 이미 뒤집지 않은 프레임으로 align 을 돌린 뒤고 :373 은 결과에 싣기만 한다.

게다가 cost.ts:415-424 는 쿼리에 적힌 키만 대조한다. apex 를 생략하면 충돌이 0이라 문서 순서 그대로 정렬된다. 색인 80행 중 78행이 apex: first 인데 정본 기본값은 last 다.

둘 다 iui 에서 고친다 — 벤더는 안 건드린다. ① src/comp-frame/rank.ts 에서 속성 대조를 align 앞으로 빼고 plan.reverse 면 units(와 matrix rows)를 뒤집는다. ② src/comp-frame/cost.ts:418-420 에서 paramSpecs.default 를 requested 에 채운다. ①이 먼저다 — ②만 하면 충돌은 보이는데 여전히 역전이다. 함께 갱신: rank·cost 골든.
카드에 보이는 것
세부 실행 과제
중기 전략
최상위 비전
꼭대기에 올 문장이 바닥에 있다

레벨 문서를 합치면서 제목을 잃는다

합쳐진 그룹의 36.8%miricanvas-iui

L1·L2·L3 가 구조적으로 같으면 한 문서로 합치고 첫 레벨을 대표로 쓴다. 코드는 "어느 것을 남기든 검색에는 상관없다"고 적어 뒀는데 틀렸다 — 제목은 위성 슬롯이 되어 titleDropped 비용을 좌우하고 카드의 제목 자리에 그대로 들어간다.

합쳐진 68그룹 중 25그룹(36.8%)이 레벨 간 제목이 다르다. 잘못 합쳐진 건 0건이다. 반대로 갈린 268쌍 중 16쌍은 셀·라벨이 완전히 같고 열의 role·unit·axis 메타만 다르다.

고칠 곳 — src/comp-frame/documentSearch.ts:263-280 의 redactStructure 가 entities·relations 만 가리고 columns·dataset·params 는 원문 그대로 키에 넣는다. 열 메타를 함께 가리면 된다(작다). 제목은 :158-163 인데 정책 결정이 먼저다 — 어느 제목을 쓸지, 아니면 제목별로 따로 검색할지.
카드에 보이는 것
L1 · L2 · L3 합침
강점·약점·기회·위협 분석
지역 행사 SWOT 분석
L3 제목은 검색도 표시도 안 된다

중첩 사다리는 상한이 없고, 색인에는 받아 줄 행이 없다

색인 0.14% · 프리셋 0%miricanvas-iui

중첩 컴포넌트는 N1 → N2(강등 조합 전부) → N3/N4 → N5 순으로 내려간다. 시도 상한이 없다 — nestedSearch.ts:43-44 에 "No attempt quota"라고 의도적으로 적혀 있다.

후보 0인 공급에 실제 함수를 돌려 셌다. List 아래 Staircase 자식이 1~5개일 때 7 · 52 · 277 · 1,402 · 7,027회다. count 왕복 중앙값 70ms 면 자식 5개에 8분이다.

그런데 색인에 중첩 경계를 가진 행이 154개(0.14%)뿐이다. 경계 4개 이상은 0행이라 자식 4개짜리 질의는 1,402회 중 1,400회가 반드시 빈 응답이다.

프리셋 403조각에 중첩이 0개다 — 생성기가 entity.components 를 안 쓴다. 이 경로는 손으로 쓴 YAML 에서만 닿고 프리셋 리포트로는 영영 못 잰다.

고칠 곳 — src/comp-frame/nestedSearch.ts. 값싼 선행 검사: 질의의 중첩 카테고리 조합을 만족하는 행이 있는지 count 한 번(또는 정적 표)으로 보고 N1·N2·묶음 시도를 통째로 건너뛴다.
자식 수 → 시도 횟수
자식 1개7
자식 2개52
자식 3개277
자식 4개1,402
자식 5개7,027
색인에 경계 4개 이상인 행은 0개다

검색이 멈춰도 이유가 화면에 안 뜬다

코퍼스 0% · 구조적 위험miricanvas-iui

관계 해석이 하나라도 실패하면 쿼리 프레임을 통째로 버리고 빈 결과에 meta.error 를 달아 돌려준다. 그런데 meta.error 를 읽는 곳이 src/comp-frame 전체에 없다. useFrameSearch.ts:100 의 주석 한 줄뿐이다.

of 소비처 여섯을 다 확인했는데 하나도 실패로 끝나지 않는다. cost.ts 에 .of 참조는 0건이다. 이 코퍼스에서는 0건이고 of 를 쓰는 17건(4.3%)이 전부 label 로 적혀 있다. 빈도가 아니라 침묵이 문제다.

고칠 곳 — src/comp-frame/useFrameSearch.ts:217-221 에서 응답의 meta.error 를 componentErrors 로 올린다. 열 줄 안팎이다. tiers 가 [] 일 때는 meta.error 조차 없으니, 벤더 establish 를 읽기 전용으로 다시 불러 사유를 모으는 헬퍼가 따로 필요하다(새 파일, 스무~서른 줄).
카드에 보이는 것
검색 결과 없음
왜인지는 안 나온다

묶음·중첩 경로의 나머지

묶음 3.5% 또는 프리셋 0%miricanvas-iui
  • 슬롯 키 겹침 (묶음 3.5%) — 슬롯 카드 키가 do_id|node_id 뿐이라 두 슬롯이 같은 결과를 고르면 React 키가 겹치고 iframe 큐 키도 공유한다. #12 의 L2 묶음은 슬롯 9개 중 두 쌍이 같고, L2·L3 묶음이 같은 1등을 고른 프리셋이 134 중 16이다. FrameGroupCard.tsx:369-371, 413-416
  • peel 이 부모 잔여를 엉뚱한 자식에 붙인다 — 부모의 모든 entity 를 펴서 children[0] 에만 붙인다. nestedSearch.ts:196-213
  • 문서 병합 1위가 미대치 (문서 32.6%) — 묶음 점수가 슬롯 비용의 합이라 슬롯이 둘이면 두 비용을 합쳐 단일 카드와 겨룬다.
  • N2·묶음 결과가 언제나 tier 1 · 보기 모드가 반쯤 죽는다 · 첫 완주 분할 우선 — 중첩 입력에서만. query-frame.ts:402-448 · documentSearch.ts:412-417 · nestedSearch.ts:168-181
전부 iui 다. 벤더도 정본도 걸리지 않는다.
낡은 주석 넷
"L3 는 L2 처럼 편다" — N 사다리가 생겼다
"⊂ #k 배지에 쓴다" — 배지는 지웠다
"◂ ▸ 버튼" — 이미 없다
"대표 문서는 상관없다" — 틀렸다

화면·비동기 경로

빈도 재지 않음iuiaippt
  • 큐 리셋 고아 카드 — 검색 한 번에 iframe 큐가 통째로 비워지는데, 그 순간 waiting 이던 카드는 pending 에서 빠지고 phase 는 그대로다. error 에서 나가는 전이도 하나도 없다. useIframeQueue.ts:23-26 · FrameThumbnail.tsx:521-527, 727
  • REQUEST 2회 전송 — 리셋은 setPhase(idle) 을 예약만 하고 REQUEST effect 는 클로저의 phase === 'loaded' 를 보고 즉시 보낸다. 첫 전송은 옛 색상 doc 을 싣는다. FrameThumbnail.tsx:715-727, 741-790
  • 미대치 표시 위치 어긋남 — renderedOverlayBoxes 가 루트 배치만 실측하고 노드 상자는 원본 것을 쓴다. resultMaps.ts:387 의 allowedIdsFromResult 가 바로 이 용도로 만들어졌는데 아무도 안 부르는 죽은 코드다. untouchedOverlay.ts:259-291
  • 자산 캐시 미충전 — 데이터셋 토글이 캐시를 비우는데 가져오기 effect 는 옛 클로저로 need = ∅ 를 낸다. 실패한 id 도 doc: null 로 영구 캐시된다. useResultAssets.ts:374-376, 385, 399-426
  • Cycle·SWOT 이 프롬프트 본문에 0회 — 「List 는 마지막 수단」 표에 순환 행이 없어 Cycle→Steps 오분류가 코퍼스 판정에 4건 있다. 이 저장소 사본(generate/prompts/v2/system.md)에서 고치면 이 화면만 바뀌고, 실서비스는 aippt generator/prompt.ts 를 고쳐야 한다.
  • LOADED 10초 초과가 「서버 실행」으로 굳는다 · 형제 축소가 빈 슬롯 임시 문구를 못 본다 · 별칭이 진짜 텍스트를 가린다 — 코드 읽기로 확정했고 빈도는 안 쟀다.
앞의 셋은 같은 패턴이다 — 큐 리셋 고아 카드 · REQUEST 2회 전송 · 자산 캐시 미충전 모두 한 커밋 안에서 effect 가 setState 를 예약만 하고, 같은 커밋의 다른 effect 가 옛 클로저 값을 읽는 구조다. 하나씩 고치기보다 FrameThumbnail.tsx·useResultAssets.ts·useIframeQueue.ts 셋을 묶어 「상태 전이는 ref 로 읽는다」로 정리하는 편이 낫다. 전부 화면 코드라 골든도 벤더도 안 걸린다.
Cycle·SWOT 프롬프트만 aippt — 이 저장소 src/comp-frame/generate/prompts/v2/system.md 에서 고치면 이 화면에서만 효과를 본다. 실서비스에 반영하려면 aippt src/lib/visual-summary/generator/prompt.ts 를 고쳐야 한다. 「List 는 마지막 수단」 표에 순환·SWOT 두 행을 더하는 게 전부인데, generate/prompt.test.ts 의 REQUIRED_RULES 가 문구를 잠그니 지우지 말고 추가만 한다.
호출자 0인 export
allowedIdsFromResult ← 기능 구멍
retainOnly
bulkInsertPendingGenerations
hasOpenAiApiKey
makeFixtureRows
CSV_PRESET_ID_PREFIX
08

못 잰 것

① 결과를 들여다보는 지표는 전부 top 10 창 안에서만 참이다 — 실제 결과는 17,520건인데 기록된 건 3,799건이다. clean_first 시뮬레이션은 그래서 개선폭의 하한이다. ② items: 누출 조인 플래그가 첫 유닛만 본다 — 3.6%는 하한이다. ③ Marker 잔여 행 중 몇 개가 1~2자 글리프인지는 스냅샷에 글자 수가 없어 못 갈랐다. ④ 화면·비동기 경로 여덟 건은 코드 읽기로 확정했고 브라우저에서 재현하지 않았다. ⑤ 중첩 경로는 프리셋으로 못 잰다 — 403조각에 중첩이 0개다.
범위. /comp-frame 화면 하나만 봤다. rust/comp-pass 구현과 src/visual-summary 는 제외했다 — 그래서 코어 모듈 동결 제약은 TS 골든 갱신 하나로 줄어든다. 단 comp-frame-dev-snapshot.jsonl.zst 는 운영 색인 덤프라 데이터로만 썼다.