{
  "schema_version": 3,
  "app": "filebrowser",
  "display_name": "File Browser",
  "upstream_repo": "https://github.com/filebrowser/filebrowser",
  "docs_url": "https://github.com/filebrowser/filebrowser/blob/v2.63.23/docs/installation.md",
  "status": "ok",
  "summary": {
    "primary_service": "filebrowser",
    "app_version": "2.63.23",
    "app_version_pinned": true,
    "runs": 3,
    "publishable": true,
    "publishable_note": null,
    "idle_total_mem_mib": 14.72,
    "idle_total_cpu_pct": 0.54,
    "peak_total_mem_mib": 22.75,
    "peak_is_under_load": true,
    "startup_seconds": 5.4,
    "startup_peak_total_mem_mib": 14.89,
    "settled": true,
    "settle_seconds_used": 120.8,
    "peak_max_mib": 22.81,
    "sizing_peak_mib": 22.81,
    "idle_mem_mib": {
      "median": 14.72,
      "min": 12.82,
      "max": 14.77,
      "values": [
        14.77,
        12.82,
        14.72
      ]
    },
    "idle_cpu_pct": {
      "median": 0.54,
      "min": 0.5,
      "max": 0.54,
      "values": [
        0.54,
        0.54,
        0.5
      ]
    },
    "peak_mem_mib": {
      "median": 22.75,
      "min": 20.78,
      "max": 22.81,
      "values": [
        22.75,
        20.78,
        22.81
      ]
    },
    "startup_peak_mem_mib": {
      "median": 14.89,
      "min": 12.92,
      "max": 15.06,
      "values": [
        15.06,
        12.92,
        14.89
      ]
    },
    "startup_s": {
      "median": 5.4,
      "min": 5.4,
      "max": 5.4,
      "values": [
        5.4,
        5.4,
        5.4
      ]
    },
    "settled_after_healthy_s": {
      "median": 122.3,
      "min": 122.3,
      "max": 122.4,
      "values": [
        122.3,
        122.4,
        122.3
      ]
    },
    "settled_runs": 3,
    "per_service": {
      "filebrowser": {
        "idle_mem_mib": {
          "median": 14.72,
          "min": 12.82,
          "max": 14.77,
          "values": [
            14.77,
            12.82,
            14.72
          ]
        },
        "peak_mem_mib": {
          "median": 22.75,
          "min": 20.78,
          "max": 22.81,
          "values": [
            22.75,
            20.78,
            22.81
          ]
        }
      }
    },
    "variance_flag": null,
    "representative_run": 3,
    "cpu_models": [
      "AMD EPYC 9V45 96-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-16T04:56:45Z",
    "date": "2026-10-16",
    "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": "20261012.334.1"
    },
    "cpu_model": "AMD EPYC 9V45 96-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:a134550be58ab783810e613ae96fd253c38f7bdd16d9bf9be350700c7a29ac06"
    },
    "python:3.12-slim": {
      "pulled_as": "python:3.12-slim",
      "digest": "python@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1"
    }
  },
  "pull_seconds": 1.7,
  "finished_at": "2026-10-16T05:05:06Z",
  "elapsed_seconds": 501.0,
  "services": {
    "filebrowser": {
      "image_ref": "filebrowser/filebrowser:v2.63.23",
      "image_repo": "filebrowser/filebrowser",
      "image_tag": "v2.63.23",
      "digest": "sha256:a469ea076d4a1b4b1d86a41d130f2f536cd9da996a2b1fb39c0d7635f9d89b9a",
      "digest_note": null,
      "version": "2.63.23",
      "version_source": "label:org.opencontainers.image.version",
      "version_pinned": true,
      "version_note": null,
      "resolved_tag": "v2.63.23",
      "resolved_tag_note": null,
      "image_size": {
        "unpacked_mb": 38.5,
        "unpacked_source": "docker image ls Size: unpacked image on the daemon host, rounded by docker to 3 significant figures",
        "compressed_mb": 16.8,
        "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": "filebrowser/filebrowser:v2.63.23",
      "compose_comment": "sha256:a469ea076d4a1b4b1d86a41d130f2f536cd9da996a2b1fb39c0d7635f9d89b9a  (version 2.63.23, from label:org.opencontainers.image.version)",
      "restart_count": 0,
      "oom_killed": false
    }
  },
  "runs": [
    {
      "run": 1,
      "started_at": "2026-10-16T04:56:53Z",
      "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": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-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-16",
      "startup": {
        "seconds": 5.4,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 5.4,
            "detail": "shb-filebrowser-filebrowser-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.2,
        "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": {
        "filebrowser": "2.63.23"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 0.4,
          "reported": {
            "login_ok": true,
            "root_entries": 0,
            "unauthenticated_api_status": 401
          },
          "output_tail": [
            "logged in as admin; file root has 0 entries; without a token the API answers HTTP 401"
          ],
          "description": "Check /health, check that the API refuses a request without a token, log in as the first user (POST /api/login) and list the empty file root (GET /api/resources/), as the first visit of a user would."
        }
      ],
      "idle": {
        "per_service": {
          "filebrowser": {
            "samples": 16,
            "mem_mean_mib": 14.77,
            "mem_max_mib": 15.04,
            "cpu_mean_pct": 0.54,
            "cpu_max_pct": 2.92
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 14.77,
          "mem_max_mib": 15.04,
          "cpu_mean_pct": 0.54,
          "cpu_max_pct": 2.92
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 14.7,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 14.7,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 15.04,
            "total_cpu_pct": 2.88
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 14.95,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 14.95,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 14.69,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 14.69,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 14.87,
            "total_cpu_pct": 2.89
          },
          {
            "t_offset_s": 16.1,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 20.2,
            "total_mem_mib": 14.7,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 22.2,
            "total_mem_mib": 14.7,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 14.68,
            "total_cpu_pct": 2.92
          },
          {
            "t_offset_s": 26.2,
            "total_mem_mib": 14.68,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 28.2,
            "total_mem_mib": 14.68,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 14.59,
            "total_cpu_pct": 0.0
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 120.8,
        "settle_started_after_healthy_s": 1.5,
        "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": 14.67,
          "min_mib": 14.46,
          "max_mib": 15.06,
          "spread_mib": 0.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": {
          "filebrowser": 15.06
        },
        "total_mem_mib": 15.06,
        "samples": 61,
        "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": [
          14.5,
          14.6,
          14.7,
          14.6,
          14.7,
          14.6,
          14.6,
          14.7,
          14.7,
          14.7,
          14.5,
          14.8,
          14.8,
          14.8,
          14.7,
          14.6
        ],
        "per_service_mem_mib": {
          "filebrowser": [
            14.5,
            14.6,
            14.7,
            14.6,
            14.7,
            14.6,
            14.6,
            14.7,
            14.7,
            14.7,
            14.5,
            14.8,
            14.8,
            14.8,
            14.7,
            14.6
          ]
        }
      },
      "load": {
        "per_service": {
          "filebrowser": {
            "samples": 3,
            "mem_mean_mib": 21.84,
            "mem_max_mib": 22.75,
            "cpu_mean_pct": 7.25,
            "cpu_max_pct": 12.92
          }
        },
        "total": {
          "samples": 3,
          "dropped_for_total": 0,
          "mem_mean_mib": 21.84,
          "mem_max_mib": 22.75,
          "cpu_mean_pct": 7.25,
          "cpu_max_pct": 12.92
        },
        "description": "The same load as the Nextcloud, Seafile and ownCloud tests, through File Browser's HTTP API. One user (the first user, an administrator), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder (POST /api/resources/loadtest/), uploads the files with one POST of the raw body each, lists the folder with one GET, and downloads five files (three small, two large; GET /api/raw/...) and checks their SHA-256. About 200 MB in total. The web interface uploads with the TUS protocol; this test uses the plain POST that scripts use, so it measures one request per file as the other apps do. No browser, no thumbnails, no sharing, no search, no command runner.",
        "duration_s": 2.3,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "file browser http api (/api/resources, /api/raw), plain POST upload (not TUS)",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 2.0,
          "listing_entries": 103,
          "listing_seconds": 0.0,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 0.1,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 110,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 2.0s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.00s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 0.1s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 20.07,
            "total_cpu_pct": 12.92
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 22.75,
            "total_cpu_pct": 8.82
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 22.7,
            "total_cpu_pct": 0.0
          }
        ],
        "series_start_offset_s": 1.3,
        "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": {
        "filebrowser": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T04:59:37Z",
      "elapsed_seconds": 164.3
    },
    {
      "run": 2,
      "started_at": "2026-10-16T04:59:37Z",
      "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": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-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-16",
      "startup": {
        "seconds": 5.4,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 5.4,
            "detail": "shb-filebrowser-filebrowser-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.2,
        "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": {
        "filebrowser": "2.63.23"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 0.5,
          "reported": {
            "login_ok": true,
            "root_entries": 0,
            "unauthenticated_api_status": 401
          },
          "output_tail": [
            "logged in as admin; file root has 0 entries; without a token the API answers HTTP 401"
          ],
          "description": "Check /health, check that the API refuses a request without a token, log in as the first user (POST /api/login) and list the empty file root (GET /api/resources/), as the first visit of a user would."
        }
      ],
      "idle": {
        "per_service": {
          "filebrowser": {
            "samples": 16,
            "mem_mean_mib": 12.82,
            "mem_max_mib": 12.99,
            "cpu_mean_pct": 0.54,
            "cpu_max_pct": 2.98
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 12.82,
          "mem_max_mib": 12.99,
          "cpu_mean_pct": 0.54,
          "cpu_max_pct": 2.98
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 12.92,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 12.7,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 12.89,
            "total_cpu_pct": 2.91
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 12.87,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 12.87,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 12.75,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 12.75,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 12.69,
            "total_cpu_pct": 2.82
          },
          {
            "t_offset_s": 16.1,
            "total_mem_mib": 12.67,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 12.66,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 20.2,
            "total_mem_mib": 12.79,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 22.2,
            "total_mem_mib": 12.79,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 12.99,
            "total_cpu_pct": 2.98
          },
          {
            "t_offset_s": 26.2,
            "total_mem_mib": 12.97,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 28.2,
            "total_mem_mib": 12.97,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 12.85,
            "total_cpu_pct": 0.0
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 120.9,
        "settle_started_after_healthy_s": 1.5,
        "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": 12.62,
          "min_mib": 12.39,
          "max_mib": 12.92,
          "spread_mib": 0.53,
          "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": {
          "filebrowser": 12.92
        },
        "total_mem_mib": 12.92,
        "samples": 61,
        "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": [
          12.5,
          12.5,
          12.7,
          12.7,
          12.8,
          12.7,
          12.5,
          12.6,
          12.7,
          12.5,
          12.7,
          12.6,
          12.8,
          12.7,
          12.8,
          12.9
        ],
        "per_service_mem_mib": {
          "filebrowser": [
            12.5,
            12.5,
            12.7,
            12.7,
            12.8,
            12.7,
            12.5,
            12.6,
            12.7,
            12.5,
            12.7,
            12.6,
            12.8,
            12.7,
            12.8,
            12.9
          ]
        }
      },
      "load": {
        "per_service": {
          "filebrowser": {
            "samples": 3,
            "mem_mean_mib": 20.34,
            "mem_max_mib": 20.78,
            "cpu_mean_pct": 6.4,
            "cpu_max_pct": 16.35
          }
        },
        "total": {
          "samples": 3,
          "dropped_for_total": 0,
          "mem_mean_mib": 20.34,
          "mem_max_mib": 20.78,
          "cpu_mean_pct": 6.4,
          "cpu_max_pct": 16.35
        },
        "description": "The same load as the Nextcloud, Seafile and ownCloud tests, through File Browser's HTTP API. One user (the first user, an administrator), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder (POST /api/resources/loadtest/), uploads the files with one POST of the raw body each, lists the folder with one GET, and downloads five files (three small, two large; GET /api/raw/...) and checks their SHA-256. About 200 MB in total. The web interface uploads with the TUS protocol; this test uses the plain POST that scripts use, so it measures one request per file as the other apps do. No browser, no thumbnails, no sharing, no search, no command runner.",
        "duration_s": 1.9,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "file browser http api (/api/resources, /api/raw), plain POST upload (not TUS)",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 1.7,
          "listing_entries": 103,
          "listing_seconds": 0.0,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 0.1,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 110,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 1.7s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.00s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 0.1s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 19.47,
            "total_cpu_pct": 16.35
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 20.78,
            "total_cpu_pct": 2.85
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 20.76,
            "total_cpu_pct": 0.0
          }
        ],
        "series_start_offset_s": 1.3,
        "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": {
        "filebrowser": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T05:02:22Z",
      "elapsed_seconds": 164.7
    },
    {
      "run": 3,
      "started_at": "2026-10-16T05:02:22Z",
      "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": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-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-16",
      "startup": {
        "seconds": 5.4,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 5.4,
            "detail": "shb-filebrowser-filebrowser-1=running/healthy"
          }
        ],
        "up_command_seconds": 0.2,
        "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": {
        "filebrowser": "2.63.23"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 0.5,
          "reported": {
            "login_ok": true,
            "root_entries": 0,
            "unauthenticated_api_status": 401
          },
          "output_tail": [
            "logged in as admin; file root has 0 entries; without a token the API answers HTTP 401"
          ],
          "description": "Check /health, check that the API refuses a request without a token, log in as the first user (POST /api/login) and list the empty file root (GET /api/resources/), as the first visit of a user would."
        }
      ],
      "idle": {
        "per_service": {
          "filebrowser": {
            "samples": 16,
            "mem_mean_mib": 14.72,
            "mem_max_mib": 14.84,
            "cpu_mean_pct": 0.5,
            "cpu_max_pct": 2.68
          }
        },
        "total": {
          "samples": 16,
          "dropped_for_total": 0,
          "mem_mean_mib": 14.72,
          "mem_max_mib": 14.84,
          "cpu_mean_pct": 0.5,
          "cpu_max_pct": 2.68
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 2.68
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 14.57,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 8.1,
            "total_mem_mib": 14.57,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 10.1,
            "total_mem_mib": 14.76,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 14.76,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 14.1,
            "total_mem_mib": 14.72,
            "total_cpu_pct": 2.63
          },
          {
            "t_offset_s": 16.1,
            "total_mem_mib": 14.55,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 14.55,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 20.1,
            "total_mem_mib": 14.81,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 22.1,
            "total_mem_mib": 14.81,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 14.71,
            "total_cpu_pct": 2.64
          },
          {
            "t_offset_s": 26.2,
            "total_mem_mib": 14.69,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 28.2,
            "total_mem_mib": 14.69,
            "total_cpu_pct": 0.0
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 14.84,
            "total_cpu_pct": 0.0
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 120.8,
        "settle_started_after_healthy_s": 1.5,
        "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": 14.63,
          "min_mib": 14.39,
          "max_mib": 14.89,
          "spread_mib": 0.5,
          "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": {
          "filebrowser": 14.89
        },
        "total_mem_mib": 14.89,
        "samples": 61,
        "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": [
          14.5,
          14.5,
          14.5,
          14.5,
          14.5,
          14.6,
          14.7,
          14.6,
          14.6,
          14.6,
          14.5,
          14.7,
          14.8,
          14.7,
          14.7,
          14.8
        ],
        "per_service_mem_mib": {
          "filebrowser": [
            14.5,
            14.5,
            14.5,
            14.5,
            14.5,
            14.6,
            14.7,
            14.6,
            14.6,
            14.6,
            14.5,
            14.7,
            14.8,
            14.7,
            14.7,
            14.8
          ]
        }
      },
      "load": {
        "per_service": {
          "filebrowser": {
            "samples": 3,
            "mem_mean_mib": 21.83,
            "mem_max_mib": 22.81,
            "cpu_mean_pct": 6.77,
            "cpu_max_pct": 12.28
          }
        },
        "total": {
          "samples": 3,
          "dropped_for_total": 0,
          "mem_mean_mib": 21.83,
          "mem_max_mib": 22.81,
          "cpu_mean_pct": 6.77,
          "cpu_max_pct": 12.28
        },
        "description": "The same load as the Nextcloud, Seafile and ownCloud tests, through File Browser's HTTP API. One user (the first user, an administrator), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder (POST /api/resources/loadtest/), uploads the files with one POST of the raw body each, lists the folder with one GET, and downloads five files (three small, two large; GET /api/raw/...) and checks their SHA-256. About 200 MB in total. The web interface uploads with the TUS protocol; this test uses the plain POST that scripts use, so it measures one request per file as the other apps do. No browser, no thumbnails, no sharing, no search, no command runner.",
        "duration_s": 2.1,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "file browser http api (/api/resources, /api/raw), plain POST upload (not TUS)",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 1.9,
          "listing_entries": 103,
          "listing_seconds": 0.0,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 0.1,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 110,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 1.9s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.00s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 0.1s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 19.95,
            "total_cpu_pct": 12.28
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 22.81,
            "total_cpu_pct": 8.03
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 22.74,
            "total_cpu_pct": 0.0
          }
        ],
        "series_start_offset_s": 1.3,
        "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": {
        "filebrowser": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T05:05:06Z",
      "elapsed_seconds": 164.5
    }
  ],
  "load_defined": true,
  "notes": [
    "Host: a GitHub Actions runner (ubuntu-latest, x86_64, 2 vCPU, 8 GB RAM; the CPU model varies between runners and each run records its own). Numbers are valid for that host only.",
    "MAINTENANCE: the project is archived. v2.63.23 (27 Jul 2026, Docker Hub tag filebrowser/filebrowser:v2.63.23, also `latest` and `v2`) is the last planned release; the README says 'File Browser is archived on 2026-09-01' and 'there will be no further releases, bug fixes, or security fixes', and lists unfixed issues (JWTs cannot be revoked, so a logout or password change does not invalidate older tokens; the command runner is off by default). The container prints a wind-down notice at start. The tested image still works and stays on Docker Hub; it is tested because readers still run it, not because it is a recommendation. See lab/notes/filebrowser-syncthing-2026-10-16.md for the evidence.",
    "Image: the default bare image (BusyBox, one static Go binary, runs as UID/GID 1000), not the `s6` variant. One container; users and settings are in a Bolt database file (/database/filebrowser.db) and files are plain files in /srv.",
    "Measured: idle RAM and CPU after the first start with one user and an empty file root; RAM and CPU while the load of load.description runs (a few seconds); image size; start-up time. Not measured: the web interface or a browser, TUS (resumable) uploads, thumbnails and previews of images or video, the search, sharing links, multiple users, a reverse proxy, desktop or mobile sync (File Browser has no sync client at all; it is a file manager, not a sync tool).",
    "Equivalence with the Nextcloud test: same 103 files (same generator and seed), same order, one request at a time, one user, plain HTTP, 5 downloads with a SHA-256 check. Differences that come from the product: no address requests, the login token is a header (X-Auth), and the folder listing returns files only, so `listing_entries` is 103.",
    "The first user is created from FB_USERNAME and FB_PASSWORD (a bcrypt hash) on the first start, the 'quick setup' of the quick-start docs; without FB_PASSWORD File Browser generates a random password and prints it once in the log. The lab sets one so the steps can log in.",
    "The load script reports every request kind with the HTTP statuses it got (`requests` in the load result); any failed request fails the run."
  ],
  "warnings": [],
  "files": {
    "compose": "filebrowser.compose.yaml",
    "env": "filebrowser.env"
  },
  "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"
  }
}
