
    =Pj                        d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlmZ ddlmZ dZd	Zdd
ZddZ	 d	 	 	 ddZ	 	 	 	 ddZddZddZy)u  제작자 정정(creator corrections) 채널 — 프로젝트 단위 세계 사실 override.

W-발명경계 wave3 (2026-07-08). 발명 경계 계약(prompt pack: shot_staging v16 /
scene_detail v37 등)은 "제작자 정정(주어진 경우) > 씬 텍스트 > 저작 재량"
우선순위를 선언하지만 production 에는 정정을 주입할 채널이 없었다
(실험 lane 의 override 파일은 scratchpad 전용). 본 모듈이 그 채널이다.

저장: ``projects/<project_id>/creator_corrections.json``
    {"corrections": [{"id": "<slug>", "text": "<정정 문장>", "active": true}]}

설계 원칙:
  - 코드=구조 검증·조립만. 정정의 **내용**은 전부 데이터 (시나리오 의존
    코드 금지 — 어떤 작품에도 범용).
  - 정정이 없으면 블록은 빈 문자열 → 소비 스텝의 프롬프트는 기존과
    byte-identical (default 무영향, flag 불요).
  - malformed 파일은 조용히 무시하지 않고 AppError fail-fast (silent skip
    금지 — problems.md #2 패턴).
    )annotationsN)Path)AnyDictList)settings)AppErrorzcreator_corrections.jsonuE  

## CREATOR CORRECTIONS (제작자 정정 — 최우선)
아래 항목은 제작자가 확정한 작품 사실이다. 시나리오 텍스트·요약·이전 단계 산출 등 상충하는 모든 다른 입력에 우선한다.
★적용 범위: 각 정정은 자신이 언급하는 대상에만 적용된다. 그 대상이 현재 다루는 장소/장면/범위에 원래 존재하지 않으면 정정을 이유로 추가·발명하지 마라 — 정정은 '이미 있는 대상의 사실을 바로잡는' 지시이지 '그 대상을 어디에나 넣으라'는 지시가 아니다:
c                H    t        t        j                        | z  t        z  S )N)r   r   projects_dirFILENAME
project_ids    R/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/creator_corrections.pycorrections_pathr   ,   s    %%&3h>>    c           	        t        | t              rt        | j                  d      t              st	        dd| dd      g }t        | d         D ]  \  }}t        |t              rt        |j                  d      t              re|d   j                         rRt        |j                  d      t              r3|d   j                         r t        |j                  d	d
      t              st	        dd| d| dd      |j                  |d   j                         |d   j                         |j                  d	d
      d        |S )uO   구조 검증 (fail-fast). 반환: 전체 항목 리스트 (active 필터 전).correctionszcreator_corrections.malformedu(   creator_corrections.json 구조 위반: u8    — {"corrections": [{id, text, active}]} 형식 필요  codemessagestatus_codeidtextactiveTu    creator_corrections.json 항목 u    구조 위반: u?    — id/text 비어있지 않은 문자열 + active bool 필요)r   r   r   )

isinstancedictgetlistr	   	enumeratestrstripboolappend)rawpathouties        r   	_validater*   0   s'   c4 
377=3I4(P0>tfPQ	
 	
 !#C#m,-11d#!!%%+s31T7==?!!%%-5QvY__=N!!%%$"7>4:1#=MdVYZ	  	

!D'--/1V9??3DeeHd35 	6 . Jr   c                H   t        |       }|j                         sg S 	 t        j                  |j	                  d            }t        ||      }|r|D cg c]
  }|d	   s	| c}S |S # t
        t        j                  f$ r}t        dd| d| d      d}~ww xY wc c}w )
u   정정 목록 로드 (단일 fail-fast reader — API GET 도 이 경로만 사용).

    파일 없음 = [] (정정 미설정은 정상 상태). active_only=False 는 관리
    UI 조회용 전체 목록.
    utf-8encodingzcreator_corrections.unreadableu(   creator_corrections.json 읽기 실패: u    — r   r   Nr   )	r   existsjsonloads	read_textOSErrorJSONDecodeErrorr	   r*   )r   active_onlyr&   r%   excentriesr)   s          r   load_creator_correctionsr8   J   s     J'D;;=	
jj9: T"G2=w.w!!H+Aw.J7J T))* 
1>tfE#O
 	

 /s#   %A* 
B!B*BBBc                   t        |       }t        ||      }|j                  j                  dd       |j	                  d      }|j                  t        j                  d|idd      d	       t        j                  ||       |S )
u  구조 검증 후 저장 (atomic replace). 반환: 전체 항목 (active 필터 전).

    분석 스텝들이 실행 중 이 파일을 직접 읽고 malformed 는 fail-fast 로
    step 을 멈추므로, partial write 가 관측되지 않도록 tmp → os.replace.
    T)parentsexist_okz	.json.tmpr   F   )ensure_asciiindentr,   r-   )
r   r*   parentmkdirwith_suffix
write_textr0   dumpsosreplace)r   r%   r&   r7   tmps        r   save_creator_correctionsrG   `   s     J'DT"GKKdT2


;
'CNN

M7+%J   JJsDNr   c                F    | syt         dj                  d | D              z   S )uX   소비 스텝 프롬프트에 붙일 블록. 정정 없음 = "" (byte-identical 보장). 
c              3  ,   K   | ]  }d |d      yw)z- r   N ).0r)   s     r   	<genexpr>z$corrections_block.<locals>.<genexpr>w   s     $K{!r!F)%5{s   )_BLOCK_HEADERjoin)r   s    r   corrections_blockrQ   s   s"    499$K{$KKKKr   c                *    t        t        |             S )uA   load + block 조립 편의 함수 (소비 스텝 1줄 주입용).)rQ   r8   r   s    r   project_corrections_blockrS   z   s    5jABBr   )r   r!   returnr   )r%   r   r&   r   rT   List[Dict[str, Any]])T)r   r!   r5   r#   rT   rU   )r   r!   r%   zDict[str, Any]rT   rU   )r   rU   rT   r!   )r   r!   rT   r!   )__doc__
__future__r   r0   rD   pathlibr   typingr   r   r   app.core.configr   app.core.errorsr	   r   rO   r   r*   r8   rG   rQ   rS   rL   r   r   <module>r\      s|   $ #  	  " " $ $%
T ?6 26K*.K:NK,"05I&LCr   