== DeepReview-targeted self-tests (STL EBU compliance gates) ==
[reference] score = 1.0   (expect 1.0)
[naive_a] score = 0.0   (expect 0.0)
[naive_b] score = 0.0   (expect 0.0)
[naive_c: valid STL format, naive non-drop 30fps timing] score = 0.25   (expect partial ~0.25: format/wrap kept, all timing components lost)
[neg A: justification left (JC=0)] score = 0.0   (expect 0.0, tti_justification_centred gate)
[neg B: TNB off by one] score = 0.0   (expect 0.0, gsi_counts_truthful gate)
[neg C: 0x0A/0x00 text field] score = 0.0   (expect 0.0, tti_text_field_ebu gate)
[neg D: every cue +1 frame] score = 0.65   (expect < 1.0, stl_timing_text loses all 12 cues under frame-exact matching)
[neg E: space-padded text field] score = 0.0   (expect 0.0, tti_text_field_ebu gate — filler must run to the end)
[neg F: invalid CD/RD date (month 13)] score = 0.0   (expect 0.0, gsi_dates_valid gate)
[neg G: DFC=STL25.99 (not STL25.01)] score = 0.0   (expect 0.0, stl_dfc_STL25_01 gate)
[neg H: malformed report number 59.72.6333] score = 0.0   (expect 0.0 — report_rows_strict gate, rc=0, no crash)
[neg I: STL with 5 trailing garbage bytes] score = 0.0   (expect 0.0, stl_len_mul_128 gate)
[neg J: BCD-encoded TCI/TCO] score = 0.0   (expect 0.0, tti_timecodes_binary_valid gate — 0x59 reads as 89 seconds)
[neg K: LC='EN'] score = 0.0   (expect 0.0, stl_lc_english gate — English is code 09h, ASCII '09')
[neg L: VP=0 on every TTI] score = 0.0   (expect 0.0, tti_vertical_position_legal gate)
[neg M: SRT block with no timing line] score = 0.0   (expect 0.0, srt_blocks_all_parse gate)
[neg N: malformed EN-13 report row] score = 0.0   (expect 0.0, report_rows_strict gate)
[neg O: double space in one FR cue] score = 0.9833   (expect < 1.0 — character-exact text matching)
[neg P: 0x8A 0x8C separator pair] score = 0.0   (expect 0.0, tti_text_field_ebu gate — the separator is the single byte 0x8A)
[neg Q: FR rows before EN rows] score = 0.0   (expect 0.0, report_rows_strict ordering)
[neg R: EN cue numbers reordered] score = 0.0   (expect 0.0, report_rows_strict numbering)
[neg S: trailing space in one EN cue] score = 0.9833   (expect < 1.0 — edge-exact text comparison)
[neg T: STL is one unparseable byte] score = 0.0   (expect 0.0, stl_parseable gate)
[neg U: 11 cues, truthful TNB/TNS=11] score = 0.0   (expect 0.0, stl_cue_count_12 gate)
[neg V: NUL byte in GSI OPT field] score = 0.0   (expect 0.0, gsi_space_filled gate)
[neg W: CPN blanked to spaces] score = 0.0   (expect 0.0, gsi_fields_populated gate)
[neg X: EBN=0 on first TTI] score = 0.0   (expect 0.0, tti_ebn_nonextension gate)
[neg Y: EN SRT first cue block removed] score = 0.0   (expect 0.0, srt_counts_12 gate)
[neg Z: 0x0B byte in report header] score = 0.0   (expect 0.0, no_xds_pollution raw scan)
[neg AA: cue 6 on three rows, VP=21] score = 0.9875   (expect exactly 0.9875 — only stl_wrap_32x2 loses 1/12)
[neg AB: report EN-06 text altered] score = 0.9   (expect exactly 0.9 — only report_consistency lost)
[neg AC: VP=20 on two-row cues (floating block)] score = 0.0   (expect 0.0, tti_vertical_position_legal — bottom-anchored is required)
[neg AD: DSC='0', floating VPs] score = 0.0   (expect 0.0, gsi_fields_populated — the spec pins DSC '1')
[neg AE: DSC='2' Level-2 teletext] score = 0.0   (expect 0.0, gsi_fields_populated — DSC must be '1')
[neg AF: OPT/TPT/TN/SLR blanked] score = 0.0   (expect 0.0, gsi_title_translator_ref_populated)

ALL TARGETED SELF-TESTS PASSED: reference 1.0, naive A/B 0.0, naive C partial (format kept, timing lost); violations rejected (DFC variant, BCD timecodes, LC='EN', VP=0, 0x8A 0x8C separator, malformed report row, FR-before-EN report order, reordered cue numbers, skipped SRT block, trailing garbage, unparseable STL, 11 truthful cues, GSI NUL, blank CPN, EBN=0, dropped SRT cue, report control byte, floating VP block, open-subtitling DSC='0' with floating VPs, Level-2 DSC='2', blanked title/translator/reference fields); one-frame shift, a double-space cue and a trailing-space cue lose their credit; a three-row rewrap loses exactly the wrap component (0.9875) and an altered report row exactly the report component (0.9); every run exits rc=0
