{
  "schema_version": 3,
  "app": "jellyfin",
  "display_name": "Jellyfin",
  "upstream_repo": "https://github.com/jellyfin/jellyfin",
  "docs_url": "https://jellyfin.org/docs/general/installation/container/",
  "status": "ok",
  "summary": {
    "primary_service": "jellyfin",
    "app_version": "12.2",
    "app_version_pinned": true,
    "runs": 3,
    "publishable": true,
    "publishable_note": null,
    "idle_total_mem_mib": 232.95,
    "idle_total_cpu_pct": 1.85,
    "peak_total_mem_mib": 507.5,
    "peak_is_under_load": true,
    "startup_seconds": 10.9,
    "startup_peak_total_mem_mib": 240.3,
    "settled": true,
    "settle_seconds_used": 121.1,
    "peak_max_mib": 532.6,
    "sizing_peak_mib": 532.6,
    "idle_mem_mib": {
      "median": 232.95,
      "min": 206.05,
      "max": 234.93,
      "values": [
        206.05,
        234.93,
        232.95
      ]
    },
    "idle_cpu_pct": {
      "median": 1.85,
      "min": 1.76,
      "max": 1.87,
      "values": [
        1.87,
        1.76,
        1.85
      ]
    },
    "peak_mem_mib": {
      "median": 507.5,
      "min": 485.0,
      "max": 532.6,
      "values": [
        485.0,
        507.5,
        532.6
      ]
    },
    "startup_peak_mem_mib": {
      "median": 240.3,
      "min": 220.5,
      "max": 244.9,
      "values": [
        220.5,
        240.3,
        244.9
      ]
    },
    "startup_s": {
      "median": 10.9,
      "min": 10.9,
      "max": 11.0,
      "values": [
        11.0,
        10.9,
        10.9
      ]
    },
    "settled_after_healthy_s": {
      "median": 124.8,
      "min": 124.7,
      "max": 126.8,
      "values": [
        126.8,
        124.7,
        124.8
      ]
    },
    "settled_runs": 3,
    "per_service": {
      "jellyfin": {
        "idle_mem_mib": {
          "median": 232.95,
          "min": 206.05,
          "max": 234.93,
          "values": [
            206.05,
            234.93,
            232.95
          ]
        },
        "peak_mem_mib": {
          "median": 507.5,
          "min": 485.0,
          "max": 532.6,
          "values": [
            485.0,
            507.5,
            532.6
          ]
        }
      }
    },
    "variance_flag": null,
    "representative_run": 3,
    "cpu_models": [
      "AMD EPYC 7763 64-Core Processor"
    ],
    "cpu_model_mismatch": false,
    "rule": "idle = median of the run idle means; peak = median of the run peaks (highest simultaneous total, under load when the app has a load step); peak_max_mib = highest run peak; sizing_peak_mib = highest over runs of max(run peak, run startup peak); variance_flag when max/min over runs is above 1.5 for idle or peak."
  },
  "run": {
    "started_at": "2026-10-08T07:45:39Z",
    "date": "2026-10-08",
    "harness_version": "3.0.0",
    "runs_requested": 3,
    "docker_host": null,
    "remote": false,
    "runs_completed": 3
  },
  "host": {
    "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
    "ci": {
      "runs_on": "ubuntu-latest",
      "runner_environment": "github-hosted",
      "runner_os": "Linux",
      "runner_arch": "X64",
      "image_os": "ubuntu24",
      "image_version": "20261004.327.1"
    },
    "cpu_model": "AMD EPYC 7763 64-Core Processor",
    "cpu_model_note": null,
    "cores": 2,
    "mem_total_mib": 7938,
    "kernel": "6.17.0-1022-azure",
    "os": "Ubuntu 24.04.5 LTS",
    "arch": "x86_64",
    "oci_arch": "amd64",
    "docker_server_version": "28.0.4",
    "docker_client_version": "28.0.4",
    "compose_client_version": "2.38.2",
    "storage_driver": "overlay2",
    "containerd_image_store": false,
    "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
    "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
  },
  "helper_images": {
    "curlimages/curl:latest": {
      "pulled_as": "curlimages/curl:latest",
      "digest": "curlimages/curl@sha256:58adaa4e8dca9c988bae2aba4ab3434a0bb2da16bbe3f92dec39ec7785166777"
    },
    "python:3.12-slim": {
      "pulled_as": "python:3.12-slim",
      "digest": "python@sha256:05cda9777409a9c3ffddd94a4c476b79f0769a0b4857f0c7ed9226b6800b0d6f"
    }
  },
  "pull_seconds": 23.6,
  "finished_at": "2026-10-08T07:58:26Z",
  "elapsed_seconds": 766.4,
  "services": {
    "jellyfin": {
      "image_ref": "jellyfin/jellyfin:12.2",
      "image_repo": "jellyfin/jellyfin",
      "image_tag": "12.2",
      "digest": "sha256:357724bf0ae27a672c7cbaa899db2d9abeb13dbd8657ccce750258a4c059d037",
      "digest_note": null,
      "version": "12.2",
      "version_source": "label:org.opencontainers.image.version",
      "version_pinned": true,
      "version_note": null,
      "resolved_tag": "12.2",
      "resolved_tag_note": null,
      "image_size": {
        "unpacked_mb": 1730.0,
        "unpacked_source": "docker image ls Size: unpacked image on the daemon host, rounded by docker to 3 significant figures",
        "compressed_mb": 754.0,
        "compressed_source": "sum of compressed layer sizes in the registry manifest for linux/amd64",
        "compressed_null_reason": null,
        "unit_note": "MB = 10^6 bytes. unpacked = disk used on the host; compressed = what is downloaded"
      },
      "compose_image": "jellyfin/jellyfin:12.2",
      "compose_comment": "sha256:357724bf0ae27a672c7cbaa899db2d9abeb13dbd8657ccce750258a4c059d037  (version 12.2, from label:org.opencontainers.image.version)",
      "restart_count": 0,
      "oom_killed": false
    }
  },
  "runs": [
    {
      "run": 1,
      "started_at": "2026-10-08T07:46:09Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261004.327.1"
        },
        "cpu_model": "AMD EPYC 7763 64-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-08",
      "startup": {
        "seconds": 11.0,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 11.0,
            "detail": "shb-jellyfin-jellyfin-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.5,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "jellyfin": "12.2"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 3.6,
          "reported": {
            "jellyfin_version": "12.2.0",
            "wizard_completed": true,
            "libraries": [
              {
                "name": "Movies",
                "type": "movies",
                "paths": [
                  "/media/movies"
                ]
              }
            ]
          },
          "output_tail": [
            "GET /health -> HTTP 200 'Healthy'",
            "GET /System/Info/Public -> HTTP 200 version=12.2.0 wizard_completed=False local_address=http://172.18.0.2:8096",
            "POST /Startup/Configuration -> HTTP 204",
            "GET /Startup/User -> HTTP 200",
            "POST /Startup/User (create admin 'labadmin') -> HTTP 204",
            "POST /Startup/RemoteAccess -> HTTP 204",
            "POST /Startup/Complete -> HTTP 204",
            "GET /System/Info/Public -> wizard_completed=True",
            "POST /Users/AuthenticateByName -> HTTP 200 (token not printed)",
            "POST /Library/VirtualFolders (Movies -> /media/movies, no scan yet) -> HTTP 204",
            "libraries: [{\"name\": \"Movies\", \"type\": \"movies\", \"paths\": [\"/media/movies\"]}]"
          ],
          "description": "Complete the startup wizard through the documented Startup API (server name and language, the admin user, remote access, complete), log in, and add a library called Movies that points at /media/movies (no metadata fetchers for movies, so no lookups on the internet; no scan yet). The library is empty of items until the load step scans it."
        }
      ],
      "idle": {
        "per_service": {
          "jellyfin": {
            "samples": 16,
            "mem_mean_mib": 206.05,
            "mem_max_mib": 209.6,
            "cpu_mean_pct": 1.87,
            "cpu_max_pct": 8.99
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 206.05,
          "mem_max_mib": 209.6,
          "cpu_mean_pct": 1.87,
          "cpu_max_pct": 8.99
        },
        "window_seconds": 30.3,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 205.8,
            "total_cpu_pct": 6.38
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 205.8,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 205.5,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 6.1,
            "total_mem_mib": 205.8,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 205.8,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 205.5,
            "total_cpu_pct": 7.63
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 205.5,
            "total_cpu_pct": 0.13
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 205.5,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 16.2,
            "total_mem_mib": 205.7,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 18.2,
            "total_mem_mib": 205.7,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 20.2,
            "total_mem_mib": 203.8,
            "total_cpu_pct": 8.99
          },
          {
            "t_offset_s": 22.2,
            "total_mem_mib": 203.8,
            "total_cpu_pct": 0.18
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 203.8,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 26.3,
            "total_mem_mib": 209.6,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 28.3,
            "total_mem_mib": 209.6,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 30.3,
            "total_mem_mib": 209.6,
            "total_cpu_pct": 6.51
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 121.2,
        "settle_started_after_healthy_s": 5.6,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 30,
          "mean_mib": 203.7,
          "min_mib": 201.8,
          "max_mib": 205.8,
          "spread_mib": 4.0,
          "threshold_mib": 10.0
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "jellyfin": 220.5
        },
        "total_mem_mib": 220.5,
        "samples": 63,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          199.0,
          220.3,
          207.2,
          207.4,
          204.4,
          206.0,
          203.1,
          202.2,
          202.4,
          203.7,
          205.3,
          204.1,
          205.2,
          205.6,
          204.9,
          208.2
        ],
        "per_service_mem_mib": {
          "jellyfin": [
            199.0,
            220.3,
            207.2,
            207.4,
            204.4,
            206.0,
            203.1,
            202.2,
            202.4,
            203.7,
            205.3,
            204.1,
            205.2,
            205.6,
            204.9,
            208.2
          ]
        }
      },
      "load": {
        "per_service": {
          "jellyfin": {
            "samples": 39,
            "mem_mean_mib": 434.45,
            "mem_max_mib": 485.0,
            "cpu_mean_pct": 174.69,
            "cpu_max_pct": 199.78
          }
        },
        "total": {
          "samples": 39,
          "dropped_for_total": 0,
          "mem_mean_mib": 434.45,
          "mem_max_mib": 485.0,
          "cpu_mean_pct": 174.69,
          "cpu_max_pct": 199.78
        },
        "description": "One scan, then one software transcode. A Python script (standard library only, on the Compose network) starts a library scan of the 13 generated films (local files only, no internet metadata lookups) and waits for the task to finish. It then plays the 12-minute film as one simulated player for 60 seconds: it asks for a 1280x720, 4 Mb/s H.264 HLS stream that cannot direct play, so Jellyfin runs ffmpeg with libx264 on the CPU (no hardware acceleration in the lab), and it fetches the 3-second segments in real time. The 1080p H.264 source is synthetic: a test pattern with added noise at about 8 Mb/s, with AAC stereo audio that Jellyfin copies. ffmpeg runs without throttling (the default), so it works as fast as the CPU allows. No browser, no subtitles, no second viewer.",
        "duration_s": 75.1,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "library_scan_seconds": 3.6,
          "library_scan_status": "Completed",
          "movies_in_library": 13,
          "scan_server_start": "2026-10-08T07:48:58.2588123Z",
          "scan_server_end": "2026-10-08T07:49:01.7064626Z",
          "phase_scan_end_offset_s": 3.9,
          "phase_transcode_start_offset_s": 5.9,
          "phase_transcode_end_offset_s": 73.0,
          "transcode_streams": 1,
          "players": [
            {
              "segments_fetched": 24,
              "playback_seconds": 62.3,
              "seconds_to_first_segment": 3.21,
              "late_segments": 0,
              "max_lateness_s": 0.0,
              "transcode_reasons": [
                "ContainerBitrateExceedsLimit"
              ]
            }
          ],
          "ffmpeg": [
            {
              "log": "FFmpeg.Transcode-2026-10-08_07-49-05_f86783fc72c0fb67a57ece9a04e57e18_f83892b0.log",
              "last_fps": 74.0,
              "last_speed_x": 3.08,
              "media_time": "00:03:18.25",
              "elapsed": "0:01:04.44",
              "frames": 4771
            }
          ],
          "min_ffmpeg_speed_x": 3.08,
          "all_players_kept_up": true,
          "ffmpeg_command": "/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/15a318d15ddd5b545b8a66eea5b66395%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/15a318d15ddd5b545b8a66eea5b66395.m3u8\""
        },
        "output_tail": [
          "POST /Library/Refresh -> HTTP 204",
          "library scan: 3.6 s wall clock, task Status=Completed, 13 movies in the library",
          "transcode: 1 stream(s), each played about 60 s",
          "  player 0: {'segments_fetched': 24, 'playback_seconds': 62.3, 'seconds_to_first_segment': 3.21, 'late_segments': 0, 'max_lateness_s': 0.0, 'transcode_reasons': ['ContainerBitrateExceedsLimit']}",
          "  ffmpeg log: {'log': 'FFmpeg.Transcode-2026-10-08_07-49-05_f86783fc72c0fb67a57ece9a04e57e18_f83892b0.log', 'last_fps': 74.0, 'last_speed_x': 3.08, 'media_time': '00:03:18.25', 'elapsed': '0:01:04.44', 'frames': 4771}",
          "  ffmpeg command: /usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/15a318d15ddd5b545b8a66eea5b66395%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/15a318d15ddd5b545b8a66eea5b66395.m3u8\""
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 229.2,
            "total_cpu_pct": 119.38
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 278.5,
            "total_cpu_pct": 166.42
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 235.7,
            "total_cpu_pct": 90.87
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 296.9,
            "total_cpu_pct": 118.16
          },
          {
            "t_offset_s": 8.0,
            "total_mem_mib": 483.6,
            "total_cpu_pct": 188.28
          },
          {
            "t_offset_s": 10.0,
            "total_mem_mib": 482.1,
            "total_cpu_pct": 197.27
          },
          {
            "t_offset_s": 12.0,
            "total_mem_mib": 473.3,
            "total_cpu_pct": 198.19
          },
          {
            "t_offset_s": 14.0,
            "total_mem_mib": 473.8,
            "total_cpu_pct": 195.39
          },
          {
            "t_offset_s": 16.0,
            "total_mem_mib": 468.4,
            "total_cpu_pct": 199.29
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 468.4,
            "total_cpu_pct": 197.13
          },
          {
            "t_offset_s": 20.1,
            "total_mem_mib": 471.9,
            "total_cpu_pct": 199.34
          },
          {
            "t_offset_s": 22.1,
            "total_mem_mib": 469.0,
            "total_cpu_pct": 198.6
          },
          {
            "t_offset_s": 24.1,
            "total_mem_mib": 469.1,
            "total_cpu_pct": 197.12
          },
          {
            "t_offset_s": 26.1,
            "total_mem_mib": 470.1,
            "total_cpu_pct": 198.4
          },
          {
            "t_offset_s": 28.1,
            "total_mem_mib": 469.0,
            "total_cpu_pct": 195.62
          },
          {
            "t_offset_s": 30.1,
            "total_mem_mib": 470.1,
            "total_cpu_pct": 198.16
          },
          {
            "t_offset_s": 32.1,
            "total_mem_mib": 470.8,
            "total_cpu_pct": 197.32
          },
          {
            "t_offset_s": 34.1,
            "total_mem_mib": 470.8,
            "total_cpu_pct": 196.86
          },
          {
            "t_offset_s": 36.1,
            "total_mem_mib": 471.0,
            "total_cpu_pct": 198.71
          },
          {
            "t_offset_s": 38.1,
            "total_mem_mib": 471.8,
            "total_cpu_pct": 195.49
          },
          {
            "t_offset_s": 40.1,
            "total_mem_mib": 470.1,
            "total_cpu_pct": 195.24
          },
          {
            "t_offset_s": 42.1,
            "total_mem_mib": 469.2,
            "total_cpu_pct": 198.76
          },
          {
            "t_offset_s": 44.1,
            "total_mem_mib": 469.8,
            "total_cpu_pct": 198.33
          },
          {
            "t_offset_s": 46.1,
            "total_mem_mib": 470.3,
            "total_cpu_pct": 196.88
          },
          {
            "t_offset_s": 48.1,
            "total_mem_mib": 472.7,
            "total_cpu_pct": 197.06
          },
          {
            "t_offset_s": 50.1,
            "total_mem_mib": 474.0,
            "total_cpu_pct": 194.83
          },
          {
            "t_offset_s": 52.2,
            "total_mem_mib": 474.1,
            "total_cpu_pct": 199.05
          },
          {
            "t_offset_s": 54.2,
            "total_mem_mib": 474.2,
            "total_cpu_pct": 199.78
          },
          {
            "t_offset_s": 56.2,
            "total_mem_mib": 477.4,
            "total_cpu_pct": 199.47
          },
          {
            "t_offset_s": 58.2,
            "total_mem_mib": 474.4,
            "total_cpu_pct": 196.82
          },
          {
            "t_offset_s": 60.2,
            "total_mem_mib": 485.0,
            "total_cpu_pct": 196.63
          },
          {
            "t_offset_s": 62.2,
            "total_mem_mib": 475.1,
            "total_cpu_pct": 196.92
          },
          {
            "t_offset_s": 64.2,
            "total_mem_mib": 477.9,
            "total_cpu_pct": 197.86
          },
          {
            "t_offset_s": 66.2,
            "total_mem_mib": 478.1,
            "total_cpu_pct": 195.11
          },
          {
            "t_offset_s": 68.2,
            "total_mem_mib": 478.6,
            "total_cpu_pct": 196.09
          },
          {
            "t_offset_s": 70.2,
            "total_mem_mib": 478.4,
            "total_cpu_pct": 195.22
          },
          {
            "t_offset_s": 72.2,
            "total_mem_mib": 250.2,
            "total_cpu_pct": 6.53
          },
          {
            "t_offset_s": 74.2,
            "total_mem_mib": 250.1,
            "total_cpu_pct": 1.9
          },
          {
            "t_offset_s": 76.2,
            "total_mem_mib": 250.4,
            "total_cpu_pct": 4.47
          }
        ],
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "jellyfin": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-08T07:50:16Z",
      "elapsed_seconds": 246.8
    },
    {
      "run": 2,
      "started_at": "2026-10-08T07:50:16Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261004.327.1"
        },
        "cpu_model": "AMD EPYC 7763 64-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-08",
      "startup": {
        "seconds": 10.9,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 10.9,
            "detail": "shb-jellyfin-jellyfin-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.3,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "jellyfin": "12.2"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 3.6,
          "reported": {
            "jellyfin_version": "12.2.0",
            "wizard_completed": true,
            "libraries": [
              {
                "name": "Movies",
                "type": "movies",
                "paths": [
                  "/media/movies"
                ]
              }
            ]
          },
          "output_tail": [
            "GET /health -> HTTP 200 'Healthy'",
            "GET /System/Info/Public -> HTTP 200 version=12.2.0 wizard_completed=False local_address=http://172.18.0.2:8096",
            "POST /Startup/Configuration -> HTTP 204",
            "GET /Startup/User -> HTTP 200",
            "POST /Startup/User (create admin 'labadmin') -> HTTP 204",
            "POST /Startup/RemoteAccess -> HTTP 204",
            "POST /Startup/Complete -> HTTP 204",
            "GET /System/Info/Public -> wizard_completed=True",
            "POST /Users/AuthenticateByName -> HTTP 200 (token not printed)",
            "POST /Library/VirtualFolders (Movies -> /media/movies, no scan yet) -> HTTP 204",
            "libraries: [{\"name\": \"Movies\", \"type\": \"movies\", \"paths\": [\"/media/movies\"]}]"
          ],
          "description": "Complete the startup wizard through the documented Startup API (server name and language, the admin user, remote access, complete), log in, and add a library called Movies that points at /media/movies (no metadata fetchers for movies, so no lookups on the internet; no scan yet). The library is empty of items until the load step scans it."
        }
      ],
      "idle": {
        "per_service": {
          "jellyfin": {
            "samples": 16,
            "mem_mean_mib": 234.93,
            "mem_max_mib": 239.6,
            "cpu_mean_pct": 1.76,
            "cpu_max_pct": 14.04
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 234.93,
          "mem_max_mib": 239.6,
          "cpu_mean_pct": 1.76,
          "cpu_max_pct": 14.04
        },
        "window_seconds": 30.3,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 233.5,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 233.2,
            "total_cpu_pct": 6.04
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 233.2,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 6.1,
            "total_mem_mib": 233.1,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 233.1,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 233.1,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 233.3,
            "total_cpu_pct": 7.69
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 233.3,
            "total_cpu_pct": 0.08
          },
          {
            "t_offset_s": 16.2,
            "total_mem_mib": 231.8,
            "total_cpu_pct": 0.04
          },
          {
            "t_offset_s": 18.2,
            "total_mem_mib": 232.3,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 20.2,
            "total_mem_mib": 232.3,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 22.2,
            "total_mem_mib": 239.6,
            "total_cpu_pct": 14.04
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 239.4,
            "total_cpu_pct": 0.09
          },
          {
            "t_offset_s": 26.3,
            "total_mem_mib": 239.4,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 28.3,
            "total_mem_mib": 239.1,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 30.3,
            "total_mem_mib": 239.1,
            "total_cpu_pct": 0.01
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 121.1,
        "settle_started_after_healthy_s": 3.6,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 30,
          "mean_mib": 230.73,
          "min_mib": 228.2,
          "max_mib": 233.5,
          "spread_mib": 5.3,
          "threshold_mib": 10.0
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "jellyfin": 240.3
        },
        "total_mem_mib": 240.3,
        "samples": 62,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          220.1,
          239.9,
          237.2,
          235.6,
          236.2,
          230.6,
          228.1,
          228.4,
          228.9,
          230.3,
          232.6,
          232.7,
          233.3,
          233.2,
          235.1,
          239.2
        ],
        "per_service_mem_mib": {
          "jellyfin": [
            220.1,
            239.9,
            237.2,
            235.6,
            236.2,
            230.6,
            228.1,
            228.4,
            228.9,
            230.3,
            232.6,
            232.7,
            233.3,
            233.2,
            235.1,
            239.2
          ]
        }
      },
      "load": {
        "per_service": {
          "jellyfin": {
            "samples": 39,
            "mem_mean_mib": 463.6,
            "mem_max_mib": 507.5,
            "cpu_mean_pct": 175.31,
            "cpu_max_pct": 200.32
          }
        },
        "total": {
          "samples": 39,
          "dropped_for_total": 0,
          "mem_mean_mib": 463.6,
          "mem_max_mib": 507.5,
          "cpu_mean_pct": 175.31,
          "cpu_max_pct": 200.32
        },
        "description": "One scan, then one software transcode. A Python script (standard library only, on the Compose network) starts a library scan of the 13 generated films (local files only, no internet metadata lookups) and waits for the task to finish. It then plays the 12-minute film as one simulated player for 60 seconds: it asks for a 1280x720, 4 Mb/s H.264 HLS stream that cannot direct play, so Jellyfin runs ffmpeg with libx264 on the CPU (no hardware acceleration in the lab), and it fetches the 3-second segments in real time. The 1080p H.264 source is synthetic: a test pattern with added noise at about 8 Mb/s, with AAC stereo audio that Jellyfin copies. ffmpeg runs without throttling (the default), so it works as fast as the CPU allows. No browser, no subtitles, no second viewer.",
        "duration_s": 75.1,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "library_scan_seconds": 3.6,
          "library_scan_status": "Completed",
          "movies_in_library": 13,
          "scan_server_start": "2026-10-08T07:53:03.2831777Z",
          "scan_server_end": "2026-10-08T07:53:06.7673592Z",
          "phase_scan_end_offset_s": 3.9,
          "phase_transcode_start_offset_s": 5.9,
          "phase_transcode_end_offset_s": 73.0,
          "transcode_streams": 1,
          "players": [
            {
              "segments_fetched": 24,
              "playback_seconds": 62.4,
              "seconds_to_first_segment": 3.17,
              "late_segments": 0,
              "max_lateness_s": 0.0,
              "transcode_reasons": [
                "ContainerBitrateExceedsLimit"
              ]
            }
          ],
          "ffmpeg": [
            {
              "log": "FFmpeg.Transcode-2026-10-08_07-53-10_f86783fc72c0fb67a57ece9a04e57e18_05858589.log",
              "last_fps": 73.0,
              "last_speed_x": 3.04,
              "media_time": "00:03:16.30",
              "elapsed": "0:01:04.47",
              "frames": 4731
            }
          ],
          "min_ffmpeg_speed_x": 3.04,
          "all_players_kept_up": true,
          "ffmpeg_command": "/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/2f29cc870e8e90562289182502a28eef%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/2f29cc870e8e90562289182502a28eef.m3u8\""
        },
        "output_tail": [
          "POST /Library/Refresh -> HTTP 204",
          "library scan: 3.6 s wall clock, task Status=Completed, 13 movies in the library",
          "transcode: 1 stream(s), each played about 60 s",
          "  player 0: {'segments_fetched': 24, 'playback_seconds': 62.4, 'seconds_to_first_segment': 3.17, 'late_segments': 0, 'max_lateness_s': 0.0, 'transcode_reasons': ['ContainerBitrateExceedsLimit']}",
          "  ffmpeg log: {'log': 'FFmpeg.Transcode-2026-10-08_07-53-10_f86783fc72c0fb67a57ece9a04e57e18_05858589.log', 'last_fps': 73.0, 'last_speed_x': 3.04, 'media_time': '00:03:16.30', 'elapsed': '0:01:04.47', 'frames': 4731}",
          "  ffmpeg command: /usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/2f29cc870e8e90562289182502a28eef%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/2f29cc870e8e90562289182502a28eef.m3u8\""
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 317.1,
            "total_cpu_pct": 123.1
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 288.3,
            "total_cpu_pct": 171.17
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 272.7,
            "total_cpu_pct": 95.59
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 329.0,
            "total_cpu_pct": 119.84
          },
          {
            "t_offset_s": 8.0,
            "total_mem_mib": 498.6,
            "total_cpu_pct": 198.61
          },
          {
            "t_offset_s": 10.0,
            "total_mem_mib": 496.6,
            "total_cpu_pct": 196.95
          },
          {
            "t_offset_s": 12.0,
            "total_mem_mib": 497.5,
            "total_cpu_pct": 198.36
          },
          {
            "t_offset_s": 14.0,
            "total_mem_mib": 496.7,
            "total_cpu_pct": 198.4
          },
          {
            "t_offset_s": 16.0,
            "total_mem_mib": 499.7,
            "total_cpu_pct": 194.33
          },
          {
            "t_offset_s": 18.0,
            "total_mem_mib": 500.5,
            "total_cpu_pct": 199.22
          },
          {
            "t_offset_s": 20.1,
            "total_mem_mib": 500.3,
            "total_cpu_pct": 198.37
          },
          {
            "t_offset_s": 22.1,
            "total_mem_mib": 500.8,
            "total_cpu_pct": 197.53
          },
          {
            "t_offset_s": 24.1,
            "total_mem_mib": 499.8,
            "total_cpu_pct": 199.39
          },
          {
            "t_offset_s": 26.1,
            "total_mem_mib": 502.0,
            "total_cpu_pct": 196.35
          },
          {
            "t_offset_s": 28.1,
            "total_mem_mib": 499.9,
            "total_cpu_pct": 198.07
          },
          {
            "t_offset_s": 30.1,
            "total_mem_mib": 500.6,
            "total_cpu_pct": 200.32
          },
          {
            "t_offset_s": 32.1,
            "total_mem_mib": 503.2,
            "total_cpu_pct": 199.47
          },
          {
            "t_offset_s": 34.1,
            "total_mem_mib": 502.9,
            "total_cpu_pct": 197.7
          },
          {
            "t_offset_s": 36.1,
            "total_mem_mib": 503.3,
            "total_cpu_pct": 195.3
          },
          {
            "t_offset_s": 38.1,
            "total_mem_mib": 496.3,
            "total_cpu_pct": 199.2
          },
          {
            "t_offset_s": 40.1,
            "total_mem_mib": 492.7,
            "total_cpu_pct": 188.51
          },
          {
            "t_offset_s": 42.1,
            "total_mem_mib": 492.7,
            "total_cpu_pct": 195.9
          },
          {
            "t_offset_s": 44.1,
            "total_mem_mib": 492.9,
            "total_cpu_pct": 197.76
          },
          {
            "t_offset_s": 46.1,
            "total_mem_mib": 495.0,
            "total_cpu_pct": 199.22
          },
          {
            "t_offset_s": 48.1,
            "total_mem_mib": 496.1,
            "total_cpu_pct": 199.36
          },
          {
            "t_offset_s": 50.1,
            "total_mem_mib": 496.6,
            "total_cpu_pct": 198.21
          },
          {
            "t_offset_s": 52.1,
            "total_mem_mib": 498.3,
            "total_cpu_pct": 194.82
          },
          {
            "t_offset_s": 54.2,
            "total_mem_mib": 497.9,
            "total_cpu_pct": 198.89
          },
          {
            "t_offset_s": 56.2,
            "total_mem_mib": 499.4,
            "total_cpu_pct": 199.96
          },
          {
            "t_offset_s": 58.2,
            "total_mem_mib": 500.8,
            "total_cpu_pct": 196.15
          },
          {
            "t_offset_s": 60.2,
            "total_mem_mib": 500.7,
            "total_cpu_pct": 198.69
          },
          {
            "t_offset_s": 62.2,
            "total_mem_mib": 507.5,
            "total_cpu_pct": 197.03
          },
          {
            "t_offset_s": 64.2,
            "total_mem_mib": 501.9,
            "total_cpu_pct": 196.57
          },
          {
            "t_offset_s": 66.2,
            "total_mem_mib": 504.8,
            "total_cpu_pct": 199.26
          },
          {
            "t_offset_s": 68.2,
            "total_mem_mib": 505.2,
            "total_cpu_pct": 196.22
          },
          {
            "t_offset_s": 70.2,
            "total_mem_mib": 505.2,
            "total_cpu_pct": 197.73
          },
          {
            "t_offset_s": 72.2,
            "total_mem_mib": 295.8,
            "total_cpu_pct": 3.63
          },
          {
            "t_offset_s": 74.2,
            "total_mem_mib": 295.6,
            "total_cpu_pct": 1.88
          },
          {
            "t_offset_s": 76.2,
            "total_mem_mib": 295.6,
            "total_cpu_pct": 0.01
          }
        ],
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "jellyfin": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-08T07:54:21Z",
      "elapsed_seconds": 245.0
    },
    {
      "run": 3,
      "started_at": "2026-10-08T07:54:21Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261004.327.1"
        },
        "cpu_model": "AMD EPYC 7763 64-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-08",
      "startup": {
        "seconds": 10.9,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 10.9,
            "detail": "shb-jellyfin-jellyfin-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.3,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "jellyfin": "12.2"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 3.8,
          "reported": {
            "jellyfin_version": "12.2.0",
            "wizard_completed": true,
            "libraries": [
              {
                "name": "Movies",
                "type": "movies",
                "paths": [
                  "/media/movies"
                ]
              }
            ]
          },
          "output_tail": [
            "GET /health -> HTTP 200 'Healthy'",
            "GET /System/Info/Public -> HTTP 200 version=12.2.0 wizard_completed=False local_address=http://172.18.0.2:8096",
            "POST /Startup/Configuration -> HTTP 204",
            "GET /Startup/User -> HTTP 200",
            "POST /Startup/User (create admin 'labadmin') -> HTTP 204",
            "POST /Startup/RemoteAccess -> HTTP 204",
            "POST /Startup/Complete -> HTTP 204",
            "GET /System/Info/Public -> wizard_completed=True",
            "POST /Users/AuthenticateByName -> HTTP 200 (token not printed)",
            "POST /Library/VirtualFolders (Movies -> /media/movies, no scan yet) -> HTTP 204",
            "libraries: [{\"name\": \"Movies\", \"type\": \"movies\", \"paths\": [\"/media/movies\"]}]"
          ],
          "description": "Complete the startup wizard through the documented Startup API (server name and language, the admin user, remote access, complete), log in, and add a library called Movies that points at /media/movies (no metadata fetchers for movies, so no lookups on the internet; no scan yet). The library is empty of items until the load step scans it."
        }
      ],
      "idle": {
        "per_service": {
          "jellyfin": {
            "samples": 16,
            "mem_mean_mib": 232.95,
            "mem_max_mib": 235.7,
            "cpu_mean_pct": 1.85,
            "cpu_max_pct": 14.47
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 232.95,
          "mem_max_mib": 235.7,
          "cpu_mean_pct": 1.85,
          "cpu_max_pct": 14.47
        },
        "window_seconds": 30.3,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 230.5,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 231.9,
            "total_cpu_pct": 9.63
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 231.7,
            "total_cpu_pct": 0.08
          },
          {
            "t_offset_s": 6.1,
            "total_mem_mib": 231.7,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 231.8,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 231.8,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 231.8,
            "total_cpu_pct": 5.01
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 231.3,
            "total_cpu_pct": 0.06
          },
          {
            "t_offset_s": 16.2,
            "total_mem_mib": 232.1,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 18.2,
            "total_mem_mib": 232.3,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 20.2,
            "total_mem_mib": 232.3,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 22.2,
            "total_mem_mib": 235.7,
            "total_cpu_pct": 14.47
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 235.7,
            "total_cpu_pct": 0.17
          },
          {
            "t_offset_s": 26.3,
            "total_mem_mib": 235.4,
            "total_cpu_pct": 0.01
          },
          {
            "t_offset_s": 28.3,
            "total_mem_mib": 235.6,
            "total_cpu_pct": 0.02
          },
          {
            "t_offset_s": 30.3,
            "total_mem_mib": 235.6,
            "total_cpu_pct": 0.01
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 121.0,
        "settle_started_after_healthy_s": 3.8,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 30,
          "mean_mib": 227.93,
          "min_mib": 226.0,
          "max_mib": 230.6,
          "spread_mib": 4.6,
          "threshold_mib": 10.0
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "jellyfin": 244.9
        },
        "total_mem_mib": 244.9,
        "samples": 62,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          225.1,
          244.4,
          243.7,
          242.5,
          233.2,
          231.5,
          227.9,
          227.0,
          226.7,
          227.7,
          229.3,
          228.1,
          230.8,
          231.7,
          233.6,
          235.5
        ],
        "per_service_mem_mib": {
          "jellyfin": [
            225.1,
            244.4,
            243.7,
            242.5,
            233.2,
            231.5,
            227.9,
            227.0,
            226.7,
            227.7,
            229.3,
            228.1,
            230.8,
            231.7,
            233.6,
            235.5
          ]
        }
      },
      "load": {
        "per_service": {
          "jellyfin": {
            "samples": 39,
            "mem_mean_mib": 471.71,
            "mem_max_mib": 532.6,
            "cpu_mean_pct": 174.15,
            "cpu_max_pct": 200.28
          }
        },
        "total": {
          "samples": 39,
          "dropped_for_total": 0,
          "mem_mean_mib": 471.71,
          "mem_max_mib": 532.6,
          "cpu_mean_pct": 174.15,
          "cpu_max_pct": 200.28
        },
        "description": "One scan, then one software transcode. A Python script (standard library only, on the Compose network) starts a library scan of the 13 generated films (local files only, no internet metadata lookups) and waits for the task to finish. It then plays the 12-minute film as one simulated player for 60 seconds: it asks for a 1280x720, 4 Mb/s H.264 HLS stream that cannot direct play, so Jellyfin runs ffmpeg with libx264 on the CPU (no hardware acceleration in the lab), and it fetches the 3-second segments in real time. The 1080p H.264 source is synthetic: a test pattern with added noise at about 8 Mb/s, with AAC stereo audio that Jellyfin copies. ffmpeg runs without throttling (the default), so it works as fast as the CPU allows. No browser, no subtitles, no second viewer.",
        "duration_s": 74.6,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "library_scan_seconds": 3.6,
          "library_scan_status": "Completed",
          "movies_in_library": 13,
          "scan_server_start": "2026-10-08T07:57:08.2411153Z",
          "scan_server_end": "2026-10-08T07:57:11.71982Z",
          "phase_scan_end_offset_s": 3.8,
          "phase_transcode_start_offset_s": 5.8,
          "phase_transcode_end_offset_s": 72.4,
          "transcode_streams": 1,
          "players": [
            {
              "segments_fetched": 24,
              "playback_seconds": 62.2,
              "seconds_to_first_segment": 2.97,
              "late_segments": 0,
              "max_lateness_s": 0.0,
              "transcode_reasons": [
                "ContainerBitrateExceedsLimit"
              ]
            }
          ],
          "ffmpeg": [
            {
              "log": "FFmpeg.Transcode-2026-10-08_07-57-15_f86783fc72c0fb67a57ece9a04e57e18_a6190f3f.log",
              "last_fps": 74.0,
              "last_speed_x": 3.07,
              "media_time": "00:03:16.08",
              "elapsed": "0:01:03.95",
              "frames": 4727
            }
          ],
          "min_ffmpeg_speed_x": 3.07,
          "all_players_kept_up": true,
          "ffmpeg_command": "/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/00882626ee7d4c48bf688f0528939b25%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/00882626ee7d4c48bf688f0528939b25.m3u8\""
        },
        "output_tail": [
          "POST /Library/Refresh -> HTTP 204",
          "library scan: 3.6 s wall clock, task Status=Completed, 13 movies in the library",
          "transcode: 1 stream(s), each played about 60 s",
          "  player 0: {'segments_fetched': 24, 'playback_seconds': 62.2, 'seconds_to_first_segment': 2.97, 'late_segments': 0, 'max_lateness_s': 0.0, 'transcode_reasons': ['ContainerBitrateExceedsLimit']}",
          "  ffmpeg log: {'log': 'FFmpeg.Transcode-2026-10-08_07-57-15_f86783fc72c0fb67a57ece9a04e57e18_a6190f3f.log', 'last_fps': 74.0, 'last_speed_x': 3.07, 'media_time': '00:03:16.08', 'elapsed': '0:01:03.95', 'frames': 4727}",
          "  ffmpeg command: /usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -i file:\"/media/movies/Long Test Feature (2010)/Long Test Feature (2010).mp4\" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 3872026 -bufsize 7744052 -profile:v:0 high -level 40 -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 \"expr:gte(t,n_forced*3)\" -sc_threshold:v:0 0 -vf \"setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\\,ih*a)\\,min(1280\\,720*a))/2)*2:trunc(min(max(iw/a\\,ih)\\,min(1280/a\\,720))/2)*2,format=yuv420p\" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename \"/cache/transcodes/00882626ee7d4c48bf688f0528939b25%d.ts\" -hls_playlist_type vod -hls_list_size 0 -y \"/cache/transcodes/00882626ee7d4c48bf688f0528939b25.m3u8\""
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 311.8,
            "total_cpu_pct": 121.76
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 285.9,
            "total_cpu_pct": 163.18
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 261.2,
            "total_cpu_pct": 95.81
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 315.1,
            "total_cpu_pct": 119.33
          },
          {
            "t_offset_s": 8.0,
            "total_mem_mib": 515.3,
            "total_cpu_pct": 198.96
          },
          {
            "t_offset_s": 10.0,
            "total_mem_mib": 527.4,
            "total_cpu_pct": 195.37
          },
          {
            "t_offset_s": 12.0,
            "total_mem_mib": 509.9,
            "total_cpu_pct": 198.58
          },
          {
            "t_offset_s": 14.0,
            "total_mem_mib": 510.1,
            "total_cpu_pct": 198.35
          },
          {
            "t_offset_s": 16.0,
            "total_mem_mib": 510.6,
            "total_cpu_pct": 196.03
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 512.0,
            "total_cpu_pct": 198.12
          },
          {
            "t_offset_s": 20.1,
            "total_mem_mib": 510.7,
            "total_cpu_pct": 198.62
          },
          {
            "t_offset_s": 22.1,
            "total_mem_mib": 511.9,
            "total_cpu_pct": 198.5
          },
          {
            "t_offset_s": 24.1,
            "total_mem_mib": 511.8,
            "total_cpu_pct": 198.05
          },
          {
            "t_offset_s": 26.1,
            "total_mem_mib": 514.5,
            "total_cpu_pct": 194.36
          },
          {
            "t_offset_s": 28.1,
            "total_mem_mib": 514.8,
            "total_cpu_pct": 199.21
          },
          {
            "t_offset_s": 30.1,
            "total_mem_mib": 514.9,
            "total_cpu_pct": 197.61
          },
          {
            "t_offset_s": 32.1,
            "total_mem_mib": 516.9,
            "total_cpu_pct": 198.4
          },
          {
            "t_offset_s": 34.1,
            "total_mem_mib": 516.6,
            "total_cpu_pct": 197.1
          },
          {
            "t_offset_s": 36.1,
            "total_mem_mib": 513.9,
            "total_cpu_pct": 193.9
          },
          {
            "t_offset_s": 38.1,
            "total_mem_mib": 515.1,
            "total_cpu_pct": 198.32
          },
          {
            "t_offset_s": 40.1,
            "total_mem_mib": 515.3,
            "total_cpu_pct": 198.3
          },
          {
            "t_offset_s": 42.1,
            "total_mem_mib": 515.5,
            "total_cpu_pct": 197.38
          },
          {
            "t_offset_s": 44.1,
            "total_mem_mib": 516.8,
            "total_cpu_pct": 197.95
          },
          {
            "t_offset_s": 46.1,
            "total_mem_mib": 517.5,
            "total_cpu_pct": 199.53
          },
          {
            "t_offset_s": 48.1,
            "total_mem_mib": 518.0,
            "total_cpu_pct": 200.28
          },
          {
            "t_offset_s": 50.1,
            "total_mem_mib": 518.4,
            "total_cpu_pct": 199.15
          },
          {
            "t_offset_s": 52.1,
            "total_mem_mib": 519.7,
            "total_cpu_pct": 195.99
          },
          {
            "t_offset_s": 54.2,
            "total_mem_mib": 522.2,
            "total_cpu_pct": 198.82
          },
          {
            "t_offset_s": 56.2,
            "total_mem_mib": 522.2,
            "total_cpu_pct": 197.76
          },
          {
            "t_offset_s": 58.2,
            "total_mem_mib": 522.0,
            "total_cpu_pct": 198.59
          },
          {
            "t_offset_s": 60.2,
            "total_mem_mib": 525.8,
            "total_cpu_pct": 197.46
          },
          {
            "t_offset_s": 62.2,
            "total_mem_mib": 532.6,
            "total_cpu_pct": 195.81
          },
          {
            "t_offset_s": 64.2,
            "total_mem_mib": 528.8,
            "total_cpu_pct": 199.2
          },
          {
            "t_offset_s": 66.2,
            "total_mem_mib": 531.0,
            "total_cpu_pct": 198.26
          },
          {
            "t_offset_s": 68.2,
            "total_mem_mib": 531.1,
            "total_cpu_pct": 193.9
          },
          {
            "t_offset_s": 70.2,
            "total_mem_mib": 290.9,
            "total_cpu_pct": 154.5
          },
          {
            "t_offset_s": 72.2,
            "total_mem_mib": 289.3,
            "total_cpu_pct": 7.06
          },
          {
            "t_offset_s": 74.2,
            "total_mem_mib": 289.5,
            "total_cpu_pct": 2.47
          },
          {
            "t_offset_s": 76.2,
            "total_mem_mib": 289.5,
            "total_cpu_pct": 0.01
          }
        ],
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "jellyfin": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-08T07:58:26Z",
      "elapsed_seconds": 244.9
    }
  ],
  "load_defined": true,
  "notes": [
    "Image: the official `jellyfin/jellyfin` (Debian based, jellyfin-ffmpeg 8.1.3 inside). The media folder is generated by lab/apps/jellyfin/make_media.sh with ffmpeg (13 synthetic films, about 1.1 GB, nothing downloaded) and bind-mounted read-only at /media, so the compose file has one bind mount (./media).",
    "Metadata fetchers for movies are switched off in the library options (TypeOptions), not just EnableInternetProviders: with only that flag the first scan still called TheMovieDb for every film (13 failed lookups, 14.4 s instead of 3.6 s in the sandbox, where the proxy's certificate breaks TLS). The scan time here is local file probing only; a scan with TheMovieDb on a normal connection was not measured.",
    "Idle is measured after the wizard and library creation, before the first scan: the library exists but has no items. The first scan is part of the load step.",
    "CPU is software transcoding on the 4-vCPU lab host and is valid for that host only. There is no GPU or iGPU in the lab: hardware acceleration is not tested.",
    "service jellyfin: bind mount /home/runner/work/claudeftw/claudeftw/lab/apps/jellyfin/media refers to a path on the daemon host; prefer named volumes so remote runs and `down -v` stay clean"
  ],
  "warnings": [],
  "files": {
    "compose": "jellyfin.compose.yaml",
    "env": null
  },
  "definitions": {
    "memory": "cgroup working set as reported by `docker stats` (usage minus inactive file cache), MiB = 2^20 bytes",
    "cpu": "percent of ONE core as reported by `docker stats` (4 busy cores = 400)",
    "total": "stats over the sum of all containers at the same instant",
    "sample_interval": "docker stats --no-stream takes about 1-2 s per call, so samples are 2-3 s apart",
    "runs": "each run is a full fresh cycle (up, health, setup, settle, idle, load, down -v); the published figure is the median over the runs, shown with the min-max range; see summary.rule"
  }
}
