Skip to content

[dev-lead timeout follow-up 2/3] Dedup handle_engine_failure escalation branches into a shared helper #1029

Closed

Description

@don-petry

Follow-up to #901 (Story B / #1018). Maintainability cleanup deferred from #1021.

Problem

scripts/dev-lead-fix-issue.sh handle_engine_failure() has three near-identical escalation branches — missing-binary, timeout (#1018), and retries-exhausted — each doing the same five steps: emit ::error::, ensure_needs_human_label, post an issue comment carrying a <!-- dev-lead-issue N status=needs-human attempt=K reason=X run=ID --> marker + cause + run link + redacted session snippet, then exit 1. As more non-retryable reasons are added, the copies drift.

Why it matters: those markers are parsed by two systems — the retry cron (dev-lead-retry.sh, which skips dev-lead:needs-human) and the fleet-monitor timeout observability (#1019, which counts reason=X). Divergence between branches silently breaks those parsers.

Goal

Extract a single shared helper (e.g. escalate_needs_human <reason> <cause_markdown>) that all three branches call, so the marker format + escalation steps are defined once.

Acceptance criteria

  1. A shared helper emits: ::error::, ensure_needs_human_label, the status=needs-human marker comment (byte-identical marker format to today), + run link + snippet, then exit 1.
  2. The three branches call it, passing only their reason-specific cause text. The timeout branch retains its extra specifics (tier / elapsed / budget / split-or-raise guidance / completed-but-unpushed work note).
  3. No behavior change: the emitted marker (<!-- dev-lead-issue N status=needs-human attempt=K reason=X run=ID -->) is unchanged, so dev-lead-retry.sh and the [dev-lead timeout C/3] Fleet-monitor observability: surface timeout count/rate #1019 fleet-monitor parsing are unaffected.
  4. Tests (tests/dev-lead/unit/test_fix_issue.bats): existing missing-binary / timeout / retries-exhausted escalation tests still pass; add an assertion that all three produce the same marker shape (only reason= differs).
  5. shellcheck clean; bash scripts/dev-lead-lint.sh passes; tests/dev-lead/unit/ green.

References (real files)

Activity

  1. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    Thanks for the detailed write-up and for linking the upstream context — this is a well-scoped refactor with clear acceptance criteria. Before diving in: should escalate_needs_human be defined as a top-level function in dev-lead-fix-issue.sh, or is there a preferred shared-library pattern (e.g., a sourced scripts/lib/ file) that other scripts in this repo already use for helpers?

  2. don-petry commented on Jul 3, 2026

    @don-petry
    CollaboratorAuthor

    Dev-Lead Implementation Plan

    Issue: #1029 — [dev-lead timeout follow-up 2/3] Dedup handle_engine_failure escalation branches into a shared helper

    Scope

    Extract a single escalate_needs_human helper in scripts/dev-lead-fix-issue.sh that owns the five common escalation steps (::error::, ensure_needs_human_label, the byte-identical status=needs-human marker comment, run link + redacted snippet, then exit), and route the missing-binary / timeout / retries-exhausted branches through it — passing only their reason-specific cause text. Pure refactor, no marker/behavior change.

    Implementation Checklist

    • Add escalate_needs_human <reason> <attempt> <snippet> <error_line> <cause_markdown> [exit_code] helper (byte-identical marker + shared heading/label/snippet/exit)
    • Route the missing-binary branch through the helper (cause text only)
    • Route the timeout branch through the helper (retains tier/elapsed/budget/split-or-raise/work-note specifics)
    • Route the retries-exhausted branch through the helper (exit 2 preserved when engine_rc==2)

    Tests to Write

    • New assertion in tests/dev-lead/unit/test_fix_issue.bats: all three escalation branches emit the same needs-human marker shape (only reason= differs)
    • Confirm existing missing-binary / timeout / retries-exhausted / attempt-ceiling escalation tests still pass unchanged

    Test Command

    bats tests/dev-lead/unit/test_fix_issue.bats (full unit dir: bats tests/dev-lead/unit/); lint via bash scripts/dev-lead-lint.sh

  3. don-petry commented on Jul 3, 2026

    @don-petry
    CollaboratorAuthor

    Dev-Lead: Implementation Complete

    Plan Execution

    • Added escalate_needs_human <reason> <attempt> <snippet> <error_line> <cause_markdown> [exit_code] helper — single source for the five common escalation steps (::error::, ensure_needs_human_label, byte-identical status=needs-human marker comment, redacted snippet, exit)
    • Routed the missing-binary branch through the helper (cause text only)
    • Routed the timeout branch through the helper — retains its tier / elapsed / budget / split-or-raise guidance / completed-but-unpushed work note
    • Routed the retries-exhausted branch through the helper, preserving the exit-2-on-rate-limit contract via the helper's exit_code arg
    • Added a bats assertion that all three branches emit the same needs-human marker shape (only reason= differs)

    No behavior change

    The emitted marker <!-- dev-lead-issue N status=needs-human attempt=K reason=X run=ID --> is byte-identical to before, so dev-lead-retry.sh (skips status=needs-human) and the #1019 fleet-monitor (summarize_dev_lead_timeouts parses reason=) are unaffected. The only cosmetic shift: the trailing human guidance in the missing-binary / retries-exhausted comments now renders above the redacted snippet instead of below it, matching the canonical cause + run link + snippet order (the timeout comment was already in that order → byte-identical).

    Test Results

    tests/dev-lead/unit/test_fix_issue.bats — 20/20 passing (was 19; +1 new marker-shape guard)
    1..20
    ok 14 fix-issue: missing-binary → escalates to needs-human, no retry marker
    ok 15 fix-issue: stage timeout (exit 124) → escalates to needs-human, reason=timeout, no retry marker
    ok 18 fix-issue: attempt ceiling (prior attempt=2) → escalates to needs-human
    ok 19 fix-issue: all three escalation branches emit the same needs-human marker shape (only reason differs)
    ok 20 fix-issue: lint fails → posts lint-failure comment on the issue
    
    bash scripts/dev-lead-lint.sh — all checks passed (shellcheck clean on 85 files + agent-profile/CODEOWNERS validation)
    

    Files Changed

    • scripts/dev-lead-fix-issue.sh: extracted escalate_needs_human helper; the three non-retryable branches now call it with only their reason-specific cause text.
    • tests/dev-lead/unit/test_fix_issue.bats: added the cross-branch marker-shape assertion (AC4).

    Notes

  4. added 2 commits that reference this issue on Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev-leadFor dev-lead agent pickupenhancementFeature requests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions