§
    ŸSÇj%t  ã                   ó   — d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZmZmZmZ ej        dk    rC	 ej                             d¬¦  «         ej                             d¬¦  «         n# e$ r Y nw xY w ee¦  «                             ¦   «         j        j        Zedz  Zed	z  Zed
z  Zedz  dz  Z ee¦  «         ee¦  «         ee¦  «        fD ]&Zeej         vrej          !                    de¦  «         Œ'ddl"m#Z# ddl$Z%ddl&m'Z'm(Z(m)Z) ddl*Z+ G d„ de	j,        ¦  «        Z-e.dk    r e	j/        ¦   «          dS dS )uû  
=============================================================================
KIEU STORY â€” EMPIRICAL ADVERSARIAL TEST SUITE: TIER 5 PIPELINE HARDENING
=============================================================================
Agent: teamwork_preview_challenger (Tier 5 Challenger 2 - Audio, Pipeline & Assembly)
Target Scope: Features F8 through F13
- F8: Audio Continuity & Crossfade Concat (Mode A/B, stream pre-conditioning, mute fallback)
- F9: 4-Stem Continuous Audio Architecture (stems, ducking, EQ notch)
- F10: Two-Pass Linear EBU R128 -14 LUFS Loudness Normalization & Silence Guard
- F11: Web Review Studio (0.0.0.0:1515, 188-shot matrix, concurrency 409 guard, validation)
- F12: Production Orchestrator & Automation (scene shot retrieval, versioning resolution)
- F13: Grand Feature Assembly (assemble_ep01_feature.py evaluation: 15-scene coverage,
       versioning _v*, missing scene handling, headless CI/CD execution)
=============================================================================
é    N)ÚPath)ÚDictÚAnyÚListÚOptionalÚwin32úutf-8©ÚencodingÚ05_Production_PipelineÚ
web_reviewÚ
06_ExportsÚ	04_AssetsÚvideos)Ú
TestClient)ÚAudioContinuityEngineÚ
get_ffmpegÚget_ffprobec                   ó  — e Zd ZdZed„ ¦   «         Zed„ ¦   «         Zd,dededede	e         fd	„Z
d
„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd-dededededef
d„Zd.dedededefd„Zd„ Zd„ Zd „ Zd!„ Zd"„ Zd#„ Zd$„ Zd%„ Zd&„ Zd'„ Zd(„ Zd)„ Z d*„ Z!d+„ Z"dS )/ÚTestTier5PipelineHardeningzQ
    Tier 5 Adversarial Coverage & Hardening Test Suite for Features F8-F13.
    c                 ó>  — t          ¦   «         | _        t          ¦   «         | _        t	          ¦   «         | _        t          t          j        ¦  «        | _	        t          dz  dz  | _        dt          j        dt          j        ¦   «         ¦  «        dddg i dœ| _        d S )NÚtestsz1adversarial_tier5_pipeline_hardening_results.jsonz0Tier 5 Pipeline Hardening & Adversarial Coveragez%Y-%m-%dT%H:%M:%SZr   )Ú
test_suiteÚ	timestampÚtotal_testsÚpassed_testsÚfailed_testsÚfindingsÚtest_details)r   Úffmpegr   Úffprober   Úenginer   ÚsrvÚappÚclientÚBASE_DIRÚresults_json_pathÚtimeÚstrftimeÚgmtimeÚ	telemetry)Úclss    ú<C:\Projects\KieuStory\tests\test_tier5_pipeline_hardening.pyÚ
setUpClassz%TestTier5PipelineHardening.setUpClass<   sƒ   € å‘\”\ˆŒ
Ý!‘m”mˆŒÝ*Ñ,Ô,ˆŒ
Ý¥¤Ñ(Ô(ˆŒ
Ý (¨7Ñ 2Ð5hÑ hˆÔàLÝœÐ';½T¼[¹]¼]ÑKÔKØØØØØð)
ð )
ˆŒˆˆó    c                 ó"  — 	 t          | j        dd¬¦  «        5 }t          j        | j        |dd¬¦  «         d d d ¦  «         n# 1 swxY w Y   t          d| j        › �¦  «         d S # t          $ r}t          d|› �¦  «         Y d }~d S d }~ww xY w)	NÚwr	   r
   é   F)ÚindentÚensure_asciiu   
[âœ“] Telemetry exported to: z)[!] Warning: failed to export telemetry: )Úopenr'   ÚjsonÚdumpr+   ÚprintÚ	Exception)r,   ÚfÚes      r-   ÚtearDownClassz(TestTier5PipelineHardening.tearDownClassM   s	  € ð	CÝ�cÔ+¨S¸7ÐCÑCÔCð JÀqÝ”	˜#œ-¨°1À5ÐIÑIÔIÐIðJð Jð Jñ Jô Jð Jð Jð Jð Jð Jð Jøøøð Jð Jð Jð JåÐK°CÔ4IÐKÐKÑLÔLÐLÐLÐLøÝð 	Cð 	Cð 	CÝÐA¸aÐAÐAÑBÔBÐBÐBÐBÐBÐBÐBÐBøøøøð	Cøøøs9   ‚A' ™A·A' ÁAÁA' Á
AÁA' Á'
BÁ1B	Â	BNÚ	test_nameÚpassedÚmessageÚfinding_typec                 ó
  — | j         }|j        dxx         dz  cc<   |r|j        dxx         dz  cc<   n;|j        dxx         dz  cc<   |r$|j        d                              |||dœ¦  «         ||dœ|j        d         |<   d S )	Nr   é   r   r   r   )ÚtestÚtyper?   )r>   r?   r   )Ú	__class__r+   Úappend)Úselfr=   r>   r?   r@   r,   s         r-   Ú_record_resultz)TestTier5PipelineHardening._record_resultV   sÎ   € ØŒnˆØŒ�mÐ$Ð$Ô$¨Ñ)Ð$Ð$Ñ$Øð 		ØŒM˜.Ð)Ð)Ô)¨QÑ.Ð)Ð)Ñ)Ð)àŒM˜.Ð)Ð)Ô)¨QÑ.Ð)Ð)Ñ)Øð Ø”˜jÔ)×0Ò0Ø%Ø(Ø&ð2ð 2ñ ô ð ð Øð4
ð 4
ˆŒ�nÔ% iÑ0Ð0Ð0r/   c                 ó¶  — t           dz  }|                      |                     ¦   «         d¦  «         |                     d¬¦  «        }g }t	          dd¦  «        D ]!}d|d›�}||vr|                     |¦  «         Œ"t          |¦  «        d	k    }|rd
|› �nd}|                      d||d¦  «         |                      t          |¦  «        d	d|› d�¦  «         dS )u  
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py accounts for ALL 15 scenes (C01 to C15).
        EP01 screenplay defines 15 scenes (188 shots = 29m40s). Scene 15 is the
        critical cliffhanger (Gian thá»� tá»• tiÃªn - 6 shots).
        úassemble_ep01_feature.pyz#assemble_ep01_feature.py must existr	   r
   rB   é   ÚsceneÚ02dr   z,Missing scenes in assemble_ep01_feature.py: zAll 15 scenes accounted forÚ4test_f13_01_assemble_ep01_accounts_for_all_15_scenesz$DEFECT: Missing Scene 15 in Assemblyz(assemble_ep01_feature.py misses scenes: z%. Scene 15 is the climax cliffhanger!N)	ÚPIPELINE_DIRÚ
