Skip to content

Make release archives repeatable#30

Merged
dd3ok merged 1 commit into
mainfrom
codex/watchlist-reproducible-archive
Jul 16, 2026
Merged

Make release archives repeatable#30
dd3ok merged 1 commit into
mainfrom
codex/watchlist-reproducible-archive

Conversation

@dd3ok

@dd3ok dd3ok commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • pin archive input, commit time, UTC timezone, and line-ending conversion
  • validate each archive with the checker and manifest extracted from the same immutable commit
  • make --archive validation independent of a source skill directory
  • probe a functional Python 3.8+ interpreter with python3python fallback for Bash/Git Bash
  • document Git 2.40+ and same-toolchain reproducibility boundaries

Why

Post-release verification found that git archive <commit>:<subtree> used invocation time, then differed by process timezone and Windows core.autocrlf. The original commands could therefore produce different SHA-256 values from the same source. The first Git Bash recipe also failed when WindowsApps exposed a nonfunctional python3 alias.

The existing v0.4.2 asset is intentionally not deleted, replaced, or re-uploaded; its published digest remains an immutable historical identifier. This fix is recorded under Unreleased for the next version.

Validation

  • 168 unit tests
  • policy, release metadata, semantic, and seven-file package checks
  • Python 3.8 syntax and 12 Git Bash code-block syntax checks
  • documented standalone recipe executed unchanged on Windows Git Bash under ambient Asia/Seoul and UTC; both produced SHA-256 5d927f339183164146e85bb9fa28c7f5037748007fa32cac360a4716f82d0110
  • archive contents match exact committed blobs
  • independent code/docs review of timestamp, timezone, CRLF, Git-version, checker/manifest race, and Python-command portability

@dd3ok dd3ok left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review completed against exact PR head e6695e2c6d76c1d31b3cc72d663ab044a0b09dbb.

No remaining P0-P2 findings in the reviewed snapshot.

Review focus:

  • immutable source SHA, checker, and manifest stay on one contract
  • --mtime, TZ=UTC, and core.autocrlf=false/core.eol=lf remove observed invocation-time, timezone, and Windows line-ending drift
  • documentation limits byte identity to the same Git/platform toolchain and requires Git 2.40+
  • archive validation no longer needs a source skill directory, while normal build mode retains that guard
  • Bash probes a functional Python 3.8+ executable and falls back from python3 to python, covering Windows Git Bash aliases
  • v0.4.2's published asset remains untouched; this change stays Unreleased

Evidence: 168 tests, exact package/policy/semantic checks, 12 Bash blocks, committed-blob equality, and unchanged documented recipe runs under ambient Asia/Seoul and UTC with the same SHA-256.

@dd3ok dd3ok marked this pull request as ready for review July 16, 2026 18:18
@dd3ok dd3ok merged commit 9fb523b into main Jul 16, 2026
2 checks passed
@dd3ok dd3ok deleted the codex/watchlist-reproducible-archive branch July 16, 2026 18:19

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves the reproducibility of the standalone ZIP skill bundle by pinning entry times, forcing the UTC time zone, and disabling line-ending conversion during the git archive process. It also adds a Python version check (3.8+) across various scripts and documentation. My feedback suggests refactoring the duplicated Python version check logic into a reusable shell function for better maintainability and simplifying the test loop in evals/test_check_watchlist.py to improve clarity.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +36 to +44
python_check='import sys; raise SystemExit(sys.version_info < (3, 8))'
if python3 -c "${python_check}" >/dev/null 2>&1; then
python_cmd=python3
elif python -c "${python_check}" >/dev/null 2>&1; then
python_cmd=python
else
echo "Python 3.8 or newer is required" >&2
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This Python version check logic is duplicated in four separate code blocks within this file. To improve maintainability and reduce redundancy, consider defining a shell function for this check at the beginning of each script block.

For example:

find_python() {
  python_check='import sys; raise SystemExit(sys.version_info < (3, 8))'
  if python3 -c "${python_check}" >/dev/null 2>&1; then
    python_cmd=python3
  elif python -c "${python_check}" >/dev/null 2>&1; then
    python_cmd=python
  else
    echo "Python 3.8 or newer is required" >&2
    exit 1
  fi
}

find_python
# Now use "${python_cmd}"

This would make each script block cleaner and easier to update if the Python requirement changes.

Comment on lines +1240 to +1244
for ambient_timezone, archive in zip(["UTC", "Asia/Seoul"], archives):
environment = os.environ.copy()
environment["TZ"] = ambient_timezone
archive_environment = environment.copy()
archive_environment["TZ"] = "UTC"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This loop is a bit confusing. The ambient_timezone variable is used to set environment['TZ'], but this environment variable is not used. archive_environment is created from it, but then TZ is immediately hardcoded to 'UTC'. This means the test runs the exact same command twice, which proves repeatability but not necessarily independence from the ambient timezone in the way that seems intended.

To make the test clearer, you could simplify the loop to remove the unused variables. If the goal is to also prove that archives would differ without forcing TZ=UTC, you could add a separate test case for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant