Problem
Release and maintainer scripts currently treat some GitHub signals as if they should be immediately available. In practice, a few of those signals are eventually consistent: checks may not appear on a just-created PR for several seconds, review/comment state can lag after PR creation or merge setup, and branch/tag/release visibility can take a moment after pushing.
We hit this in SwiftASB v0.9.3: the standard release flow created the release PR and immediately called the PR-check watcher, but GitHub initially reported no checks for the new branch. The check appeared shortly after and passed, so the script had stopped on a timing gap rather than a real failure.
Surfaces to review
socket/scripts/release.sh, especially any CI, PR, tag, branch, release-object, and comment/review gates.
- The generated or reusable repo-maintenance release scripts shipped by the productivity/Apple guidance surfaces, where the protected-main release flow opens a PR, watches checks, inspects comments/reviews, merges, fast-forwards, tags, and creates a release.
- Any helper that creates a PR and then immediately asks
gh pr checks, gh pr view, gh run view, or gh release view for state that GitHub may not have indexed yet.
Suggested implementation
Add a small wait/poll helper instead of scattering fixed sleeps. At a high level:
-
Introduce a script-local wait_for_condition helper with:
- a human-readable label for logs
- an interval
- a timeout
- a command predicate that returns success when the signal exists or is ready
- clear timeout diagnostics showing the last observed state
-
Add named waits for known delayed states:
wait_for_pr_checks_to_appear before treating “no checks reported” as failure
wait_for_pr_comments_ready before making a final no-comments/no-review-state decision
wait_for_remote_branch after pushing a branch that will immediately be used for PR creation
wait_for_remote_tag before gh release create --verify-tag or equivalent
- optionally
wait_for_release_visible after creating a GitHub release if later script steps depend on reading it back
-
Make the waits configurable through environment variables with conservative defaults, for example:
SOCKET_GH_WAIT_TIMEOUT_SECONDS=120
SOCKET_GH_WAIT_INTERVAL_SECONDS=5
- more specific overrides like
SOCKET_GH_CHECKS_TIMEOUT_SECONDS only where the generic value is too blunt
-
Keep the failure distinction sharp:
- “checks did not appear within timeout” should be a timing/indexing failure
- “checks appeared and failed” should stay a real CI failure
- “PR comments exist” should stay a review-loop stop, but only after the comment/review state has had a short chance to settle
-
Add tests or dry-run fixtures for the helper behavior:
- condition succeeds immediately
- condition succeeds after N attempts
- condition times out and reports the last state
- PR-check wait does not fail just because the first
gh pr checks call returns no checks
Acceptance criteria
- Release scripts no longer fail immediately when a newly created PR has not yet reported checks.
- The wait behavior is documented in maintainer docs and can be tuned without editing scripts.
- Timeouts produce clear operator-facing messages that distinguish delayed GitHub state from actual CI/review failure.
- The reusable guidance/scripts are updated anywhere this timing pattern is copied out to child repos.
Problem
Release and maintainer scripts currently treat some GitHub signals as if they should be immediately available. In practice, a few of those signals are eventually consistent: checks may not appear on a just-created PR for several seconds, review/comment state can lag after PR creation or merge setup, and branch/tag/release visibility can take a moment after pushing.
We hit this in SwiftASB
v0.9.3: the standard release flow created the release PR and immediately called the PR-check watcher, but GitHub initially reported no checks for the new branch. The check appeared shortly after and passed, so the script had stopped on a timing gap rather than a real failure.Surfaces to review
socket/scripts/release.sh, especially any CI, PR, tag, branch, release-object, and comment/review gates.gh pr checks,gh pr view,gh run view, orgh release viewfor state that GitHub may not have indexed yet.Suggested implementation
Add a small wait/poll helper instead of scattering fixed sleeps. At a high level:
Introduce a script-local
wait_for_conditionhelper with:Add named waits for known delayed states:
wait_for_pr_checks_to_appearbefore treating “no checks reported” as failurewait_for_pr_comments_readybefore making a final no-comments/no-review-state decisionwait_for_remote_branchafter pushing a branch that will immediately be used for PR creationwait_for_remote_tagbeforegh release create --verify-tagor equivalentwait_for_release_visibleafter creating a GitHub release if later script steps depend on reading it backMake the waits configurable through environment variables with conservative defaults, for example:
SOCKET_GH_WAIT_TIMEOUT_SECONDS=120SOCKET_GH_WAIT_INTERVAL_SECONDS=5SOCKET_GH_CHECKS_TIMEOUT_SECONDSonly where the generic value is too bluntKeep the failure distinction sharp:
Add tests or dry-run fixtures for the helper behavior:
gh pr checkscall returns no checksAcceptance criteria