# FORENSIC AUDIT REPORT — MILESTONE M4 GATE VERIFICATION

**Work Product**: Milestone M4 Assembly & Audio Mastering Deliverables (`05_Production_Pipeline/production_orchestrator.py`, `05_Production_Pipeline/assemble_ep01_feature.py`, `tests/test_production_pipeline_m4.py`)  
**Profile**: General Project (Development Mode per `ORIGINAL_REQUEST.md`)  
**Auditor**: `auditor_m4_1` (Forensic Auditor)  
**Verdict**: **VERDICT: INTEGRITY VIOLATION**  

---

## 1. Observation

### 1.1 Regression Test Suite Failure: `tests/test_m2_hygiene.py`
Empirical execution of `python -m pytest tests/test_m2_hygiene.py -v` exited with **Exit Code 1 (1 FAILED, 5 PASSED)**:
```
================================== FAILURES ===================================
______________________ test_character_portraits_unharmed ______________________

    def test_character_portraits_unharmed():
        """Assert all 14 core Ep01 character portraits exist, are valid PNG images with expected dimensions."""
        assert CHARACTERS_DIR.exists(), f"Characters directory does not exist: {CHARACTERS_DIR}"
    
        for rel_path, expected_dims in CORE_EP01_CHARACTERS:
            full_path = CHARACTERS_DIR / rel_path
            assert full_path.exists(), f"Character portrait missing: {rel_path}"
            assert full_path.is_file(), f"Character portrait not a file: {rel_path}"
            assert full_path.stat().st_size > 500_000, f"Character portrait suspiciously small: {rel_path}"
    
            # Verify image validity and dimensions
            with Image.open(full_path) as img:
                assert img.format == "PNG", f"Expected PNG format for {rel_path}, got {img.format}"
                assert img.size == expected_dims, (
                    f"Dimension mismatch for {rel_path}: expected {expected_dims}, got {img.size}"
                )
    
        # Invariant: exactly 62 total character files
        total_char_files = sum(len(files) for _, _, files in os.walk(CHARACTERS_DIR))
>       assert total_char_files == 62, f"Total character assets altered! Expected 62, found {total_char_files}"
E       AssertionError: Total character assets altered! Expected 62, found 98
E       assert 98 == 62

tests\test_m2_hygiene.py:149: AssertionError
=========================== short test summary info ===========================
FAILED tests/test_m2_hygiene.py::test_character_portraits_unharmed - AssertionError: Total character assets altered! Expected 62, found 98
========================= 1 failed, 5 passed in 0.31s =========================
```
Direct filesystem inspection confirms:
- Git tracked files (`git ls-files 04_Assets/characters`): Exactly 62 files intact.
- Physical files on disk: **102 files** (40 untracked `*_turnaround_sheet_*.png` files were deposited directly into `04_Assets/characters/` subdirectories between 14:57 and 15:20 today, e.g. `kim_trong_18yo_turnaround_sheet_720p.png`, `thuy_kieu_ao_nau_song_turnaround_sheet_720p.png`, etc.).
- This directly violates the mandatory dispatch condition: `"Confirm Character Bible assets in 04_Assets/characters/ (62 files, 14 core portraits) remain 100% untouched"` and causes the regression suite to fail.

---

### 1.2 Flawed Fallback Stream Specifier Probe in `production_orchestrator.py:1170`
In `05_Production_Pipeline/production_orchestrator.py`, line 1170:
```python
1166:     has_audio_list = []
1167:     for v in video_files:
1168:         has_a = True
1169:         try:
1170:             ffprobe_exe = ffmpeg_exe.replace("ffmpeg", "ffprobe")
1171:             probe_cmd = [
1172:                 ffprobe_exe, "-v", "error",
1173:                 "-show_entries", "stream=codec_type",
1174:                 "-of", "json", str(v)
1175:             ]
1176:             p_res = subprocess.run(probe_cmd, capture_output=True, text=True)
1177:             if p_res.returncode == 0:
1178:                 p_data = json.loads(p_res.stdout)
1179:                 has_a = any(s.get("codec_type") == "audio" for s in p_data.get("streams", []))
1180:         except Exception:
1181:             has_a = True
1182:         has_audio_list.append(has_a)
```
- In the active Windows environment, `get_ffmpeg()` returns:  
  `C:\Users\Admin\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-9.0.2-full_build\bin\ffmpeg.exe`.
- `ffmpeg_exe.replace("ffmpeg", "ffprobe")` blindly replaces all occurrences of `"ffmpeg"`, transforming the directory name `ffmpeg-9.0.2-full_build` into `ffprobe-9.0.2-full_build`:  
  `C:\Users\Admin\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffprobe-9.0.2-full_build\bin\ffprobe.exe`.
- Verbatim empirical check:  
  `os.path.exists("...\\ffprobe-9.0.2-full_build\\bin\\ffprobe.exe") == False`.
- Because the executable does not exist, `subprocess.run(probe_cmd)` raises `FileNotFoundError`, caught silently by line 1180 `except Exception: has_a = True`.
- For any silent clip without an audio track (`-an`), `has_audio_list` falsely reports `True`.
- In line 1186, it appends `[{i}:a]aresample=48000...`, causing FFmpeg in the fallback branch to crash with verbatim error:  
  `Stream specifier ':a' in filtergraph description [0:a]aresample=48000... matches no streams.`

---

### 1.3 Successful Deliverable Verifications
The following components were verified as genuine and passing:
1. **Source Code Authenticity**:
   - `resolve_audio_asset` (lines 1001–1036) correctly searches across `04_Assets/audio/`, `04_Assets/audio_sfx/`, `04_Assets/audio_voice/`, `04_Assets/archive/audio/`, and project root.
   - `resolve_scene_master` (lines 1044–1090) genuine 4-tier candidate scoring (`_master_audio` > `_cinematic_master` > `_master`), version descending, and mtime descending.
   - `concat_scene_shots` (lines 1092–1150) defaults to `mode="boundary_smoothing"` (Mode A: 30ms micro-fade with `curve=qsin`), eliminating timeline drift.
   - `assemble_episode_master` (lines 1292–1426) genuine multi-scene assembly supporting 10 canonical scenes, `--check`, `--dry-run`, FFmpeg `filter_complex concat`, and Two-Pass Linear EBU R128 Loudnorm.
   - `assemble_ep01_feature.py`: Genuine `--scenes 10` support and `_master_audio` candidate prioritization.
   - **Zero OpenCV `cv2.VideoWriter`**: Verified 0 occurrences in video concatenation logic.
2. **Milestone M4 Test Suite**:
   - `python -m pytest tests/test_production_pipeline_m4.py -v`: **15 passed in 10.13s**.
3. **Other Regression Test Suites**:
   - `python -m pytest tests/test_production_pipeline_m3.py -v`: **16 passed in 6.53s**.
   - `python -m pytest tests/test_adversarial_m3_audio_engine.py -v`: **6 passed in 29.52s**.
   - `python -m pytest tests/test_critic_gate.py -v`: **30 passed in 13.49s**.
   - `python -m pytest tests/test_tier5_pipeline_hardening.py -v`: **20 passed in 4.69s**.
4. **Archive Preservation**:
   - `04_Assets/archive/ep01_legacy_v1/` intact with 185 items (184 video files + `README.md`).

---

## 2. Logic Chain

1. **Step 1 (Mandatory Dispatch Criteria)**: The audit dispatch instructs:  
   `"Regression Test Integrity: Run and verify all suites: python -m pytest tests/test_m2_hygiene.py -v (6/6 PASS)"` and `"Confirm Character Bible assets in 04_Assets/characters/ (62 files, 14 core portraits) remain 100% untouched."`
2. **Step 2 (Empirical Test Execution)**: When `tests/test_m2_hygiene.py` is executed, `test_character_portraits_unharmed` fails with an unhandled `AssertionError` (`assert 98 == 62` or `102 == 62`). The test suite does NOT pass (5/6 pass, 1 fail).
3. **Step 3 (Asset Invariant Violation)**: While git tracking retains the 62 baseline assets intact, 40 untracked turnaround sheet files were written directly to `04_Assets/characters/`, violating the workspace hygiene invariant and breaking automated regression CI.
4. **Step 4 (Silent Fallback Defect)**: Line 1170 of `production_orchestrator.py` introduces a string-replacement bug that corrupts the path to `ffprobe`, causing `has_a` to default to `True` for all clips and triggering fatal stream specifier crashes on silent clips in the fallback concatenation branch.
5. **Step 5 (Integrity Forensics Enforcement Principle)**: Per system instructions: *"If ANY check fails, your verdict is INTEGRITY VIOLATION and you MUST reject the work product."* A broken regression test and defective path probe constitute a failure of the verification gate.

---

## 3. Caveats

- The 62 original Character Bible files tracked by Git (including all 14 core Ep01 portraits) are 100% unmodified (`git diff HEAD -- 04_Assets/characters` is empty). The failure in `test_m2_hygiene.py` is caused strictly by the 40 additional untracked turnaround sheet PNG files present on disk.
- In `production_orchestrator.py`, the primary concat engine is `AudioContinuityEngine.stitch_with_audio_crossfade`, which correctly uses `get_ffprobe()` and passes silent clip tests. The bug at line 1170 only manifests if the primary engine fails and triggers the hard-cut fallback branch.
- No dummy mocks, hardcoded test return stubs, or fabricated test results were found in the production implementation.

---

## 4. Conclusion

**VERDICT: INTEGRITY VIOLATION**

The Milestone M4 work product is **REJECTED** due to two blocking failures:
1. **Regression Failure**: `tests/test_m2_hygiene.py::test_character_portraits_unharmed` fails because `04_Assets/characters/` has 102 files instead of the invariant 62 files due to untracked turnaround sheet pollution.
2. **Defective Probe**: `production_orchestrator.py:1170` uses `ffmpeg_exe.replace("ffmpeg", "ffprobe")`, mutating directory paths on Windows to non-existent executables, which breaks silent clip detection and crashes the fallback concatenation routine.

---

## 5. Verification Method

To independently reproduce these findings:

```bash
# 1. Reproduce test_m2_hygiene failure (Exit code 1):
python -m pytest tests/test_m2_hygiene.py -v

# 2. Inspect physical character asset count on disk (> 62):
python -c "import os; from pathlib import Path; print('Total:', sum(len(f) for _, _, f in os.walk('04_Assets/characters')))"

# 3. Reproduce ffprobe path bug in production_orchestrator:
python -c "import sys; sys.path.insert(0, '05_Production_Pipeline'); from audio_continuity_engine import get_ffmpeg; import os; f = get_ffmpeg(); p = f.replace('ffmpeg', 'ffprobe'); print('Path:', p); print('Exists:', os.path.exists(p))"
```

### Remediation Required for Gate Closure:
1. Clean up or relocate the untracked turnaround sheet files from `04_Assets/characters/` into a dedicated directory (or update the hygiene test invariant if turnaround sheets are intended to be tracked assets).
2. Fix line 1170 in `05_Production_Pipeline/production_orchestrator.py` by importing and using `get_ffprobe()` from `audio_continuity_engine` instead of naive string `.replace("ffmpeg", "ffprobe")`.
