Skip to content

t18650: fix(pulse): async housekeeping still dies before preflight_ownership_reconcile, starving parent/merged-PR reconcile #34287

Closed

Description

@marcusquinn

Task

Async post-dispatch housekeeping still dies before its last stage, preflight_ownership_reconcile, in about a third of runs. That stage runs reconcile_issues_single_pass, which closes completed parent-task trackers, merged-PR issues and stale status:done issues. Those reconciles are therefore starved for whole cycles, even after GH#33256.

Full task brief and audit context

Task Brief

What

Async post-dispatch housekeeping still dies before its last stage, preflight_ownership_reconcile, in about a third of runs. That stage runs reconcile_issues_single_pass, which closes completed parent-task trackers, merged-PR issues and stale status:done issues. Those reconciles are therefore starved for whole cycles, even after GH#33256.

Evidence (local pulse.log, 2026-10-10, ~130k lines)

Root cause (confirmed)

Setup reconciliation kills the housekeeping on every deploy. setup.sh runs from auto-update after each new main commit and from interactive deploys. It calls pulse-lifecycle-helper.sh _stop_reconciliation_processes, which SIGTERMs every Pulse runtime process. The detached housekeeping subshell's argv is bash pulse-wrapper.sh, so it matches _PULSE_PATTERN whatever its process group. GH#33256's set -m only protects it from process-group teardown.

  • 19 of 24 dead housekeeping PIDs in pulse.log appear in Stopping pre-reconciliation Pulse process(es): ... lists in ~/.aidevops/logs/auto-update.log / pulse-wrapper.log (for example 32467 and 49038). The other 5 coincide with interactive setup.sh --non-interactive deploys, whose output is not written to those logs.
  • launchd shows the pulse job's last exit as -15 (SIGTERM). With no TERM trap the wrapper's EXIT trap never runs, which also explains the repeated Stale mkdir lock detected (owner PID … is dead) lines in pulse-wrapper.log.
  • Stopping old-bundle processes on deploy is intended, because new code must replace old code. The defect is that housekeeping takes 30+ minutes and always restarts from its first stage. On a busy day with many deploys, its last stage (preflight_ownership_reconcile) is starved indefinitely.

Files Scope

  • .agents/scripts/pulse-dispatch-engine.sh
  • .agents/scripts/tests/test-pulse-post-dispatch-housekeeping.sh

Fix direction

  1. Persist per-stage completion (for example, a small state file next to the housekeeping lock with stage=epoch lines, written after each stage finishes). A run that reclaims a stale lock should skip stages completed within a freshness window (for example, < 30 min) and resume at the first incomplete stage. A clean, complete run clears or refreshes the state.
  2. Move preflight_ownership_reconcile ahead of _pulse_run_blocker_refresh_catchup, so the cheap terminal reconciles (parent close, merged-PR close) are not queued behind roughly 17 minutes of graph rebuild and brief-hold release.
  3. Add a TERM/HUP trap in the housekeeping subshell that logs Async post-dispatch housekeeping: terminated by <signal> during <stage> before exiting, so future deaths are attributable from pulse.log alone.
  4. Do not exempt housekeeping from setup reconciliation; old-bundle code must still be replaced on deploy. Keep stage timeouts and the GH#33246 catch-up semantics intact.

Verification

  • bash .agents/scripts/tests/test-pulse-post-dispatch-housekeeping.sh (extend it to cover the stage-order/resume contract).
  • shellcheck -x on modified files.
  • Runtime: after deploy, the ratio of Async post-dispatch housekeeping: complete to started in pulse.log approaches 1. Stage start: preflight_ownership_reconcile appears in every housekeeping run that survives past the scanners.
Brief workflow contract

Brief Workflow

This issue body is composed under .agents/workflows/brief.md. Newly queued auto-dispatch work must pass its Dispatch Readiness Contract (brief schema v2): complete write surface, hazards and compatibility, executable verification mapped to affected surfaces, and positive plus negative/regression acceptance criteria.


Synced from TODO.md by issue-sync-helper.sh


aidevops.sh v3.39.0 plugin for OpenCode v1.18.35 with claude-opus-5-5 spent 4h 42m and 448,179 tokens on this with the user in an interactive session.

