Skip to content

rebase fork patch queue onto upstream v2026.6.19 (incl. #44338 hand-port) - #7

Merged
cwest merged 0 commit into
cwest/integrationfrom
topic/rebase-v2026.6.19
Jun 21, 2026
Merged

rebase fork patch queue onto upstream v2026.6.19 (incl. #44338 hand-port)#7
cwest merged 0 commit into
cwest/integrationfrom
topic/rebase-v2026.6.19

Conversation

@cwest

@cwest cwest commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Rebase the fork patch queue onto upstream v2026.6.19

Re-establishes the integration line as upstream tag v2026.6.19 + our patch
queue replayed atomically on top
, replacing the previous base (v2026.6.5 +
170 commits of drift). Each carried patch is preserved as its own atomic commit
via git cherry-pick -x (origin refs recorded in each commit trailer).

Kanban card: t_ec2b5f16.

Patches replayed (12, in order)

Commit Patch
1a222c5 feat(discord): VoiceMixer as discord.AudioSource (PR NousResearch#44023, OPEN)
988c5fc docs: PATCHES.md fork patch manifest (permanent-local)
e16fd02 test(discord): VoiceMixer mocked-discord base (PR NousResearch#44023)
2045862 ci(fork): daily upstream-sync workflow (permanent-local)
c890de8 ci(fork): secret scan of fork commits (permanent-local)
915a433 docs(patches): record PR NousResearch#44338
5866d9b docs(patches): record NousResearch#44338 partial carry
7c75a22 fix(kanban): review tasks bypass dup-PR respawn guards (PR NousResearch#46549, OPEN)
2ec7e60 docs(patches): record NousResearch#46549
7a77d4b feat(webhook): action allow-list filter for routes (local feature)
79dc66c fix(profiles): count external_dirs skills so dashboard matches CLI
926ecb4 fix(gateway): dispatcher dedicated executor (upstream PR #4, OPEN)

git cherry v2026.6.19 topic/rebase-v2026.6.19 shows exactly these 12 (all +)
— upstream has absorbed none of them.

Excluded by design

70bb7153f fix(gateway): retry failed kanban notifications (NousResearch#44338 hand-port)
is not in this branch — it is carried separately as its own atomic step in
card A2 (already decided KEEP).

Conflicts resolved (2 of 12)

  • 79dc66c skill-count fix — conflict in scripts/release.py author-map
    dict; upstream added many new author entries after the old tail line.
    Resolution: kept every upstream entry and appended our casey@geeknest.com → cwest mapping at the end of the dict.
  • 926ecb4 dispatcher executor — code-move conflict: upstream
    v2026.6.19 extracted the kanban watcher/dispatcher loops out of
    gateway/run.py into the new GatewayKanbanWatchersMixin
    (gateway/kanban_watchers.py, god-file Phase 3). Took HEAD for
    gateway/run.py (the extraction) and re-applied the dedicated-executor
    change to its new home in gateway/kanban_watchers.py (preserving the
    upstream singleton-lock release logic). The two stubbed dispatcher tests had
    their monkeypatch targets retargeted from gateway.run.* to
    gateway.kanban_watchers.* so they patch the code under test; the new
    starvation regression test drives _kanban_dispatcher_watcher() directly and
    needed no module change.

The other 10 patches applied cleanly (a few benign auto-merges, no markers).

Notes

  • Build/test deferred to card B (not run here, per card scope).
  • PATCHES.md will be refreshed in card B.
  • Signed commits (ssh), Conventional Commits, no AI attribution.

Draft — do not mark ready or merge.


Update — card A2 carried onto this branch (t_74112775)

The NousResearch#44338 kanban-notifier hand-port and its manifest retire-trigger fix are
now included on this branch (they were excluded from the original rebase as
their own atomic step; A2 places them here per the card plan). Two new commits:

Commit Patch
91dd0a8 fix(gateway): retry failed kanban notifications (NousResearch#44338 hand-port)
18f39b6 docs(patches): re-key NousResearch#44338 retire trigger to behavior, bump base-tag

NousResearch#44338 hand-port — re-targeted after the god-file refactor

git cherry-pick -x 70bb7153f collided with upstream's Phase 3 extraction: the
original carry modified the notifier loop in gateway/run.py, but v2026.6.19
moved that loop into GatewayKanbanWatchersMixin (gateway/kanban_watchers.py).
Resolution: gateway/run.py taken --ours (the extraction stands; no orphan
loop re-introduced), and the four behaviors re-applied by hand to the loop's new
home in gateway/kanban_watchers.py:

  1. Treat SendResult(success=False) from adapter.send as a delivery failure (raise).
  2. Keep the subscription alive on permanent failure (never silently unsub a terminal notification).
  3. Rewind the pre-send claim on any delivery failure so a later tick retries.
  4. Per-subscription exponential backoff (doubling, capped at 1h) gated before the cursor claim.

The cherry-picked test changes (_kanban_sub_fail_counts -> _kanban_sub_fail_states
plus 4 new behavior tests) applied cleanly. All 25 notifier tests pass locally
(tests/gateway/test_kanban_notifier.py,
tests/gateway/test_kanban_notifier_watcher_dispatch_gate.py,
tests/hermes_cli/test_kanban_notify.py).

Manifest retire-trigger fix (PATCHES.md)

The NousResearch#44338 row's old trigger ("auto-retire when NousResearch#44338 merges upstream") can
never fireNousResearch#44338 was closed administratively, not merged. Rewrote it to be
behavior-keyed: retire only when upstream gateway/kanban_watchers.py implements
ALL of (i) SendResult failure-detection, (ii) keep-alive-on-permanent-failure,
and (iii) bounded exponential backoff. Explicitly do not drop on NousResearch#45940 merge
alone (NousResearch#45940 is detection-only and would regress behaviors ii + iv). Watch
NousResearch#45940 and NousResearch#46443. Bumped the row's base-tag to v2026.6.19 and added a per-row
override caveat to the global Auto-retire rule.

Signed commits (ssh), Conventional Commits, no AI attribution. Still a draft.


Update — card B: build + targeted tests + PATCHES.md reconciled (t_a8821d26)

Built and tested the branch in the worktree's own .venv (Python 3.12.13,
pytest 9.0.2; uv sync --extra dev, --extra voice added for the VoiceMixer
numpy path). The live install at ~/.hermes/hermes-agent was not touched. One
new commit:

Commit Patch
650f403 docs(patches): reconcile manifest for the v2026.6.19 rebase

Targeted regression tests — all green

Carried patch Selector Result
Dispatcher dedicated-executor (fork PR #4) test_kanban_core_functionality.py -k "dispatcher or corrupt or executor or starv" 13 passed
Skill-count external_dirs (fork PR #6) tests/tools/test_skills_tool.py::TestCountProfileSkills passed
Kanban notifier NousResearch#44338 (3 files) test_kanban_notifier.py, test_kanban_notifier_watcher_dispatch_gate.py, test_kanban_notify.py passed
Review respawn-guard NousResearch#46549 test_kanban_db.py -k respawn (incl. the 4 review-bypass tests) 21 passed
VoiceMixer NousResearch#44023 tests/gateway/test_discord_voice_mixer.py 19 passed (skips without the voice extra's numpy)
Webhook allow-list (local) test_webhook_cli.py -k "allow or filter or action" 1 passed

Combined targeted run (executor + skill-count + 3 notifier files + 4
respawn-bypass tests): 35 passed, 0 failed. No failures across any carried
patch.

hermes doctor (worktree binary, code under test)

Reports v0.17.0 (2026.6.19), local 650f403. All code/environment-integrity
checks clean: Python Environment ✓ (version files consistent 0.17.0), Required
Packages ✓, SSL/CA ✓, Security Advisories ✓, MCP Security ✓, Directory
Structure ✓, Profiles ✓. The only warnings are runtime-config/credential items
for this isolated environment (missing API keys, optional telegram/discord
libs, config v27→v30 migration available) — none are code defects from the
rebase.

PATCHES.md reconciled

Signed commit (ssh), Conventional Commits, no AI attribution. Still a draft —
do not mark ready or merge.

@cwest cwest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed as a rebase, not a line diff — the 237k/50k churn is the v2026.6.5 → v2026.6.19 bump, and the real question is whether the 12-patch queue replayed correctly and the two conflicts were resolved right.

Verified against the branch:

  • git cherry v2026.6.19 topic/rebase-v2026.6.19 shows exactly the 12 commits the description lists, all +. Upstream has absorbed none. Each carries its (cherry picked from commit …) provenance line; 7c75a22 correctly shows two (the squash of the original pair).
  • Conflict 1 (79dc66c, scripts/release.py author map): the upstream additions are all preserved (AUTHOR_MAP intact) and casey@geeknest.com → cwest is appended at the tail. Matches the description.
  • Conflict 2 (926ecb4, dispatcher executor): the change landed in its new home, gateway/kanban_watchers.py, after upstream's extraction out of gateway/run.py. A private single-thread ThreadPoolExecutor backs an _offload helper, and all four dispatcher offloads (zombie reaper, auto-decompose, _tick_once, _ready_nonempty) route through it — none through the shared asyncio.to_thread. The singleton-lock release on cancel is preserved and the executor is shut down (wait=False) in the finally. The corrupt-board tests were retargeted from gateway.run.* to gateway.kanban_watchers.* so they patch the code actually under test. This is the right resolution.

Ran the affected suites in a throwaway clone (uv sync, py3.11): dispatcher executor / starvation / corrupt-board 18 passed 1 skipped; external_dirs skill-count (#6) 4 passed; review respawn-guard bypass (NousResearch#46549) 66 passed; webhook/cron-fire 278 passed. Green.

The one genuinely new (non-replayed) code path is the webhook action allow-list (7a77d4b). The guard allowed_actions and action and action not in allowed_actions is correct and additive — empty/absent actions accepts everything. The fail-open on a missing action field is deliberate and called out in a code comment rather than left silent, which is the right call for GitHub payloads that always carry one.

One discrepancy, non-blocking: the 1a222c5 commit message says the VoiceMixer voice tests stay red until a companion T3 change lands, but on this branch they pass (19 passed) — the mocked-AudioSource base from e16fd02 is what makes them green. The note in the commit body is stale relative to where the branch ended up; worth a one-line correction in card B's PATCHES.md refresh so the manifest doesn't carry a wrong status.

Build/test was deferred to card B per scope, so this is a structural + targeted-suite review, not a full-suite run. As a draft this is in good shape — the queue is faithful and both conflicts are resolved correctly.

@cwest cwest changed the title rebase fork patch queue onto upstream v2026.6.19 (all except #44338) rebase fork patch queue onto upstream v2026.6.19 (incl. #44338 hand-port) Jun 21, 2026

@cwest cwest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of the current head (650f403) after the synchronize from 926ecb4. The delta is a clean fast-forward: three new commits, nothing dropped or re-ordered, and the diff touches exactly five files. The earlier findings on the rebase queue (both conflict resolutions, the webhook allow-list, provenance) are unchanged because none of those files moved.

The only new code is 91dd0a8, the hand-port of the NousResearch#44338 notifier fix into gateway/kanban_watchers.py. It replaces the drop-after-N-failures behavior with: rewind the pre-send claim on every delivery failure so the terminal event stays unseen, keep the subscription, and after MAX_SEND_FAILURES enter per-subscription exponential backoff gated before the cursor claim. I traced it end to end:

  • SendResult(success=False) now raises into the same failure path as an exception, so a non-raising adapter (matrix) no longer advances the cursor on a failed send.
  • The backoff gate at line 245 builds its lookup key inline as (task_id, platform, chat_id, thread_id or ""), identical to sub_key at the write site, so the read and write hit the same dict entry. Both sides read the same monotonic clock.
  • _kanban_unsub is no longer reachable from the failure path; the only remaining unsub is the success path on done/archived, which is correct.
  • The four new tests cover false-result delivery, keep-alive across repeated failures, backoff-window suppression, and recovery-after-backoff. I ran the notifier suite plus the two helper tests the rename touched: 25 passed.

The PATCHES.md reconciliation is accurate. I checked every PR-state claim against live upstream: NousResearch#44023 and NousResearch#46549 are OPEN, NousResearch#44338 is CLOSED, NousResearch#45940 and NousResearch#46443 are OPEN. The behavior-keyed retire rule for the NousResearch#44338 row follows from that: the PR was closed administratively rather than merged, so the default PR-merge retire trigger can never fire, and NousResearch#45940 adds only SendResult detection without the keep-alive or backoff, so dropping the carry on its merge would regress. The per-row override note in the auto-retire section guards a future rebaser against applying the merge rule here.

Still a draft, so this is a COMMENT, not an approve. One non-blocking note inline. Merge stays Casey's call.

send_result = await adapter.send(
sub["chat_id"], msg, metadata=metadata,
)
if getattr(send_result, "success", True) is False:

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getattr(send_result, "success", True) treats a None return (an adapter that returns nothing) as success and skips the raise. That is the right back-compat default for adapters that signal delivery by not raising, and the matrix case this fixes returns an explicit SendResult, so it is covered. Worth a one-line comment naming the None-means-success assumption so a future adapter author does not start returning None on failure and silently reintroduce the dropped-notification bug.

@cwest
cwest merged commit 650f403 into cwest/integration Jun 21, 2026
@cwest
cwest force-pushed the cwest/integration branch from 902cded to 650f403 Compare June 21, 2026 23:28
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