Figma 퍼블리싱 파이프라인 09. v5 → v6: 세션, 스코프, 안정성
v5에서 뭔가 아쉬웠나?
v5의 핵심은 "LLM이 비교하지 않는다" 였다. Figma JSON과 코드를 LLM에게 던져서 "이거 비교해줘"라고 하면 부정확하다는 걸 깨달았고, 그래서 Design IR → Code IR → Normalize → Mapping → Diff Engine이라는 파이프라인을 만들었다. 비교는 기계가, 설명과 코드 생성만 LLM이 하도록.
결과적으로 정확도는 많이 올라갔다. 그런데 실제로 쓰면서 다른 문제들이 보이기 시작했다.
첫 번째: 파이프라인 중간에 오류가 나면 처음부터 다시 시작해야 했다. Phase 7까지 돌렸는데 Phase 8에서 뭔가 잘못되면? 다시 Phase 0부터. 시간이 아깝다.
두 번째: Figma 파일이 크면 API에서 받아온 데이터가 수십 MB짜리 JSON이 된다. 이걸 통째로 다음 Phase에 넘기면 노이즈가 너무 많았다. 사용자가 "이 섹션만 퍼블리싱해줘"라고 했는데 전체 파일을 분석하고 있는 셈이었다.
세 번째: LLM Phase가 3개(Phase 9, 10, 11)였다. 토큰이 ~3,500이나 나왔다.
v6는 이 세 가지 문제를 해결하려는 시도였다.
v6 — 세션, 스코프, 그리고 안정성 (2026-04-09)
핵심 아이디어: "한 번 선택하면 끝까지 그 범위만"
v6의 철학은 Scope Contract다. 사용자가 Phase 0.5에서 "이 섹션들을 퍼블리싱해줘"라고 선택하면, 이후 모든 Phase는 그 범위 밖으로 절대 나가지 않는다. 스코프 바깥 노드를 처리하려 하면 즉시 에러.
{
"scope": {
"selected_root_node_ids": ["20530:86930"],
"mode": "strict_subtree_only"
}
}이게 생각보다 중요했다. 기존엔 "사용자가 이 섹션 선택했으니까 이 섹션 위주로 분석하면 되겠지"라는 암묵적 규칙이었는데, 명시적인 계약으로 만드니까 각 Phase 스크립트가 훨씬 단순해졌다. "내 입력의 scope에 없는 노드는 처리하지 않는다"는 규칙 하나로.
세션 기반 실행
모든 Phase 결과를 세션 디렉토리에 저장한다.
/tmp/figma_publish_sessions/
└── pub_20260409_143022_abc12345/
├── scope.json
└── phase_outputs/
├── phase0.json
├── phase05.json
├── phase06.json
...Phase 3까지 완료된 상태에서 오류가 나면? --session pub_20260409_143022_abc12345 옵션으로 재개하면 Phase 3 결과는 이미 있으니 Phase 4부터 시작한다. 이게 생각보다 체감이 컸다. 중간에 Figma API 타임아웃이 나도 처음부터 안 해도 된다.
데이터 축소: 11MB → 4.8MB
v5의 문제 중 하나가 Figma 전체 데이터를 들고 다닌다는 거였다. v6에서는 Phase 0.5(섹션 선택) 직후에 선택된 섹션의 subtree만 추출해서 targeted spec을 만든다. 원본 11MB → 4.8MB로 59% 절감. 이후 Phase들은 이 작은 JSON만 보면 된다.
Phase 0.6 — "자식 노드 개별 분석" 강제화
기존에 가장 많이 틀렸던 이유 중 하나가 Props/Variant를 대충 봤던 거다. Badge의 colorPalette가 "green"인지 "grey"인지를 놓치는 식으로. v6에서는 Phase 0.6을 별도로 두고, 선택된 섹션의 각 자식 노드를 개별 분석한다. componentPropertyValues에서 variant, colorPalette, size 같은 열거형 Props를 명시적으로 뽑아낸다.
Phase 0 → Phase 0.5 → Phase 0.6 → Phase 1 → Phase 2 → Phase 2.5 → Phase 3 → Phase 4 → Phase 5
REST API 사용자 선택 딥 분석 에셋 설계서 비교 코드생성 검증 정리Annotation Guidance — 디자이너 메모를 어디에 쓸까
Figma에 디자이너가 남긴 annotation이나 description이 있을 때, 이걸 어떻게 다뤄야 할까? IR에 섞어버리면 비교 정확도가 떨어진다. 그렇다고 무시하면 디자이너 의도를 놓친다.
v6의 결론은 advisory-only다. annotationGuidance라는 별도 필드에 담아서, LLM이 코드를 생성할 때 "참고"는 하되 Design IR이나 Diff 계산에는 절대 섞지 않는다.
토큰: v5 ~3,500 → v6 ~2,200
LLM Phase가 3개에서 2개로 줄었다(Phase 2 설계서 + Phase 3 코드 생성). 세션 기반으로 중간 결과를 재사용하니까 전체적으로 더 효율적이었다.
v6에서 아직 아쉬웠던 것
v6는 분명히 안정성과 효율성이 올라갔다. 하지만 비교 엔진을 새로 만들었다. v5의 6-tier 매칭, 8-type diff 같은 정밀한 비교 도구를 버리고 "semantic diff"라는 더 단순한 방식을 썼다. 결과적으로 정확도는 v5가 더 높은데 안정성은 v6가 더 좋은 상황이 됐다.
두 개를 합치면 어떨까?