Activity

  1. Repository owner locked as resolved and limited conversation to collaborators on Oct 10, 2026
  2. added
    bugSomething isn't working
    auto-dispatchEligible for automated worker dispatch
    on Oct 10, 2026
  3. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    Self-Hosting Tier Override

    Pre-dispatch self-hosting detector replaced lower workload-tier labels with tier:thinking on this issue.

    Matched pattern: pulse-dispatch- in issue body

    Rationale: Issues modifying the dispatch path have a self-referential property — workers dispatched to fix them run through the code being fixed. Applying the terminal workload tier upfront avoids wasted lower-tier attempts while runtime routing retains control of the exact model and reasoning level.

    Bypass: AIDEVOPS_SKIP_SELF_HOSTING_DETECTOR=1

    Automated by pre-dispatch-validator-helper.sh (t2819). This comment is posted once via the <!-- self-hosting-tier-override --> marker; re-runs are no-ops.


    aidevops.sh v3.39.0 automated scan.

  4. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    DISPATCH_CLAIM nonce=596f1a12bee762886ce61ec6c2b7e186 runner=alex-solovyev ts=2026-10-10T22:42:40Z max_age_s=1800 version=3.39.1 opencode_version=1.18.34 lease_token=596f1a12bee762886ce61ec6c2b7e186 device=device-1783824075-2103358-6141 session=issue-34287 phase=prelaunch expires_at=1791672281

  5. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    DISPATCH_LEASE phase=prelaunch lease_token=596f1a12bee762886ce61ec6c2b7e186 device=device-1783824075-2103358-6141 session=issue-34287 expires_at=1791672623 ts=2026-10-10T22:42:53Z attempt_id=attempt:84b96e62-dd5c-40cb-851b-0035c9eae67e

  6. added
    status:queuedWorker dispatched, not yet started
    and removed
    status:queuedWorker dispatched, not yet started
    on Oct 10, 2026
  7. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    Dispatching worker (deterministic).

  8. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    DISPATCH_LEASE phase=ready lease_token=596f1a12bee762886ce61ec6c2b7e186 device=device-1783824075-2103358-6141 session=issue-34287 expires_at=1791679409 ts=2026-10-10T22:43:29Z attempt_id=attempt:84b96e62-dd5c-40cb-851b-0035c9eae67e


    aidevops.sh v3.39.1 automated scan.

  9. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    CLAIM_RELEASED reason=worker_complete runner=alex-solovyev ts=2026-10-10T22:50:52Z aidevops_version=3.39.1 opencode_version=1.18.34


    aidevops.sh v3.39.1 plugin for OpenCode v1.18.34

  10. alex-solovyev commented on Oct 10, 2026

    @alex-solovyev
    Collaborator

    DISPATCH_LEASE phase=terminal lease_token=596f1a12bee762886ce61ec6c2b7e186 device=device-1783824075-2103358-6141 session=issue-34287 expires_at=0 ts=2026-10-10T22:51:13Z attempt_id=attempt:84b96e62-dd5c-40cb-851b-0035c9eae67e


    aidevops.sh v3.39.1 automated scan.

  11. vladimirdulov commented on Oct 10, 2026

    @vladimirdulov
    Collaborator

    Completion Summary

    • What: Deploy reconciliation (setup.sh) SIGTERMs the detached housekeeping subshell, so long runs always restarted from stage 1 and preflight_ownership_reconcile was starved. Housekeeping now persists stage=epoch progress in ~/.aidevops/logs/pulse-post-dispatch-housekeeping.state (next to the lock, survives stale-lock reclaim); a following run skips stages completed within AIDEVOPS_PULSE_HOUSEKEEPING_RESUME_WINDOW_S (default 1800s, 0 disables) and a clean complete run removes the state. Stages whose child died by signal (rc>128) are not recorded. preflight_ownership_reconcile now runs before the GH#33246 blocker-refresh catch-up. The async subshell traps TERM/HUP and logs 'terminated by SIG during '. Housekeeping is still stopped on deploy; stage timeouts and catch-up gating are unchanged.
    • Issue: t18650: fix(pulse): async housekeeping still dies before preflight_ownership_reconcile, starving parent/merged-PR reconcile #34287
    • Files changed: .agents/scripts/pulse-dispatch-engine.sh, .agents/scripts/tests/test-pulse-post-dispatch-housekeeping.sh
    • Testing: bash .agents/scripts/tests/test-pulse-post-dispatch-housekeeping.sh (7/7, new: resume, signal-killed stage not recorded, SIGTERM attribution, reconcile-before-catch-up order); test-pulse-dispatch-engine-stage-wiring.sh 70/70; test-pulse-dispatch-first-wave.sh and test-pulse-systemd-timeout.sh pass; shellcheck -x clean on both files.
    • Key decisions: none

    aidevops.sh v3.39.1 plugin for OpenCode v1.18.34 with claude-opus-5-5 spent 4m and 12,698 tokens on this as a headless worker.


    Merged via PR #34291 to main.
    Merged by deterministic merge pass (pulse-wrapper.sh).

  12. Repository owner unlocked this conversation on Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingorigin:interactiveCreated by interactive user sessionsolved:workerTask was solved by a headless workerstatus:doneTask is completetier:thinkingRoute at the thinking workload tier

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions