Skip to content

Review pull-from-HEAD pattern for skill upgrade flow #31

@edmondscommerce

Description

@edmondscommerce

Context

Plan 00109 (v3.14.0+) collapsed the skill scripts/upgrade.sh to a thin curl-and-exec shim that fetches the canonical scripts/upgrade.sh from main HEAD and execs it. This matches the established hot-patch flow already used by version_check.py's upgrade suggestion:

curl -fsSL https://raw.githubusercontent.com/.../main/scripts/upgrade.sh -o /tmp/upgrade.sh
less /tmp/upgrade.sh
bash /tmp/upgrade.sh

The user confirmed during plan drafting that this pattern stays because freezing logic at release time has already caused two SEV-class incidents (v3.9.x write-venv-metadata field bug; v3.10.0 print_info stdout-corruption hotfix). Hot-patchability is a hard requirement.

Open Questions for Long-Term Review

Pull-from-main HEAD has known tradeoffs that this issue tracks for future revisit:

  1. No verification. A user pulling mid-release could get an inconsistent script if scripts/upgrade.sh is updated and pushed to main without an accompanying tag.

    • Mitigation today: release process should hold scripts/upgrade.sh changes for the same PR as the tag (informal — not currently enforced by CI).
  2. No reproducibility. Two users invoking /hooks-daemon upgrade minutes apart can get different versions of the upgrade script. For an upgrade flow that should be deterministic per from_version → to_version pair, this is uncomfortable.

  3. Alternative: releases/latest/download/upgrade.sh with sha256 verification against bootstrap-checksums.txt (the pattern the three sibling scripts — daemon-cli.sh, health-check.sh, init-handlers.sh — currently use). Verified but frozen-at-release, re-introducing the failure mode that motivated this refactor.

  4. Alternative: Pinned tag with periodic refresh. A middle ground — pull from a fixed ref like latest-stable that's updated server-side after each release passes a soak period. Verified-ish (still freshness-controlled), but adds release-process complexity.

  5. Alternative: Two-channel pull. Default to main, fall back to releases/latest/download/upgrade.sh on fetch failure. Hedges against main being momentarily broken (mitigates risk 1) but doubles the fetch logic.

Decision Point

Revisit when:

  • (a) The sibling-script thinning plan lands (then all four entry points share the same fetch pattern and a unified decision can be made), OR
  • (b) A mid-release inconsistency actually bites a user (then risk 1 has moved from theoretical to observed).

Until either trigger, the env override HOOKS_DAEMON_UPGRADE_REF (default main) is the lightweight hedge — paranoid users can pin to a tag manually.

Related

  • Plan 00109: CLAUDE/Plan/Completed/00109-skill-thin-shim-and-atomic-upgrade-commit/PLAN.md (after this plan ships)
  • Plan 00104, Plan 00105: introduced + extended self-bootstrap to all four scripts
  • CLAUDE/development/RELEASING.md Step 14: documents the inert-but-published upgrade.sh artifact

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions