The archive also contains build decisions
The lab writes two original files into a ZIP: app.py and dependency.py. It creates representations dated 2026 and 2027 while preserving identical member bytes. Per-file hashes match, but whole-archive SHA-256 differs. Another group reverses only inclusion order and again observes different overall identity. This matters when QA approves a package and deployment rebuilds it: apparently identical internal content does not guarantee identical delivered bytes. Define whether the release identifier represents the whole archive, members or another object. Do not silently change criteria to bypass rejection; alternative equivalence requires an explicit traceable decision. Preserve the representation actually assessed so later comparison uses the same scope.
Normalization with observable limits
The normalized build sorts names, fixes the date to 1980-01-01, sets Unix metadata explicitly and uses ZIP_STORED. Two builds in the same environment produce identical bytes. The exercise chooses uncompressed storage to reduce variables; it does not claim this is a mandatory format for a real release. Normalization should belong to the reviewed process because changing dates after approval also changes the digest. Retain toolchain, inputs and metadata policy. The result was observed on CPython 3.13.1 on Darwin arm64, not across a matrix of systems or tool versions. Reproducing identical bytes can also reproduce the same defect, so functional verification remains necessary.
The main application does not pin dependencies
app.py imports SCALE from dependency.py and multiplies it by ten. The first dependency defines two and the second defines three. The script starts two Python processes with these original inputs and observes 20 and 30 while retaining identical app.py bytes. It downloads no libraries and executes no files extracted from ZIP archives. The experiment isolates one behavioral input and shows why rebuilding the same application may not equal the reviewed bundle. In an APS scenario, identify resolved dependencies, tools, configuration and produced artifacts. If the approved package is lost, rebuilding with current dependencies creates a candidate needing assessment; the window deadline does not turn it into the already-tested version.
Recover an identified artifact
The recovery plan should retain access to required bytes and evidence identifying them. A path named old.zip may have been overwritten; a stable label in a report may resolve different content later. Record the relationship between version, digest, inputs and validation outcome with service-appropriate retention. This does not guarantee the earlier package remains compatible with current state: migrations, configuration and already-produced effects still need assessment. In the fictional exercise, if drift is discovered near cut-off, decide on redelivery or rescheduling with room for validation. Merely replacing the expected hash with the received one removes the control instead of addressing the change.
python3 content/labs/release-artifacts/run.py --output /tmp/dr-release-artifacts.json
# Compare timestampChangesArchiveIdentity and sameApplicationDifferentInput.
# Only original local fixtures; no package download or archive execution.Identical members with different dates change the ZIP digest; the same app.py with a different dependency changes output from 20 to 30.
Common pitfalls
Main source as complete build, member hash as whole-archive identity or two local repetitions as a universal guarantee.
Related topics: Manifests and provenance · Promotion and recovery
Identity depends on chosen scope and actual inputs; control metadata and dependencies and retain evidence for the delivered artifact.
Reference: Archive metadata · Release management practices 2026-09; scoped GitLab GitHub CodeDeploy and EF Core documentation