🌱 Forward-merge v4 into v5 through 201c69c8a (20 commits) - #7545
Merged
Merged
Conversation
…7516) A PR GitHub reports as not mergeable hovered as the bare GitHub enum — "not mergeable on GitHub (blocked)" — even when classifyMergeEligibility had just been handed the exact gate that made GitHub say blocked ("CI failing: build, lint", "awaiting review approval", "held: …") and threw it away in blockedOrOutstanding. On a protected branch that discarded reason is the one that mattered, so the operator had to open the PR on GitHub — the trip the pill was meant to save. Step 1 of #7515, no new API calls: - blockedOrOutstanding keeps the sweep's reason for MergeableNo: "blocked — CI failing: build, lint", "blocked — awaiting review approval", "blocked — held: …", "blocked — intent verification: …", "blocked — CI pending". - The review gate now runs before the GitHub-says-no return, so a PR blocked for want of a review carries that reason. Both paths file a MergeableNo PR in the skip bucket; only the wording changes. - When every sweep gate passes and GitHub still says blocked, say "blocked — all sweep gates pass; a branch-protection rule is unsatisfied" until step 2 can name the rule. - Plain-language wording for the rest: "has merge conflicts with v4 — needs a rebase", "behind v4 — needs an update from the base branch", "draft — mark ready for review to enter the sweep", "mergeability not yet computed by GitHub — re-checked next tick". - PullRequest gains BaseRef (base_ref), read from the list payload the enumeration already has, so the wording can name the base branch. The frontend needs no change: prMergeNote already shows a blocked verdict's reason verbatim. Fixtures in the pill test move to the new wording and pin that "blocked — CI failing: build, lint" reaches the tooltip without GitHub's raw state appended. Tests: merge_verdict_7515_test.go pins every row of the issue's table as an exact string and fails on the parent commit (all 14 cases); the 7478 table is updated for the new wording; fetchPRs is checked to populate BaseRef. Refs #7515 Signed-off-by: Douglas Baggett <doug.baggett@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Automated release commit. Compiles changelog.d/ fragments and moves the CHANGELOG.md Unreleased section into a dated v4.54.2 entry. See src/docs/releases.md. Signed-off-by: hive-release-bot <actions@github.com>
release: v4.54.2
…self (#7520) ROADMAP.md gains a 'v6 — Future Line (not open)' section and src/docs/roadmap.md gains a matching Later row: no v6 branch exists, v6-designated work is design-only, the line opens after the v5 GA bar (#6016) via the same RFC gate that governs v5, and the one existing v6-designated design (github-mention-triggers.md, #7483) is indexed. Closes #7519 Signed-off-by: sec-check <sec-check@hive.kubestellar.io> Co-authored-by: sec-check <sec-check@hive.kubestellar.io> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A hive at ACMM L5 cannot merge, so the only possible outcome of a review
is a human acting on it. Reviewers already produce well-cited comments
with requires_human and reject verdicts, but nothing carried those to a
person: a blocking finding landed in a queue of hundreds looking exactly
like routine review noise, and the two reviews posted on the projectbluefin
spoke contained zero mentions and no way to filter for "a human must
decide this".
Add a routing block to the publish half of the kick. A requires_human or
reject verdict must open the comment with a pinned
`**HUMAN DECISION NEEDED**` marker, which is the string a maintainer
triaging a long queue can actually search on; its whole value is being
identical everywhere, so it is pinned by test.
Mention the PR author only when the author is a person. On a hive fleet
most PRs are agent-authored, so the author is an App ("app/<name>") or a
bot ("<name>[bot]"), and @-mentioning either notifies no one while still
reading as though the review had been routed somewhere. That false signal
is worse than no mention, so for those authors the prompt explicitly
suppresses the mention and leans on the marker instead.
Also ask the reviewer to report the limits of its own review. An honest
"I could not verify X" is more useful than a confident guess, and leaving
it out is how an unreviewed change gets waved through on the strength of
an automated approval.
Routing rides the existing review.post_comments switch, so a hive that
has not opted into commenting sees no prompt change.
Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PlanDispatch spends a fixed parallel-review budget in PR order, and an uncapped PR takes as many slots as it has missing perspectives. On a short queue that is exactly right - fanning every perspective out at once is the review swarm's designed behavior. On a deep one it inverts the intent: the head of the queue absorbs the entire budget, the PRs behind it get nothing this cycle, and adding reviewers buys more opinions on one PR rather than coverage across many. A spoke with hundreds of open PRs is the case where that matters, because there the scarce thing is PRs looked at, not depth per PR. Add review.max_perspectives_per_pr, which caps perspectives dispatched to one PR per cycle. It loses no coverage: a perspective skipped this cycle is still missing next cycle and gets dispatched then, so the cap schedules depth rather than dropping it. It also bounds how many comments a single PR can collect at once, which starts to matter now that reviewers publish their verdicts. Zero means no cap, so every existing hive keeps the behavior it has. The cap is subordinate to MaxParallelReviews, which still bounds total concurrency. Signed-off-by: Andrew Anderson <andy@clubanderson.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ackport #6303 to v4) (#7523) Backport of #6303 (merged to v5) to the v4 release line, which still ships the vulnerable dev:node 0664 token-access.jsonl: every agent UID is in group node, so any prompt-injected agent could truncate the trail of its own token use, rewrite lines to blame a peer, or forge entries (CWE-284/CWE-345). Fixed on v5 on 2026-09-08; v4 has released ~20 versions since (HEAD is v4.54.0) without it. Deviations from the v5 commit, forced by branch divergence: - src/cmd/hive/notifywire.go does not exist on v4; the StartTokenAccessAuditWatcher call is wired into cmd/hive/main.go next to the existing PrepareRequestDirs call (same placement rationale). - .github/workflows/v2-ci.yml step ('Entrypoint token-access audit log not agent-writable') is NOT included: this agent tier cannot push workflow changes. The test script src/deploy/test_entrypoint_token_access_audit.sh IS included; wiring it into CI needs a human (see tracking issue). Verified: go build ./cmd/hive ./pkg/github ./pkg/dashboard, go vet, and go test ./pkg/github -run TokenAccess all pass on this branch. bin/test_git_credential_hive.sh: 21/22 pass; the one failure is the known live-host non-hermeticity (the UID map resolves the harness UID to the real agent, overriding the claimed name — the forge-guard working as designed, not a defect). Refs #6287 Signed-off-by: sec-check <sec-check@hive.kubestellar.io> Signed-off-by: Andrew Anderson <andy@clubanderson.com> Co-authored-by: Andy Anderson <andy@clubanderson.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ss of existing spokes #7457 fixed the 401 on /api/contribute/me (#7453) in two halves: code on the hub and the spoke, and two nginx annotations — auth-url and auth-response-headers — on the hive-contribute Ingress in k8sManifestTemplate. The code half rolled out with the next image. The Ingress half is `kubectl apply`ed only by provisionHive, so every hosted spoke provisioned before the merge still serves /api/contribute through an Ingress with no auth-url: nginx never asks the hub who is calling, X-Hive-User never arrives, and /api/contribute/me answers 401 to the hive's own signed-in owner on a spoke whose served_sha is well past the fix (hosted-projectbluefin-common-nmq5, #7517). Add the missing re-apply as a hub reconcile on the NET_ADMIN / per-hive-env pattern (contribute_ingress_reconcile.go): - Every 15 minutes, for each hosted hive on an nginx cluster (OpenShift- Route clusters render Routes, not this Ingress; pull-only clusters have no kubectl path), read the live hive-contribute Ingress and merge-patch the two annotations on when absent or stale. Only the drifted keys go in the patch, so the issuer, timeouts and any vanity-host marks are untouched. A converged Ingress is a Debug no-op; an unparseable one is a Warn and no patch, never a blind one. An annotation patch rolls no pod, so there is no per-cycle cap. - The expected values come from the same inputs the template renders from (hubPublicURL, hive ID); TestContributeIngressReconcileMatchesThe- Template renders the template and pins them equal, so the sweep and provisioning cannot disagree about what converged means. - Wired into the SHA poller next to its siblings; a test pins the call site so the lane cannot be written, tested and never run (#2674). - Sweep accounting: a filter that selects nobody on a populated registry warns, and a sweep that patched or failed anything logs a summary. docs/security-model.md records the general rule the issue asks for: a template change to an existing object reaches only spokes provisioned after it, so it needs a reconcile path or a re-provision note. Not covered here: the sign-in bounce the issue mentions in passing — its redirect chain has not been captured yet, and the issue itself says it may be a separate cookie-scope question. Fixes #7517 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Douglas Baggett <doug.baggett@gmail.com>
…cile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: clubanderson <andy@clubanderson.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: clubanderson <andy@clubanderson.com>
GitHub folds every unsatisfied branch-protection rule into the single word "blocked", so a PR pill that hovered as "blocked — all sweep gates pass; a branch-protection rule is unsatisfied" (the step-1 placeholder from #7516) still sent the operator to GitHub to learn which rule — the trip the pill exists to save. The sweep now collects the two facts GitHub's REST PR payload does not carry, both at enumeration time and neither per PR: - GitHub's own reviewDecision plus each reviewer's current position, from ONE GraphQL query per repository per pass (paginated 100 PRs at a time); - the base branch's required status-check set — from the operator's auto_merge.required_checks when installed, which costs no API call at all — compared against the check runs EnrichCIStatus already walks. github.PullRequest.BranchProtectionBlockReason is the one place that turns those facts into words. It is deliberately conservative: it returns ok=false whenever nothing on hand identifies a rule, and it refuses to claim a required check "has not reported" on a repository where no required context was seen as a check run at all, because there the context is a commit status and every one of them would look absent. The dashboard needs no frontend change: prMergeNote already renders a blocked verdict's reason verbatim. Refs #7515 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson <andy@clubanderson.com>
The warm-cache restore is only a win when it is faster than the compile it replaces. On some cluster nodes the download from the Actions cache backend crawls — observed 16-minute 'Restore warm Go build cache' steps (run 35299669695, test agent 3/5 and dashboard shuffle 2/2) against a ~2-minute cold compile, making the two slow jobs the run's 21-minute long poles. The actions/cache default gives each segment 10 minutes; cap it at 1 so a slow restore aborts and the job builds from scratch instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: clubanderson <andy@clubanderson.com>
Automated release commit. Compiles changelog.d/ fragments and moves the CHANGELOG.md Unreleased section into a dated v4.55.0 entry. See src/docs/releases.md. Signed-off-by: hive-release-bot <actions@github.com>
release: v4.55.0
TestProbeCopilotModelsSDK_AbsentHelperYieldsSentinel and
TestProbeCopilotModelsSDK_HelperNotInstalled exec'd whatever lived at the
production helper path (/usr/local/bin/copilot-models.mjs). They handled two
states — helper absent (assert sentinel) or helper works (skip) — but not the
third: helper installed without stored copilot auth, the normal state on live
agent hosts, where the helper exits 1 ('Not authenticated'), the sentinel
check fatals, and the entire pkg/dashboard suite goes red.
Fix: copilotSDKHelperPath becomes a var with an in-package test seam
(setCopilotSDKHelperPathForTest, mirroring knowledge.SetBaseDirForTest).
Both tests repoint it at a nonexistent temp path so the absence assertion
holds on every host, and a new TestProbeCopilotModelsSDK_FailingHelperIsNotAbsent
covers the present-but-failing exec path (#7365's signature) with a stub
script, hermetically. No production behavior change.
Signed-off-by: hive-quality[bot] <hive-quality[bot]@users.noreply.github.com>
Co-authored-by: hive-quality[bot] <hive-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… 8,072 lines) (#7510) * 🌱 cmd/hive: extract five domains from main.go into their own files main.go was 9,795 lines of package main, mixing unrelated business logic with the process entrypoint. The file this issue is named after, main_helpers.go, is already gone (dissolved across #7241..#7308), but the other half of #7238 — "package main concentrates business logic" — still held: main.go alone was 9,795 of the package's 12,059 non-test lines. This is a stage. Five self-contained domains move out, each into one file in the same package main: appkeyfile.go GitHub App private-key file management: where per-App-ID and per-hive key files live, how a key is written, resolved, fingerprinted, and how a missing key is described. selfupgrade.go self-upgrade bookkeeping: the upgrade marker and last-outcome files, the retry/backoff budget, and the boot-time reconciliation of the two. login_scan.go login-required scanning: detecting a backend dropping to an interactive login prompt and debouncing that across sightings so one noisy line cannot pause an agent. merge_eligibility.go merge eligibility: hold gates, required-check state, bucket classification, the trusted-merger authz binding, and the merge-eligible report. intent_verdicts.go intent verdicts: PR/issue evidence gathering, alignment summary, the advisory record, and the intent-verdicts report. main.go: 9,795 -> 8,072 lines. The diff on main.go is 1,723 deletions and 0 additions: nothing was edited in place. Pure code motion. Declarations were moved byte-identically, with their doc comments; nothing was renamed, reformatted, or "improved". Verified with a structural declaration diff that parses every top-level func (including methods), type, const and var — including members of grouped const(...) and var(...) blocks — from the original main.go and from the union of the six resulting files, keyed by name and compared byte-exactly: BEFORE files: 1 declarations: 242 AFTER files: 6 declarations: 242 LOST: 0 ADDED: 0 CHANGED: 0 DUPLICATE: 0 RESULT: PURE CODE MOTION Cross-checked against go/ast: 241 unique declaration names before and after, identical sets. One grouped var block (ciFailingPath, intentVerdictsPath) is deliberately left in main.go: its two members belong to different domains and splitting the group would have meant rewriting a declaration rather than moving it. Design-doc file:line citations that this motion shifted are updated by content anchoring — each cited line was located by its exact text in the new tree (see #7493 for why this drift keeps recurring). The App-key and trustedMergerFunc citations now name their new files. Pre-existing drift in citations unrelated to this move is left alone rather than silently rewritten. main.go remains 8,072 lines and #7238 stays open; the remaining bulk is main() and runEvalCycle, tracked under #7232. Refs #7238 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson <andy@clubanderson.com> * 🌱 test(github): let the F3 trusted-merger guard follow trustedMergerFunc out of main.go TestF3AuthorizerIsWiredInMain read cmd/hive/main.go and looked for trustedMergerFunc in it. This PR moves that declaration to cmd/hive/merge_eligibility.go, so the guard failed with "trustedMergerFunc not found -- it was renamed or removed", which reads as a lost fix when this is pure code motion. The func-body assertions now scan every non-test .go file in cmd/hive via a new f3ReadPackage helper, so the guard follows the declaration wherever the ongoing cmd/hive split puts it next. The package, not the filename, is the unit that matters for "does this declaration still exist". The wiring assertion stays pinned to cmd/hive/main.go on purpose: that one is about where startup installs the authorizer, and it should fail if the call moves out of startup. Teeth verified by mutation, each a genuine assertion failure: - lowering the floor to config.RoleRead -> "no longer requires at least config.RoleMerger" - deleting the SetMergerAuthorizer call from main.go -> "does not install the trusted-merger authorizer ... INERT" - renaming trustedMergerFunc -> "not found -- it was renamed or removed" Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson <andy@clubanderson.com> * 📖 docs: correct five cmd/hive file:line citations this split left stale Two shifts landed after the citations in this PR were first computed, and each moved a cited line without moving the citation. The new files' header comments were relocated below the `package main` clause, which shifted every line in appkeyfile.go and merge_eligibility.go up by one. And the v4 merge grew main.go by ~570 lines via #7512, which moved runHub. Re-anchored by content, not arithmetic: each citation's target was read out of v4's main.go and located by its exact text in the merged tree. Verified by reading every cited line back and matching it against the symbol the prose names: appkeyfile.go:47-48 -> "Vars rather than consts so tests can point ..." appkeyfile.go:50 -> spokeProvisionedAppKeyPath = "/secrets/..." appkeyfile.go:51 -> spokeAppKeyPath = "/data/..." merge_eligibility.go:50 -> func trustedMergerFunc( main.go:8104 -> func runHub( The thirteen main.go citations this PR already rewrote were re-checked the same way and are correct as they stand; they are untouched here. src/scripts/check-api-reference-citations.sh still exits 0. Refs #7238 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson <andy@clubanderson.com> --------- Signed-off-by: Andrew Anderson <andy@clubanderson.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…7526) (#7539) /api/status (and the SSE replay frame a reconnecting tab receives) serves the cached s.status snapshot, which is only replaced by UpdateStatusIfFresh at the end of an eval cycle — after the whole-fleet GitHub enumeration. On a rate-limited 16-repo spoke that cycle runs far past eval_interval_s, so agents the manager started (state=running assigned on the same code path that logs "audit: agent started") still read state=stopped for 10-15+ minutes and the dashboard paints a healthy fleet red. BroadcastAgentStatus already carries correct in-memory liveness on a 10s tick with no GitHub calls, but only fanned it out over SSE. It now also patches the agent block (Agents/HiddenAgents/ConfiguredAgents) of the cached snapshot, copy-on-write so handleStatus — which marshals its loaded pointer outside statusMu — can never see a torn payload. The refresh runs ahead of the redundant-frame skip, so a skipped broadcast still freshens the cache. Signed-off-by: Andrew Anderson <andy@clubanderson.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Automated release commit. Compiles changelog.d/ fragments and moves the CHANGELOG.md Unreleased section into a dated v4.55.1 entry. See src/docs/releases.md. Signed-off-by: hive-release-bot <actions@github.com>
release: v4.55.1
Contributor
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
This was referenced Sep 18, 2026
Carries v4 e74d45e..201c69c (v4.54.2, v4.55.0, v4.55.1) into v5, including #7510 (cmd/hive domain extraction), #7532 (manager.go split), #7527/#7528 (review routing + breadth-first slots), #7523 (token-access audit backport of v5 #6303), #7515 (branch-protection facts on blocked PR pills), #7535, #7539, #7520. Resolution notes: - cmd/hive, pkg/agent: declaration-level 3-way merge against base ff7630e; v5 seams (spokeStatePath, SetHubPushedDashboardURL, applyModeUnscheduledAlert, mutation boundary, runDuplicateSweepIfDue) preserved. F24 tombstone intact. - pkg/github/client.go: v5 fetchPRs signature (RepoPRBreakdown) + v4 BaseRef/prBaseRef; added Client.requiredStatusCheckContexts shim so v4's protection_facts.go compiles against v5, where the sweep lives in pkg/github/automerge. - pkg/github/token_access_audit{,_test}.go: v4 side (its backport of v5's own #6303, now using testutil.Eventually). - pkg/github/automerge/f3_trusted_merger_source_test.go: v4's f3ReadPackage path adjusted one level deeper for v5's subpackage. - pkg/review/prompts.go: v4 routing instruction + mentionableAuthor added; v5's #6212 deletion of dead BuildPerspectivePrompts / BuildSequentialPrompt kept. - pkg/agent tests: v4's normalizeModelName cases rewritten against v5's normalizeModelNameForBackend (v5 removed the wrapper in #5795). - docs/knowledge-curator.md: v5 promotion-only body + v4's knowledge.git_sources section (code exists on v5). roadmap.md: v4 rows. api-reference.md: v5 table, citations re-resolved (--fix). - .github/workflows/v2-ci.yml: v5 UID-isolation step + v4's fuller audit-log step comment. Refs #7463 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andy Anderson <andy@clubanderson.com>
clubanderson
force-pushed
the
sync/v4-to-v5
branch
from
September 18, 2026 04:57
1972daa to
aecaaba
Compare
Contributor
|
Thank you for your contribution! Your PR has been merged. We'd love to hear how your experience was: share feedback |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🌱 Forward-merge v4 into v5 through 201c69c (20 commits)
Carries v4 e74d45e..201c69c (v4.54.2, v4.55.0, v4.55.1) into v5,
including #7510 (cmd/hive domain extraction), #7532 (manager.go split),
#7527/#7528 (review routing + breadth-first slots), #7523 (token-access
audit backport of v5 #6303), #7515 (branch-protection facts on blocked
PR pills), #7535, #7539, #7520.
Resolution notes:
ff7630e; v5 seams (spokeStatePath, SetHubPushedDashboardURL,
applyModeUnscheduledAlert, mutation boundary, runDuplicateSweepIfDue)
preserved. F24 tombstone intact.
BaseRef/prBaseRef; added Client.requiredStatusCheckContexts shim so
v4's protection_facts.go compiles against v5, where the sweep lives in
pkg/github/automerge.
v5's own 🔒 security: make the token-access audit log non-writable by agents #6303, now using testutil.Eventually).
f3ReadPackage path adjusted one level deeper for v5's subpackage.
added; v5's [architect] refactor: delete dead review prompt wrappers (BuildPerspectivePrompts, BuildSequentialPrompt in pkg/review/prompts.go) #6212 deletion of dead BuildPerspectivePrompts /
BuildSequentialPrompt kept.
normalizeModelNameForBackend (v5 removed the wrapper in 🐛 fix: remove dead manager tmux launch layer #5795).
knowledge.git_sources section (code exists on v5). roadmap.md: v4
rows. api-reference.md: v5 table, citations re-resolved (--fix).
audit-log step comment.
Refs #7463
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com