assertTrueÚexistsÚ	read_textÚrangerF   ÚlenrH   ÚassertEqual)rG   Úscript_pathÚcontentÚmissing_scenesÚiÚexpected_scene_tagr>   Úmsgs           r-   rN   zOTestTier5PipelineHardening.test_f13_01_assemble_ep01_accounts_for_all_15_scenesl   s>  € õ #Ð%?Ñ?ˆØ�Š˜×*Ò*Ñ,Ô,Ð.SÑTÔTÐTØ×'Ò'°Ð'Ñ9Ô9ˆð ˆÝ�q˜"‘”ð 	:ð 	:ˆAØ!0¨   ÐØ!¨Ð0Ð0Ø×%Ò%Ð&8Ñ9Ô9Ð9øå�^Ñ$Ô$¨Ò)ˆØQ_ð  CÐM¸^ÐMÐMÐMð  fCˆØ×ÒÐRÐTZÐ\_ð  bHñ  	Iô  	Ið  	IØ×Ò�˜^Ñ,Ô,¨að  2RÐ\jð  2Rð  2Rð  2Rñ  	Sô  	Sð  	Sð  	Sð  	Sr/   c                 ó¤  — t           dz  }|                     d¬¦  «        }t          j        d|¦  «        }|                      |d¦  «         |                     d¦  «        }t          t          j        d|t          j        ¦  «        ¦  «        }|}|sd|› d	�nd|› d
�}|                      d||d¦  «         |  	                    |d|› d�¦  «         dS )a8  
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py adheres to user directive 2026-10-08T05:38:03Z:
        All video MP4 files must have _v<N> versioning suffix (e.g., _v1.mp4, _v2.mp4).
        Master feature output must be versioned (e.g. ep01_grand_feature_master_v1.mp4).
        rJ   r	   r
   z/output_master\s*=\s*.*?["\']([^"\']+\.mp4)["\']z/output_master must be defined with an .mp4 filerB   z_v\d+\.mp4$zoutput_master 'z' lacks _v<N> versioning suffixz' correctly versionedÚ2test_f13_02_grand_feature_master_output_versioningz,DEFECT: Non-versioned output_master filenamezH' lacks mandatory _v<N> suffix (violates Directive 2026-10-08T05:38:03Z)N)
rO   rR   ÚreÚsearchÚassertIsNotNoneÚgroupÚboolÚ
IGNORECASErH   rP   )rG   rV   rW   ÚmÚoutput_filenameÚhas_version_suffixr>   r[   s           r-   r]   zMTestTier5PipelineHardening.test_f13_02_grand_feature_master_output_versioningƒ   s.  € õ #Ð%?Ñ?ˆØ×'Ò'°Ð'Ñ9Ô9ˆõ ŒIÐHÈ'ÑRÔRˆØ×Ò˜QÐ QÑRÔRÐRØŸ'š' !™*œ*ˆå!¥"¤)¨N¸OÍRÌ]Ñ"[Ô"[Ñ\Ô\ÐØ#ˆØX^ð  ]ÐP ÐPÐPÐPÐPð  e]ð  wFð  e]ð  e]ð  e]ˆØ×ÒÐPÐRXÐZ]ð  `Nñ  	Oô  	Oð  	OØ�ŠÐ*ð  -X¸oð  -Xð  -Xð  -Xñ  	Yô  	Yð  	Yð  	Yð  	Yr/   c                 óÒ   — t           dz  }|                     d¬¦  «        }d|v pd|v pd|v pd|v }|}|sdnd	}|                      d
||d¦  «         |                      |d¦  «         dS )ai  
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py supports versioned scene masters (_v1.mp4, _v2.mp4)
        as output by production_orchestrator.py:master_scene_audio.
        Hardcoding unversioned 'ep01_sceneXX_cinematic_master.mp4' breaks when
        the orchestrator generates 'ep01_sceneXX_cinematic_master_v1.mp4'.
        rJ   r	   r
   ÚglobÚ_vÚresolve_versionedÚresolve_next_versionzlassemble_ep01_feature.py uses static unversioned filenames, incompatible with versioned orchestrator outputsz$Dynamic version resolution supportedÚ2test_f13_03_scene_inputs_support_versioned_mastersz&DEFECT: Rigid unversioned scene inputsznassemble_ep01_feature.py must support versioned scene masters (_v1.mp4) produced by production_orchestrator.pyN©rO   rR   rH   rP   )rG   rV   rW   Úhas_dynamic_resolutionr>   r[   s         r-   rl   zMTestTier5PipelineHardening.test_f13_03_scene_inputs_support_versioned_masters˜   sâ   € õ #Ð%?Ñ?ˆØ×'Ò'°Ð'Ñ9Ô9ˆð #)¨GÐ"3ð  #N°t¸w°ð  #NÐJ]ÐahÐJhð  #Nð  mCð  GNð  mNÐØ'ˆð EKð  wÐ|Ð|ð  QwˆØ×ÒÐPÐRXÐZ]ð  `Hñ  	Iô  	Ið  	IØ�ŠÐ.ð  1añ  	bô  	bð  	bð  	bð  	br/   c                 óÂ   — t           dz  }|                     d¬¦  «        }d|v pd|v }|}|sdnd}|                      d||d	¦  «         |                      |d
¦  «         dS )a9  
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py does NOT execute top-level execution/sys.exit(1) on import.
        Currently, lines 40-44 check parts and execute sys.exit(1) at top-level import,
        making the module un-importable and untestable in CI/CD environments.
        rJ   r	   r
   z__name__ == "__main__"z__name__ == '__main__'zZassemble_ep01_feature.py lacks if __name__ == '__main__': guard (calls sys.exit on import)zProtected by main guardÚ/test_f13_04_no_top_level_side_effects_on_importz4DEFECT: Module executes top-level sys.exit on importzuassemble_ep01_feature.py must be wrapped in `if __name__ == '__main__':` to allow programmatic invocation and testingNrm   )rG   rV   rW   Úhas_main_guardr>   r[   s         r-   rp   zJTestTier5PipelineHardening.test_f13_04_no_top_level_side_effects_on_importª   s¯   € õ #Ð%?Ñ?ˆØ×'Ò'°Ð'Ñ9Ô9ˆà1°WÐ<ÐcÐ@XÐ\cÐ@cˆØˆØrxð  XÐjÐjð  XˆØ×ÒÐMÈvÐWZð  ]Sñ  	Tô  	Tð  	TØ�Š˜ð  )`ñ  	aô  	að  	að  	að  	ar/   c                 óÒ   — t           dz  }|                     d¬¦  «        }d|v pd|v pd|v pd|v }|}|sdnd	}|                      d
||d¦  «         |                      |d¦  «         dS )a  
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py supports CLI flags (--dry-run, --check, --allow-missing, or argparse)
        so headless CI/CD can validate pipeline integrity without failing on missing multi-gigabyte render assets.
        rJ   r	   r
   Úargparsezsys.argvz	--dry-runz--checkzXassemble_ep01_feature.py lacks CLI argument parsing or dry-run inspection mode for CI/CDzCLI arguments supportedÚ?test_f13_05_headless_cicd_dry_run_or_missing_parts_gracefulnessz1GAP: Missing CLI argument handling / dry-run modezqassemble_ep01_feature.py should provide argparse CLI support with --dry-run / --status options for headless CI/CDNrm   )rG   rV   rW   Úhas_cli_argsr>   r[   s         r-   rt   zZTestTier5PipelineHardening.test_f13_05_headless_cicd_dry_run_or_missing_parts_gracefulnessº   sÅ   € õ #Ð%?Ñ?ˆØ×'Ò'°Ð'Ñ9Ô9ˆà! WÐ,Ðw°
¸gÐ0EÐwÈÐX_ÐI_ÐwÐclÐpwÐcwˆØˆØpvð  VÐhÐhð  }VˆØ×ÒÐ]Ð_eÐgjð  m`ñ  	aô  	að  	aØ�Š˜ð  'Zñ  	[ô  	[ð  	[ð  	[ð  	[r/   c                 óÄ   — t           dz  }|                     d¬¦  «        }d|v pd|v }| }|sdnd}|                      d||d	¦  «         |                      |d
¦  «         dS )zÿ
        [ADVERSARIAL CHALLENGE - F13]
        Verify assemble_ep01_feature.py title and logs do not contradict the 25-30 minute requirement.
        Currently line 75 prints: '7m30s' and line 37 names it '10min', while R1 requires 25-30 minutes.
        rJ   r	   r
   Ú7m30sÚ10minzrassemble_ep01_feature.py contains stale duration labels ('7m30s', '10min') contradicting 25-30m EP01 specificationzDuration labels consistentÚ.test_f13_06_duration_specification_consistencyz<GAP: Stale duration labels in script (7m30s/10min vs 25-30m)zqassemble_ep01_feature.py contains stale duration labels (7m30s / 10min) that contradict 25-30m EP01 specificationN)rO   rR   rH   ÚassertFalse)rG   rV   rW   Úhas_stale_durationr>   r[   s         r-   ry   zITestTier5PipelineHardening.test_f13_06_duration_specification_consistencyÉ   s¾   € õ #Ð%?Ñ?ˆØ×'Ò'°Ð'Ñ9Ô9ˆà$¨Ð/ÐE°7¸gÐ3EÐØ'Ð'ˆð KQð  sð  Cð  Cð  WsˆØ×ÒÐLÈfÐVYð  \Zñ  	[ô  	[ð  	[Ø×ÒÐ+ð  .añ  	bô  	bð  	bð  	bð  	br/   ç       @Té¸  ç      à?Úoutput_pathÚdurationÚ	has_audioÚfreqÚvolc                 ót  — | j         ddddd|› �g}|r+|                     dddd|› d|› �dd	d
ddddd|› �g¦  «         n|                     dg¦  «         |                     dddddt          |¦  «        |g¦  «         t          j        |dd¬¦  «        }|                      |j        dd|j        › �¦  «         dS )z1Helper to create minimal valid mp4 test fixtures.ú-yú-fÚlavfiú-izcolor=c=black:s=160x120:d=úsine=frequency=ú
:duration=ú-c:aÚaacú-b:aÚ128kú-arÚ48000ú-afúvolume=z-anú-c:vÚlibx264z-pix_fmtÚyuv420pz-tT©Úcapture_outputÚtextr   z%FFmpeg failed creating test fixture: N)r    ÚextendÚstrÚ
subprocessÚrunrU   Ú
returncodeÚstderr)rG   r   r€   r�   r‚   rƒ   ÚcmdÚress           r-   Ú_generate_test_videoz/TestTier5PipelineHardening._generate_test_videoÜ   s  € ð ŒK˜Ø�'˜4Ð!H¸hÐ!HÐ!Hð
ˆð ð 	 Ø�JŠJØ�g˜tÐ%Q°tÐ%QÐ%QÀxÐ%QÐ%QØ˜˜v v¨u°gØ� ��ðñ ô ð ð ð �JŠJ˜�wÑÔÐØ�
Š
Ø�I˜z¨9°d½CÀ¹M¼MØð
ñ 	ô 	ð 	õ Œn˜S°¸DÐAÑAÔAˆØ×Ò˜œ¨Ð,`ÐTWÔT^Ð,`Ð,`ÑaÔaÐaÐaÐar/   ç      @éè  ç333333Ó?c                 óº   — | j         ddddd|› d|› �dd|› �d	d
dddd|g}t          j        |dd¬¦  «        }|                      |j        dd|j        › �¦  «         dS )z;Helper to create minimal valid audio wav/m4a test fixtures.r…   r†   r‡   rˆ   r‰   rŠ   r‘   r’   r‹   rŒ   r�   rŽ   r�   r�   Tr–   r   z&FFmpeg failed creating audio fixture: N)r    r›   rœ   rU   r�   rž   )rG   r   r€   r‚   rƒ   rŸ   r    s          r-   Ú_generate_test_audioz/TestTier5PipelineHardening._generate_test_audioñ   sŒ   € ð ŒK˜Ø�'˜4Ð!M°4Ð!MÐ!MÀ8Ð!MÐ!MØ�?˜S�?�?Ø�E˜6 6¨5°'Øð
ˆõ Œn˜S°¸DÐAÑAÔAˆØ×Ò˜œ¨Ð,aÐUXÔU_Ð,aÐ,aÑbÔbÐbÐbÐbr/   c                 ó„  — t          j        ¦   «         5 }t          |¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }|                      |dd¬¦  «         |                      |ddd	¬
¦  «         | j                             ||g|dd¬¦  «        }|                      |d¦  «         |                      t          j	         
                    |¦  «        ¦  «         | j                             |¦  «        }|                      |d         d¦  «         |                      |d         d¦  «         | j                             ||g|ddd¬¦  «        }	|                      |	d¦  «         |                      t          j	         
                    |¦  «        ¦  «         | j                             |¦  «        }
|                      |
d         ¦  «         |                      |
d         d¦  «         |                      ddd¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a  
        [ADVERSARIAL CHALLENGE - F8]
        Stress test stitch_with_audio_crossfade when input contains video WITHOUT audio stream (-an).
        Engine must synthesize aevalsrc=0 stereo silence and produce a valid 48kHz AAC master
        without FFmpeg crash.
        zsilent_shot.mp4zaudio_shot.mp4zout_mode_a.mp4zout_mode_b.mp4r|   F)r€   r�   Tr}   )r€   r�   r‚   Úboundary_smoothing)ÚmodeÚnormalize_lufsz?stitch_with_audio_crossfade Mode A must succeed with mute videor�   z8Mode A output must have audio track despite silent inputÚsample_rateé€»  r~   Ú
acrossfade)Úcrossfade_durr©   rª   z?stitch_with_audio_crossfade Mode B must succeed with mute videoÚ1test_f08_mute_fallback_and_stream_preconditioningz@Both Mode A and Mode B synthesize stereo silence for mute videosN)ÚtempfileÚTemporaryDirectoryr   rš   r¡   r"   Ústitch_with_audio_crossfaderP   ÚosÚpathrQ   Úinspect_shot_audiorU   rH   )rG   ÚtmpdirÚtdÚvid1Úvid2Ú
out_mode_aÚ
out_mode_bÚok_aÚrep_aÚok_bÚrep_bs              r-   r¯   zLTestTier5PipelineHardening.test_f08_mute_fallback_and_stream_preconditioningý   s›  € õ Ô(Ñ*Ô*ð  	_¨fÝ�f‘”ˆBÝ�rÐ-Ñ-Ñ.Ô.ˆDÝ�rÐ,Ñ,Ñ-Ô-ˆDÝ˜RÐ"2Ñ2Ñ3Ô3ˆJÝ˜RÐ"2Ñ2Ñ3Ô3ˆJà×%Ò% d°SÀEÐ%ÑJÔJÐJØ×%Ò% d°SÀDÈsÐ%ÑSÔSÐSð ”;×:Ò:Ø�t�˜jÐ/CÐTYð ;ñ ô ˆDð �OŠO˜DÐ"cÑdÔdÐdØ�OŠO�BœGŸNšN¨:Ñ6Ô6Ñ7Ô7Ð7ð ”K×2Ò2°:Ñ>Ô>ˆEØ�OŠO˜E +Ô.Ð0jÑkÔkÐkØ×Ò˜U =Ô1°5Ñ9Ô9Ð9ð ”;×:Ò:Ø�t�˜j¸À,Ð_dð ;ñ ô ˆDð �OŠO˜DÐ"cÑdÔdÐdØ�OŠO�BœGŸNšN¨:Ñ6Ô6Ñ7Ô7Ð7Ø”K×2Ò2°:Ñ>Ô>ˆEØ�OŠO˜E +Ô.Ñ/Ô/Ð/Ø×Ò˜U =Ô1°5Ñ9Ô9Ð9à×ÒÐ SÐUYð  \^ñ  _ô  _ð  _ðA 	_ð  	_ð  	_ñ  	_ô  	_ð  	_ð  	_ð  	_ð  	_ð  	_ð  	_ð  	_øøøð  	_ð  	_ð  	_ð  	_ð  	_ð  	_s   ”HH5È5H9È<H9c                 óD  — t          j        ¦   «         5 }t          |¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }|                      |dddd¬¦  «         | j                             |¦  «        }| j                             |g|dd¬	¦  «        }|                      |¦  «         | j                             |¦  «        }|  	                    |d
         dd|d
         › d�¦  «         |  
                    ddd¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zî
        [ADVERSARIAL CHALLENGE - F8]
        Empirical test of active RMS gain staging:
        When audio has high peak (e.g. 0.0 dBTP), headroom protection must cap gain
        to ensure max_volume_db + gain_adj <= -1.0 dBTP.
        zloud_shot.mp4zstaged_out.mp4r|   Tr£   g      ð?©r€   r�   r‚   rƒ   F)Úactive_gain_stagingrª   Úmax_volume_dbgÍÌÌÌÌÌì¿z*Headroom guard must prevent clipping (got z dB)Ú2test_f08_gain_staging_headroom_clipping_protectionz&Headroom guard prevents audio clippingN)r°   r±   r   rš   r¡   r"   rµ   r²   rP   ÚassertLessEqualrH   )rG   r¶   r·   Úloud_vidÚout_vidÚ
