증분 정보 구조화기. 미리캔버스에 신규 기능이 생겼을 때 자체 모델(Structuriser)을 재학습하지 않고, 이미 뽑아 둔 Old RLSC 위에 델타만 얹어 New RLSC를 만드는 2단계 추출 레이어다. 아키텍처는 2026-05-26에 확정됐고 코드 구현체는 아직 없다 — 그래서 이 문서의 절반은 "델타가 꽂힐 자리가 코드에서 어디인가"다.
rlsc-worker.ts → rlsc_results → extract-design-object-worker.ts 구간.src/lib/incrementalInformationStructuriser/ 는 존재하지 않는다. MOR-1425(skeleton)가 나머지를 blocks 하고, 2026-07-24 기준 6월 중순부터 멈춰 있다.목차
기존 파이프라인은 ALSC → Structuriser → RLSC 한 방이다.
IIS는 그 뒤에 한 칸을 더 끼운다 — 기존 결과물을 고치지 않고 입력으로 받아서,
신규 정보만 더한 새 결과물을 낸다.
| 단계 | 입력 | 출력 | 비고 |
|---|---|---|---|
| Structuriser (기존) | ALSC | Old RLSC | 자체모델 / GPT — 변경 최소화 |
| IIS | Old RLSC (+ ALSC · sheet context) | New RLSC | 델타: 신규 role · type · 속성 |
| (미래) New Structuriser | ALSC | New RLSC | Old→New 를 학습 데이터로 재학습 |
미리캔버스에 신규 차트 타입이 붙거나, 도형에 텍스트를 넣을 수 있게 되거나, 보조텍스트·BigNumber 같은 새 텍스트 role이 생기면 선택지는 원래 둘뿐이었다.
Case 4 MLLM을 신규 element/role 마다 다시 학습한다.
비용 · 리스크 · 리드타임이 크다. 프롬프트·모델을 건드리면 영향 범위를 예측하기 어렵다 — 기존 추출이 어떻게 흔들릴지 모른다.
일단 둔다.
신규 기능 정보가 RLSC에 영원히 반영되지 않는다. 검색·대치·컴포넌트 추출이 모두 RLSC를 근거로 돌기 때문에, 그만큼 정합성 공백이 남는다.
Old RLSC를 읽기 전용 입력으로 두고, 신규 정보만 추가해 New RLSC를 만든다.
기존 Structuriser는 손대지 않으니 회귀 위험이 격리되고, 쌓인 Old→New 쌍이 나중에 재학습 데이터가 된다.
신규 요소가 전부 IIS 대상은 아니다. ALSC 변환만으로 결정적으로 처리되면 IIS는 불필요하다 — 그 경로를 blueprint 는 Native Element path 라 부른다.
| 케이스 | 대응 | 예 |
|---|---|---|
| ALSC 변환만으로 처리 (결정적) | Native Element path — IIS 불필요 | ExtendableShapeItem → SVG (MOR-1416) |
| RLSC role · 속성 추가 | IIS 2단계 추출 | 보조텍스트, BigNumber, 신규 ChartType |
LLM을 부르기 전에 결정적 규칙으로 처리할 수 있는 델타를 먼저 뗀다.
차트의 BarType/ChartType 분류처럼 시트에 답이 적혀 있는 것은 rule layer가,
가짜 차트 판별처럼 rule의 한계 영역만 LLM이 맡는다.
이 원칙은 이미 이 레포의 습관이다. 바디 컴포넌트 3축 분류에서 Information Type과 Visual Focus는 모델에게 묻되 답을 버리고 코드로 유도한다 — 규칙으로 결정되는 값을 모델에 맡기면 흔들린다는 같은 이유다.
/** * Component 1순위 → Information Type. * * 세 축을 각각 모델에게 물으면 "Component 는 Timeline 인데 Information Type 은 Comparison" * 같은 체계 위반이 나온다. 1순위가 정해지면 상위 분류는 하나로 결정되므로 코드에서 유도해 * 위반을 구조적으로 차단한다. */ export const IT_OF_COMPONENT: Readonly<Record<ComponentTypeValue, InformationTypeValue>> = { [ComponentType.BigNumber]: InformationType.Enumeration, [ComponentType.Timeline]: InformationType.Sequence, // … }; /** 구조가 강제하는 Visual Focus. 프롬프트에도 같은 규칙이 있지만 모델이 빠뜨릴 수 있어 코드에서 확정한다. */ export const FOCUS_OF_COMPONENT = { [ComponentType.BigNumber]: VisualFocus.Metric, // 수치가 주인공인 것이 이 타입의 정의 [ComponentType.Timeline]: VisualFocus.Index, // 날짜·연도 레이블이 각 항목의 표식 };
IIS의 rule layer가 새로 발명할 것은 없다 — 이 패턴을 델타 판정에 옮겨 붙이는 것이다.
범용 IIS 하나로 모든 델타를 처리하지 않는다. 차트 전용 · 텍스트 role 전용처럼 좁게 나누면 프롬프트가 짧아져 비용이 내려가고 정확도가 올라간다. Jira 구조가 그대로 이 분할을 따른다 — MOR-1425가 skeleton, 1426·1427·1448이 각 전용 Structuriser다.
각 항목마다 "코드에서 지금 무엇이 비어 있는가"를 실측으로 붙였다. 델타의 목적지가 특정되지 않으면 IIS는 설계도로만 남는다.
차트 델타의 rule layer 는 사실상 이미 있다. 시트의 vizType·chartType 문자열을
캐논 문자열로 정규화하는 결정적 매핑이 ALSC 추출 단계에 박혀 있고, 매핑에 없는 신규 타입은
ChartType.Unknown sentinel 로 떨어져 명시적으로 표시된다.
즉 "신규 차트 타입이 들어왔다"는 신호를 코드가 이미 낸다 — IIS 가 받을 트리거가 준비돼 있는 셈이다.
/** * 원본(레거시 소문자 스네이크 / 엔진 vizType) → 캐논(RLSC ChartType 값) 정규화 매핑. * 게이지(GaugeItem)의 vizType 은 세부(HOR/HALF/ARC/FULL)까지 있으나 RLSC 에서는 * 막대형(BAR_GAUGE)·원형(CIRCLE_GAUGE) 두 종으로 합쳐 표현한다. */ const LEGACY_TO_CANONICAL: Record<string, string> = { vertical_bar: 'BAR_CHART_VER', horizontal_bar: 'BAR_CHART_HOR', BAR_GAUGE_HOR: 'BAR_GAUGE', BAR_GAUGE_VER: 'BAR_GAUGE', CIRCLE_GAUGE_HALF: 'CIRCLE_GAUGE', /* … */ }; /** * 매핑 안 되거나 타입이 없으면 `ChartType.Unknown` 을 반환한다. * 과거엔 `VerticalBar` 로 떨어뜨렸으나, 미지원 신규 타입·빈 차트·오타가 * 세로막대로 둔갑해 문제가 조용히 가려지는 문제가 있어 명시적 sentinel 로 바꿨다. */ export function normalizeChartTypeToSchema(rawType: string): ChartType { const canonical = LEGACY_TO_CANONICAL[rawType] ?? rawType; return CHART_TYPE[canonical] ?? ChartType.Unknown; }
BarType 은 별도 필드가 아니다. 가로/세로 구분은 원문 타입 문자열과 axisFlip 을 조합해
seriesAxis: 'rows' | 'columns' 로 환원된다
(:131-142).
RLSC 스키마가 차트에서 들고 있는 값은 네 개뿐이다 —
chartType · rowCount · columnCount · seriesAxis
(layoutStructure.ts:246-261).
실제로 터진 적이 있다. 2026-06-29 프로덕션에서 에디터가 차트 데이터 위치를
chartProps → dataVizProps 로 옮겼는데 추출 코드가 옛 자리만 읽어
차트 노드 하나 때문에 레이아웃 39개의 추출이 통째로 실패했다. 신규 차트 타입이 아니라
시트 내부 구조가 바뀐 경우였고, 해법은 IIS가 아니라 입력 매핑을 넓히는 것이었다 —
RLSC 출력 모양은 그대로 두고 읽는 자리만 늘렸다.
// - 구버전: props.chartProps ({ type, dataSource, options.axisFlip ... }) // - 신버전(version 3.0.0~): props.dataVizProps ({ vizType, datasource, ... }) // 둘 다 없는 ChartItem 도 prod 입력으로 존재하므로 옵셔널 체이닝으로 방어한다. const chartProps = props?.chartProps; const dataVizProps = props?.dataVizProps; const rawType = chartProps?.type ?? dataVizProps?.vizType ?? ''; const matrix = chartProps?.dataSource ?? dataVizProps?.datasource ?? []; // … const chartType = normalizeChartTypeToSchema(rawType); if (chartType === ChartType.Unknown) { /* 로깅 — 조용히 가려지지 않게 */ }
가짜 차트 판별도 이미 rule 로 한 겹 있다. 유효 컴포넌트 v3.4 · v3.5 정의의 조건 2b/2c 가
"표/차트면 진짜 Role.Element.* element 가 있어야 한다"로 가짜 표·차트를 풀에서 제외한다
(valid-component-meta/v3_5.ts:56-66).
IIS가 LLM으로 맡을 몫은 이 rule 이 못 잡는 잔여다.
RLSC role 어휘의 정본은 워크스페이스 패키지
packages/structured-layout/src/role-v2.ts 다. 여기에
Role.Element 8종 · Role.LayoutContainer 12종 · Role.Page 5종이 있고,
린터의 isValidRole() 이 이 네임스페이스를 재귀 순회해 유효 집합을 만든다.
보조텍스트도 BigNumber도 여기에 없다 — 델타가 꽂힐 자리는 정확히 이 파일의 Element 블록이다.
export const Element = { Title: 'Role.Element.Title', Subtitle: 'Role.Element.Subtitle', Highlight: 'Role.Element.Highlight', Description: 'Role.Element.Description', Separator: 'Role.Element.Separator', Marker: 'Role.Element.Marker', Decoration: 'Role.Element.Decoration', Background: 'Role.Element.Background', } as const; // ← 보조텍스트 · BigNumber 없음
BigNumber 라는 이름은 코드에 이미 존재한다 — 단
RLSC 텍스트 role 이 아니라 바디 컴포넌트 3축 분류(VLL)의 Component Type 17종 중 하나다
(component-labels.ts:16-34).
labels.ts 의 VLL 14종과도 이름이 겹치지만 별개 상수라고 파일 헤더가 못 박아 둔다.
MOR-1427 이 요구하는 것은 세 번째 어휘 — Role.Element.* 에 들어갈 텍스트 role 이다.
이름 충돌을 그대로 두면 나중에 셋을 구별할 수 없다.
보조텍스트의 현재 대체 경로. 2026-06-06 스레드에서 정원석은
Header/Footer 지정 시 제거보다 Role 교체가 안전하다며
"IIS로도 가능, 당장은 Description 전환"으로 정리했다. 실제 린터에도 그 규칙이 있다 —
INVALID_TEXT_ROLE_IN_PAGE_HEADER_FOOTER 는 PageHeader/Footer 내부 Text Decoration 을
Description 으로 바꾼다
(ruleDefinitions.ts).
보조텍스트 role 이 없어서 Description 으로 뭉개고 있는 상태가 곧 정합성 공백의 실체다.
Layout Type 은 유효 컴포넌트 풀의 포함·제외 기준으로 직접 쓰인다.
구조 시각화 전용 타입 일부(Graph · VennDiagram · LayeredDiagram · Gantt · Quadrant · ZStack)가
v3 정의에서 의도적으로 제외돼 있고, 그 제외분을 다시 넣었을 때 Bad/Perfect 비율이 어떻게 변하는지가
별도 실험(MOR-1461 · MOR-1477)으로 돌고 있다. 즉 Layout Type 은 검색 품질에 직결돼서,
신규 타입이 RLSC에 안 들어오면 그 페이지들은 풀에서 조용히 빠진다.
블루프린트에는 이 티켓이 없다. 2026-05-26 blueprint 의 workstream 은 MOR-1425·1426·1427 셋뿐이고, MOR-1448 은 2026-07-24 논의 문서에서 "I.I.S.(MOR-1425/1448/1426/1427) 언제 다시 시작할지" 로만 등장한다 — 나중에 IIS 하위로 붙은 항목이다.
ExtendableShapeItem 은 ALSC 변환 테이블에서 결정적으로 SVG 로 떨어진다.
LLM이 개입할 판단이 없으니 IIS 대상이 아니다.
export const JSON_TYPE_TO_SCHEMA_TYPE = { TextItem: ContentElementKeyType.Text, ShapeItem: ContentElementKeyType.SVG, ExtendableShapeItem: ContentElementKeyType.SVG, // ← Native path (:41) ChartItem: ContentElementKeyType.Chart, GaugeItem: ContentElementKeyType.Chart, // … };
단, "확장형 도형" 전체가 끝난 문제는 아니다.
Native 표현이 가능한 ExtendableShapeItem 만 IIS 불필요이고,
텍스트를 품은 확장형 도형은 엔진 쪽에서 별도 분리 경로를 탄다
(web-2 SplitExtendableShapeItemWithText).
"RLSC 추출과 컴포넌트 추출 사이"를 코드로 옮기면 두 워커 사이다.
rlsc-worker 가 RLSC를 만들어 rlsc_results 에 쓰고,
extract-design-object-worker 가 그걸 읽어 컴포넌트를 뽑는다.
IIS 는 이 두 워커 사이에 끼거나, rlsc_results 를 다시 읽는 두 번째 패스로 들어간다.
rlsc_results · rlsc_meta.extractorVersion (:379)rlsc_results 확장 vs 별도 table)가 먼저 정해져야 한다 — 그게 MOR-1425 다.
다행히 versioning 과 source 구분의 자리는 이미 뚫려 있다.
rlsc_meta.extractorVersionrlscSource 4종'llm' | 'custom' | 'agentic' | 'human' 중 어느 RLSC를 쓸지 고른다. New RLSC 는 다섯 번째 값이 된다.IIS 는 백지에서 시작하지 않는다. "이미 뽑은 RLSC 를 나중에 고친다"는 행위, "어휘를 버전으로 이중화한다"는 행위, "재학습 없이 유지되는지 판정한다"는 행위가 각각 프로덕션 코드로 존재한다. IIS 가 하는 일은 이 셋에 LLM 을 더하는 것이다.
CUSTOM_RLSC_TYPE_REMAP_FROM_SHEET
External Custom Structuriser(MOR-1580)가 남긴 유효하지 않은 type(예: Unknown)을,
시트에서 nodeType 을 조회할 수 있을 때만 MOR-1326 매핑으로 고친다.
구조가 IIS 와 똑같다 — 이미 나온 RLSC 를 입력으로 받아 델타만 고치고,
원본(rlsc_results custom)은 건드리지 않고 결과를 linter_results.rlsc 에만 쓴다.
다른 점은 하나, LLM 이 없다는 것뿐이다.
custom-rlsc-type-remap-from-sheet.ts:10-34 — "sheet 조회 불가하거나 매핑 결과가 유효 type이 아니면 skip". 실패 시 조용히 물러나는 이 계약도 IIS 가 그대로 물려받을 만하다.
src/common/schema/role.ts 의 Role.Presentation.* 계열(v1)과
packages/structured-layout/src/role-v2.ts 의 Role.* 계열(v2)이
동시에 존재하고, detectRoleVersion() 이 값만 보고 어느 세대인지 판별한다.
린터의 유효 집합은 v2 만 쓴다 — getAllRoleValues() 주석이
"v1 role 값들 추가하지 않음" 이라고 못 박는다.
schema.utils.ts:128-152 · linter/index.ts:200-216 — Old/New RLSC 를 어휘 세대로 구분하는 패턴이 이미 검증된 상태다.
structuriser-verifyBackground Extractor 도입으로 Structuriser 입력이 full ALSC → foreground ALSC 로 바뀌었을 때 재학습 없이 RLSC 추출이 유지되는지를 페이지 단위로 자동 판정하려고 만든 모듈이다(MOR-1472). 3계층 판정 — ① 유효성 게이트 ② baseline 대비 변화 ③ 귀책(structuriser 인가 BE 인가) — 이 구조는 IIS 델타 검증에 그대로 재사용할 수 있다. 질문만 바꾸면 된다: "BE 때문인가 Structuriser 때문인가" → "IIS 델타 때문인가 원본 RLSC 때문인가".
src/lib/incrementalInformationStructuriser/ 는 존재하지 않는다. 2026-08-26 기준으로
aippt-prisonbreak 전체에 incremental 이름의 소스 디렉터리가 없고,
IIS 는 문서 9편(docs/projects/mordor/)에만 산다.
miricanvas-web-2 에는 Structuriser 라는 문자열조차 없다 — IIS 는 전적으로 MORDOR 영역이다.
| 항목 | 상태 (근거 시점) |
|---|---|
| 아키텍처 | 확정 — 2026-05-26 회의 (Confluence 통합 회의록 + IIS 개발 논의) |
| 코드 | 없음 — 2026-06-11 기준 그대로, 2026-08-26 실측 확인 |
| 블로킹 구조 | MOR-1425(skeleton)가 MOR-1426 · 1427 · 1448 을 blocks |
| 담당 | q3 TPM 이예림 → 류민 이관, 실무 후보 이강윤 |
| 진행 | 6월 중순부터 멈춤 — 2026-07-24 논의에 "류민님께 물어볼 것: I.I.S. 언제 다시 시작할지" |
| 6월 말 우선순위 | IIS 개별 feature 보다 MOR-1421 전체 재추출이 앞. 이어 MOR-1422 Search Signature v2 pool (blocking MOR-1423 · 1424) |
| 차트 IIS 시점 | 7월이 현실적 — 신규 템플릿 디자인·summarizer 선행 필요 |
| 대체된 접근 | MOR-1409 (rlscDiffChecker / updater) Hold — IIS 2단계 추출로 대체 |
| scope 재정렬 | MOR-1042 (BarType) · MOR-1317 (ChartType) → MOR-1426 으로 흡수 |
rlsc_results 를 확장할지 별도 table 을 둘지가 미결이다. 이게 §5 의 삽입 지점 A/B 를 결정한다.
BigNumber 이름 충돌VLL Component Type 17종에 이미 BigNumber 가 있다. RLSC 텍스트 role 로 같은 이름을 쓰면 세 어휘(VLL 14종 · Component 17종 · Role.Element)가 구별 불가능해진다.
role-v2.ts 는 @miri-unicorn/structured-layout 워크스페이스 패키지다. role 하나를 더하면 이 패키지를 쓰는 45개 파일이 함께 영향을 받는다.
줄 번호는 아래 커밋 기준 실측이며, 링크는 permalink 다. 전부 워킹트리가 해당 커밋과 같은 상태에서 읽었다.
① role 어휘가 두 개다. blueprint 는 "RLSC role 추가"라고만 쓰지만, 코드에는
Role.Presentation.*(v1)과 Role.*(v2)이 공존하고 린터 유효 집합은 v2 만 쓴다.
신규 role 은 packages/structured-layout/src/role-v2.ts 에 넣어야 하고, 그건
src/ 밖의 워크스페이스 패키지 변경이다.
② BigNumber 는 이미 코드에 있다 — 단 RLSC role 이 아니라 VLL Component Type 이다. 정의문이 말하는 "신규 텍스트 role BigNumber"와 같은 이름 · 다른 축이다.
③ MOR-1448 은 blueprint 에 없다. 2026-05-26 workstream 은 1425·1426·1427 셋이고, Layout Type 증분은 2026-07-24 논의 문서에서야 IIS 하위로 등장한다.
④ MORDOR 가 가리키는 엔진 SSoT 경로가 로컬 web-2 체크아웃에 없다.
추출기 주석은 신규 차트 구조의 정본을
packages/engine/node-props-schema/src/nodes/DataVizPropsSchema.ts 로 지목하지만
(types.ts:288-295),
feature/mordor 브랜치 a5e7ed9(2025-12-08) 체크아웃에는 그 src 가 없고
빌드 산출물 dist/type/…/DataVizPropsSchema.d.ts 만 있다. 같은 체크아웃의 엔진
CHART_TYPE 은 6종뿐인데 MORDOR 는 이미 10종 + UNKNOWN 을 매핑한다 —
엔진에서 먼저 늘고 MORDOR 가 뒤따르는 구조이므로, 이 표의 web-2 줄 번호는
현재 엔진 상태가 아니라 이 체크아웃 기준으로 읽어야 한다.
신규 기능이 생길 때마다 자체모델을 재학습하는 것은 비싸고, 방치하면 RLSC 에 정합성 공백이 남는다. IIS 는 그 사이의 제3의 경로다 — 기존 결과물을 건드리지 않고 델타만 얹어 정합성을 메우고, 그렇게 쌓인 Old→New 쌍이 곧 재학습 데이터가 되어 New Structuriser 를 만든다. New Structuriser 가 서면 IIS 는 사라진다.
코드 관점에서 남은 일은 셋이다 — ① rlsc_results 에 Old/New 를 어떻게 담을지 정하고
(삽입 지점 A/B), ② role-v2.ts 에 신규 role 을 어떤 이름으로 넣을지 정하고,
③ structuriser-verify 의 3계층 판정을 델타 귀책으로 돌려쓰는 것.
아키텍처는 이미 확정됐고, 자리도 이미 뚫려 있다.