
    )j                        U d Z ddlmZ ddlmZmZmZmZmZ dZ	de
d<   dddZd	e
d
<   dZde
d<   dZde
d<   ddZ	 	 	 	 	 	 	 	 	 	 ddZy)u.  W21B-w4 · #4(C) render-input substrate policy — deterministic resolver core.

brief ``docs/w21b-wave4-bg-render-substrate-policy-20260531`` (APPROVED v0.2) +
Codex design lock (2026-05-31).

Single pure helper :func:`resolve_render_substrate` that decides, per
shot-aware-plan node, what render-input substrate the bg gets — WITHOUT calling
any image/LLM API. It reads the 3a/3b stamped fields (``render_action`` /
``needs_new_plate`` / ``ref_tree_parents`` / ``ref_role_per_parent``) and the
caller-supplied PNG snapshots, and returns an ordered reference plan:

  - **reuse alias** (``reuse_existing_plate`` / ``needs_new_plate=False``)
    → render input 0 (copy-less alias is materialised elsewhere; ``proceed=False``).
  - **fresh plate** → FP PNG first, then ``ref_tree_parents`` reordered
    ``space_continuity`` → ``style`` (already canonical anchors from 3b), each
    resolved to its rendered-plate PNG. A parent whose PNG is not yet rendered is
    dropped and recorded in ``missing_parent_bg_ids`` + ``fallback_reason`` (brief
    §5 v0 = graceful degrade, never a silent drop). All parents missing →
    ``fallback_fp_only``.
  - **fp-less / direct** → no FP png for the fp → ``direct`` (parents/text only).

card-withheld fresh folds into ``fresh`` (route_v2 already dropped its
reuse_target, so it is not in ``ref_tree_parents`` — never re-added here).

The resolver decides the **PNG substrate only**. Plate prose / projection-card
``pass`` gating stays with C4 ``resolve_projection_plate_injection`` /
background_prompt (Codex caution — no overlap). This module is a pure helper and
is **not wired into any step yet** (default-inert): the ``background_render_step``
consumer (replacing the legacy ``depends_on_bg`` prior selection behind a
selector/flag) is a separate, separately-reviewed change.
    )annotations)AnyDictListOptionalTuple   intMAX_PARENT_REFS   )space_continuitystylezDict[str, int]
_ROLE_RANK_DEFAULT_ROLE_RANK
bg_id
node_classproceedfp_pathordered_parent_bg_idsordered_prior_bg_pathsattached_ref_labelsref_usedfallback_reasonmissing_parent_bg_idszTuple[str, ...]SUBSTRATE_FIELDSc                    | ddd g g g ddg d
S )Nreuse_aliasF r    )r   s    f/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/background_render_substrate.py_reuse_alias_decisionr"   :   s*    #!#"$!!!#     c                   | j                  d      }| j                  d      dk(  s| j                  d      du rt        |      S |j                  |      }|rt        |      nd}| j                  d      xs g D cg c]  }t        |t              r|r| }}| j                  d      xs i t	        |fd	
      dt
         }	g }
g }g }|	D ]R  }|j                  |      }|r,|
j                  |       |j                  t        |             B|j                  |       T g }d}|r|j                  d|d|d       d}t        |
|      D ]3  \  }}|j                  ||j                  |      xs d|d       |dz  }5 |rdj                  d |D              nd}|d}d}nd}|
rd}n|	rd}nd}||d||
|||||d
S c c}w )u  Resolve the render-input substrate for one shot-aware-plan node.

    ``fp_png_by_fp`` maps ``fp_id -> floor-plan PNG path``; ``rendered_plate_png_by_bg``
    maps an already-rendered plate ``bg_id -> PNG path`` (the render snapshot).
    Both are caller-supplied — this function performs no IO. See module docstring
    for the node-class policy. The returned dict always carries every
    :data:`SUBSTRATE_FIELDS` key.
    r   render_actionreuse_existing_plateneeds_new_plateFNref_tree_parentsref_role_per_parentc                V    t         j                  j                  |       t              S )N)r   getr   )proless    r!   <lambda>z*resolve_render_substrate.<locals>.<lambda>o   s    z~~eiil<NOr#   )keyr   
floor_plan)orderr   rolepathr   unspecified;c              3  &   K   | ]	  }d |   yw)zmissing_parent_plate:Nr    ).0ms     r!   	<genexpr>z+resolve_render_substrate.<locals>.<genexpr>   s     >g(,gs   r   fp_less_directdirectfreshfp_plus_refsfallback_fp_onlyfp_onlyTr   )	r+   r"   str
isinstancesortedr   appendzipjoin)	plan_nodefp_idfp_png_by_fprendered_plate_png_by_bgr   raw_fpr   r,   parentsordered_parentsresolved_idsresolved_pathsmissingpnglabelsorder_ir   r   r   r-   s                      @r!   resolve_render_substraterS   I   s!    MM'"E 	o&*@@==*+u4$U++
 e$F,2S[G
 MM"45;;;aa! 	
;   &MM*?@FBEOO !L "NG&**1-"!!#c(+NN1  $&FG%wO	
 lN33 IIaL1M
 	 	1 4 CJ>g>>r  %

%H)H H  !-"0%*!( os   <G N)r   zOptional[str]returnDict[str, Any])
rF   rU   rG   r@   rH   rU   rI   rU   rT   rU   )__doc__
__future__r   typingr   r   r   r   r   r   __annotations__r   r   r   r"   rS   r    r#   r!   <module>rZ      s   > # 3 3   34a@
N @ C % / bb b !	b
 -b br#   