
A client says the fix is live. Tonight, three proofs, in a repository the agency or the client can open. Name the image that deploy ran: the reference, and the digest that was pulled. Show a different deploy whose digest is not this one. Show another client's registry that does not list this image. If any of the three needs the person who pressed deploy, you have not shown which image ran. You have a green check and a tag.
This is the container the job executed. It is not the file a workflow uploaded and kept. Which artifact did that run keep? is a name, a run, and a retention. A zip that expires is not an image digest, and a digest is not a retention clock. It is not the commit the client is running. Name the commit the client is running is the revision of the source. A commit can be the one you meant while the image that booted is a different build of a floating tag. It is not the package the lockfile pinned. Name the package the lockfile pinned is a dependency version inside the source. A lockfile entry is not the image reference the runner pulled. And it is not the migration the database applied. Name the migration the deploy applied is a schema version. A schema is not a layer.
None of what follows is a promise that a rebuild will match, and none of it is a legal opinion about a registry's terms. The fields below are one vendor's current names for the image a job runs, and for the image a registry stores. The percentages below that are a 2026 measurement of Dockerfiles that did not rebuild to the same hash. A sample of repositories is not the deploy you opened tonight. They do tell you which numbers people mix up when they try to sound precise about an image they have not named.
GitHub Actions runs job steps in a container when you set jobs.<job_id>.container. If you do not set it, steps run on the host named by runs-on, unless a step's action brings its own container. The example job is named container-test-job, runs on ubuntu-latest, and sets image to node:18. node:18 is a tag in an example. It is not a digest. The same example sets NODE_ENV to development, exposes port 80, mounts my_docker_volume at /volume_mount, and passes options --cpus 1. 80 is a port in a sample. 1 is a CPU flag in a sample. Neither is a count of images. The default shell for run steps inside a container is sh, not bash. sh is not bash. When the image is the only field, you may write container: node:18 and omit the image key. Omitting the key does not pin the tag. Credentials, when the registry requires them, are a map of username and password, the same pair docker login would take. The example image there is ghcr.io/owner/image, with no tag and no digest. A name with no digest is not a pin (GitHub, Running jobs in a container).
Two options the same page refuses are easy to add because they look like ordinary Docker. --network and --entrypoint are not supported on container.options. Not supported is not "supported if you pass them carefully." Docker Hub rate limits on push and pull apply to self-hosted runners. GitHub-hosted runners are not subject to those limits, the page says, based on an agreement between GitHub and Docker. An agreement is not a digest. A self-hosted job and a GitHub-hosted job are not the same runner, even when both print node:18. Volumes have three shapes in the example: a named volume with a mount path, a host path alone, and a host path mapped to a container path. Three shapes are not three images. The image value may be a Docker Hub name or a registry name. A registry name is not a digest either.
The registry page is where a tag and a digest are printed next to each other, and where the examples do not agree with each other. Pulling by digest is the sentence that says you are using the same image. The inspect example tells you to copy the value after Digest: and then shows a pull of ghcr.io/NAMESPACE/IMAGE_NAME@sha256:82jf9a84u29hiasldj289498uhois8498hjs29hkuhs. That string is not hexadecimal. A sha256 digest is. Do not treat the placeholder as a digest you can verify. A different example pulls the tag 1.14.1 and prints Digest: sha256:ae3b135f133155b3824d8b1f62959ff8a72e9cf9e884d88db7895d8544010d8e. The command in that block is ghcr.io/NAMESPACE/IMAGE_NAME:1.14.1. The status line that follows names ghcr.io/NAMESPACE/IMAGE_NAME/release:1.14.1. The page inserts /release. Do not delete it to make the status match the command, and do not treat /release as a rule. A third example pulls :latest and prints a different digest, sha256:b3d3e366b55f9a54599220198b3db5da8f53592acbbb7dc7e4e9878762fc5344. latest is not 1.14.1. The two hex digests are two examples. Neither is the non-hex placeholder. A push example uses the tag 2.5. 2.5 is not 1.14.1, and it is not latest. The first publish of a package defaults to private visibility. Private is not a digest (GitHub, Working with the Container registry).
The same registry page prints sizes and clocks that are not the digest. A docker images sample shows ghcr.io/my-org/hello_docker, tag latest, image id 38f737a91f39, created 47 hours ago, size 91.7 MB. The next row is hello-world, tag latest, id fce289e99eb9, created 16 months ago, size 1.84 kB. 91.7 MB is not 1.84 kB. 47 hours is not 16 months. An image id of twelve hex characters is not a sha256 digest. Both rows say latest. Two latests are not one image. A description annotation is limited to 512 characters. A license annotation is limited to 256 characters. 512 is not 256. The registry has a 10 GB size limit for each layer, and a 10 minute timeout for uploads. 10 GB is not 10 minutes. 10 GB is not the port 80 on the job page, and it is not --cpus 1. The multi-arch workflow example pins docker/build-push-action to the commit f2a1d5e99d037542a71f64918e516c093c6f3fc4. That is a commit of an action. It is not an image digest. The annotation in that step is a description string. A description is not a layer.
The study people reach for when they want a percentage of images that rebuild is a different document, and it is not this deploy. Oreofe Solarin, Case Western Reserve University, arXiv:2602.17678v1, 3 February 2026. The PDF's running header says Conference'17, and the DOI line ends in XXXXXXX. Those are template leftovers on the page. They are not a count of repositories, and they are not a venue you should cite as if the paper named it. The population is 19,262 repositories with at least 5 stars that modified a Dockerfile in 2024. The sample is 2,000, stratified into four star buckets: 5 to 7, 8 to 19, 20 to 82, and above 82. Four buckets. 5 is the floor of the first bucket and also the star minimum. They are the same numeral in two roles. 82 is the top of the third bucket. It is not a digest (Solarin, It's Not Just Timestamps: A Study on Docker Reproducibility).
Table 1 splits the percentages across two denominators, and the caption says so. The top rows are relative to the 2,000 sampled repositories. The bottom rows are relative to the 1,123 buildable ones. Buildable: 1,123, 56.1%. Not buildable: 877, 43.9%. 1,123 plus 877 is 2,000. 56.1 plus 43.9 is 100. As-is bitwise reproducible: 30, 2.7%. Fixed by infrastructure changes: 209, 18.6%. Non-reproducible: 884, 78.7%. 30 plus 209 plus 884 is 1,123. Those three percentages are of the buildable set, not of the 2,000. 2.7% of 1,123 is 30. 2.7% of 2,000 would be a different integer, and the table does not print it. Do not apply 2.7 to the sample. The abstract says 56% produce any buildable image, and 2.7% of those are bitwise reproducible. Of those means of the buildable. 56 is the abstract's rounding of 56.1. 30 is not 56. The prose says infrastructure changes raise bitwise reproducibility by roughly 18.6%, and about one in five buildable Dockerfiles then support a hash check. 30 plus 209 is 239. 239 of 1,123 is about one in five. 18.6 is the increment, not the total. One in five is not 18.6, and it is not 2.7.
Table 2 is a third denominator. It is 954 diffoscope reports, not the 884 non-reproducible Dockerfiles, and not the 2,000. Timestamps and metadata: 954, 100.0%. Formatting and file ordering: 745, 78.1%. System logs: 413, 43.3%. Caches and databases: 351, 36.8%. Compiled artifacts: 191, 20.0%. Application-specific files: 124, 13.0%. Random data: 90, 9.4%. Package-manager state: 53, 5.6%. Those percentages do not add to 100, because one report can carry more than one cause. 100.0 is the only row that is all of them. The prose rounds 43.3 to 43, 36.8 to 37, 20.0 to 20, and 13.0 to about 13. 43 is not 43.3 if you are quoting a cell. Quote the cell or quote the sentence, and do not blend them. Table 4, from the same 954 reports, prints pip and Python at 7.7% and npm and Node at 1.7%, and it prints logs at 43% and caches at 37%. 7.7 is not 13.0. 1.7 is not 5.6. 43 on that table is the prose rounding, not the 43.3 cell. They observed zero semantically reproducible cases. Zero is not 30.
The appendix's one official image is not the sample. They rebuilt golang:1.25.5-alpine3.22 and compared five layers to Docker Hub. Two of the five differed. Two is not five. Layer 2: 291,165 bytes locally against 291,156 on the Hub. The difference is 9 bytes. Layer 4: 124 bytes against 126. The difference is 2. The config digest size is 2,165 bytes against 2,171. The difference is 6. 9 is not 2, and 2 is not 6. Layers that matched include sizes 3,802,452, 60,151,314, and 32. 32 is not 3,802,452. Figure 1's sketch uses the prefixes 44c6fb81 and e391a774 for two builds that differ, and 50d70b92 for two builds that match, beside python:3.11-slim and a shortened sha256:5be4. Those prefixes are a figure. They are not Table 1, and a shortened prefix is not a digest you can pull.
Do the three proofs on one real deploy, in the log the client can open. First, the binding. Copy the image reference and the digest the job pulled. If the log shows node:18 and no digest, write that the digest was not stored. Do not infer a pin from a green check. Second, the other deploy. A different run, with a different digest or with only a tag, is not this one. A percentage of Dockerfiles is not that second deploy. Third, the other client. A registry that belongs to someone else does not list this image. If the only registry is shared and you cannot say whose namespace it is, write that.
Three moves feel like the proof and are a second problem. Re-running the workflow so the new log shows a digest, and calling that the image the client already has. Quoting 2.7% because it is small, or 78.7% because it is large, while the deploy you were asked about is one run. 2.7 is a share of someone else's buildable Dockerfiles. It is not a receipt. Asking a model which image is in production. The model will name a tag. It will not open the run.
The path is ordinary when an operator can point at one release without pointing at the next. Cove consolidates an operator portal for device provisioning onto Kubernetes, with blue/green deploys. The shape that matters here is one deploy you can name, distinct from the other color. That case is not a digest ledger. Nothing in the description is a headcount, a duration, or a result figure. If the only status page says healthy and will not print an image, you do not have this proof. You have a pulse.
There is a version of this call where hiring the path is the wrong purchase. The work is not sold under the agency's name, so there is no client production to name. The client has asked to meet the people who will write the code, and a digest will not hide that. The thing in the room is a slide. Or the buyer only wants a template of a provenance file, with no cluster to read. A white label software development partner is the wrong purchase for a blank. The criteria for choosing a firm, when you are still choosing, sit on the page for a top SaaS development company. That page is criteria. It does not rank anyone, including us. Or the buyer wants a legal opinion about a registry's terms. A repository does not answer that.
When a client is already asking which image they are on, the missing object is specific. A digest you can read without the person who deployed it, and a second deploy that is not that digest. A white label software development partner that expects this will have put the digest in the log the client already has, before the client's question is the way anyone learns the tag moved. If the first slice is a fixed capability, an AI integration sprint is the shape where the acceptance sentence can include one production digest you can read yourself. If nothing has been deployed and the question is whether the pipeline could name an image at all, a two-week AI readiness assessment hands you the findings either way. The findings are yours. They are not 2.7, and they are not 78.7.
A webhook delivery, and the tool result a model was shown, are different objects: which webhook did that event hit? and which tool result did the model see?. Do not record either on this page. An event id is not a digest. A tool payload is not a layer.
Before you tell the client the fix is live, write the image and the time you read it. The reference. The digest, or the sentence that the digest was not stored. A different deploy that is not this one. Another client's registry that does not list it. Do not re-run the job to improve the answer, and do not ask a model which tag is current. A paper can tell you how often a Dockerfile rebuilt in a 2026 sample. The binding is the page you can defend.
Questions
Three records, in a repository the agency or the client can open. The image reference and the digest the job actually pulled. A different deploy whose digest is not this one. Another client's registry that does not list it. If the log only prints a tag, write that the digest was not stored.
No. A percentage of Dockerfiles that rebuilt to the same hash is a share of someone else's sample. An image you can defend is the reference and the digest on this run, or a written line that the workflow did not record the digest. 2.7% of buildable Dockerfiles is not 2.7% of 2,000 repositories, and neither figure is a tag.
When the work is not sold under the agency's name, when the client asked to meet the builders, when the room only has a slide, when the buyer only wants a template, or when the buyer wants a legal opinion.
Find this useful? Tell Google to show you more of it.
