zola, tamarin-prover: fix reproducibility (parallel codegen order; compile-time clock) - #525
Draft
bryan-minimal wants to merge 2 commits into
Draft
zola, tamarin-prover: fix reproducibility (parallel codegen order; compile-time clock)#525bryan-minimal wants to merge 2 commits into
bryan-minimal wants to merge 2 commits into
Conversation
Both were flagged `unknown` by a build-twice audit of the 87 packages added since the last fleet run. They turned out to be completely different problems. zola — the reproducibility guide was applied halfway. The recipe already cites minimal-repro's guide and strips build paths, but never pinned codegen. rustc's default release build shards codegen across parallel units that finish in thread-completion order, so functions are EMITTED in a different order each build. Measured on 0.22.1: 16.89% of bytes differed while the total size stayed identical, and 69% of differing windows had a byte-exact twin elsewhere in the other build — a size-preserving permutation, i.e. ordering, not codegen variance. Adds `-C codegen-units=1` (ordering) and `-C symbol-mangling-version=v0` (legacy mangling embeds a per-session hash). Same fix as nushell and difftastic. tamarin-prover — not GHC, and not the toolchain. Its version banner embeds the wall-clock compile time via a TemplateHaskell splice that calls getCurrentTime while compiling; it asks the clock directly, so SOURCE_DATE_EPOCH never reaches it. Exactly 26 bytes of a 135 MB binary differ, and the Haskell codegen is otherwise bit-identical — the GHC determinism work is holding fine. Rewrites the splice to a fixed instant derived from SOURCE_DATE_EPOCH, locating the source file by content so an upstream file move fails loudly instead of silently reverting to a wall clock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
The reproducibility patch only matched a BARE call:
s|runIO Data\.Time\.getCurrentTime|...|
s|runIO getCurrentTime|...|
but upstream composes the action rather than naming it:
$(stringE =<< runIO (show `fmap` Data.Time.getCurrentTime))
`runIO` is followed by `(show ` fmap ` ...`, so neither pattern matched,
getCurrentTime survived, and the guard correctly refused the build on both
arches rather than shipping a wall-clock binary:
ERROR: tamarin compile-time-clock patch did not apply in src/Main/Console.hs
Add a pattern for the whole parenthesised argument; keep the two bare forms in
case upstream simplifies back to them. Verified by running the patched block
verbatim against the real line:
compileTime = "Compiled at: " ++ $(stringE =<< pure ("1970-01-01 00:00:00 UTC"))
which type-checks (`pure :: String -> Q String` feeding `stringE`) and leaves no
getCurrentTime for the guard to catch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
twitchyliquid64
approved these changes
Jul 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both packages were flagged
unknownby a build-twice audit of the 87 packages added since the last fleet run (83/86 reproducible, 96.5%). They looked identical in the verdict table and turned out to be completely different problems.zola — the reproducibility guide was applied halfway
The recipe already cites minimal-repro's guide, and applies the path half:
…but never pinned codegen. rustc's default release build shards codegen across parallel units, and those units finish in whatever order the thread pool produces — so functions are emitted in a different order every build.
The forensics say exactly that, independently of reading the recipe:
A size-preserving permutation is ordering non-determinism, not codegen variance. Fix:
-C codegen-units=1— one unit, one deterministic emission order-C symbol-mangling-version=v0— the legacy mangling scheme embeds a per-compilation-session hash in symbol namesSame fix that landed for
nushell(#292) anddifftastic.tamarin-prover — not GHC, and not the toolchain
Worth stating plainly, since the GHC determinism work is recent: that work is holding. tamarin's Haskell codegen is bit-identical across builds. What differs is 26 bytes out of a 135 MB binary:
tamarin's version banner embeds the wall-clock compile time through a TemplateHaskell splice that calls
getCurrentTimewhile compiling. It asks the clock directly, so the sandbox'sSOURCE_DATE_EPOCHnever reaches it. (The git fields are already deterministic — there's no repo in the build tree, so both builds sayUNKNOWN.)This is the same family as perl's
cf_time(#291): an application baking a timestamp, not a compiler being nondeterministic.The patch rewrites the splice to a fixed instant derived from
SOURCE_DATE_EPOCH, and locates the source file by content (grep -rl 'Compiled at') rather than by path, so an upstream file move fails loudly here instead of silently reverting to a wall clock. It follows the verify-grep style the recipe already uses for its other source patches.Verification status — please read
min buildpath and the client detached mid-build, so I do not have a byte-identical result to show yet.Marking this a draft for that reason. This repo's rule has been "never claim fixed without a real build-twice", and I'd rather show the analysis than assert a result I haven't seen. I'll post both double-build results here before marking it ready.
Reviewers: the reasoning is independently checkable from the measurements above even before the builds land.
Part of the reproducibility epic: gominimal/inbox#253
🤖 Generated with Claude Code