rep_beforeÚokÚ	rep_afters           r-   rÄ   zMTestTier5PipelineHardening.test_f08_gain_staging_headroom_clipping_protection&  sº  € õ Ô(Ñ*Ô*ð 	F¨fÝ�f‘”ˆBÝ˜2 Ñ/Ñ0Ô0ˆHÝ˜"Ð/Ñ/Ñ0Ô0ˆGð ×%Ò% h¸ÈÐSWÐ]`Ð%ÑaÔaÐaØœ×7Ò7¸ÑAÔAˆJà”×8Ò8Ø�
˜G¸Èeð 9ñ ô ˆBð �OŠO˜BÑÔÐØœ×6Ò6°wÑ?Ô?ˆIð × Ò  ¨?Ô!;¸Tð  DQÐpyð  {Jô  qKð  DQð  DQð  DQñ  Rô  Rð  RØ×ÒÐ TÐVZð  ]Eñ  Fô  Fð  Fð#	Fð 	Fð 	Fñ 	Fô 	Fð 	Fð 	Fð 	Fð 	Fð 	Fð 	Fð 	Føøøð 	Fð 	Fð 	Fð 	Fð 	Fð 	Fs   ”C4DÄDÄDc                 ó€  — t          j        ¦   «         5 }t          |¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }|                      |dddd¬	¦  «         |                      |d
dd¬¦  «         |                      |d
dd¬¦  «         | j                             ||||dddd¬¦  «        }|                      |d¦  «         |                      t          j
                             |¦  «        ¦  «         | j                             |¦  «        }|                      |d         ¦  «         |                      |d         d¦  «         |                      |d         d¦  «         |                      ddd¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a#  
        [ADVERSARIAL CHALLENGE - F9]
        Verify mix_four_stems operates correctly when optional stems (Stem 3 Foley, Stem 4 Dialogue)
        are omitted, and only Stem 1 BGM and Stem 2 Ambience are provided.
        Must succeed, apply notch filter, and normalize to -14 LUFS.
        zscene_shot.mp4zbgm.m4azambience.m4azmixed_master.mp4r¢   Ti,  r~   rÁ   g      @iô  r¤   )r€   r‚   rƒ   éx   gš™™™™™É?Nç      ,ÀF)Ú
