* test: red — bounded git subprocess + structured worktree warnings (#3281) Regression tests for #3281: worktree-related git subprocess calls have no timeout bound, and timeout/error outcomes are not surfaced as structured signals. Failing assertions: - planWorktreePrune / listLinkedWorktreePaths / snapshotWorktreeInventory must return reason=git_timed_out (not generic git_list_failed) when execGit returns timedOut:true — enables callers to distinguish timeout from auth failure - executeWorktreePrunePlan must include timedOut:true in result when the git prune call itself times out Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(worktree): bounded git subprocess + structured warning surfacing (#3281) Root cause (PRED.k014): execGit / execGitDefault called spawnSync with no timeout, so `git worktree list --porcelain` against a hung/locked repo blocked the parent process indefinitely. Downstream callers in core.cjs and verify.cjs then swallowed any resulting failure silently via catch { /* intentionally empty */ } (PRED.k302). Fix: - worktree-safety.cjs: execGitDefault now passes timeout:10000 to spawnSync. Detects SIGTERM+ETIMEDOUT and returns { timedOut:true } in the result shape. readWorktreeList maps timedOut:true -> reason:'git_timed_out' (distinct from generic git_list_failed) so callers can emit a structured warning. executeWorktreePrunePlan propagates timedOut:true as a first-class result field. - core.cjs: execGit receives the same timeout+timedOut treatment (PRED.k014 uniform-fix discipline). pruneOrphanedWorktrees now emits a [gsd-tools] WARNING to stderr when the git prune call times out instead of silent-catch. - verify.cjs: Check 11 branches on worktreeHealth.ok to surface W018 warning when the worktree list times out, instead of silent-catch on ok:false. Backward-compatible: exitCode/stdout/stderr continue to work for all existing callers; timedOut and error are additive new fields. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: pr=3283 for #3281 * fix(verify): rename W020 for worktree-timeout warning to avoid W018 collision W018 is already used for milestone archive drift (Check 12). The new worktree-health-degraded timeout warning was assigned W018, causing warning-code ambiguity in triage. Rename to W020 (next available code). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -913,7 +913,17 @@ function cmdValidateHealth(cwd, options, raw) {
|
||||
{ staleAfterMs: 60 * 60 * 1000 },
|
||||
{ execGit, existsSync: fs.existsSync, statSync: fs.statSync }
|
||||
);
|
||||
if (worktreeHealth.ok) {
|
||||
if (!worktreeHealth.ok) {
|
||||
// AC2 / AC3: surface degraded-git state as a structured warning instead
|
||||
// of silently suppressing it (PRED.k302 — error-swallowing-empty-sentinel).
|
||||
if (worktreeHealth.reason === 'git_timed_out') {
|
||||
addIssue('warning', 'W020',
|
||||
'Worktree health check degraded: git worktree list timed out after 10s — orphan/stale worktrees could not be inspected',
|
||||
'Run: git worktree list --porcelain to diagnose; check for .git/index.lock or a hung git process');
|
||||
}
|
||||
// Other non-ok reasons (not_a_git_repo, git_list_failed) are silent — not
|
||||
// meaningful for users who have no git repo or whose git is not configured.
|
||||
} else {
|
||||
for (const finding of worktreeHealth.findings) {
|
||||
if (finding.kind === 'orphan') {
|
||||
addIssue('warning', 'W017',
|
||||
|
||||
Reference in New Issue
Block a user