Skip to content

rebase(fork): 17-patch integration stack onto upstream main@9be292f1e - #24

Closed
cwest wants to merge 19 commits into
cwest/integration-basefrom
cwest/integration
Closed

rebase(fork): 17-patch integration stack onto upstream main@9be292f1e#24
cwest wants to merge 19 commits into
cwest/integration-basefrom
cwest/integration

Conversation

@cwest

@cwest cwest commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

Rebases the fork's integration stack — 17 atomic, signed patches — onto upstream main@9be292f1e (~1,941 commits past the old base v2026.6.19/2bd1977). Each patch was applied and verified one at a time under a strict TDD gate, so every commit is provably clean on the new base.

This PR is scoped to show only the patch stack: base cwest/integration-base (9be292f1e, the exact upstream HEAD we rebased onto) → head cwest/integration. The 18 commits below are the 17 fork patches plus the PATCHES.md manifest bump.

Why rebase onto main, not a release tag

The upstream community runs main HEAD — the curl|bash installer tracks main (git reset --hard origin/main on update), not release tags. Releases are checkpoints, not what users run. So the fork develops against main.

Method — TDD-gated, one patch at a time

For each patch, a three-state gate:

  1. Run the patch's own tests on the rebased base before applying → GREEN-before means upstream absorbed it (DROP the patch); RED-before means the gap still exists (apply it).
  2. Apply (cherry-pick), resolve conflicts by composing both intents (never blind "take ours").
  3. Run the tests again → GREEN-after checkpoint & commit; RED-after means STOP (never stack on a broken commit).

Commits re-signed (SSH, casey@geeknest.com); demi's authorship preserved on the respawn-guard patch.

