LH015 sources
Read on 29 September 2026 in phase 1, before any repository in the frame was cloned or read. Each read is logged in data/read_log_phase1.csv with its UTC time, status and bytes. Copies were kept in scratch space only, not in the repository. Times are UTC.
Literature (the bounded check)
Five web searches, from 15:26 to about 15:29 UTC, with these queries: (1) empirical study Dockerfile smells GitHub pip install unpinned versions DL3013; (2) study Dockerfiles Python projects lockfile ignored requirements pinned dependencies reproducible image builds; (3) empirical study lock files adoption Python poetry.lock Pipfile.lock uv.lock ecosystems arXiv; (4) "Dockerfile" empirical study dependency version pinning Python requirements.txt image rebuild different versions temporal reproducibility; (5) empirical study Dockerfiles "lockfile" OR "lock file" usage "npm ci" OR "uv sync" OR "poetry install" container builds GitHub mining. A search result is a lead; only what is listed here as opened was read.
| # | Source | Published | Read | What was taken from it |
|---|---|---|---|---|
| L1 | Malka, Zacchiroli and Zimmermann, "Docker Does Not Guarantee Reproducibility", arXiv 2601.12811: https://arxiv.org/abs/2601.12811 and the full text https://arxiv.org/html/2601.12811 | submitted 19 January 2026 (v1) | abstract 15:27:17, full text 15:27:30 | 5,298 Docker builds from GitHub workflow runs of July to October 2023, rebuilt later: 3,836 still built (72 per cent); in half of the images compared, at least 22.6 per cent of packages changed version, and 70 of 1,096 had every package at the same version. Its pinning recommendations are tested through hadolint rules, including DL3013 ("Pin versions in pip"), and it records the literature's trade-off between pinning and security updates. It does not measure whether a recipe installs from a lockfile. |
| L2 | Gamage, Tiwari, Monperrus and Baudry, "The Design Space of Lockfiles Across Package Managers", arXiv 2505.04834: https://arxiv.org/abs/2505.04834 and https://arxiv.org/html/2505.04834 | v1 7 May 2025, v3 27 October 2025 (read: v3) | abstract 15:27:18, full text 15:28:06 | A table of lockfile generation, lockfile-based resolution and enforcement for seven package managers: for Poetry all three by default; for Pipenv lockfile-based resolution and enforcement are optional (--deploy, sync); "Cargo and Pipenv ignore them when resolving dependencies". Interviews with 15 developers; no measure of container recipes. |
| L3 | Rosa, Scalabrino and Oliveto, "Fixing Dockerfile Smells: An Empirical Study", arXiv 2208.09097: https://arxiv.org/abs/2208.09097 | submitted 19 August 2022 (ICSME 2022 registered report) | abstract only, 15:27:19 | A plan to study which hadolint smells developers fix, on 9.4 million Dockerfiles. The abstract gives no figure on pip pinning; the journal version was not opened. |
| L4 | Eng and Hindle, "Revisiting Dockerfiles in Open Source Software Over Time", arXiv 2103.12298: https://arxiv.org/abs/2103.12298 | submitted 23 March 2021 | abstract only, 15:27:19 | 9.4 million unique Dockerfiles from 2013 to 2020; smell counts slightly decreasing. The abstract gives no figure on pip pinning or lockfiles. |
| L5 | hadolint, rule DL3013, source as served from the master branch: https://raw.githubusercontent.com/hadolint/hadolint/master/src/Hadolint/Rule/DL3013.hs | commit not recorded | 15:28:36 | The rule is not raised for pip install with -r, --requirement or . among its arguments, nor with -c or --constraint, and counts a package as pinned when it carries any of ==, >=, <=, >, <, !=, ~= or ===, is a wheel or archive, a versioned VCS URL or a path. So DL3013 does not look inside requirement files, does not see lockfile use, and counts a lower bound as a pin. |
Not opened: the Springer pages of Rosa and others (Empirical Software Engineering, 2024) and of Gamage and others (Empirical Software Engineering); ResearchGate copies; Cito and others, "An Empirical Analysis of the Docker Container Ecosystem on GitHub" (PeerJ preprint 2905, 2017), seen only as L1 cites it; "Not all Dockerfile Smells are the Same" (ACM, 2024); the ar5iv rendering of L4; DeepSource's page on DL3013; arXiv 1905.11127 (DockerizeMe), 2103.02591 (Shipwright), 2504.01742 (Doctor), 2511.20313 (SBOM-based vulnerability management) and 2511.22186 (SECURITY.md in PyPI); issues and pull requests in thirteen GitHub repositories whose titles report lockfiles ignored in Docker builds; blog posts and guides by OneUptime (three), pythonspeed.com (an article and a repository), apxml.com, Depot, Socket, nesbitt.io, and four Medium or dev.to posts. No published measure of how often a repository's container recipe installs from its own lockfile was found in five searches, which says little about whether one exists.
Documentation of installers and of Docker
Read with curl between 15:29:25 and 15:33:03 UTC, before any recipe. Version is what the page showed, where it showed one.
| # | Page | Version shown | Read | What the brief takes from it |
|---|---|---|---|---|
| D1 | pip install: https://pip.pypa.io/en/stable/cli/pip_install/ | pip 26.2.1 | 15:29:25 | -r/--requirement installs from a requirements file or, experimentally, pylock.toml; -c/--constraint constrains versions; --group installs a dependency group from pyproject.toml; a local project's metadata comes from its build backend; "the latest version that satisfies the given constraints will be installed"; -U/--upgrade upgrades the specified packages, dependencies by --upgrade-strategy (default only-if-needed); environment variables PIP_REQUIREMENT, PIP_CONSTRAINT, PIP_UPGRADE. |
| D2 | Requirements file format: https://pip.pypa.io/en/stable/reference/requirements-file-format/ | pip 26.2.1 | 15:29:46 | A requirements file may refer to other requirements files (-r) and constraints files (-c). |
| D3 | User guide: https://pip.pypa.io/en/stable/user_guide/ | pip 26.2.1 | 15:29:47 | Constraints files control which version is installed, not whether; pip install SomePackage does not upgrade an installed SomePackage or its dependency; --upgrade affects direct requirements, --upgrade-strategy the indirect ones. |
| D4 | uv, locking and syncing: https://docs.astral.sh/uv/concepts/projects/sync/ | not shown | 15:30:08 | Locking and syncing are automatic (uv run locks and syncs first); --locked errors if the lockfile is not up to date; --frozen uses it without checking; with an existing uv.lock, uv sync and uv lock prefer the locked versions, which change only if the project's constraints exclude them; uv lock --upgrade and --upgrade-package; uv export to requirements.txt or pylock.toml; --no-install-project still installs the dependencies. |
| D5 | uv in Docker: https://docs.astral.sh/uv/guides/integration/docker/ | not shown | 15:30:20 | Patterns RUN uv sync --locked, bind mounts of uv.lock and pyproject.toml with uv sync --locked --no-install-project, CMD ["uv", "run", ...], and a pip-interface pattern (COPY pyproject.toml ., uv pip install -r pyproject.toml, uv pip install -e .) that does not read uv.lock. |
| D6 | uv pip, installing packages: https://docs.astral.sh/uv/pip/packages/ | not shown | 15:30:32 | uv pip install -r requirements.txt and uv pip install -r pyproject.toml install from those files. |
| D7 | uv pip compile and sync: https://docs.astral.sh/uv/pip/compile/ | not shown | 15:30:33 | uv pip install keeps installed packages unless they conflict; uv pip sync makes the environment match a requirements.txt or pylock.toml exactly; uv pip compile -o F keeps F's existing pins unless asked to upgrade. |
| D8 | uv environment variables: https://docs.astral.sh/uv/reference/environment/ | lists variables to 0.11.16 | 15:30:33 | UV_FROZEN, UV_LOCKED, UV_NO_SYNC, UV_NO_DEV and UV_CONSTRAINT equal their flags. |
| D9 | Poetry commands: https://python-poetry.org/docs/cli/ | Poetry 2 | 15:30:48 | poetry install uses the exact versions in poetry.lock when present, and without one resolves and creates it; poetry sync also removes packages not in the lock; --no-root skips the project, "mainly useful for caching in CI or when building Docker images"; poetry lock keeps already locked packages by default, --regenerate starts afresh; poetry update updates; export comes from a plugin not installed by default since Poetry 2.0. |
| D10 | poetry-plugin-export on PyPI's JSON API: https://pypi.org/pypi/poetry-plugin-export/json | 1.10.1, uploaded 2026-09-19 | 15:31:01 | "allows the export of locked packages" to requirements.txt and constraints.txt. |
| D11 | Pipenv commands: https://pipenv.pypa.io/en/latest/commands.html | pipenv 2026.8.0 | 15:31:09 | --deploy aborts if Pipfile.lock is out of date; --ignore-pipfile installs from the lock but may re-lock without --deploy; pipenv sync installs exactly the lock and never re-locks; --system installs into the system Python; since Pipenv 2024 a bare pipenv install updates the lock only when adding or changing a package, where before it re-locked on every run; pipenv requirements writes requirements.txt from Pipfile.lock. |
| D12 | PDM lock file: https://pdm-project.org/latest/usage/lockfile/ | mentions 2.28.1 | 15:31:38 | pdm install reuses a fresh lock and creates a missing one or updates an outdated one, reusing compatible pins; pdm sync reads the lock without creating or updating it; --frozen-lockfile prevents writing, not resolution; install --check refuses a missing or outdated lock; pdm export writes requirements.txt or pylock.toml from the lock. |
| D13 | pip-tools on PyPI's JSON API: https://pypi.org/pypi/pip-tools/json | 7.6.1, uploaded 2026-08-12 | 15:31:48 | pip-sync installs, upgrades and uninstalls to match requirements.txt exactly; pip-compile makes no change to an existing output file that fulfils the dependencies unless --upgrade or --upgrade-package is given. |
| D14 | Docker build context: https://docs.docker.com/build/concepts/context/ | not shown | 15:32:04 | The context is the set of files a build can access; .dockerignore at the context root, or a Dockerfile-specific ignore file beside the Dockerfile named after it, which takes precedence; Go filepath.Match after filepath.Clean, ** for any number of directories, ! exceptions, the last matching line decides; excluded files cannot be copied or bind-mounted. |
| D15 | Dockerfile overview: https://docs.docker.com/build/concepts/dockerfile/ | not shown | 15:32:16 | The default filename is Dockerfile; a common convention for others is <something>.Dockerfile, used with --file. |
| D16 | Multi-stage builds: https://docs.docker.com/build/building/multi-stage/ | not shown | 15:32:17 | --target stops at a named stage ("you don't necessarily need to build the entire Dockerfile"); BuildKit builds only the stages the target depends on; its example built without a target gives the last stage's image ("a tiny production image with nothing but the binary inside"); COPY --from may copy from an external image. The page does not state the default target in words. |
| D17 | Dockerfile reference: https://docs.docker.com/reference/dockerfile/ | not shown | 15:32:28 | Stages are named with AS and used by FROM, COPY --from and RUN --mount=type=bind,from=; COPY and ADD take files from the context, a stage, a named context or an image, local paths relative to the context; COPY --exclude (Dockerfile 1.19) leaves out matching files; a bind mount's source defaults to the build context. |
| D18 | Compose build specification: https://docs.docker.com/reference/compose-file/build/ | not shown | 15:32:51 | context relative to the project directory; dockerfile resolved from the context; dockerfile_inline; target; args give ARG values. |
| D19 | podman build: https://docs.podman.io/en/latest/markdown/podman-build.1.html | latest | 15:33:03 | A Containerfile uses the Dockerfile syntax; podman builds from a file named Containerfile or Dockerfile. |
Lighthouse records read (not outcomes of this study)
studies/LH006/LH006.md 0.2 and data/candidates.csv, candidate_hits.csv; studies/LH007/LH007.md 0.2, brief.md and scripts/analyse.py (classify), data/candidates.csv, candidate_hits.csv, image_builds.csv (repository names only); studies/LH008/LH008.md 0.2, brief.md and scripts/collect.py; the Method and Limits of LH009 0.2 and LH010 0.3; the retained tables of LH008, LH009 and LH010 that scripts/frame.py reads (lags.csv, moves.csv, snapshot_files.csv, screen.csv, LH010's reused_moves.csv); studies/LH011/brief.md and scripts/analyse.py (pct); studies/LH014/brief.md.
From studies/LH015/sources.md in the repository, last changed 29 September 2026.