rebase(fork): 17-patch integration stack onto upstream main@9be292f1e - #24
rebase(fork): 17-patch integration stack onto upstream main@9be292f1e#24cwest wants to merge 19 commits into
Conversation
…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.
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
left a comment
There was a problem hiding this comment.
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.
…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
left a comment
There was a problem hiding this comment.
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.
|
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 |
What
Rebases the fork's integration stack — 17 atomic, signed patches — onto upstream
main@9be292f1e(~1,941 commits past the old basev2026.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) → headcwest/integration. The 18 commits below are the 17 fork patches plus the PATCHES.md manifest bump.Why rebase onto
main, not a release tagThe upstream community runs
mainHEAD — thecurl|bashinstaller tracksmain(git reset --hard origin/mainon update), not release tags. Releases are checkpoints, not what users run. So the fork develops againstmain.Method — TDD-gated, one patch at a time
For each patch, a three-state gate:
Commits re-signed (SSH,
casey@geeknest.com);demi's authorship preserved on the respawn-guard patch.Results
dispatch_onceinto a wrapper +_dispatch_once_locked, so our new params landed on the wrapper while the usage was in the inner fn, giving aNameErrorat runtime. "Markers gone + syntax OK" would have shipped both broken; only running each patch's tests exposed them.Verification
G);demiauthorship intact.origin/main.Backup / undo
Pre-rebase state of
cwest/integration(028d2f2) is preserved on the remote atcwest/integration-prepush-20260701-114638.