Results

  • Zero patches absorbed upstream — the recon held; all 15 pending patches still carry real work.
  • Four patches needed genuine semantic merges (compose both intents): P3 (skill-count cache + external_dirs), P8 (dispatcher executor + live auto-decompose), P14 (restore_status + new CAS guard), P9 (union'd columns).
  • The TDD gate caught two silent merge defects behind clean auto-merges (P15, P17): upstream refactored dispatch_once into a wrapper + _dispatch_once_locked, so our new params landed on the wrapper while the usage was in the inner fn, giving a NameError at runtime. "Markers gone + syntax OK" would have shipped both broken; only running each patch's tests exposed them.
  • Dropped P16 (per-task max-iterations, fix(kanban): add per-task --max-iterations override for worker budget #19) — the knob cut against the board's decompose-first design and had no upstream home; replaced by a planning-time t-shirt-sizing discipline. Stack went 18 to 17 patches.

Verification

  • Full patch-relevant suite: 760 passed / 1 skip across all kanban/gateway/webhook test files; VoiceMixer 19, profiles 27, HTTP round-trips 9 — all green.
  • All 18 commits signed (G); demi authorship intact.
  • Control baseline: 672 pass / 1 skip on vanilla origin/main.

Backup / undo

Pre-rebase state of cwest/integration (028d2f2) is preserved on the remote at cwest/integration-prepush-20260701-114638.

cwest and others added 18 commits July 1, 2026 11:10
…ew skill

Fork-only release engineering, kept indefinitely (permanent-local):

- .github/workflows/fork-daily-sync.yml — daily upstream-sync workflow that
  fetches/rebases the patch queue onto the newest upstream tag, runs tests,
  and opens a review PR; scripts/fork_retire_patches.py supports it.
- .github/workflows/fork-secret-scan.yml — gitleaks gate on every PR/push to
  cwest/integration, enforcing the fork's "no secrets, ever" invariant.
- PATCHES.md — the manifest of everything the fork carries on top of its
  upstream base tag, plus the bucket model, auto-retire rule, and per-row
  behavior-keyed override; docs/patches/* hold per-patch rationale.
- skills/github/github-code-review — homestead PR-review pipeline expansion
  (webhook review context, post-once idempotency, author-resolves-threads
  loop, humanizer/de-claude gate).

Never sent upstream.
Optional per-route action allow-list filter for webhook routes, plus an
author allow-list hard gate enforced BEFORE any worker is spawned. A local
feature for the fork's webhook deployment; kept indefinitely as a deliberate
local divergence (fork PR #2, #13).
Count skills.external_dirs-granted skills in the profiles dashboard and
`hermes profile list` so the count matches `hermes skills list` exactly.
Extracts _scan_skill_dirs(local, external), adds count_profile_skills +
get_external_skills_dirs_for, and makes _count_skills delegate to that single
source of truth (symlink-following + frontmatter-name dedup). Also adds
casey@geeknest.com -> cwest to the scripts/release.py author-map.

Fork-specific behavior (the fork's external_dirs grant); kept indefinitely
(fork PR #6).
…l join

Make VoiceMixer a real discord.AudioSource subclass so Discord voice playback
can consume it directly (adds the discord import and changes the class base in
plugins/platforms/discord/voice_mixer.py). Gives the mocked discord.AudioSource
in the gateway conftest a real base class so the 19 TestVoiceMixerCore tests
run without the real discord package.

upstream-pending: PR NousResearch#44023
Treat SendResult(success=False) from adapter.send as a delivery failure (not a
delivered ping), keep the subscription alive on send failure, rewind the
pre-send claim so the terminal blocked/completed event is retried, and back off
per-subscription (exponential, capped at 1h) so a dead chat is not hammered
every tick. Ported into GatewayKanbanWatchersMixin._kanban_notifier_watcher.

upstream-pending: PR NousResearch#44338 (partial carry — SendResult non-delivery only)
…ent_success)

check_respawn_guard applied the recent_success and active_pr guards — which
exist only to stop a builder re-opening a duplicate PR — to review-lane spawns
too, so a card in status='review' (whose build run already completed and left a
PR-URL comment) got blocked from spawning its reviewer for up to 24h. Reads
tasks.status and skips those two guards for status='review' while keeping
rate_limit_cooldown and blocker_auth active.

upstream-pending: PR NousResearch#46549
…cards

Subscribe the configured report-back target so a card created without an
originating session still delivers its terminal notification.

upstream-pending: fork PR #9
Run the in-process kanban dispatcher on a dedicated single-thread executor so
a busy default ThreadPoolExecutor (saturated by agent turns + nested tool/
sub-agent/vision/compression fan-out) can never starve the dispatcher tick.
Routes every dispatcher offload (zombie reaper, auto-decompose, _tick_once,
_ready_nonempty) through the private executor; preserves _release_singleton_lock
in both the CancelledError and normal-exit paths. Ships a starvation regression
test that fails on the old shared-pool behaviour.

upstream-pending: fork PR #4 (no upstream PR yet)
Deduplicate review cards on their PR URL in create_task so a repeated
PR-review request does not open a second review card for the same PR.

upstream-pending: fork PR #3
detect_crashed_workers grants a freshly-spawned worker a launch-window grace so
its PID can become visible before liveness is checked — but it measured the
grace from tasks.started_at, pinned to the task's first-ever start and never
refreshed on re-claim. A card re-claimed for its next lane inherited a stale
started_at, the grace had expired, and the new worker was reaped mid-init. Now
measures the grace from the active task_runs row via
COALESCE(r.started_at, t.started_at) joined on current_run_id — the exact
per-attempt pattern enforce_max_runtime already uses — with a fallback to
tasks.started_at when no run row is present.

upstream-pending (PR TBD)
…g lanes

Clear a dead worker's stale claim regardless of lane, so a worker that dies
while its card sits in a NON-running lane (most commonly review, after the
implementer opened a PR and the card moved on) no longer wedges that lane for
the full 1h stale-claim TTL. Widens the crash scan to any card with a non-NULL
worker_pid and, for a non-running card, does an in-place claim clear with a
stale_claim_cleared event and NO lane change; the running path is byte-for-byte
unchanged.

upstream-pending: fork PR #16
A card in review is claimed by claim_review_task, which CAS-transitions
review->running, so while the reviewer works the row status is running,
indistinguishable from a build run. When detect_crashed_workers reaped such a
crash it ran SET status='ready', losing the review lane (the implementer re-ran
instead of the reviewer respawning). Reads the durable source_status='review'
signal off the crashed run's claimed event and restores the card to review
instead of ready; the breaker-trip WHERE-IN widens to include 'review' so a
repeatedly-crashing reviewer still trips to blocked via the failure-count path.

upstream-pending: fork PR #17
Pin a dispatcher-spawned worker's git identity to the host config at spawn time
so worker commits carry the correct author instead of a container default.

upstream-pending: fork PR #14
Make the active_pr respawn guard honor an explicit unblock so the review->author
rework loop can spawn without waiting out the 24h PR window. Uses the latest
unblocked task event as an additional lower bound on the PR-comment scan window
(pr_cutoff = max(window, latest_unblock_ts)): PR URLs posted before a deliberate
unblock no longer veto respawn, while URLs at/after still guard. Additive over
NousResearch#46549 (which covers status='review' only; the author-rework card is in 'ready').

upstream-pending: PR NousResearch#46204
Auto-route a reviewer's review-changes-requested block back to the original
author from the housekeeping tick, closing the reviewer->author hop the GitHub
pull_request_review webhook cannot close when reviewer and author share one
GitHub identity. Board-internal (lives in the dispatcher, not the reviewer):
auto_route_review_bounce scans blocked cards each dispatch_once tick and, for a
card whose most-recent sticky blocked event carries the review-changes-requested
reason prefix, reassigns it to the original author and unblocks it. Idempotent.

upstream-pending: fork PR #18
_default_spawn now REQUIRES a non-empty resolved CLI toolset and raises when
resolution is degenerate, so the spawn-failure handler reclaims the card to
ready for a clean retry instead of running crippled. Adds a
kanban.max_spawn_per_tick config knob capping how many workers a single tick
may launch (ready + review combined), wired through the gateway dispatcher and
the CLI dispatch path; unset preserves historical unbounded behavior. No new
user-facing env var — the knob lives in config.yaml.

upstream-pending: fork PR #20
…(default-off)

Optional, default-OFF bridge that lets a kanban lifecycle transition wake the
orchestrator as an agent RUN (not merely a chat ping) by POSTing the transition
to a loopback webhook route — mirroring how a GitHub pull_request event triggers
a review run. New module gateway/kanban_transition_emit.py adds pure decision
logic (should_emit_transition, build_transition_payload with a stable
(board,task_id,kind,event_id) idempotency key) plus a fail-safe emit_transition
coroutine that HMAC-signs and POSTs; it NEVER raises. The payload is classifiable
by the webhook adapter, and transition wakes route back to the origin
thread/session. Guarded by kanban.transition_emit.enabled (default OFF); when
disabled the notifier path is byte-for-byte unchanged. No new core tool, no new
model surface, no user-facing HERMES_* config var.

upstream-pending: fork PR #21, #22, #23
Rebased the fork stack onto upstream main@9be292f1e and dropped the
per-task --max-iterations override (former P16, upstream #19). The knob
cut against the board's decompose-first design: a card that exhausts the
global 90-turn ceiling is almost always a sizing failure (too big, should
be split into smaller cards), not a budget failure. The escape hatch for
a genuinely atomic-large task already exists natively — upstream bridges
HERMES_MAX_ITERATIONS from agent.max_turns in config — so the per-task DB
column was redundant carry with no upstream home. Stack is now 17 patches.

@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.

The rebase itself is in good shape. The 18 commits are signed, the composition points hold up: the auto-route and spawn-cap params are threaded through both dispatch_once and _dispatch_once_locked with matching passthrough at both call sites, and the review-lane cutoff sits inside the is_review wrapper where it belongs. kanban_db.py compiles clean.

Two CI checks are red, and both trace to this stack rather than to upstream, so they need fixing before this can go forward.

The secret scan fails before it ever runs gitleaks. Its scoping step parses a Base tag: line out of PATCHES.md and expects a vN.N.N tag it can resolve with git rev-parse refs/tags/.... The Base section was rewritten to main@9be292f1e, so there is no Base tag: line to match and the step exits 1 with "Could not read the base tag." The scan is effectively disabled, not passing. v2026.6.19 still exists as a tag and is the real fork point, so restoring a machine-readable Base tag: v2026.6.19 line (kept alongside the human-readable "rebased onto main@SHA" note) lets the scan scope v2026.6.19..HEAD over exactly the carried stack. Noted inline.

The attribution check fails on demi's commit. christophergervais92@users.noreply.github.com authors the review-respawn-bypass patch and isn't in the AUTHOR_MAP in scripts/release.py, so contributor-check flags it. Adding that one mapping clears the part of the failure this stack owns. Noted inline. (The check also lists eight other unmapped emails; those are upstream-baseline contributors surfaced by the merge-base scope, not commits in this stack — worth a glance to confirm none of them are ours, but the demi entry is the one this PR introduced.)

The PR is still a draft, which is correct while it's being reworked. Once both checks are green it can move forward.

Comment thread PATCHES.md
Comment thread scripts/release.py
…hor map

The fork now develops against upstream `main` HEAD (the community installer
tracks main, not release tags), so the CI fork-point is a commit SHA, not a
`vX.Y.Z` tag. Two CI gates assumed a tag base and broke after the rebase onto
main@9be292f1e:

- fork-secret-scan: the range step grep'd `Base tag: vX.Y.Z` and verified
  `refs/tags/<tag>`, which no longer matches a SHA base. Reworked to prefer a
  machine-readable `<!-- Base commit: <sha> -->` line in PATCHES.md (falling
  back to the legacy tag), emitting a generic `base_ref` used by the scan +
  summary steps. Scopes gitleaks to exactly the carried patch stack (18 commits).
- check-attribution walks `merge-base(origin/main, HEAD)..HEAD`; with the fork's
  main mirror advanced to the rebase base, that range is now our patches only —
  add demi (christophergervais92) to release.py AUTHOR_MAP so the sole non-cwest
  author in range is mapped.

PATCHES.md records the SHA base + notes the fork tracks main HEAD.

@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.

The two CI reds from the last round are both fixed, and the fix goes deeper than a one-line restore — nice.

Rather than just re-adding a Base tag: line, the secret-scan workflow now reads a machine-readable <!-- Base commit: <sha> --> from PATCHES.md and scopes gitleaks to that SHA..HEAD, with the release-tag path kept as a fallback. That matches the new reality that the fork tracks upstream main HEAD instead of a release tag. I confirmed on the live run that it took the SHA branch (Scanning carried patch stack: 9be292f1e…..HEAD), ran gitleaks with --exit-code 1, and still fails closed if the base can't be resolved or a leak is found — so the gate is genuinely enforcing, not silently disabled. Attribution is fixed too: demi is now mapped in the release author map, and that commit's signed authorship is preserved.

The rework is a single signed commit on top of the previous head; the diff touches only the two CI configs and PATCHES.md, so the whole rebase stack underneath is byte-identical to what was already verified — the composition work stands. Full check suite is green and the PR is clean to merge.

No changes needed.

@cwest
cwest marked this pull request as ready for review July 1, 2026 16:55
@cwest

cwest commented Jul 1, 2026

Copy link
Copy Markdown
Owner Author

Accepted. Lamport PASS'd at head e15393b (round 3): CLEAN, MERGEABLE, 33 checks SUCCESS/0 FAILURE, 0 unresolved threads, all 19 commits signed, demi authorship preserved.

This PR was a review vehicle — base cwest/integration-base (the upstream rebase point 9be292f) was pushed solely to render the 18-commit patch stack as a clean diff for review. The approved head IS already the tip of cwest/integration, so there is nothing to merge into; closing rather than merging (a GitHub merge would push integration into the throwaway base ref, backwards). The reviewed state is live on cwest/integration and deployed to the running install. Casey accepted.

@cwest cwest closed this Jul 1, 2026
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