Prove Your Rebuild Matches the Shipped Binary
A comment-stripped source tree, a byte-reproducible build, and a script that lets a customer check both.
3 milestones 15 sprints 43 agents
9 plan 17 execute 19 review 4 fix
212k peak context
137k median execute
7h 1m total 16m 2s per sprint
29m 48s plan 2h 57m execute 31m 32s review
154 edits 562 commands
claude harness
87.3M tokens in 942.8k tokens out
$112.05 nominal cost
Gantry already had a source-available release story, but the readable source and the shipped binary were still joined mostly by trust. The source archive could expose internal comments, and a straightforward rebuild from the archive could differ because build paths and timestamps entered the compiled output.
This job made the release auditable from the customer side. It built a comment-stripped source tree, moved the producer to build and archive that tree under a pinned reproducibility environment, then added a verifier that rebuilds from the archive and compares the result to the signed release material.
How this walkthrough is structured
Feature
What did the run build and ship?
The tree now carries the comment-strip tool, stripped-tree release scripts, reproducibility tests, and a customer verifier that are still visible in the current source.
Build
How did Gantry structure the work?
The run split the problem into a reusable stripping transform, a release build that consumes its output, and a customer verification layer, with the repaired gates concentrated where archive policy met external rebuild behavior.
Milestone 1
Comment Stripping Transform
4 sprints 13 agents 1h 1m wall time 133k peak context $22.32 nominal cost
The current tree still has the `comment-strip` workspace member and its documented transform. It strips allow-listed source, preserves attribution where required, reports files that legitimately keep comments, and keeps the tokenizer out of the shipped `gantry` runtime dependency graph.
This milestone isolated the source sanitation problem before any release packaging depended on it. A fresh agent could reason about lexing, preservation, tree walking, and reporting inside one tool crate, with the release scripts still outside the boundary. Its plan impact was important: later work had to treat untokenizable files as reported passthroughs rather than failed stripping.
Rust Stripper Core
3 agents 19m 48s wall time 118k peak context 61.6k tokens out $6.13 nominal cost 1 replan
The tool crate still exposes lexer-driven stripping and checking, backed by tests for strings, raw strings, nested block comments, and generated documentation attributes. Later work revised the exact policy around documentation comments, so this sprint's contribution survives as the shared tokenizer structure rather than every original preservation rule.
The first sprint carried the lexical primitive alone: remove comments from Rust source and use the same tokenizer to check whether any remain. That was a good clean-context task because it had no tree traversal or release wiring, just string input, string output, and hard fixture cases. Review sent it into a re-plan, which exposed that real parsing errors had to become part of the interface rather than an exceptional crash path.
License Header Preservation
3 agents 11m 58s wall time 98k peak context 32.9k tokens out $4.21 nominal cost 1 fix
Header preservation is still present in the `comment-strip` library and its README. The current implementation documents the marker set, treats vendored paths as attribution-bearing, and makes the checker ignore headers that are supposed to survive.
This sprint layered legal preservation onto the already-built Rust stripper. Its scope was narrow enough for a fresh agent: detect attribution at the head of a file, apply the vendored-location rule, and keep ordinary narration removable below that point. The gate went red and a fix ran, placing the stress at the boundary between aggressive stripping and conservative license handling.
Tree File Transform
2 agents 11m 10s wall time 124k peak context 45.3k tokens out $3.91 nominal cost
The live `tree` module is the canonical release-tree transform. It emits only allow-listed paths, strips Rust files when they can be tokenized, copies other permitted files as required, and excludes reported passthroughs from the comment-absence check.
The third sprint lifted the per-file behavior into a repository-shaped transform. It had a clear input and output directory contract, plus an allow-list copied from the archive script, so the agent could prove determinism, idempotence, and passthrough behavior without touching release production. The inherited parser-failure finding became a machine-readable skipped-file report here.
Config & Density Report
2 agents 11m 18s wall time 133k peak context 46.5k tokens out $4.43 nominal cost
Hash-comment handling and high-density reporting remain in the transform. Shebangs and attribution survive, ordinary configuration narration can be removed, and documentation-by-comment files are listed instead of being quietly emptied.
This final stripping sprint completed the non-Rust policy after the tree walk existed. The work was bounded to shell and configuration files plus a report for files whose comments were too much of the file's meaning to remove silently. It passed at its boundary, leaving the milestone with a complete transform and an explicit report shape for downstream release code.
Milestone 2
Reproducible Release Build
6 sprints 18 agents 2h 10m wall time 212k peak context $46.08 nominal cost
Release construction now starts from the stripped tree. The current scripts include the strip-tree bridge, shared reproducibility environment, source archive builder, and local release producer that build from the same sanitized source used for the customer archive.
This milestone moved from a proven transform to a release producer that actually builds from its output. The cut kept shell integration, buildability, semantic checks, reproducibility checks, archive assembly, and release production in separate sprints. Its plan impact was that customer verification could not rely on a bare locked build; the remap flags and pinned epoch had to be reproduced outside the producer.
Stripped-Tree Producer
2 agents 6m 52s wall time 120k peak context 24.3k tokens out $3.31 nominal cost
The `strip-tree` binary still lives inside the comment-strip crate. It writes the canonical stripped tree, runs the report-aware absence check, emits passthrough listings for shell consumption, and keeps the main Gantry binary from depending on the lexer crate.
The bridge sprint gave shell scripts a single command rather than asking them to reach into Rust library code. Its boundary was the invocation contract: source ref or tree in, output tree and report out, with leftover comments as failures and expected passthroughs as visible non-failures. It stayed green, which fits a sprint built on the already-proven transform.
Reproducible Build Config
3 agents 32m 25s wall time 212k peak context 119.6k tokens out $10.92 nominal cost 1 replan
The present tree includes the toolchain pin, the workspace membership that keeps the shipped lock file valid, and comments in the manifest explaining which reproducibility inputs live outside static cargo config. The allow-list agreement between the Rust transform and archive script is also covered by tests.
This sprint handled the first hard composition problem in the milestone: the stripped tree had to remain buildable while the lock file stayed honest. The brief gave the agent a concrete reconciliation choice around the workspace member, plus the toolchain and build-flag placement. Review triggered a re-plan, marking this as the point where the release tree's shape had to be redrawn before later gates could trust it.
Semantic Identity Gate
4 agents 28m 1s wall time 139k peak context 93.1k tokens out $9.56 nominal cost
The stripped-tree integration coverage remains in the comment-strip test suite. It verifies that the produced tree has the expected shape and that the shipped source can be built and tested under the locked configuration.
After the tree was configured, this sprint made buildability a testable property. It asked the agent to produce the stripped tree, check comments with the report in hand, then build and test inside that tree. The run shows an extra execution and review note, but no failed gate, so the difficulty was in tightening the proof rather than repairing a broken boundary.
Binary Reproducibility
2 agents 19m 53s wall time 137k peak context 51.1k tokens out $5.49 nominal cost
The shared `repro-build-env.sh` fragment and the stripped-tree reproducibility tests are still in use. They apply the cargo-registry and source-root remaps plus the pinned epoch so independently placed builds can produce matching bytes.
This sprint turned reproducibility from configuration into a checked equality. The work was scoped to a host-target gate that builds the same stripped source in different locations under the producer's environment. That boundary let the expensive release targets remain out of the default gate while still proving the path and timestamp inputs mattered.
Source Archive Pipeline
2 agents 16m 2s wall time 150k peak context 37.4k tokens out $5.44 nominal cost
`make-source-archive.sh` now snapshots a supplied stripped tree. Its allow-list remains explicit, its metadata and compliance material are added on top, and the current integration tests exercise determinism and forbidden-path exclusions against that tree input.
This sprint changed the archive builder's input contract without changing its security contract. The agent had to preserve deterministic zip assembly, compliance injection, metadata sealing, and the allow-list while swapping the snapshot source from the internal repository to the stripped tree. It stayed within that mechanical boundary and passed.
Release Build Workflow
2 agents 14m 20s wall time 162k peak context 53.1k tokens out $5.36 nominal cost
`build-local-release.sh` now materializes the stripped tree before producing release artifacts. The script builds paid and demo binaries inside that tree, assembles the source archive from it, checks per-target reproducibility before writing signed output, and keeps the previous release preflight and catalog checks.
The final build milestone sprint composed the preceding pieces into the local release producer. Its scope was broad but well-fenced: produce one stripped tree, build inside it, archive that same tree, surface comment reports, and add the release-time double-build guard. It passed after the earlier build and archive contracts had already been proven.
Milestone 3
Verification and Round-Trip
5 sprints 19 agents 2h 53m wall time 195k peak context $39.68 nominal cost
Customer verification is now part of the release system. The archive conveys the build epoch, ships the documented verifier, the producer runs customer round-trip checks, and the README and metadata point to the same rebuild procedure.
This milestone put the reproducible-build promise in the customer's hands. The decomposition started with the missing archive input, then wrote the verifier, allowed it through the stripped archive unchanged, exercised the round trip, and reconciled the public procedure. This is where the gates pushed back: several sprints needed fixes, and the final documentation sprint had to be rerun after investigation.
Embed Build Epoch
2 agents 7m 27s wall time 105k peak context 20.4k tokens out $3.22 nominal cost
The release scripts still pass the pinned epoch into archive metadata. `build-local-release.sh` resolves it from the shared environment fragment, and `make-source-archive.sh` accepts it so the archive can tell a rebuild script which timestamp to use.
The first customer-verification sprint carried a single missing value across the producer/archive boundary. It was sized for a fresh agent because it only had to resolve the build epoch once and thread that same value into binary builds and metadata. It passed cleanly, giving the verifier a machine-readable input before the script existed.
Build Verification Script
3 agents 21m 11s wall time 163k peak context 70.9k tokens out $7.40 nominal cost 1 replan
`verify-build.sh` remains at the repository root and is heavily documented. Its integration tests drive match and mismatch paths with stubbed tools, assert the remap placeholders and pinned epoch, and guard drift against the producer's reproducibility environment.
This was the milestone's main external-interface sprint: write the script a customer runs and keep its reproducibility inputs aligned with the producer. Its brief named the hard parts, including toolchain checks, path remapping from the customer's machine, signed-checksum anchoring, and mismatch behavior. Review forced a re-plan, which records that the script's design needed adjustment before packaging could depend on it.
Package Verify Script
3 agents 19m 20s wall time 160k peak context 34.6k tokens out $7.72 nominal cost 1 fix
The archive allow-list and transform allow-list both include the verifier. The transform has an explicit comment-preserved category for `verify-build.sh`, and tests assert that the internal reproducibility fragment does not ship while the verifier's documentation survives byte-for-byte.
This sprint was a narrow archive-policy change with a sharp trap: the verifier needed to ship with comments intact while other shell comments were normally stripped. The first gate failed and a fix ran, locating the difficulty at the distinction between deliberate customer documentation and heuristic passthrough. After repair, the allow-list and transform rule agreed.
Round-Trip Verification
3 agents 28m 4s wall time 195k peak context 77.9k tokens out $8.63 nominal cost 1 fix
The local release producer still contains a customer round-trip guard. For each shipped target it unpacks the source archive, runs the verifier from that archive against the release directory, and refuses to continue if the script cannot report a match.
This sprint connected all earlier customer pieces into an end-to-end release guard. It asked for a host-target routine test plus a full release-time check that unpacks the archive and runs the shipped verifier against the produced binary. The gate went red and was fixed, putting the stress at the exact point where the archive, signed material, and rebuilt binary had to agree.
Canonical Rebuild Procedure
5 agents 12m 47s wall time 78k peak context 17.2k tokens out $4.76 nominal cost 1 fix
The current README's verification section directs customers to the verifier rather than to a bare cargo command. The archive metadata builder uses the same procedure text, and consistency coverage ties that public instruction back to the script's actual invocation.
The last sprint was nominally a small documentation and metadata reconciliation, but it was the noisiest boundary in the run. It had to remove rival rebuild instructions and make generated metadata, README prose, and script invocation describe one procedure. The gate failed more than once, a fix ran, and an investigate stage was opened before the work was rerun and passed.