Skip to content

fix(kanban): active_pr respawn guard yields to deliberate follow-ups and dead PRs - #7

Merged
nikitaBarkov merged 1 commit into
mainfrom
nikita.barkov/kanban_guard_pr_fix
Jul 13, 2026
Merged

fix(kanban): active_pr respawn guard yields to deliberate follow-ups and dead PRs#7
nikitaBarkov merged 1 commit into
mainfrom
nikita.barkov/kanban_guard_pr_fix

Conversation

@nikitaBarkov

@nikitaBarkov nikitaBarkov commented Jul 13, 2026

Copy link
Copy Markdown

What does this PR do?

The Kanban dispatcher's active_pr respawn guard (block "4." of
check_respawn_guard in hermes_cli/kanban_db.py) blocked a task's respawn
whenever a GitHub PR URL appeared in its comments within the last 24h. It
matched the URL by regex only — it never checked the PR's real state
(open/closed/merged), and there was no supported way to clear it. So a
deliberate follow-up / rework / unblock stayed parked behind the guard until
the 24h window expired or someone edited the SQLite DB by hand.

This reworks the guard so it blocks only the unintended duplicate-PR
auto-respawn it was built for, while yielding to deliberate continuation and
to PRs that are no longer live:

  • Pick the newest PR-URL comment in the window (only the latest PR can be
    duplicated; older links are irrelevant).
  • Yield when a fresher deliberate signal exists after that comment —
    unblocked (from unblock_task), review_reopened (from
    reopen_review_task), or respawn_guard_cleared (from the new
    clear_respawn_guard).
  • Yield when the PR is actually closed/merged. Unknown state keeps the
    guard (safe default — no false "all clear" when gh is unavailable).
  • Otherwise still return "active_pr", so ordinary auto-respawn on a live PR
    is still de-duplicated exactly as before.

It also adds a supported operator override and an opt-in live PR-state check.

Related Issue

No tracked issue in this fork. Mirrors upstream reports
NousResearch/hermes-agent NousResearch#62418 (guard blocks legitimate rework after unblock)
and NousResearch#29458 (no operator clear-path; ignores closed PRs).

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • hermes_cli/kanban_db.py — rework block "4." of check_respawn_guard; add
    helpers _has_fresh_continuation_signal, _resolve_github_pr_state (cached
    gh lookup, 5-min TTL), _resolve_pr_state_check_enabled; add the public
    clear_respawn_guard() (emits a respawn_guard_cleared event, no status/
    claim mutation). New pr_state_resolver arg is keyword-only (back-compat).
  • hermes_cli/kanban.py — new unguard verb (parser + dispatch + handler)
    and /kanban help entry.
  • hermes_cli/config.py — opt-in kanban.respawn_guard_check_pr_state
    (default False) gating the built-in gh-backed live PR-state check.
  • website/docs/user-guide/features/kanban.md — rewrote the Respawn-guard
    section, documented unguard, added the respawn_guard_cleared event.
  • tests/hermes_cli/test_kanban_db.py, tests/hermes_cli/test_kanban_cli.py
    — tests for every branch (see below).

How to Test

Run the touched suites:

scripts/run_tests.sh tests/hermes_cli/test_kanban_db.py tests/hermes_cli/test_kanban_cli.py tests/hermes_cli/test_config.py

410 tests pass, 0 failed.

Behavioral coverage:

  1. Live PR, no fresh signal → guard still returns "active_pr" (dup protection intact).
  2. After unblock / reopen-review / hermes kanban unguard → guard yields (None) on the next dispatcher tick.
  3. PR reported closed/merged (via injected pr_state_resolver / opt-in gh) → guard yields; unknown state → guard held.
  4. Newest-PR selection; a stale signal before the newest PR still blocks.

Checklist

Code

  • My commit messages follow Conventional Commits (fix(kanban):)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (no unrelated commits)
  • I've run the relevant tests and they pass (test_kanban_db, test_kanban_cli, test_config — 410 passed, 0 failed)
  • I've added tests for my changes
  • I've tested on my platform: macOS 15 (arm64)

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/user-guide/features/kanban.md)
  • I've added the config key to DEFAULT_CONFIG in hermes_cli/config.py (opt-in, documented in kanban.md)
  • N/A — no architecture/workflow changes needing CONTRIBUTING.md / AGENTS.md
  • Cross-platform impact considered — the gh lookup degrades safely to "unknown" (guard held) when gh is missing/unauthenticated, and it is off by default
  • Updated the CLI surface — new hermes kanban unguard verb + /kanban help entry

…and dead PRs

The Kanban dispatcher's active_pr respawn guard blocked a task's respawn
whenever a GitHub PR URL appeared in its comments within the last 24h. It
matched the URL by regex only — it never checked the PR's real state, and
there was no supported way to clear it. Deliberate follow-up / rework /
unblock stayed parked behind the guard until the 24h window expired or
someone edited the SQLite DB by hand (upstream NousResearch/hermes-agent
NousResearch#62418, NousResearch#29458).

Rework block "4." of check_respawn_guard so it now:
- picks the newest PR-URL comment (only the latest PR can be duplicated);
- stands down when a fresher deliberate signal exists after that comment
  (unblocked / review_reopened / respawn_guard_cleared);
- stands down when the PR is actually closed/merged (unknown state keeps
  the guard as a safe default);
- otherwise still returns "active_pr", preserving duplicate-PR protection
  for the ordinary auto-respawn case.

Also:
- add a supported operator override `hermes kanban unguard` (+ /kanban),
  backed by the new public clear_respawn_guard() which records a
  respawn_guard_cleared event without touching status/claims;
- add opt-in kanban.respawn_guard_check_pr_state (default off) gating the
  built-in gh-backed live PR-state check, so the dispatcher hot path pays
  nothing by default;
- update the Kanban docs and add tests for every branch.

Public signatures are preserved: check_respawn_guard(conn, task_id) still
works (the new pr_state_resolver arg is keyword-only, default None), so the
sole production caller (dispatch_once) is unchanged.
@github-actions

Copy link
Copy Markdown

🔎 Lint report: nikita.barkov/kanban_guard_pr_fix vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11534 on HEAD, 11531 on base (🆕 +3)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 6047 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@nikitaBarkov
nikitaBarkov merged commit f9e31cc into main Jul 13, 2026
45 of 50 checks passed
@nikitaBarkov

Copy link
Copy Markdown
Author

Hermes PR: NousResearch#72555

nikitaBarkov pushed a commit that referenced this pull request Aug 3, 2026
…ovider

Cancelling the API-key prompt mid-wizard (Enter → 'Cancelled.') let the
wizard continue through Terminal/Gateway/Tools and finish 'successfully'
with no model configured — the user exits believing they're set up, then
hits a broken chat.

_print_setup_summary() (called by every setup path: full, quick,
blank-slate, portal) now probes resolve_provider() and, when nothing is
configured, prints an unmissable warning with the two one-line fixes
(hermes model / hermes setup --portal).

Consumer-onboarding audit finding #7 (sev 4), Aug 2026.
nikitaBarkov pushed a commit that referenced this pull request Aug 3, 2026
… (re-review #7)

- website/docs/user-guide/configuration.md (en) and the zh-Hans
  translation gain a 'Session Stall Watchdog' section: default 300,
  0=disabled, notify-only semantics (never kills the turn — contrast
  gateway_timeout), one notification per stall episode, and the exact
  stall message text so it is greppable.
- cli-config.yaml.example: the two in-agent compression timeout keys
  (compression.context_timeout_seconds /
  compression.context_total_ceiling_seconds) are shown as commented
  lines next to session_stall_timeout's example for discoverability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant