* test(#3144): bound the git/worktree cluster onto the process seam
Migrates 180 unbounded sync spawn sites across 19 files. Every previously
unbounded call now carries an explicit timeout with a comment giving the
number and why.
The migration is not a callee swap. execSync and execFileSync throw on a
non-zero exit and the seam never does, so each site was classified first:
sites that rely on the throw route to gitOrThrow, and sites that already read
.status to detect an EXPECTED non-zero -- an intended cherry-pick conflict, a
rev-parse outside a repo driving a skip -- route to the never-throwing runGit
instead, which would otherwise throw on exactly the exit being probed for.
Two same-named git() helpers in worktree-cleanup.test.cjs have different
return contracts, one trimmed and one raw; both are preserved rather than
unified.
Collapses five hand-rolled throw wrappers onto one throwIfFailed in
git-fixture.cjs, which gitOrThrow now also uses so the shape cannot drift.
Allowlist drops 139 to 120; BASELINE lowered to match.
* test(#3144): fix pre-PR review findings
Documents throwIfFailed in the CONTEXT.md glossary and CONTRIBUTING.md --
it became the shared throw mechanism without either doc naming it.
Routes the sixth and seventh hand-rolled copies of the throw shape through
throwIfFailed (worktree-baseref-install, worktree-safety-reap); the first
consolidation missed both.
Converts ci-rebase-check's 8 fixture-setup calls from unchecked runGit to
gitOrThrow so a failed setup step aborts where it fails rather than
surfacing later as a confusing failure against the wrong subject.
Adds 12 direct unit tests for throwIfFailed, which until now was only
exercised transitively.
Splits verify.test.cjs's non-git grep/sed bound off GIT_TIMEOUT_MS.
---------
Co-authored-by: sim <sim@local>
* test(#2913): add regression for hotfix empty-cherry-pick discrimination
Two layers: (1) real-git test proving the discrimination logic (check for
unmerged paths → skip if empty, abort if conflict) is correct; (2) source-text
assertions proving the logic and summary heading are in release.yml.
Before the fix: release.yml treats any non-zero cherry-pick exit as a conflict,
so an already-applied commit (empty pick) aborts the entire hotfix create.
* fix(#2913): distinguish empty cherry-pick from genuine conflict
git cherry-pick exits non-zero for BOTH genuine conflicts AND empty picks
(the change is already present by content). The hotfix create job treated
every non-zero exit as a conflict, so an already-applied commit (notably the
structural 'chore: sync next package version' that follows every release
finalize) aborted the entire run.
Now the error handler checks for unmerged paths (git diff --diff-filter=U):
- No unmerged paths → already applied by content → skip, record, continue.
- Unmerged paths present → genuine conflict → existing abort/push/exit-1
behavior and operator guidance, unchanged.
The job summary now has a separate 'Skipped (already applied by content)'
heading, distinct from 'Skipped (feat/refactor/etc)'.
* fix(#2913): address review — post-skip continuation test + conflict observability
Two findings from isolated adversarial review:
1. MINOR (test gap): no test proved the sequencer is clean after --skip, so a
regression switching --skip to --quit would pass green. Added a second
cherry-pick after the skip asserting it succeeds.
2. MINOR (observability): SKIPPED_EMPTY was dropped on the conflict-exit path
— already-applied commits before a genuine conflict were silently lost from
the summary. Now the conflict summary emits them under a dedicated heading.
* chore(#2913): add changeset fragment
* chore(#2913): backfill changeset PR number 2970
---------
Co-authored-by: sim <sim@local>