video_pathr   Ú	stem1_bgmÚstem2_ambienceÚstem3_foleyÚstem4_dialogueÚtarget_lufsÚtwo_passz<mix_four_stems must succeed with only BGM and Ambience stemsr�   Úchannelsr2   r«   r¬   Ú-test_f09_four_stem_mixing_with_optional_stemsz;mix_four_stems gracefully mixes partial stems without error)r°   r±   r   rš   r¡   r¦   r"   Úmix_four_stemsrP   r³   r´   rQ   rµ   rU   rH   )	rG   r¶   r·   ÚvidÚbgmÚambÚoutrÉ   Úreps	            r-   rÖ   zHTestTier5PipelineHardening.test_f09_four_stem_mixing_with_optional_stems@  s)  € õ Ô(Ñ*Ô*ð 	V¨fÝ�f‘”ˆBÝ�bÐ+Ñ+Ñ,Ô,ˆCÝ�b˜9‘nÑ%Ô%ˆCÝ�b˜>Ñ)Ñ*Ô*ˆCÝ�bÐ-Ñ-Ñ.Ô.ˆCà×%Ò% c°CÀ4ÈcÐWZÐ%Ñ[Ô[Ð[Ø×%Ò% c°C¸cÀsÐ%ÑKÔKÐKØ×%Ò% c°C¸cÀsÐ%ÑKÔKÐKà”×+Ò+ØØØØ"Ø Ø#Ø!Øð ,ñ 	ô 	ˆBð �OŠO˜BÐ ^Ñ_Ô_Ð_Ø�OŠO�BœGŸNšN¨3Ñ/Ô/Ñ0Ô0Ð0Ø”+×0Ò0°Ñ5Ô5ˆCØ�OŠO˜C Ô,Ñ-Ô-Ð-Ø×Ò˜S œ_¨aÑ0Ô0Ð0Ø×Ò˜S Ô/°Ñ7Ô7Ð7à×ÒÐ OÐQUð  XUñ  Vô  Vð  Vð9	Vð 	Vð 	Vñ 	Vô 	Vð 	Vð 	Vð 	Vð 	Vð 	Vð 	Vð 	Vøøøð 	Vð 	Vð 	Vð 	Vð 	Vð 	Vs   ”FF3Æ3F7Æ:F7c                 ó¼  — t          j        ¦   «         5 }t          |¦  «        }t          |dz  ¦  «        }t          |dz  ¦  «        }| j        dddddddddd	d
ddddd|g}t          j        |dd¬¦  «         | j                             |¦  «        }|  	                    |d¦  «         |  
                    |                     d¦  «        d¦  «         | j                             ||dd¬¦  «        }|ot          j                             |¦  «        }|sdnd}	|                      d||	d¦  «         |  
                    ||	¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a  
        [ADVERSARIAL CHALLENGE - F10]
        Verify measure_loudness detects pure silence (-inf) and sets is_silent=True.
        Verify normalize_loudness with two_pass=True safely falls back on silent audio
        without crashing FFmpeg or raising JSON decode errors.
        zpure_silence.mp4znorm_silent.mp4r…   r†   r‡   rˆ   zcolor=c=black:s=160x120:d=2.0z!aevalsrc=0:d=2.0:s=48000:c=stereor“   r”   r‹   rŒ   r�   rŽ   z	-shortestTr–   z0measure_loudness must return dict on silent fileÚ	is_silentz'is_silent must be True for pure silencerÍ   )rÓ   rÔ   z]normalize_loudness on pure silence triggers FFmpeg AAC Qavg:nan crash in single-pass fallbackz8Silence guard successfully intercepts -inf without crashÚ4test_f10_two_pass_loudnorm_measurement_silence_guardzADEFECT: Pure silence crashes FFmpeg loudnorm single-pass fallbackN)r°   r±   r   rš   r    r›   rœ   r"   Úmeasure_loudnessr`   rP   ÚgetÚnormalize_loudnessr³   r´   rQ   rH   )
rG   r¶   r·   Ú
silent_vidrÇ   rŸ   ÚmeasrÉ   r>   r[   s
             r-   rß   zOTestTier5PipelineHardening.test_f10_two_pass_loudnorm_measurement_silence_guarde  sÐ  € õ Ô(Ñ*Ô*ð 	)¨fÝ�f‘”ˆBÝ˜RÐ"4Ñ4Ñ5Ô5ˆJÝ˜"Ð0Ñ0Ñ1Ô1ˆGð ”˜TØ�g˜tÐ%DØ�g˜tÐ%HØ˜	 6¨5°&¸&À+ØðˆCõ ŒN˜3¨t¸$Ð?Ñ?Ô?Ð?à”;×/Ò/°
Ñ;Ô;ˆDØ× Ò  Ð'YÑZÔZÐZØ�OŠO˜DŸHšH [Ñ1Ô1Ð3\Ñ]Ô]Ð]à”×/Ò/°
¸GÐQVÐaeÐ/ÑfÔfˆBØÐ3�BœGŸNšN¨7Ñ3Ô3ˆFØyð  @ÐqÐqð  F@ˆCØ×ÒÐ VÐX^Ð`cð  fiñ  jô  jð  jØ�OŠO˜F CÑ(Ô(Ð(ð/	)ð 	)ð 	)ñ 	)ô 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)øøøð 	)ð 	)ð 	)ð 	)ð 	)ð 	)s   ”D0EÅEÅEc                 ó¸   — |                       t          j        dd¦  «         |                       t          j        dd¦  «         |                      ddd¦  «         dS )	z}
        [ADVERSARIAL CHALLENGE - F11]
        Verify web_review/server.py default host is 0.0.0.0 and port is 1515.
        z0.0.0.0z8DEFAULT_HOST must be 0.0.0.0 for Tailscale remote accessië  z6DEFAULT_PORT must be 1515 per PROJECT.md and AGENTS.mdÚ+test_f11_01_default_host_and_port_constantsTz/Host 0.0.0.0 and port 1515 correctly configuredN)rU   r#   ÚDEFAULT_HOSTÚDEFAULT_PORTrH   )rG   s    r-   ræ   zFTestTier5PipelineHardening.test_f11_01_default_host_and_port_constants‰  so   € ð
 	×Ò�Ô)¨9Ð6pÑqÔqÐqØ×Ò�Ô)¨4Ð1iÑjÔjÐjØ×ÒÐIÈ4ð  RCñ  	Dô  	Dð  	Dð  	Dð  	Dr/   c                 óª  — | j                              d¦  «        }|                      |j        d¦  «         |                     ¦   «         }|                      |                     d¦  «        d¦  «         |                     dg ¦  «        }|                      t          |¦  «        d¦  «         t          d„ |D ¦   «         d¦  «        }|                      |d	¦  «         |                      |                     d
¦  «        d¦  «         |                      t          |                     dg ¦  «        ¦  «        d¦  «         |                      ddd¦  «         dS )zÆ
        [ADVERSARIAL CHALLENGE - F11]
        Verify /api/matrix/ep01 returns all 188 shots across all 15 scenes.
        Explicitly check Scene 15 (id='ep01_scene15') has exactly 6 shots.
        z/api/matrix/ep01éÈ   Útotal_shotsé¼   Úscenesé   c              3   óL   K  — | ]}|                      d ¦  «        dk    ¯|V — Œ dS )Úscene_idÚep01_scene15N)rá   )Ú.0Úss     r-   ú	<genexpr>zbTestTier5PipelineHardening.test_f11_02_matrix_ep01_full_188_shots_and_15_scenes.<locals>.<genexpr>¡  s8   è è € ÐNÐN˜1¨!¯%ª%°
Ñ*;Ô*;¸~Ò*MÐ*M�QÐ*MÐ*MÐ*MÐ*MÐNÐNr/   Nz(ep01_scene15 must be in /api/matrix/ep01Úshots_totalé   ÚshotsÚ4test_f11_02_matrix_ep01_full_188_shots_and_15_scenesTz;Matrix EP01 correctly serves all 188 shots across 15 scenes)	r%   rá   rU   Ústatus_coder6   rT   Únextr`   rH   )rG   ÚrespÚdatarí   Úsc15s        r-   rø   zOTestTier5PipelineHardening.test_f11_02_matrix_ep01_full_188_shots_and_15_scenes’  sI  € ð Œ{�ŠÐ1Ñ2Ô2ˆØ×Ò˜Ô)¨3Ñ/Ô/Ð/Ø�yŠy‰{Œ{ˆà×Ò˜Ÿš -Ñ0Ô0°#Ñ6Ô6Ð6Ø—’˜( BÑ'Ô'ˆØ×Ò�˜V™œ bÑ)Ô)Ð)õ ÐNÐN ÐNÑNÔNÐPTÑUÔUˆØ×Ò˜TÐ#MÑNÔNÐNØ×Ò˜Ÿš -Ñ0Ô0°!Ñ4Ô4Ð4Ø×Ò�˜TŸXšX g¨rÑ2Ô2Ñ3Ô3°QÑ7Ô7Ð7à×ÒÐRÐTXð  [Xñ  	Yô  	Yð  	Yð  	Yð  	Yr/   c                 ó�  — t           j        d         }	 dt           j        d<   | j                             dddi¬¦  «        }|                      |j        d¦  «         |                      |                     ¦   «                              d¦  «        d¦  «         | j                             d	d
di¬¦  «        }|                      |j        d¦  «         |                      |                     ¦   «                              d¦  «        d¦  «         dt           j        d<   | j                             dddi¬¦  «        }|                      |j        d¦  «         | j                             d	d
di¬¦  «        }|                      |j        d¦  «         |                      ddd¦  «         |t           j        d<   dS # |t           j        d<   w xY w)a'  
        [ADVERSARIAL CHALLENGE - F11]
        Verify HTTP 409 Conflict rejection when state machine is busy:
        1. When status == 'generating', both /api/generate and /api/concat return 409.
        2. When status == 'concatenating', both /api/generate and /api/concat return 409.
        ÚstatusÚ
generatingú/api/generateÚpromptztest prompt©r6   i™  Úbusyú/api/concatrð   Úep01_scene01Úconcatenatingztest prompt 2Úep01_scene02Ú'test_f11_03_concurrency_409_state_guardTz.Concurrency 409 guard active on both endpointsN)	r#   Ú	gen_stater%   ÚpostrU   rù   r6   rá   rH   )rG   Úoriginal_statusÚr_genÚr_conÚr_gen2Úr_con2s         r-   r	  zBTestTier5PipelineHardening.test_f11_03_concurrency_409_state_guard¨  s¸  € õ œ-¨Ô1ˆð	6à&2�CŒM˜(Ñ#Ø”K×$Ò$ _¸HÀmÐ;TÐ$ÑUÔUˆEØ×Ò˜UÔ.°Ñ4Ô4Ð4Ø×Ò˜UŸZšZ™\œ\×-Ò-¨hÑ7Ô7¸Ñ@Ô@Ð@à”K×$Ò$ ]¸*ÀnÐ9UÐ$ÑVÔVˆEØ×Ò˜UÔ.°Ñ4Ô4Ð4Ø×Ò˜UŸZšZ™\œ\×-Ò-¨hÑ7Ô7¸Ñ@Ô@Ð@ð '6�CŒM˜(Ñ#Ø”[×%Ò% o¸XÀÐ<WÐ%ÑXÔXˆFØ×Ò˜VÔ/°Ñ5Ô5Ð5à”[×%Ò% m¸:À~Ð:VÐ%ÑWÔWˆFØ×Ò˜VÔ/°Ñ5Ô5Ð5à×ÒÐ IÈ4ð  RBñ  Cô  Cð  Cà&5�CŒM˜(Ñ#Ð#Ð#ø o�CŒM˜(Ñ#Ð5Ð5Ð5Ð5s   ”FF4 Æ4Gc                 ó  — | j                              di ¬¦  «        }|                      |j        dd¦  «         | j                              dddi¬¦  «        }|                      |j        dd¦  «         |                      d	d
d¦  «         dS )zÜ
        [ADVERSARIAL CHALLENGE - F11]
        Verify schema validation on endpoints:
        - POST /api/generate without prompt or shot_id -> HTTP 422
        - POST /api/concat with empty scene_id -> HTTP 422
        r  r  i¦  z<POST /api/generate without prompt or shot_id must return 422r  rð   z   z9POST /api/concat with whitespace scene_id must return 422Ú test_f11_04_api_validation_rigorTz6Endpoint input validation enforces required parametersN)r%   r  rU   rù   rH   )rG   r  r  s      r-   r  z;TestTier5PipelineHardening.test_f11_04_api_validation_rigorÇ  s•   € ð ”× Ò  °rÐ Ñ:Ô:ˆØ×Ò˜Ô*¨CÐ1oÑpÔpÐpà”× Ò  °jÀ%Ð5HÐ ÑIÔIˆØ×Ò˜Ô*¨CÐ1lÑmÔmÐmà×ÒÐ>ÀÐF~ÑÔÐÐÐr/   c                 ó  — d}	 t          j        |¦  «         |                      |t           j        d         d         ¦  «         |                      ddd¦  «         dS # t
          $ r#}|                      d|› �¦  «         Y d}~dS d}~ww xY w)	z°
        [ADVERSARIAL CHALLENGE - F11]
        Verify log_msg function does not crash on complex Vietnamese diacritics
        even if stdout has encoding limitations.
        u‡   ðŸŽ¬ Tháº­p NgÅ© NiÃªn: Ä�oáº¡n TrÆ°á»�ng KÃ½ â€” ThÃºy Kiá»�u ngáº¥n lá»‡ bÃªn náº¥m má»“ sÃ¨ sÃ¨ ngá»�n cá»� dáº§u dáº§u Ä�áº¡m TiÃªnÚlogséÿÿÿÿÚ(test_f11_05_logging_utf8_encoding_safetyTz2log_msg successfully buffers Vietnamese diacriticsz*log_msg crashed on Vietnamese diacritics: N)r#   Úlog_msgÚassertInr
  rH   r9   Úfail)rG   Úcomplex_vietnameser;   s      r-   r  zCTestTier5PipelineHardening.test_f11_05_logging_utf8_encoding_safetyÖ  sÆ   € ð gÐð	HÝŒKÐ*Ñ+Ô+Ð+Ø�MŠMÐ,­c¬m¸FÔ.CÀBÔ.GÑHÔHÐHØ×ÒÐ JÈDð  SGñ  Hô  Hð  Hð  Hð  HøÝð 	Hð 	Hð 	HØ�IŠIÐFÀ1ÐFÐFÑGÔGÐGÐGÐGÐGÐGÐGÐGøøøøð	Høøøs   „AA Á
