목차
STATE — 말포이 5편 파이프라인 상태 공간
- 정본:
state_schema.json(키·타입·reducer·쓰는/읽는 노드) ·state.py(TypedDict + Annotated reducer) ·pipeline.yaml(노드 reads/writes) - 이 문서는 위 3파일에서 뽑은 사람용 정리. 노드 정본 =
설명/05_배선도/roster.jsonv2(77노드·113배선·반려 15) - 원칙: 키는 도메인별 12개로만 묶음 → 노드는 자기 도메인 하위 키만 씀, 병렬로 같은 키에 써도 reducer가 합침
- 표기: W = 씀, R = 읽음, RW = 둘 다. 모든 노드는 추가로
runtime.trace에 자기 id를 누적(표에서 생략)
1. 한눈에
| 도메인 | 키 | 누적 방식(reducer) |
|---|---|---|
| 입력·계획 | brief · plan · rules |
merge_dict · merge_dict · upsert_by_id |
| 에셋 | assets · audio · blocks |
merge_nested_by_id · merge_nested_by_id · merge_by_id |
| 산출 | renders · docs |
merge_by_id · merge_by_id |
| 관리 | qa · feedback · budget · runtime |
merge_qa · upsert_by_id · merge_budget · merge_runtime |
- 흐름 한 줄:
brief→plan→ (assets.images→assets.clips→assets.mattes) ∥audio∥blocks→renders→docs, 옆에서qa·budget·runtime이 계속 쌓이고feedback이rules를 키움
2. 상태 키 표
| 키 | 담는 것 | 타입 | reducer | 쓰는 노드 | 읽는 노드 | 실제 값 예 |
|---|---|---|---|---|---|---|
brief |
밈 리서치·레퍼런스 | object{reference, meme_research, flow_research, pinterest} | merge_dict: 딕셔너리 얕은 병합(뒤가 이김) | S0 ref·r_meme·r_flow·r_pin | S0 sb·sb3 S1 img_design S2 flow_test |
00_ref/ref_DeKsEh0sBPy.mp4, 00_ref/research-flow.md, 핀터레스트 122장 |
plan |
storyboard·EDL·박 격자·배치 정의 | object{episodes, storyboard, edl, beat_grid, image_batches, flow_jobs, credit_plan} | merge_dict: 딕셔너리 얕은 병합(뒤가 이김) | S0 sb·sb3 S6 c_v4 |
S0 sb3 S1 img_design·img_frames·img_outfits·img_s6·img_v3 S2 전부(6) S4 au_v1_bgm·au_v1_vo·au_v1_sfx·au_v3_song·au_v3_vo·au_v4 S5 mo_a·mo_b·mo_c S6 c_v1·c_v3o S7 lay_v1·lay_v2·lay_v3·lay_v4 S8 pr_P1·pr_P2·graph |
STORYBOARD.md S1~S7, V1-EDL.md, 06_flow/v1_jobs.json 11잡 |
rules |
누적 제약(사용자 반려·사고 교훈) — 이후 전 노드 적용 | list[Rule{id,text,source,scope}] | upsert_by_id: 리스트, 같은 id면 필드 병합 아니면 추가 | S2 flow_test user_review |
S0 r_meme·r_flow·r_pin·sb·sb3 S1 img_design·img_frames·img_outfits·img_s6·img_v3 S2 전부(6) S4 au_v1_bgm·au_v1_vo·au_v3_song·au_v3_vo·au_v4·au_v5_song S5 mo_a·mo_b·mo_c S6 c_v1·c_v2·c_v2_fix·c_v3·c_v4·c_v5 S8 pr_P4 |
R-I01 텍스트만 영상 생성 금지 · heavy 동시 2 |
assets |
이미지·클립·매트 (id → 레코드) | object{images: id→ImageRec, clips: id→ClipRec, mattes: id→MatteRec} | merge_nested_by_id: 하위 맵마다 merge_by_id | S1 전부(6) S2 전부(6) S3 matte_q1·matte_q2·matte_q4 |
S1 img_frames·img_outfits·img_s6·img_v3·img_fix S2 전부(6) S3 matte_rd·matte_q1·matte_q2·matte_q4 S5 mo_c S6 c_v1·c_v2·c_v3·c_v4 S7 fx_A·fx_B·fx_C·fx_D·fx_E·lay_v1·lay_v2·lay_v3·lay_v4 S8 pr_P1·pr_P2·wire_prev |
02_frames/S4_fullbody.png → 06_flow/v1/V1_S4.mp4(8초·12크레딧·채택) → 05_matte/v1/V1_S4.webm |
audio |
곡·VO·SFX·박 실측·후보 | object{tracks, vo, sfx, beats, candidates} (각 id→레코드) | merge_nested_by_id: 하위 맵마다 merge_by_id | S4 전부(7) | S4 au_v5_song S5 mo_b S6 c_v1·c_v2·c_v3o·c_v3·c_v4·c_v5 S7 fx_A·fx_B·fx_C·fx_D·fx_E S8 pr_P3·wire_prev |
04_audio/bgm/BGM_MAIN_aligned.wav 128.17BPM, beats 드롭 7.484 |
blocks |
코드 배경·오버레이 블록 (id → Block) | id→Block | merge_by_id: id → 레코드, 레코드끼리 필드 병합 | S5 mo_a·mo_b·mo_c S6 c_v3o |
S5 mo_b·mo_c S6 c_v1·c_v2·c_v3·c_v4·c_v5 S7 fx_A·fx_B·fx_C·fx_D·fx_E·lay_v1·lay_v2·lay_v3·lay_v4 |
03_motion/compositions/kinetic_wall.html layer=bg/fg |
renders |
편별 패스·드래프트·최종·업로드본·컨택트시트 (V1~V5 → RenderRec) | V1~V5→RenderRec | merge_by_id: id → 레코드, 레코드끼리 필드 병합 | S6 c_v1·c_v2·c_v2_fix·c_v3·c_v4·c_v5 user_review |
S6 c_v2_fix·c_v5 S7 fx_A·fx_B·fx_C·fx_D·fx_E·lay_v1·lay_v2·lay_v3·lay_v4 S8 wire_prev |
V1 07_render/V1_SRANK_PULL.mp4 26.5초 · V1_contact.jpg |
qa |
판정 결과·재시도 횟수·게이트 상태 | object{verdicts: list[Verdict], retries: id→int, gates: id→GateState} | merge_qa: verdicts 리스트 누적 · retries 합산 · gates 덮어쓰기 | S1 전부(6) S2 전부(6) S4 au_v1_bgm·au_v1_vo·au_v3_song·au_v3_vo·au_v4·au_v5_song S6 c_v1·c_v2·c_v3·c_v4·c_v5 S7 fx_merge S8 pr_merge·news_JA·news_JB |
S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6·news_merge | retries {c_v4: 2}(r1→r3), gates {flow_b_ref: retry} |
feedback |
사용자 반려 큐(quote·target_node·status) | list[Feedback{id,quote,target_node,status}] | upsert_by_id: 리스트, 같은 id면 필드 병합 아니면 추가 | user_review | S0 sb S4 au_v5_song S6 c_v2_fix S8 pr_P4·graph·news_merge·wire |
I08 「왜 아래쪽에 악역영애 말포이 좀 없애봐」 → c_v2_fix |
budget |
Flow·ElevenLabs·codex 원장 | object{flow_credits, eleven_credits, codex} (각 Ledger) | merge_budget: 원장별 spent 합산 · entries 누적 · start/cap 덮어쓰기 | S0 sb S2 전부(6) S4 전부(7) |
S2 전부(6) S4 전부(7) S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
Flow 1,050 → 664(386 사용) · ElevenLabs 19,475 |
runtime |
동시성 슬롯·heavy 세마포어·도구 설정·장애/재개 로그·실행 trace | object{slots, heavy, toolchain, incidents, resume_log, trace} | merge_runtime: trace·incidents·resume_log 누적 · slots·heavy·toolchain 병합 | S2 flow_test S3 전부(5) S5 gpu_render S6 sema |
S2 flow_b_v1·flow_b_ref·flow_b_extra·flow_b_v3·flow_b_v4 S3 matte_gpu·matte_q1·matte_q2·matte_q4 S5 gpu_render S6 c_v1·c_v2·c_v3·c_v4·c_v5·sema S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
slots |
docs |
설명 산출물 (id → Doc) | id→Doc | merge_by_id: id → 레코드, 레코드끼리 필드 병합 | S7 전부(11) S8 pr_P1·pr_P2·pr_P3·pr_P4·pr_merge·pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6·pipe_merge·graph·news_S1·news_S2·news_S3·news_S4·news_S5·news_S6·news_merge·wire·wire_prev |
S7 fx_merge·lay_merge S8 pr_merge·pipe_merge·graph·news_S1·news_S2·news_S3·news_S4·news_S5·news_S6·news_JA·news_JB·news_merge·wire |
설명/04_도구별_파이프라인.md(pipe_merge) |
하위 키
| 하위 키 | 쓰는 노드 | 읽는 노드 |
|---|---|---|
brief.reference |
S0 ref | S0 sb S1 img_design |
brief.meme_research |
S0 r_meme | S0 sb |
brief.flow_research |
S0 r_flow | S0 sb S2 flow_test |
brief.pinterest |
S0 r_pin | S0 sb·sb3 S1 img_design |
plan.episodes |
S0 sb | - |
plan.storyboard |
S0 sb·sb3 | S0 sb3 S4 au_v1_bgm·au_v1_vo·au_v3_song·au_v3_vo S5 mo_a·mo_b·mo_c S6 c_v3o S8 graph |
plan.edl |
S0 sb S6 c_v4 |
S4 au_v1_sfx S5 mo_a S6 c_v1 S7 lay_v1·lay_v2·lay_v3·lay_v4 |
plan.beat_grid |
S0 sb·sb3 | S4 au_v1_bgm·au_v3_song·au_v4 |
plan.image_batches |
S0 sb·sb3 | S1 img_design·img_frames·img_outfits·img_s6·img_v3 S8 pr_P1 |
plan.flow_jobs |
S0 sb·sb3 | S2 전부(6) S8 pr_P2 |
plan.credit_plan |
S0 sb | - |
assets.images |
S1 전부(6) | S1 img_frames·img_outfits·img_s6·img_v3·img_fix S2 전부(6) S6 c_v3 S7 lay_v1·lay_v2·lay_v3·lay_v4 S8 pr_P1·wire_prev |
assets.clips |
S2 전부(6) | S3 matte_rd·matte_q1·matte_q2·matte_q4 S5 mo_c S6 c_v3 S7 lay_v1·lay_v2·lay_v3·lay_v4 S8 pr_P2·wire_prev |
assets.mattes |
S3 matte_q1·matte_q2·matte_q4 | S6 c_v1·c_v2·c_v3·c_v4 S7 fx_A·fx_B·fx_C·fx_D·fx_E·lay_v1·lay_v2·lay_v3·lay_v4 |
audio.tracks |
S4 au_v1_bgm·au_v3_song·au_v4·au_v5_song | S4 au_v5_song S6 c_v1·c_v2·c_v3o·c_v3·c_v4·c_v5 S7 fx_A·fx_B·fx_C·fx_D·fx_E S8 pr_P3·wire_prev |
audio.vo |
S4 au_v1_vo·au_v3_vo | S6 c_v1·c_v3o·c_v3 S8 pr_P3 |
audio.sfx |
S4 au_v1_sfx·au_v4 | S6 c_v1·c_v4 S8 pr_P3 |
audio.beats |
S4 au_v1_bgm·au_v3_song·au_v4·au_v5_song | S4 au_v5_song S5 mo_b S6 c_v1·c_v3o·c_v3·c_v4·c_v5 |
audio.candidates |
S4 au_v1_bgm·au_v1_vo·au_v3_song·au_v3_vo·au_v4·au_v5_song | S8 pr_P3 |
qa.verdicts |
S1 전부(6) S2 전부(6) S4 au_v1_bgm·au_v1_vo·au_v3_song·au_v3_vo·au_v4·au_v5_song S6 c_v1·c_v2·c_v3·c_v4·c_v5 S7 fx_merge S8 pr_merge·news_JA·news_JB |
S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6·news_merge |
qa.retries |
S1 전부(6) S2 전부(6) S4 au_v1_bgm·au_v3_song·au_v4·au_v5_song S6 c_v1·c_v2·c_v3·c_v4·c_v5 |
- |
qa.gates |
- | - |
budget.flow_credits |
S0 sb S2 전부(6) |
S2 전부(6) S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
budget.eleven_credits |
S0 sb S4 전부(7) |
S4 전부(7) S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
budget.codex |
- | S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
runtime.slots |
S6 sema | S3 matte_q1·matte_q2·matte_q4 |
runtime.heavy |
S6 sema | S6 c_v1·c_v2·c_v3·c_v4·c_v5 |
runtime.toolchain |
S2 flow_test S3 matte_rd·matte_gpu S5 gpu_render |
S2 flow_b_v1·flow_b_ref·flow_b_extra·flow_b_v3·flow_b_v4 S3 matte_gpu·matte_q1·matte_q2·matte_q4 S5 gpu_render S6 sema S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
runtime.incidents |
S3 matte_q1·matte_q2·matte_q4 | S6 sema S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
runtime.resume_log |
- | S8 pipe_T1·pipe_T2·pipe_T3·pipe_T4·pipe_T5·pipe_T6 |
runtime.trace |
- | - |
3. reducer — 병렬 쓰기가 안 깨지는 이유
| reducer | 규칙 | 실제로 막는 사고 |
|---|---|---|
| merge_dict | 얕은 병합, 뒤가 이김 | 리서치 3갈래가 brief에 동시에 써도 각자 하위 키만 바뀜 |
| merge_nested_by_id | 하위 맵마다 id 병합 | Flow 워커 5기가 assets.clips에 동시에 써도 컷 id별로 들어감 |
| merge_by_id | id → 레코드 필드 병합 | 섹션 워커 5~6기가 docs에 동시 기록, renders.V2를 c_v2 → c_v2_fix가 덧씀 |
| upsert_by_id | 같은 id면 갱신, 아니면 추가 | 반려 I08 status open → rewound → resolved 갱신, 규칙 중복 방지 |
| merge_qa | verdicts 누적 · retries 합산 · gates 덮어쓰기 | 재시도 횟수가 병렬 판정에서도 정확(재생성 1회 상한 집행) |
| merge_budget | spent 합산 · entries 누적 | Flow 동시 5잡이 각자 12크레딧을 내도 합계 정확 → 배치 상한(v1 110·v4 90) 판정 |
| merge_runtime | trace·incidents·resume_log 누적, 나머지 병합 | 재부팅 사고·되감기 기록이 덮이지 않음 |
4. 스테이지 × 키 읽기/쓰기 행렬
| 스테이지 | 노드 수 | brief |
plan |
rules |
assets |
audio |
blocks |
renders |
qa |
feedback |
budget |
runtime |
docs |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S0 기획·리서치 | 6 | RW | RW | R | R | W | |||||||
| S1 이미지 (codex) | 6 | R | R | R | RW | W | |||||||
| S2 영상 (Flow via Aside) | 6 | R | R | RW | RW | W | RW | RW | |||||
| S3 매팅 (사람만 오려내기) | 5 | RW | RW | ||||||||||
| S4 소리 (ElevenLabs) | 7 | R | R | RW | W | R | RW | ||||||
| S5 코드 배경·효과 | 4 | R | R | R | R | RW | RW | ||||||
| S6 편별 합성·render | 8 | RW | R | R | R | RW | RW | W | R | RW | |||
| S7 분석 정리 (효과·레이어) | 11 | R | R | R | R | R | W | RW | |||||
| S8 문서·뉴스레터·배선도 | 24 | R | R | R | R | R | RW | R | R | R | RW | ||
Send 워커 *__job(9) |
- | R | W | W | W | ||||||||
| user_review(interrupt) | - | W | RW | RW | |||||||||
| 게이트 라우터(21) | - | R | |||||||||||
| 드라이버 rewind_to | - | W | RW |
- 읽는 법: 열 하나를 세로로 보면 그 키의 생산 → 소비 순서가 보임(예:
assets는 S1·S2·S3에서 W, S6~S8에서 R) plan을 S6이 W하는 건 4편 c_v4가edl.py로 78컷 EDL을 직접 만들기 때문rules를 S2가 W하는 건 360p 테스트 교훈(프레임 모드·flat solid blue·One continuous shot)을 규칙으로 박기 때문
5. 노드별 읽기/쓰기 (77)
| 스테이지 | 노드 | 이름 | 담당 | stub 핸들러 | 읽기 | 쓰기 | 동시성 | 재시도·게이트 |
|---|---|---|---|---|---|---|---|---|
| S0 | ref |
레퍼런스 확보 | main | research | - | brief.reference | - | - |
| S0 | r_meme |
밈 조사 | sub | research | rules | brief.meme_research | subagents 8 | 재시도 ≤1 |
| S0 | r_flow |
Flow 조사 | sub | research | rules | brief.flow_research | subagents 8 | 재시도 ≤1 |
| S0 | r_pin |
핀터레스트 수집 | sub | research | rules | brief.pinterest | subagents 8 | 재시도 ≤1 |
| S0 | sb |
스토리보드·EDL | main | plan | brief.reference, brief.meme_research, brief.flow_research, brief.pinterest, rules, feedback | plan.episodes, plan.storyboard, plan.edl, plan.beat_grid, plan.image_batches, plan.flow_jobs, plan.credit_plan, budget.flow_credits, budget.eleven_credits | - | - |
| S0 | sb3 |
3편 OP 기획 (opus) | sub | plan | plan.storyboard, brief.pinterest, rules | plan.storyboard, plan.beat_grid, plan.image_batches, plan.flow_jobs | subagents 8 | 재시도 ≤1 |
| S1 | img_design |
캐릭터 시안 4종 | codex | codex_batch | plan.image_batches, brief.reference, brief.pinterest, rules | assets.images, qa.verdicts, qa.retries | codex 4 | Send ×4 · 게이트 ≤1(Send 재시도) |
| S1 | img_frames |
1편 첫 프레임 8장 | codex | codex_batch | plan.image_batches, assets.images, rules | assets.images, qa.verdicts, qa.retries | codex 4 | Send ×8 · 게이트 ≤1(Send 재시도) |
| S1 | img_outfits |
의상 7벌 | codex | codex_batch | plan.image_batches, assets.images, rules | assets.images, qa.verdicts, qa.retries | codex 4 | Send ×7 · 게이트 ≤1(Send 재시도) |
| S1 | img_s6 |
대연회장 귀족 드레스 1장 | codex | codex_batch | plan.image_batches, assets.images, rules | assets.images, qa.verdicts, qa.retries | codex 4 | 게이트 ≤1(자기 루프) |
| S1 | img_v3 |
3편 일러 15장 | codex | codex_batch | plan.image_batches, assets.images, rules | assets.images, qa.verdicts, qa.retries | codex 4 | Send ×15 · 게이트 ≤1(Send 재시도) |
| S1 | img_fix |
내용↔파일명 대조 | main | name_check | assets.images | assets.images, qa.verdicts, qa.retries | - | 게이트 ≤2(자기 루프) |
| S2 | flow_test |
Flow 정찰·360p 테스트 | sub | flow_test | assets.images, brief.flow_research, plan.flow_jobs, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, rules, budget.flow_credits, runtime.toolchain | flow 2 | 게이트 ≤1(자기 루프) |
| S2 | flow_b_v1 |
1편 첫 프레임 11컷 | sub | flow_batch | plan.flow_jobs, assets.images, runtime.toolchain, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, budget.flow_credits | flow 5 | Send ×11 · 게이트 ≤1(Send 재시도) |
| S2 | flow_b_ref |
참조(Ingredients) 4컷 | sub | flow_batch | plan.flow_jobs, assets.images, runtime.toolchain, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, budget.flow_credits | flow 5 | Send ×4 · 게이트 ≤1(Send 재시도) |
| S2 | flow_b_extra |
추가 9컷 + 2편 변신 | sub | flow_batch | plan.flow_jobs, assets.images, runtime.toolchain, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, budget.flow_credits | flow 5 | Send ×9 · 게이트 ≤1(Send 재시도) |
| S2 | flow_b_v3 |
3편 7컷 | sub | flow_batch | plan.flow_jobs, assets.images, runtime.toolchain, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, budget.flow_credits | flow 5 | Send ×7 · 게이트 ≤1(Send 재시도) |
| S2 | flow_b_v4 |
4편 빠른 동작 10컷 | sub | flow_batch | plan.flow_jobs, assets.images, runtime.toolchain, budget.flow_credits, rules | assets.clips, qa.verdicts, qa.retries, budget.flow_credits | flow 5 | Send ×10 · 게이트 ≤1(Send 재시도) |
| S3 | matte_rd |
매팅 방식 비교 | sub | matte_dev | assets.clips | runtime.toolchain | subagents 8 | 재시도 ≤1 |
| S3 | matte_gpu |
GPU 포팅 | sub | matte_dev | runtime.toolchain | runtime.toolchain | subagents 8 | 재시도 ≤1 |
| S3 | matte_q1 |
매팅 큐 1 (1편→추가) | gpu | matte_queue | assets.clips, runtime.toolchain, runtime.slots | assets.mattes, runtime.incidents | matte_lines 1 | 재시도 ≤1 |
| S3 | matte_q2 |
매팅 큐 2 (참조·3편) | gpu | matte_queue | assets.clips, runtime.toolchain, runtime.slots | assets.mattes, runtime.incidents | matte_lines 1 | 재시도 ≤1 |
| S3 | matte_q4 |
매팅 큐 4편 | gpu | matte_queue | assets.clips, runtime.toolchain, runtime.slots | assets.mattes, runtime.incidents | matte_lines 1 | 재시도 ≤1 |
| S4 | au_v1_bgm |
1편 BGM | eleven | eleven_music | plan.beat_grid, plan.storyboard, budget.eleven_credits, rules | audio.candidates, audio.tracks, audio.beats, budget.eleven_credits, qa.verdicts, qa.retries | eleven 2 | 게이트 ≤2(자기 루프) |
| S4 | au_v1_vo |
1편 VO 오디션 | eleven | eleven_tts | plan.storyboard, budget.eleven_credits, rules | audio.vo, audio.candidates, budget.eleven_credits, qa.verdicts | eleven 2 | 재시도 ≤1 |
| S4 | au_v1_sfx |
효과음 19개 | eleven | eleven_sfx | plan.edl, budget.eleven_credits | audio.sfx, budget.eleven_credits | eleven 2 | - |
| S4 | au_v3_song |
3편 한국어 OP곡 | eleven | eleven_music | plan.beat_grid, plan.storyboard, budget.eleven_credits, rules | audio.candidates, audio.tracks, audio.beats, budget.eleven_credits, qa.verdicts, qa.retries | eleven 2 | 게이트 ≤2(자기 루프) |
| S4 | au_v3_vo |
3편 한국어 VO | eleven | eleven_tts | plan.storyboard, budget.eleven_credits, rules | audio.vo, audio.candidates, budget.eleven_credits, qa.verdicts | eleven 2 | 재시도 ≤1 |
| S4 | au_v4 |
4편 170BPM 곡 | eleven | eleven_music | plan.beat_grid, budget.eleven_credits, rules | audio.candidates, audio.tracks, audio.beats, audio.sfx, budget.eleven_credits, qa.verdicts, qa.retries | eleven 2 | 게이트 ≤2(자기 루프) |
| S4 | au_v5_song |
5편 영어 곡 | eleven | eleven_music | audio.beats, audio.tracks, budget.eleven_credits, rules, feedback | audio.candidates, audio.tracks, audio.beats, budget.eleven_credits, qa.verdicts, qa.retries | eleven 2 | 게이트 ≤2(자기 루프) |
| S5 | mo_a |
모션 워커 A | sub | motion_block | plan.storyboard, plan.edl, rules | blocks | subagents 8 | 재시도 ≤1 |
| S5 | mo_b |
모션 워커 B | sub | motion_block | plan.storyboard, blocks, audio.beats, rules | blocks | subagents 8 | 재시도 ≤1 |
| S5 | mo_c |
모션 워커 C | sub | motion_block | plan.storyboard, blocks, assets.clips, rules | blocks | subagents 8 | 재시도 ≤1 |
| S5 | gpu_render |
render 가속 실측 | sub | render_bench | runtime.toolchain | runtime.toolchain | subagents 8 | 재시도 ≤1 |
| S6 | c_v1 |
1편 합성 | sub | composite | assets.mattes, audio.tracks, audio.vo, audio.sfx, audio.beats, blocks, plan.edl, runtime.heavy, rules | renders, qa.verdicts, qa.retries | heavy 2 | 게이트 ≤3(자기 루프) |
| S6 | c_v2 |
2편 합성 | sub | composite | assets.mattes, blocks, audio.tracks, runtime.heavy, rules | renders, qa.verdicts, qa.retries | heavy 2 | 게이트 ≤3(자기 루프) |
| S6 | c_v2_fix |
2편 수정 | main | fix | renders, feedback, rules | renders | heavy 2 | - |
| S6 | c_v3o |
3편 오버레이 | sub | motion_block | audio.tracks, audio.beats, audio.vo, plan.storyboard | blocks | subagents 8 | 재시도 ≤1 |
| S6 | c_v3 |
3편 장면 조립 | sub | composite | blocks, assets.images, assets.clips, assets.mattes, audio.tracks, audio.vo, audio.beats, runtime.heavy, rules | renders, qa.verdicts, qa.retries | heavy 2 | 게이트 ≤3(자기 루프) |
| S6 | c_v4 |
4편 하이퍼 에딧 | sub | composite | assets.mattes, audio.tracks, audio.beats, audio.sfx, blocks, runtime.heavy, rules | plan.edl, renders, qa.verdicts, qa.retries | heavy 2 | 게이트 ≤3(자기 루프) |
| S6 | c_v5 |
5편 영어판 재render | sub | composite | renders, audio.tracks, audio.beats, blocks, runtime.heavy, rules | renders, qa.verdicts, qa.retries | heavy 2 | 게이트 ≤3(자기 루프) |
| S6 | sema |
heavy.sh 세마포어 | gpu | semaphore | runtime.toolchain, runtime.incidents | runtime.heavy, runtime.slots | - | - |
| S7 | fx_A |
효과 A 배경 블록 | sub | section_worker | renders, blocks, assets.mattes, audio.tracks | docs | doc_subagents 12 | 섹션 fx · 재시도 ≤1 |
| S7 | fx_B |
효과 B 1·2편 | sub | section_worker | renders, blocks, assets.mattes, audio.tracks | docs | doc_subagents 12 | 섹션 fx · 재시도 ≤1 |
| S7 | fx_C |
효과 C 3·5편 | sub | section_worker | renders, blocks, assets.mattes, audio.tracks | docs | doc_subagents 12 | 섹션 fx · 재시도 ≤1 |
| S7 | fx_D |
효과 D 4편 | sub | section_worker | renders, blocks, assets.mattes, audio.tracks | docs | doc_subagents 12 | 섹션 fx · 재시도 ≤1 |
| S7 | fx_E |
효과 E 매팅·오디오 | sub | section_worker | renders, blocks, assets.mattes, audio.tracks | docs | doc_subagents 12 | 섹션 fx · 재시도 ≤1 |
| S7 | fx_merge |
효과 병합 | sub | merge | docs | docs, qa.verdicts | - | - |
| S7 | lay_v1 |
레이어 1편 | sub | section_worker | renders, blocks, assets.images, assets.clips, assets.mattes, plan.edl | docs | doc_subagents 12 | 섹션 lay · 재시도 ≤1 |
| S7 | lay_v2 |
레이어 2편 | sub | section_worker | renders, blocks, assets.images, assets.clips, assets.mattes, plan.edl | docs | doc_subagents 12 | 섹션 lay · 재시도 ≤1 |
| S7 | lay_v3 |
레이어 3·5편 | sub | section_worker | renders, blocks, assets.images, assets.clips, assets.mattes, plan.edl | docs | doc_subagents 12 | 섹션 lay · 재시도 ≤1 |
| S7 | lay_v4 |
레이어 4편 | sub | section_worker | renders, blocks, assets.images, assets.clips, assets.mattes, plan.edl | docs | doc_subagents 12 | 섹션 lay · 재시도 ≤1 |
| S7 | lay_merge |
레이어 병합 | main | merge | docs | docs | - | - |
| S8 | pr_P1 |
원문집 이미지 | sub | section_worker | assets.images, plan.image_batches | docs | doc_subagents 12 | 섹션 pr · 재시도 ≤1 |
| S8 | pr_P2 |
원문집 영상 | sub | section_worker | assets.clips, plan.flow_jobs | docs | doc_subagents 12 | 섹션 pr · 재시도 ≤1 |
| S8 | pr_P3 |
원문집 소리 | sub | section_worker | audio.candidates, audio.tracks, audio.vo, audio.sfx | docs | doc_subagents 12 | 섹션 pr · 재시도 ≤1 |
| S8 | pr_P4 |
원문집 규칙·공식 | sub | section_worker | rules, feedback | docs | doc_subagents 12 | 섹션 pr · 재시도 ≤1 |
| S8 | pr_merge |
원문집 병합 | main | merge | docs | docs, qa.verdicts | - | - |
| S8 | pipe_T1 |
파이프라인 Aside | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_T2 |
파이프라인 codex | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_T3 |
파이프라인 매팅 | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_T4 |
파이프라인 합성 | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_T5 |
파이프라인 오디오 | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_T6 |
파이프라인 지휘 | sub | section_worker | runtime.toolchain, runtime.incidents, runtime.resume_log, qa.verdicts, budget | docs | doc_subagents 12 | 섹션 pipe · 재시도 ≤1 |
| S8 | pipe_merge |
파이프라인 병합 | main | merge | docs | docs | - | - |
| S8 | graph |
파이프라인 그래프 | sub | section_worker | docs, plan.storyboard, feedback | docs | doc_subagents 12 | 재시도 ≤1 |
| S8 | news_S1 |
뉴스레터 도입 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_S2 |
뉴스레터 이미지 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_S3 |
뉴스레터 영상 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_S4 |
뉴스레터 코드 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_S5 |
뉴스레터 소리 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_S6 |
뉴스레터 지휘 | sub | section_worker | docs | docs | doc_subagents 12 | 섹션 news · 재시도 ≤1 |
| S8 | news_JA |
문체 판정 앞 | sub | judge | docs | qa.verdicts | doc_subagents 12 | - |
| S8 | news_JB |
문체 판정 뒤 | sub | judge | docs | qa.verdicts | doc_subagents 12 | - |
| S8 | news_merge |
뉴스레터 병합·반영 | main | merge | docs, qa.verdicts, feedback | docs | - | - |
| S8 | wire |
배선도 | sub | section_worker | docs, feedback | docs | doc_subagents 12 | 재시도 ≤1 |
| S8 | wire_prev |
배선도 시안 에셋 | sub | section_worker | assets.images, assets.clips, audio.tracks, renders | docs | doc_subagents 12 | 재시도 ≤1 |
6. 상태 전이 다이어그램
- 스테이지 단위. 분기(fork)·합류(join)·판정 루프·재시도·사용자 반려 되감기만 표시. 노드 단위 배선은
python3 graph.py --dry-run
stateDiagram-v2
direction TB
state "기획·리서치 S0<br>brief·plan W" as S0
state "이미지 배치 S1<br>Send 행 단위 · codex 4" as S1
state "이름 대조 img_fix" as FIX
state "360p 테스트 flow_test" as TEST
state "Flow 배치 S2<br>Send 잡 단위 · 동시 5" as S2
state "클립 판정" as JUDGE
state "매팅 큐 S3 · 2줄" as S3
state "곡 후보 → 실측 S4 · 동시 2" as S4
state "코드 배경 블록 S5" as S5
state "편별 합성 S6 · heavy 2" as S6
state "드래프트 컨택트시트" as SHEET
state "user_review<br>interrupt()" as REVIEW
state "효과·레이어 섹션 S7<br>Send 섹션 워커" as S7
state "문서·뉴스레터·배선도 S8<br>Send 섹션 워커 → 판정 → 병합" as S8
state fork1 <<fork>>
state join1 <<join>>
[*] --> S0
S0 --> fork1
fork1 --> S1
fork1 --> S4
fork1 --> S5
S1 --> S1 : timeout 행만 재시도 1회 (TIMEOUT=600)
S1 --> FIX
FIX --> FIX : 내용↔파일명 불일치 → 교정·재대조 (≤2)
FIX --> TEST
TEST --> TEST : 불합격 → 교훈을 rules에 넣고 재테스트 (≤1)
TEST --> S2 : 통과
S2 --> JUDGE
JUDGE --> S2 : regen 컷만 _r2 재생성 1회
JUDGE --> S3 : 블루 컷
JUDGE --> join1 : 인월드 컷(매팅 생략)
S3 --> join1
S4 --> S4 : 기준 충족 후보 0 → 요청 수정 재생성 (≤2)
S4 --> join1
S4 --> S5 : beats.json 실측 상수(점선)
S5 --> join1
join1 --> S6
S6 --> SHEET
SHEET --> S6 : 배치·박·자막 어긋남 (r1→r3)
SHEET --> REVIEW : 최종·업로드본
REVIEW --> S7 : 승인
REVIEW --> S0 : 반려 → rewind_to(원인 노드)<br>+ rules 누적
S7 --> S8
S8 --> REVIEW : 뉴스레터·배선도
S8 --> [*]
- 반려 되감기 15건(원인 노드): I01→
flow_test· I02→img_design· I03→img_outfits· I04→mo_b· I05→flow_b_ref· I06→flow_b_v1· I07→matte_gpu· I08→c_v2_fix· I09→au_v5_song· I10→c_v4· I11→fx_merge· I12→lay_merge· I13→news_merge· I14→wire· I15→wire - 되감기 방식: 체크포인트 이력에서 원인 노드가 next인 지점으로 포크 재실행, 반려 규칙은
configurable.inject로 실어 첫 노드가rules·feedback에 넣음(graph.pyrewind_to) - 되감기 뒤 다시 도는 노드는 산출 파일이 있으면 건너뛰어야 함(실제 파이프라인도
imagegen_runner.py·matte_queue.sh가 멱등)
7. 그래프에만 있는 가상 노드
| 종류 | 이름 규칙 | 개수 | 하는 일 |
|---|---|---|---|
| dispatch | <노드>__dispatch |
9 | 배치 행·잡 목록을 읽어 Send(<노드>__job, item) |
| worker | <노드>__job |
9 | 이미지 1장 / Flow 클립 1개 |
| pass | <노드>__pass |
21 | 게이트 통과 출구. 원래 배선은 여기서 나감(대기 엣지가 조건 엣지에 막히지 않게) |
| group_dispatch | fx·lay·pr·pipe·news__dispatch |
5 | 멤버 선행 노드 합집합을 기다렸다가 섹션 워커 동시 Send(실제로도 같은 시각 동시 기동) |
| interrupt | user_review |
1 | 산출물 검토, interrupt()로 정지 |
- 합계: roster 77 + 가상 45 = 그래프 노드 122, compile 후
get_graph()노드 122 일치
8. 실행·검증
python3 verify.py # yaml·json 파싱, roster 77·113·15 대조, Schema 유효성, state.py↔schema, dry-run
python3 graph.py --dry-run # 구조(노드·엣지) 출력. langgraph 있으면 compile 요약 추가
python3 graph.py --simulate # stub으로 끝까지(외부 호출 0), 판정 루프는 실제 관측 횟수 재현
python3 graph.py --simulate --reject c_v2_fix # 반려 → 되감기 경로 시험
python3 graph.py --simulate --review all # 반려 대상 14노드 뒤마다 interrupt_after 정지
- langgraph 설치는 C 오염 없이:
python3 -m venv /mnt/d/_cache/venv-langgraph && PIP_CACHE_DIR=/mnt/d/_cache/pip /mnt/d/_cache/venv-langgraph/bin/pip install langgraph pyyaml jsonschema - 시뮬레이션 관측 재현값: img_s6 재시도 1 · flow_b_ref 2컷 재생성 · flow_b_v3 1컷 재생성 · c_v2 라운드 2 · c_v4 라운드 3