Uncommitted changes are part of the build
24 October 2026 · Guardrails & fail-closed · the engineering team
The story
We compute a fingerprint for the site we build. It is a list of inputs, each on its own line: the commit at HEAD, the versions of two installed packages, the brand, and more. Change one input and the fingerprint changes.
The commit line has a limit. It names what was committed, and an edit that sits in the working tree is not in that commit. So we added a line for the dirty state. It hashes two things: the diff against HEAD of the engine source, the tools directory and the package manifests, and the list of untracked files under the source directory. If git fails, that line reads unknown instead of a hash.
We wrote the test around the cases that matter. It builds a small throwaway git repository with one committed source file and takes the fingerprint. It edits the file and checks that the fingerprint differs. It adds a new, untracked file and checks that the fingerprint differs from the edited one. Then it removes the new file, restores the original contents and checks that the fingerprint equals the first. The last step shows the new line does not leave a permanent mark on the fingerprint once the tree is clean again.
The pattern
A fingerprint answers the question "is this the same build?" The commit at HEAD answers a narrower one: "is this the same commit?" The two come apart as soon as someone edits a file and does not commit.
So the working tree belongs in the fingerprint. Hash the diff against HEAD for the paths that feed the build. Add the untracked files in those paths, because a diff against HEAD does not list them. Keep the paths explicit. The fingerprint then covers the inputs you chose, not everything git can see.
Test it in both directions. A tracked edit must move the fingerprint, and so must a new untracked file. Reverting both must bring the original value back. The third check matters as much as the first two, because a fingerprint that moves and never returns is just a counter.
Try it
Open the code that fingerprints your build and list its inputs. For each one, ask whether an uncommitted change could alter it without the value moving. If the answer is yes for the source tree, add a dirty term:
Hash the diff against HEAD for the build's source paths and manifests.
Add the sorted list of untracked files under the source path.
Decide what the term reads when git fails, and test that case.
Write one test in a throwaway repository: edit a file, add a file, revert both, and assert the fingerprint moves twice and then returns.