B
Á'BÂB
c                 ó6  — t          dd¦  «        D ]p}d|d›�}t          j        |¦  «        }|                      t	          |¦  «        dd|› �¦  «         |dk    r'|                      t	          |¦  «        d|› d	�¦  «         Œq|                      d
dd¦  «         dS )zÍ
        [ADVERSARIAL CHALLENGE - F12]
        Verify production_orchestrator.get_shots_for_scene retrieves shots for all 15 scenes.
        Verify Scene 15 (ep01_scene15) returns exactly 6 shots.
        rB   rK   Ú
ep01_scenerM   r   zNo shots retrieved for rî   rö   z must have exactly 6 shotsÚ+test_f12_01_all_15_scenes_shots_retrievableTz0All 15 scenes have indexed shots in orchestratorN)rS   ÚorchÚget_shots_for_sceneÚassertGreaterrT   rU   rH   )rG   rY   Úsc_idr÷   s       r-   r  zFTestTier5PipelineHardening.test_f12_01_all_15_scenes_shots_retrievableè  sÈ   € õ �q˜"‘”ð 	Vð 	VˆAØ( Ð(Ð(Ð(ˆEÝÔ,¨UÑ3Ô3ˆEØ×Ò�s 5™zœz¨1Ð.OÈÐ.OÐ.OÑPÔPÐPØ�BŠwˆwØ× Ò ¥ U¡¤¨Q°5Ð0TÐ0TÐ0TÑUÔUÐUøØ×ÒÐIÈ4ð  RDñ  	Eô  	Eð  	Eð  	Eð  	Er/   c                 ó  — t          j        ¦   «         5 }t          |¦  «        }t          j        |d¦  «        }|                      |j        d¦  «         |                     ¦   «          t          j        |d¦  «        }|                      |j        d¦  «         |                     ¦   «          t          j        |d¦  «        }|                      |j        d¦  «         |                      ddd¦  «         ddd¦  «         dS # 1 swxY w Y   dS )	a  
        [ADVERSARIAL CHALLENGE - F12]
        Verify production_orchestrator.resolve_versioned_path:
        - When no version exists -> returns stem_v1.mp4
        - When stem_v1.mp4 exists -> returns stem_v2.mp4
        - When stem_v2.mp4 exists -> returns stem_v3.mp4
        Útest_scene_masterztest_scene_master_v1.mp4ztest_scene_master_v2.mp4ztest_scene_master_v3.mp4Ú1test_f12_02_resolve_versioned_path_auto_incrementTz;Versioned path generator correctly increments _v1, _v2, _v3N)	r°   r±   r   r  Úresolve_versioned_pathrU   ÚnameÚtouchrH   )rG   r¶   r·   Úp1Úp2Úp3s         r-   r$  zLTestTier5PipelineHardening.test_f12_02_resolve_versioned_path_auto_incrementö  sX  € õ Ô(Ñ*Ô*ð 	Z¨fÝ�f‘”ˆBÝÔ,¨RÐ1DÑEÔEˆBØ×Ò˜RœWÐ&@ÑAÔAÐAØ�HŠH‰JŒJˆJåÔ,¨RÐ1DÑEÔEˆBØ×Ò˜RœWÐ&@ÑAÔAÐAØ�HŠH‰JŒJˆJåÔ,¨RÐ1DÑEÔEˆBØ×Ò˜RœWÐ&@ÑAÔAÐAà×ÒÐ SÐUYð  \Yñ  Zô  Zð  Zð	Zð 	Zð 	Zñ 	Zô 	Zð 	Zð 	Zð 	Zð 	Zð 	Zð 	Zð 	Zøøøð 	Zð 	Zð 	Zð 	Zð 	Zð 	Zs   ”CD Ä DÄDc                 óX  — t          j        ¦   «         5 }t          j        }	 t	          |¦  «        t          _        t          j        dz  }t          j        dz  }|                     d¦  «         t          j        d¦  «         |                     d¦  «         t          j        d¦  «        }|  	                    |¦  «         |  
                    |j        dd¦  «         |                      ddd	¦  «         |t          _        n# |t          _        w xY w	 d
d
d
¦  «         d
S # 1 swxY w Y   d
S )z”
        [ADVERSARIAL CHALLENGE - F12]
        Verify find_rendered_video prioritizes the highest version number (_v2 > _v1 > unversioned).
        zep01_test_shot01_10s_v1.mp4zep01_test_shot01_10s_v2.mp4sÐ  00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000g{®Gáz„?Úep01_test_shot01z,find_rendered_video must choose _v2 over _v1Ú2test_f12_03_find_rendered_video_version_preferenceTz3find_rendered_video prioritizes highest version tagN)r°   r±   r  Ú
VIDEOS_DIRr   Úwrite_bytesr(   ÚsleepÚfind_rendered_videor`   rU   r&  rH   )rG   r¶   Úorig_videos_dirÚshot_v1Úshot_v2Úfounds         r-   r-  zMTestTier5PipelineHardening.test_f12_03_find_rendered_video_version_preference  sh  € õ
 Ô(Ñ*Ô*ð 	2¨fÝ"œoˆOð2Ý"& v¡,¤,•”Ýœ/Ð,IÑI�Ýœ/Ð,IÑI�ð ×#Ò# KÑ0Ô0Ð0Ý”
˜4Ñ Ô Ð Ø×#Ò# KÑ0Ô0Ð0åÔ0Ð1CÑDÔD�Ø×$Ò$ UÑ+Ô+Ð+Ø× Ò  ¤Ð-JÐLzÑ{Ô{Ð{Ø×#Ò#Ð$XÐZ^ð  aVñ  Wô  Wð  Wà"1•”�ø /•”Ð1Ð1Ð1Ð1�ð#	2ð 	2ð 	2ñ 	2ô 	2ð 	2ð 	2ð 	2ð 	2ð 	2ð 	2ð 	2øøøð 	2ð 	2ð 	2ð 	2ð 	2ð 	2s)   ”D¢CD Ã3DÄ DÄDÄD#Ä&D#c                 óˆ   — t          j        d¦  «        }|                      |d¦  «         |                      ddd¦  «         dS )z·
        [ADVERSARIAL CHALLENGE - F12]
        Verify concat_scene_shots aborts safely and returns None when shots are missing,
        without throwing unhandled exceptions.
        rñ   z:concat_scene_shots must return None when shots are missingÚ6test_f12_04_concat_scene_shots_missing_shot_safe_abortTz;concat_scene_shots returns None gracefully on missing shotsN)r  Úconcat_scene_shotsÚassertIsNonerH   )rG   Úresults     r-   r7  zQTestTier5PipelineHardening.test_f12_04_concat_scene_shots_missing_shot_safe_abort%  s_   € õ Ô(¨Ñ8Ô8ˆà×Ò˜&Ð"^Ñ_Ô_Ð_Ø×ÒÐTÐVZð  ]Zñ  	[ô  	[ð  	[ð  	[ð  	[r/   c                 ób  — d}g }t                                d¦  «        D ]Q}|                     d¬¦  «        }||v r5d|j                             ¦   «         v r|                     |j        ¦  «         ŒR|                      t          |¦  «        dd|› �¦  «         |                      dd	d
¦  «         dS )zË
        [ADVERSARIAL CHALLENGE - F12]
        Scan all pipeline scripts in 05_Production_Pipeline to verify zero use
        of cv2.VideoWriter for concatenation (which destroys audio streams).
        zcv2.VideoWriterz*.pyr	   r
   Úconcatr   z)Found cv2.VideoWriter in concat scripts: Ú3test_f12_05_no_opencv_concat_in_any_pipeline_scriptTz9Zero OpenCV VideoWriter violations in production pipelineN)	rO   rh   rR   r&  ÚlowerrF   rU   rT   rH   )rG   Úforbidden_patternÚviolating_scriptsÚpy_filer˜   s        r-   r=  zNTestTier5PipelineHardening.test_f12_05_no_opencv_concat_in_any_pipeline_script0  sÜ   € ð .ÐØÐÝ#×(Ò(¨Ñ0Ô0ð 	7ð 	7ˆGØ×$Ò$¨gÐ$Ñ6Ô6ˆDØ  DÐ(Ð(¨X¸¼×9KÒ9KÑ9MÔ9MÐ-MÐ-MØ!×(Ò(¨¬Ñ6Ô6Ð6øØ×Ò�Ð.Ñ/Ô/°Ð4sÐ`qÐ4sÐ4sÑtÔtÐtØ×ÒÐQÐSWð  ZUñ  	Vô  	Vð  	Vð  	Vð  	Vr/   )N)r|   Tr}   r~   )r¢   r£   r¤   )#Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úclassmethodr.   r<   rš   rb   r   rH   rN   r]   rl   rp   rt   ry   ÚfloatÚintr¡   r¦   r¯   rÄ   rÖ   rß   ræ   rø   r	  r  r  r  r$  r-  r7  r=  © r/   r-   r   r   7   s€  € € € € € ðð ð ð
ð 
ñ „[ð
ð  ðCð Cñ „[ðCð
ð 
¨ð 
°Tð 
ÀCð 
ÐW_Ð`cÔWdð 
ð 
ð 
ð 
ð,Sð Sð Sð.Yð Yð Yð*bð bð bð$að að að [ð [ð [ðbð bð bð&bð b°ð b¸uð bÐW[ð bÐjmð bÐzð bð bð bð bð*
cð 
c°ð 
c¸uð 
cÐRUð 
cÐchð 
cð 
cð 
cð 
cð'_ð '_ð '_ðRFð Fð Fð4#Vð #Vð #VðJ)ð )ð )ðHDð Dð DðYð Yð Yð,6ð 6ð 6ð>@ð @ð @ðHð Hð Hð$Eð Eð EðZð Zð Zð.2ð 2ð 2ð0	[ð 	[ð 	[ðVð Vð Vð Vð Vr/   r   Ú__main__)0rE  r³   Úsysr^   r6   r(   Úshutilr°   r›   ÚunittestÚpathlibr   Útypingr   r   r   r   ÚplatformÚstdoutÚreconfigurerž   r9   Ú__file__ÚresolveÚparentr&   rO   ÚWEB_REVIEW_DIRÚEXPORTS_DIRr.  rš   Úpr´   ÚinsertÚstarlette.testclientr   Úserverr#   Úaudio_continuity_enginer   r   r   Úproduction_orchestratorr  ÚTestCaser   rB  ÚmainrI  r/   r-   ú<module>r`     sU  ððð ð  
€	€	€	Ø 
€
€
€
Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø €€€Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,ð „<�7ÒÐðØŒ
×Ò¨ÐÑ0Ô0Ð0ØŒ
×Ò¨ÐÑ0Ô0Ð0Ð0øØð ð ð Øˆðøøøð ˆ4�‰>Œ>×!Ò!Ñ#Ô#Ô*Ô1€ØÐ2Ñ2€Ø˜LÑ(€Ø˜Ñ%€Ø˜Ñ# hÑ.€
à
ˆ#ˆlÑ
Ô
˜S˜S Ñ0Ô0°#°#°h±-´-Ð	@ð ð €AØ�”ÐÐØŒ�Š˜˜1ÑÔÐøà +Ð +Ð +Ð +Ð +Ð +Ø Ð Ð Ð Ø RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RØ &Ð &Ð &Ð &ðFVð FVð FVð FVð FV Ô!2ñ FVô FVð FVðR ˆzÒÐØ€H„M�O„O€O€O€Oð Ðs   Á6A< Á<BÂB