Skip to content

πŸ› Hold relayed merges to the contributor-lane policy - #13192

Merged
hivecommons-hive[bot] merged 1 commit into
v5from
fix/merge-relay-contributor-gates
Oct 20, 2026
Merged

hivecommons-hive[bot] merged 1 commit into
v5from
fix/merge-relay-contributor-gates

Conversation

@clubanderson

Copy link
Copy Markdown
Member

Problem

Observed live 2026-10-20 on hivecommons/docs#401: a PR from an untrusted-tier contributor (labels stage/060-reviewed + contributor-lane:claim-tier-untrusted, never 090/095, no 30-minute soak, config require_tiers: merger,trusted, soak 30m) was merged by the hive at 15:27Z via the merge-request relay:

merge-request watcher: CI positively confirmed… agent=scanner β†’ MergePR: merged PR as the App bot

Root cause

The relay path (hive-merge β†’ StartMergeRequestWatcher β†’ handleOneMergeRequest β†’ MergePR) gates on: agent authority + merge-eligible.json at the pinned head (bindMergeAuthz / classifyMergeEligibility), write allowlist, repo pause/scope, human-merge paths, and positive CI (which includes min_head_age). It never evaluated the contributor-lane policy β€” tier admission within require_tiers, contributor soak, review verdict β€” that trySweepContributorLanePR enforces in the auto-merge lane. So any agent's merge request bypassed the lane for a contributor-authored PR. classifyMergeEligibility also did not treat a needs-decision park as blocking.

Fix

  • pkg/github/automerge: split the contributor-lane sweep into evaluateContributorLanePR (all gates, read-only in relay mode) + the merge tail; new Engine.RelayMergeRefusal(ctx, repo, number, expectSHA) runs the same evaluation and returns "" (allow), a refusal naming the gate (e.g. contributor-lane:claim-tier-untrusted (author tier "untrusted", require_tiers merger, trusted), contributor-lane:soaking(remaining=27m) (… soak is 30m0s …), pending: head pushed … (auto_merge.min_head_age …)), or an error (fail closed). App / trusted-bot / trusted-author-role authors keep today's behaviour.
  • pkg/github: MergeRequestPolicyGate hook + SetMergeRequestPolicyGate; the watcher consults it before any branch update, denies terminally (.denied) with the reason in the result the agent reads, audits merge_request_refused, and routes gate errors through the bounded retry path.
  • cmd/hive: relayLanePolicyGate(autoMergeOpts) wires the engine's gate into startRequestRelays (re-armed on every client rebuild by the relay supervisor); classifyMergeEligibility now parks stage/085-needs-decision / stage/045-needs-decision PRs as not eligible.
  • Docs note in hive-merge.md; changelog fragment.

Relay honouring of hold, sentinel-alert, do-not-merge*, needs-rebase and needs-decision labels is now pinned by tests on both the eligibility classifier and the lane gate.

Tests

  • pkg/github/automerge: TestRelayMergeRefusalUntrustedTierScannerRequest (the docs#401 reproduction β€” fails on v5, passes here), TestRelayMergeRefusalSoakAndHeadAge, TestRelayMergeRefusalAllowsWhatTheLaneWouldMerge, TestRelayMergeRefusalHiveAuthoredAndTrustedAuthorsPassThrough, TestRelayMergeRefusalPolicyScope, TestRelayMergeRefusalFailsClosed, TestRelayMergeRefusalText
  • pkg/github: TestMergeRequestPolicyGateRefusalDeniesAndAudits, TestMergeRequestPolicyGateErrorRetriesWithoutMerging, TestMergeRequestPolicyGateAllowsAndNilGateKeepsBehaviour
  • cmd/hive: TestClassifyMergeEligibility_RelayControlLabels, TestClassifyMergeEligibility_ParkedRedPRStaysFailing, TestNeedsDecisionParkLabel, TestBindMergeAuthz_RefusesParkedHeldAndSentinelTargets, TestRelayLanePolicyGateWiring

cd src && go build ./... && go test ./cmd/hive/... ./pkg/github/... passes; coverage pkg/github 90.0%, pkg/github/automerge 90.7%, new functions 100%.

The merge-request relay (hive-merge β†’ merge-request watcher β†’ MergePR as
the App) gated on agent authority, merge-eligible.json at a pinned head,
labels and positive CI, but never on the contributor-lane policy the
auto-merge sweep enforces. A scanner's merge request therefore landed an
untrusted-tier contributor PR (green at stage/060, never soaked) that the
lane would have refused on tier and soak alone.

- Split the contributor-lane sweep's evaluation out of its merge tail
  (evaluateContributorLanePR) and expose Engine.RelayMergeRefusal, which
  runs the same gates read-only: tier admission, association, diff fences,
  control labels, review verdict, CI with min_head_age, soak, human-merge
  paths and head-SHA pinning. App, trusted-bot and trusted-author-role
  authors keep today's relay behaviour.
- Add a MergeRequestPolicyGate hook on the GitHub client; the watcher
  consults it before any branch update, denies terminally (.denied) with
  the gate named in the agent's result, audits merge_request_refused, and
  fails closed on unreadable evidence through the bounded retry path.
  The hive installs the auto-merge engine's RelayMergeRefusal through the
  request-relay supervisor, so rebuilt clients re-arm it.
- classifyMergeEligibility no longer lists PRs parked on a human decision
  (stage/085-needs-decision, or the issue-side stage/045 spelling).

Signed-off-by: Andy Anderson <andy@clubanderson.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Oct 20, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign danathar for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Open PR overlap check

Base branch: v5

Conflicts are checked with every PR merged onto the current tip of v5, so a PR that only needs a rebase is not reported as conflicting with its siblings.

PR Title Relation Files
#13165 ✨ Webhook deliveries wake the eval loop and refresh the stage tracker in seconds same files src/cmd/hive/main.go
#13188 πŸ› fix: let a trusted human's approval clear the review gate and deliver fix kicks before governor kicks same files src/cmd/hive/main.go
src/docs/hive-merge.md
#13187 πŸ› Evidence: resolve PR outcomes from the review-outcome ledger same files src/cmd/hive/main.go
#13182 πŸ› Publish the dashboard status snapshot before the serial kick dispatch same files src/cmd/hive/main.go

@hivecommons-hive

Copy link
Copy Markdown
Contributor

@clubanderson is auto-promoted for contributor-lane merging on this PR: the last 5 merged PRs by this author in this repository have no revert or sentinel-alert evidence. CI, reviewer verdict, diff fences, soak, holds and branch protection still apply.

@hivecommons-hive hivecommons-hive Bot added author/human A person pushed this PR themselves dco All commits are DCO signed-off role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 20, 2026
@hivecommons-hive
hivecommons-hive Bot merged commit 2602a74 into v5 Oct 20, 2026
72 of 73 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the fix/merge-relay-contributor-gates branch October 20, 2026 16:40
@hivecommons-hive

Copy link
Copy Markdown
Contributor
Evidence bundle `#1319229e852a` sha256:5e594a1f39e29a116d162e3b41e70de21fcb96fb9fc79959cd76059f41190ca3 β€” download from the dashboard or `hivectl review evidence #13192`.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

merged by Hive trusted-author auto-merge: author @clubanderson holds role owner and GitHub permission admin on repo; CI green at 29e852a.

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

We'd love to hear how your experience was: share feedback

@hivecommons-hive hivecommons-hive Bot removed role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 20, 2026
hivecommons-hive Bot added a commit that referenced this pull request Oct 20, 2026
* πŸ› In-progress sweep and claim read fall back to the hub's claim ledger (#13133)

* πŸ› In-progress sweep and claim read fall back to the hub's claim ledger

A ledger claim whose hive:claim marker comment was suppressed by the
per-issue comment budget read as 'no claim' to SweepInProgressIssues and
annotateIssueClaims, which stripped stage/020-claimed and flipped the
issue back to 010-actionable while the scheduler still withheld it.

Fixes #13132

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ“– Refresh scale-envelope citation after client.go field insertion

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› 085 entry comment follows the decision cause; flag @maintainer placeholder questions (#13139)

* πŸ› 085 entry comment follows the decision cause; flag @maintainer placeholder questions

A PR parked at stage/085-needs-decision gets its entry comment once per
stage visit. When the maintainer clears the cause the comment named
(sentinel alert) and a different lane fence keeps the PR at 085
(workflow-path), the stage does not change and nothing tells them why the
PR is still parked. The stage store now remembers the cause digest of each
entry comment per stage+head and postHumanEntry re-posts for a cause this
visit has not explained; each distinct cause is posted once per head and
records from before the change count as explained.

Reviewer decision questions copied the policy example's literal
@maintainer, which GitHub notifies nobody for. The policy now asks for a
real approver login and the 085 comment marks a placeholder mention.

Fixes #13137

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* changelog: fragment for #13139

Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* πŸ› Moves within 070/071/072 re-attribute the fix, not a regression (#13140)

* πŸ› Moves within 070/071/072 re-attribute the fix, not a regression

072 β†’ 070 on hive-signoff-attribution (the hive's own follow-up commit
broke the squash sign-off gate, so the hive takes the breakage back) and
072 β†’ 071 when the author kind is learned late were flagged regressed, with
a stage-regressed comment and tracker chip, because 070 < 072 numerically.
Nothing moved backwards for the author; IsRegression now treats the
fixing family as one state split by who owes the fix.

Fixes #13138

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* changelog: fragment for #13140

Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* πŸ› fix: route requires_human contributor PRs to stage/085 before admission reasons (#13152)

Backport of #13117 to v5, in the engine-native form that
landed on v6 with the v5β†’v6 top-up (#13141, ed14048): requiresHumanStage
gives the trusted-lane role check and contributor-lane admission reasons a
weak 085 opinion when the head's reviewer verdict is already
requires_human, resolveStage keeps that weak 085 whatever the tier, and
RouteHuman's fresh-head exit no longer applies when the verdict is
requires_human. A requires_human verdict on an untrusted contributor-lane
PR therefore derives stage/085-needs-decision instead of
050-review-pending + stalled.

Stage goldens regenerated with -update (44 cases, all
route=fresh/verdict=requires_human 050 β†’ 085). transition_table.go untouched.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: withhold review-fix pushes for hive-attributed PRs under a person login (#13150)

Backport of #13125 to v5. fixPushAllowed delegated to
hiveAuthored, so contributor-relay PRs (person login, `β€” hive:` trailer)
still got a hive-signed fix commit that the squash sign-off gate rejects as
bot-signoff. The push now requires an agent/App login author, or a PR the
stage reconciler adopted in place (stage/074-adopted-by-hive, the v5
exception the v6 top-up kept); the fix is proposed in the review otherwise.

(cherry picked from commit 31662b0)

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* ✨ Sidebar x/y count pills for Overview and Governor (#13148)

* ✨ Sidebar x/y count pills for Overview and Governor

Overview shows open issues / open PRs from the stage tracker working set
(GET /api/stage-tracker items by kind); Governor shows the shared
actionableNow.issues / .prs split from /api/status, the same numbers the
Governor tiles print. Both reuse .badge-count .oc-nav-count and stay
hidden until their feed has answered once.

Closes #13147

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* changelog: fragment for #13148

Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* πŸ› unpark: answer `/hive approve` on a PR and name the lane's release action (#13163)

Backport of #13092 (fixes #13087 on v6)
to v5.

`/hive approve` on a pull request was silently skipped by the un-park
sweep unless the PR sat at `stage/085-needs-decision`, and the 085 entry
comment never said what would actually release the hold. The sweep now
answers `/hive approve` on any open PR once per comment (marker-
deduplicated, no label writes) with what the merge lane will do with it,
and `stage/085-needs-decision` comments carry a "How to release it" list
supplied by the lane, naming manual-only merges explicitly.

Deviations from the v6 change: v5 has no review hold-release ledger
(#13088 is v6-only), so no lane consumes `/hive approve`
on a PR here. The reply therefore acknowledges the comment and names the
v5 release lever β€” a trusted merger's GitHub Approve review on the exact
head β€” instead of recording a release; the "no active hold" and
"predates the latest verdict" branches are not ported. Lane actions use
the same wording and the existing #13041 "What to do" block is kept.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: offer superseded PR decisions without auto-close (v5) (#13155)

* πŸ› fix: lead superseded contributor PR threads with the close/keep-open decision

Backport of #13120 to v5 (additive rendering only).

- Review comments render the hive-decision-question as visible text at
  the top; the HTML marker is unchanged.
- A review marked <!-- hive-redundant-of: #N --> shows "no-op merge:
  duplicate of #N" instead of the numeric score headline.
- The supersession sweep notice states the recommendation (close as
  superseded) and the other choices.

(cherry picked from commit d0c869e)
Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: offer superseded PR decisions without auto-close

Backport of #13118 to v5. Superseded contributor PRs now
appear in the Review Queue with close / keep-open actions even when
supersession_sweep.close_contributor_prs is unset.

The sweep emits a detected-contributor audit event on every detection
(and kept-open when hive/keep-open is present), including when its notice
is already present. The queue reader accepts detection and legacy grace
entries; existing auto-close guards and grace events remain intact.
An explicit keep-open label suppresses the recommendation, and disabled
auto-close shows no countdown and never promises an automatic close.

Deviation from v6: the your-turn inbox (dashboard ownership rules,
SupersessionStatusOption, superseded_recommended_close) is v6-only and is
not ported; only the Review Queue half lands here.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* fix: show the running release semver in the dashboard (#13130) (#13161)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: MikeSpreitzer <14296719+MikeSpreitzer@users.noreply.github.com>

* fix: match agent token-cache files exactly when re-owning (#13123) (#13160)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: gregoryhunt <31053269+gregoryhunt@users.noreply.github.com>

* πŸ“ docs: describe Prow dco-signoff labels as coexisting with hive's dco pair (#13131)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* πŸ› entrypoint: provision users and token caches for replicas: copies (#13171)

* πŸ› entrypoint: provision users and token caches for replicas: copies

A replicas: copy (<agent>-2 .. <agent>-N) is derived in memory by
ExpandAgentReplicas and stripped on save, so the entrypoint never saw its
name: no hive-<agent>-N user, no private token group, no pre-created token
cache. The manager ran it as a bare uid:node and the token write created
the cache dev:node 0600, so every gh call in the replica was blocked with
token_cache_unavailable, permanently.

Move the inline agent-name collection into hive_collect_agent_names and
expand replicas there with the same naming and 2..MaxAgentReplicas bound
as config.replicaAgentName, so replicas are provisioned at boot like
declared agents. Raising replicas on a running hive still needs a restart
for the new copies, the same as an agent added through the API.

Fixes #13166

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoYvUkv8Gp4AHGWLo97nqb
Signed-off-by: Gregory Hunt <greg@on-board.ai>

* πŸ“ changelog fragment for #13166

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoYvUkv8Gp4AHGWLo97nqb
Signed-off-by: Gregory Hunt <greg@on-board.ai>

---------

Signed-off-by: Gregory Hunt <greg@on-board.ai>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* πŸ› fix(fleetreport): exclude nudge-recovered stalls from agent-stall evidence (#13172)

v5 backport of #13099. A stall that the harness nudge recovered is
self-recovery working (#12814) and is no longer counted toward the
fleet-report defect bar; only unrecovered stalls remain evidence.

(cherry picked from commit 9802648)

Closes #13157

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* ci: make the dco-squash default-branch fetch actually run (#13159)

The 'Make the default branch resolvable' step used --depth=0, which git rejects ('depth 0 is not a positive number'), and the failure was masked by '|| true', so the step was dead code and the check only worked because actions/checkout fetch-depth: 0 happened to populate the ref. Drop --depth=0 and || true and verify the ref so a fetch failure fails the step visibly.

(cherry picked from commit c35db2f)

Closes #13158

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Findings blocked on an unmerged PR are parked, unclaimable, and don't ping fork authors (#13143)

A review-backlog finding whose evidence file exists only on the reviewed
PR (absent on its base branch) is filed with the blocked label and a
<!-- hive:blocked-on pr=owner/repo#N --> marker, without help wanted. A
blocked issue lands in the filtered bucket, derives no stage label, and
IssueClaimBlockReason refuses every automated claim on it; a sweep after
each stage-label sync lifts the label once the tracked PR merges or
closes and strips help wanted while it is open.

hive-open-issue comment --blocked-on-pr <n> posts the same neutral note
through the issue-request watcher with @-mentions stripped, and the
scanner prompts point at it instead of @-mentioning the fork author.

The contributor lane keeps a session off an issue it just failed,
abandoned or had its lease revoked on for
governor.claims.reclaim_cooldown_s (default 6h) instead of handing it
back every ten minutes when the global failure cooldown lapses.

Fixes #13142
Part of #12999

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Fix TestCampaignDeleteRemovesArchiveOnly order dependence (#13195)

GET /api/campaigns folds completed runs from the package-global
lifecycle timeline store (lifecycleStore singleton) into the list. Under
-shuffle a stage-completion journey for acme/repo!graph-a:node-a
recorded by an earlier test leaked in and the unfiltered list returned
3 campaigns instead of 2. Reset the singleton at the top of the test
like the other campaign/run tests already do.

Reproduced deterministically by replaying the CI shuffle seed
1792510983440914831 on dashboard slice 1/2 before; passes after.

Fixes #13167

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Fix TestBootDashboardWithClassifier data race on log sink (#13194)

bootDashboardWith launches backfillRecentMergedPRs in a goroutine that
logs through b.logger; the test read log.String() from an unsynchronised
strings.Builder while that goroutine was still writing, which -race
flags intermittently. Use the package's existing goroutine-safe
syncLogBuffer as the sink instead.

Reproduced 1/900 with -count=300 -race -cpu 1,2,4 before; 0/900 after,
plus -count=200 -race -shuffle=on clean.

Fixes #13168
Fixes #13169
Fixes #13170

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Hold relayed merges to the contributor-lane policy (#13192)

The merge-request relay (hive-merge β†’ merge-request watcher β†’ MergePR as
the App) gated on agent authority, merge-eligible.json at a pinned head,
labels and positive CI, but never on the contributor-lane policy the
auto-merge sweep enforces. A scanner's merge request therefore landed an
untrusted-tier contributor PR (green at stage/060, never soaked) that the
lane would have refused on tier and soak alone.

- Split the contributor-lane sweep's evaluation out of its merge tail
  (evaluateContributorLanePR) and expose Engine.RelayMergeRefusal, which
  runs the same gates read-only: tier admission, association, diff fences,
  control labels, review verdict, CI with min_head_age, soak, human-merge
  paths and head-SHA pinning. App, trusted-bot and trusted-author-role
  authors keep today's relay behaviour.
- Add a MergeRequestPolicyGate hook on the GitHub client; the watcher
  consults it before any branch update, denies terminally (.denied) with
  the gate named in the agent's result, audits merge_request_refused, and
  fails closed on unreadable evidence through the bounded retry path.
  The hive installs the auto-merge engine's RelayMergeRefusal through the
  request-relay supervisor, so rebuilt clients re-arm it.
- classifyMergeEligibility no longer lists PRs parked on a human decision
  (stage/085-needs-decision, or the issue-side stage/045 spelling).

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* ✨ Webhook deliveries wake the eval loop and refresh the stage tracker in seconds (#13165)

* ✨ Webhook deliveries wake the eval loop and refresh the stage tracker

A verified GitHub webhook that invalidates cached PR/issue state now asks
the governor loop for an early, debounced eval cycle (governor.
webhook_wake_debounce_s / webhook_wake_min_gap_s) that re-enriches only the
dirty PRs, so eval_interval_webhook_s is a safe base tick and GitHub calls
go down. The loop re-checks webhook health as the 2x eval_interval_s window
closes and falls back to eval_interval_s at once, logging one line per
transition; /api/status reports evalMode, lastWakeReason, lastWakeAt.

Every status publish invalidates the /api/stage-tracker cache and sends a
stage-tracker SSE event the SPA refetches on. The spoke handles
pull_request_review_comment and the hub relays it plus issues.

Closes #13164

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* 🌱 Fix webhook waker coalesced expectation in test

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* 🌱 Only nudge the stage tracker over SSE once it has been served

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* 🌱 Expose webhook wake pacing keys in the governor Settings UI

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ“– Refresh api-reference citations after server.go line shift

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Fix TestKickHits… flake by gating the kick response (#13201)

The test pressed K three times and asserted exactly one POST left,
relying on the second press being processed before the first response
cleared kickPending. The fixture answers instantly, so when the test
goroutine is descheduled between presses (CI under -race load) the first
kickResultMsg lands first, kickPending is cleared and the second press
issues a second request.

Hold the /api/kick/scanner response with the fixture's existing gate()
until all three presses have been processed (same pattern as the ACMM
exactly-once test), then release it and assert the queued footer.

Fixes #13191

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: honor contributor target branches (#13190)

Hive-Run: #13146

Hive-Plan: contributor-dispatch-target-branch

Hive-Spec: contributor-dispatch#wrong-base-verdict

Signed-off-by: hanthor <5840441+hanthor@users.noreply.github.com>
Co-authored-by: hanthor <5840441+hanthor@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>

* πŸ› fix: let a trusted human's approval clear the review gate and deliver fix kicks before governor kicks (#13188)

The merge-lane review gate skipped the trusted-human-approval lookup for
any changes-requested outcome, and classified the head from the
perspective map rather than the aggregate verdict, so a requires_human
head read as changes-requested:style to the gate and an owner's APPROVED
review on the exact head never cleared it. The gate now follows the
normalized aggregate verdict (new requires-human outcome) and a trusted
human's approval on the head overrides every non-approved outcome; the
review_evaluated audit line records human_approver and overrode.

Review-plan fix kicks (a maintainer's changes_requested review or
/hive decision) were assembled after the governor kick to the same
agent, so the governor kick owned the agent and the fix kick timed out
every cycle; fix kicks now go first, and an undelivered review/fix kick
is logged and audited by PR.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* [scanner] fix: stop EPIPE false failures in contribute-k8s workload test (#13198)

contains() piped the full generated YAML into grep -qF; grep exits on the
first match, printf then hits EPIPE, and set -o pipefail turns a genuine
match into 'FAIL: valid name kata-clh is emitted'. Compare with a bash
substring match instead, which reads the whole haystack.

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* πŸ› Evidence: resolve PR outcomes from the review-outcome ledger (#13187)

The Evidence card's "Outcome by author kind" reported every PR this hive
reviewed but did not merge as "outcome unknown" (33 of 137 in a 24h
window on hive's own spoke), although the governor's review-outcome
ledger had already resolved 29 of them with a GetPRState call.

- pkg/evidence: new optional `outcome` block on the bundle (source,
  state, at, merged_by/merged_at/closed_at) with Validate + JSON schema
  rules; FoldPRs honours it (OutcomeKnown, MergedElsewhere, Closed) and
  ApplyOutcomeHints applies ledger rows at read time to PRs whose
  records state no outcome.
- pkg/github: Client.RecordReviewEvidenceOutcome stamps the newest
  bundle for a PR merged by someone else (with an `unrecorded` merge
  event naming the merger) or closed without merge, under
  reviewEvidenceMu; never touches a bundle that already states an
  outcome. No GitHub API calls.
- cmd/hive: recordReviewOutcomesAt calls it after ledger.Resolve.
- pkg/dashboard: summary adds merged_elsewhere per author kind and
  missing.prs_outcome_from_ledger; prs_outcome_unknown now means truly
  unresolved; the card footnote shows the merged-elsewhere / closed /
  open breakdown.

A separate `outcome` block is used instead of `backfill` because
Validate requires backfilled:true alongside `backfill` and readers treat
backfilled bundles as carrying no live verdicts or CI.

Fixes #13186

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* ✨ Self-report evidence: hive display name and clickable spoke URL (#13217)

Runtime-error self-report issues now carry the reporting hive's display
name and dashboard URL: the Evidence table gains 'hive name' and 'spoke'
rows and each 'Affected hives (N)' line renders
'name (hive id) (instance …) β€” [open](url) β€” owner(s) …'.

The spoke emits both best-effort (project.name; dashboard.public_url else
hub.dashboard_url) only when hub-managed, so anonymous hives stay
anonymous. The hub relay overlays its authoritative project_name and
vanity URL and fills the rows for spokes that predate the fields, the
same enrichment pattern as owner(s). Rendering is byte-identical when
the fields are absent, so older reports and issues are unchanged.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* ✨ Evidence cards: plain-English grade and summary (#13213)

Every Evidence panel now shows a server-computed letter grade (A+ … C-,
or β€” when there is not enough data) in the header and a one-sentence
plain-English summary under it. Rubrics and summary generators are pure
functions in pkg/evidence/grade.go, exposed additively as cards[key] on
/api/evidence/summary. Dense stats, denominators and "what this does not
show" move behind the β“˜ popover; the CI gate card's disclosed line drops
to the muted small size so nothing in a card exceeds the title size.

Fixes #13204

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Release agent issue claims on relaunch and pace rate-limit relaunches across the fleet (#13210)

* πŸ› Release agent issue claims on relaunch and pace rate-limit relaunches across the fleet

An agent claim (2h TTL) survived the hive rollouts that killed the holding
agent: nothing released it, and the πŸ”’ marker on the forge read as live until
until= even when the ledger had dropped it, because issueclaim.Latest ignored
hive:release markers. The scanner's claim on an issue therefore parked it at
stage/020-claimed for two hours across two image rolls with nothing working it.

- agent.Manager gains a relaunch observer fired on every fresh CLI launch;
  cmd/hive wires it to Ledger.ReleaseAgentClaims, which drops only that
  agent's KindAgent claims and fires OnReleased.
- The release hook posts the release comment for the relaunch reason, and the
  release marker now carries at=; issueclaim.Latest marks the latest claim
  Released when a later release marker names its identity.
- Rate-limit relaunches of Copilot agents are spaced fleet-wide (30s) on top
  of the per-agent 300s cooldown, so the agents that tripped GitHub's limit
  during the boot stagger do not all re-validate together 300s later.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› test: assert expiry posts nothing without a sleep (sleep ratchet)

Signed-off-by: Andy Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› fix: register covering-PR-close and claim reshuffle edges as expected stage transitions (#13136)

* πŸ› fix: register covering-PR-close and claim reshuffle edges as expected stage transitions

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* test: 045β†’020 is a non-regression hop, not an undrawn regression

Every backward issue edge among 010–040 is drawn now, and IsRegression never
flags a move out of 045, so the old 'undrawn regression' sample is expected.

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* πŸ“ docs: 040 falls are narrated on the PR, not commented on the issue

The three 040 β†’ 010/030/020 edges were labelled "(backward hop, commented)"
in both the stateDiagram and transition_table.go, but the issue reconciler
only comments regressions whose previous stage is before 040
(issue_stage_labels.go: a covering PR's own falls are narrated on the PR).
Relabel them "narrated on the PR" and widen the prose enumeration of drawn
issue fallbacks to include 030 β†’ 020 and the 040 falls.

Hive-Fix-Attempt: 1/6
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* πŸ› pr titles: one emoji convention β€” πŸ“– docs, πŸ“ proposal β€” enforced where the hive opens the PR (#13209)

A hive-authored docs PR was opened as "πŸ“ docs: …" and failed the
repository's required PR Type check: the agent prompt and AGENTS.md said
πŸ“– for docs while review_priority.go read πŸ“ as docs too, so nothing told
the agent the two differ (πŸ“ is the proposal emoji).

Define the convention once (PRTitleEmoji* in pkg/github/pr_title.go),
make review_priority draw from it, spell the convention out in the
hive-open-pr instructions and AGENTS.md/CONTRIBUTING.md, and have the
pr-request watcher correct a leading emoji that contradicts the
Conventional Commits type before CreatePR. A title with no emoji is never
given one, so repositories that gate on a bare header are untouched.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› stage labels: hive-signed commits on a contributor PR go back to the author, not 070 (#13207)

A human's or clanker's PR whose commits GitHub links to the hive App (a
hive follow-up, or a contributor committing from a hive pod with the App's
noreply address) was routed to stage/070-fixing under
hive-signoff-attribution. No hive lane pushes to a non-App branch, so the
PR sat where nothing could act (pluk#315, promptargs#303, rationguard#303,
dibs#438, hivecommons.github.io#222 on 2026-10-20).

Route it by author kind (071 human / 072 clanker, 070 only when
self-authored) and tell the human author once per head exactly what to run
(git commit --amend --reset-author -s && git push --force-with-lease, or
the git rebase --exec form). The clanker's 072 nudge carries the same ask.

Also classify the trusted-author lane's review-gate holds
(no-review-bundle / awaiting-review-approval) as 050-review-pending: they
had no stage opinion, so a PR carried no stage label at all until the
swarm's verdict was noted.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› Hub auth-check: let signed webhook relays reach hosted spokes (#13233)

The hub relays GitHub App webhooks to the managing spoke at
/api/webhook/github, but the hosted Ingress auth_request gate
(handleSaaSAuthCheck -> isSaaSPublicPath) did not list that path, so nginx
answered every relayed POST with an auth-signin 302 to the hub login page
and the spoke never saw a delivery: webhooks.healthy=false, events_1h=0 on
every hosted hive while the hub relayed hundreds of events an hour.

Add the path to publicExactPaths as spokeWebhookRelayPath and make
webhook.go's relay target the same constant so they cannot drift. This
opens nothing: the spoke's handleGitHubWebhook fails closed without
GITHUB_WEBHOOK_SECRET and verifies X-Hub-Signature-256 before doing any
work.

Fixes #13231

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Evidence CI gate: resolve required checks per repo like the merge gate (#13227)

The Evidence CI-gate panel judged every merged PR's bundle snapshot against
the global auto_merge.required_checks, so on a multi-repo hive the primary
repo's gate check (e.g. build-gate) was demanded of repos that never run
it: Console showed 70 suspected missing_required breaches, none real. The
merge gate resolves the set per repo (branch protection, else
AutoMergeConfig.RequiredCheckSetForRepo), and green snapshots missing a
config-required check were never queued for GitHub confirmation, so they
could never be cleared.

- EvidenceCIPolicy resolves the config set per repo through the same
  RequiredCheckSetForRepo helper the gate uses; the per-repo sets are
  exposed as repo_required_checks for the card copy.
- collectCIRecovery queues green merges missing a config-required check
  (ciRecoveryGateDue), using the client's gate resolver
  (Client.ConfigRequiredChecksForRepo), so the trail's branch-protection
  read confirms or clears them; red/none remain due, pending is not.
- Suspected vs confirmed is unchanged: a required check that truly never
  ran stays suspected, a required red on the merged head is a breach.

Fixes #13225

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: superseded close requires a recorded supersession state (#13238)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* πŸ› fix: stop owner advice counting on-demand agents as missing a cadence (#13237)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: AN0099 <91515465+AN0099@users.noreply.github.com>

* πŸ› fix: fall back to docker.io when mirror.gcr.io throttles; deterministic embedded short hash (#13229)

* πŸ› fix: fall back to docker.io when mirror.gcr.io throttles and make the embedded short hash deterministic

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* fix: resolve ${BASE_REGISTRY} in the SUID/cap fixture builders

test_manifest_caps_runtime.sh and test_image_suid_inventory.sh lift the
runtime FROM line out of src/Dockerfile verbatim; with the registry now
parameterised as ${BASE_REGISTRY} the unexpanded placeholder became an
empty prefix ("/node:26-slim") and docker build rejected the stage name.
Resolve it the way docker build does: BASE_REGISTRY from the environment,
else the Dockerfile's ARG default.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* 🌱 images: refresh CA trust bundle and distrust two roots (#13230)

* 🌱 images: refresh CA trust bundle and distrust two roots

Distrust emSign ECC Root CA - G3 and Comodo AAA Services root in the
spoke, contributor, hub, CI-runner and OSS-scanner images (no fixed
distro ca-certificates package is published yet), and point Node-based
CLIs at the regenerated system store via NODE_OPTIONS=--use-openssl-ca.
Add src/deploy/test_image_ca_distrust.sh and run it from docker.yml so
the built spoke image is proven to reject the test chains.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* 🌱 ci-runner image: assert Comodo AAA root absent-or-disabled

Ubuntu 24.04's ca-certificates no longer ships
Comodo_AAA_Services_root, so asserting the negated entry failed the
build. Assert instead that no un-negated entry remains, and keep the
check on the generated pem.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› Run the duplicate-PR guard before the live-claim filter so a covered issue stays at 040 (#13242)

An issue whose agent claim was still live when its PR opened was withheld
by FilterLiveIssueClaims as bucket "claimed" before ApplyDuplicatePRGuard
could bucket it "claimed_by_pr". Every eval sweep after the PR opened
therefore re-derived stage/020-claimed under the event-driven 040, and the
stage store recorded a 040 -> 020 regression that the dashboard rendered as
a red regressed chip on nearly every claimed issue.

Reorder the guards so the open PR outranks the live claim, which also gives
the ledger's OpenIssuesOf the full open-issue list.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› Publish the dashboard status snapshot before the serial kick dispatch (#13182)

* πŸ› Publish the dashboard status snapshot before the serial kick dispatch

The eval cycle built and published the full dashboard snapshot only after
dispatchAgentKicks, which delivers kicks serially and waits up to the
input-prompt timeout per agent. On the hosted hive a cycle with ten due
agents spent 13.5 minutes in that phase, so /api/status (and the stage
tracker, agent states and governor.nextKickAt derived from it) showed the
previous cycle's data the whole time; a pod rolled mid-dispatch never
published its evaluation at all.

Publish an interim snapshot before the kicks when any are due, and keep
the end-of-cycle publish. Stale-build drops in UpdateStatusIfFresh are
now logged at Warn and counted in a new statusStaleDrops payload field so
a frozen snapshot can be attributed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Andy Anderson <andy@clubanderson.com>

* docs: refresh api-reference citations after rebase

Signed-off-by: Andy Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andy Anderson <andy@clubanderson.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ✨ Evidence outcome card: record reverts and issue re-opens as change failures (#13244)

* ✨ Evidence outcome card: record reverts and issue re-opens as change failures

The Outcome by author kind card hardcoded reverted_14d to nil and never
saw issue re-opens, so it could not say whether agent-written work gets
undone more often than human work (Insight 3).

- Read the existing reverted_by links into reverted_14d per author kind.
- Detect reverts from text already fetched (pull_request closed webhook,
  PR state fetch, merged-PR backfill): Revert "… (#N)" titles, Reverts #N,
  This reverts commit <sha>; resolve to merged bundles within 14 d and
  write reverted_by back-links. No new per-PR GitHub calls.
- Record issue re-opens: when the claim ledger voids a merged claim for a
  reopened issue, stamp the closing PR's bundle with issue_reopens (new
  schema field) if within 14 d of the merge.
- Card: issue_reopened_14d, change_failures and change_failure_rate
  = (reverts + re-opens) Γ· merged per kind; grade rubric and plain
  summary include re-opens; β“˜ text names both signals, the window and
  the detection method.
- Docs and changelog fragment.

Fixes #13241

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ“– scale-envelope: re-anchor client.go citation shifted by PRState fields

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: acknowledge /hive approve on hive-authored PRs only for trusted mergers (#13185)

* fix: acknowledge /hive approve on hive-authored PRs only for trusted mergers

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* fix: require a trusted merger for /hive approve on the trusted-author lane too

Address review findings on #13185: the trusted-author lane also releases a
requires_human hold only on a trusted merger's Approve (mergeReviewGate), so
gate its acknowledgement the same way; drop the duplicate "trusted merger on
App lane" test row in favour of an untrusted trusted-author-lane case; and
reword maintainer-commands.md so the "not a trusted merger" reply is not
scoped to the contributor lane.

Hive-Fix-Attempt: 1/6
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* πŸ› fix: show the feedback form in the popover and surface submission errors (#13173)

* fix: show the feedback form in the popover and surface submission errors

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: MikeSpreitzer <14296719+MikeSpreitzer@users.noreply.github.com>

* fix: keep header feedback and theme buttons from overlapping the ACMM bubble

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: MikeSpreitzer <14296719+MikeSpreitzer@users.noreply.github.com>

* fix: address review findings on the feedback submission error path

- Log every rejected /api/feedback/report (read, too-large, invalid JSON,
  validation) through the guarded s.logger with the "feedback:" prefix
  instead of a single global slog.Warn.
- Stop passing the raw non-JSON error body through feedbackStripQuery,
  which truncated it at the first ? or #.
- Gate the "before the request completed" toast suffix on whether fetch
  resolved, and console.error the caught error so the pointer to the
  browser console is true.
- Make the wiring test assert the new message fragment and console log.
- Fold the #13135 bullet into the single changelog fragment.

Hive-Fix-Attempt: 1/6

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: MikeSpreitzer <14296719+MikeSpreitzer@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ✨ feat: separate current repository consent from follow policy (#13193)

* ✨ feat: separate current repository consent from follow policy

Add shared deselect-current and follow-policy operations and expose them through hives repos. Preserve exclusions and provenance, reject implicit legacy conversion, and reuse commit/projection/reload without enrollment.

Hive-Run: #12571
Hive-Plan: ecosystem-onboarding/independent-selection-controls
Hive-Spec: #12571#5
Hive-Spec: #13153#3
Hive-Spec: #13153#8
Co-authored-by: hanthor <5840441+hanthor@users.noreply.github.com>
Signed-off-by: mendezr <mendezr@users.noreply.github.com>

* fix: reconcile SetFollowNewRepositories with the landed preset-adopt declaration

v5 already declares ProfileSet.SetFollowNewRepositories (bool, error) in
preset_adopt.go; drop the duplicate from selection_ops.go and adapt the
--follow-new-repos caller and its tests to the two-value signature.

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
(cherry picked from commit 42084bf)

---------

Signed-off-by: mendezr <mendezr@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: mendezr <mendezr@users.noreply.github.com>
Co-authored-by: hanthor <5840441+hanthor@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* ✨ Review swarm honours review_models for cross-family perspective reviews (#13250)

Thread agents.<reviewer>.review_models selection into the per-perspective
swarm kicks: each DispatchKick carries the author model and the selected
{backend, model}, the perspective prompt reuses the queue kick's
'Independent review' overlay text, and skip / requires_human fallbacks
withhold the kick or place a human hold. Add review.perspective_models to
pin a model per perspective. Stamp author_model and review_model into
pending records and collected verdicts (falling back to the reviewer's
launch model), add a per-author-family and same-family vs cross-family
breakdown to the reviewer-accuracy summary, the Evidence Accuracy card and
/api/evidence/summary, and store same_family on evidence verdicts.

Fixes #13243

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› images: CA-distrust check passes platform and ignores docker stderr (#13247)

* πŸ› images: CA-distrust check passes platform and ignores docker stderr

The arm64 docker.yml lane runs the cross-built image on an amd64 runner;
docker prints a platform-mismatch warning on stderr that the node probe
captured via 2>&1 and reported as unexpected output, failing the build
that publishes the fixed candidate image. Pass --platform from the
matrix and read only the probe's stdout line.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› images: CA-distrust check drops --platform, prints docker stderr on odd rc

docker run --platform fails (rc=125) on the arm64 lane against the
locally loaded PR image; stdout-only parsing is sufficient to ignore the
QEMU platform warning. Show docker's stderr when curl returns a code the
check does not understand.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

* πŸ› fix: require header auth for Commons API (#13259)

Hive-Run: #13245
Hive-Plan: API query-token removal
Hive-Spec: issue-13245#api-header-auth

Signed-off-by: hanthor <5840441+hanthor@users.noreply.github.com>
Co-authored-by: hanthor <5840441+hanthor@users.noreply.github.com>

* ✨ feat: hivectl hives hub add/list/show/remove tracks hubs and discovers their Hives (#13189)

* feat: hivectl hives hub add/list/show/remove with read-only hub discovery

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* ci: retrigger build after registry 429 on arm64 image pull

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: fan out hub webhook relays to every hive tracking the repository (#13228)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>

* [scanner] feat: cross-process lock and expected-revision commit for ProfileStore (#13200)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* πŸ› fix: do not self-report model_discovery_degraded for a not-licensed Copilot 403 (#13256)

* fix: do not self-report model_discovery_degraded for a not-licensed Copilot 403

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* changelog: fragment for #13256

Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: hivecommons-hive[bot] <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* chore: make the changelog fragment a bullet entry and drop the autofix duplicate

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

---------

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Signed-off-by: hivecommons-hive[bot] <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [scanner] fix: harden hives web with Host/Origin checks, no-store headers and token-free history (#13196)

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>

* feat(dashboard): activity monitor shows a 'triage needed' action chip on Open issues (#13268)

An issue sitting at Open with the needs-triage label still shows only the
grey Open chevron, so a reader cannot tell it from an issue nobody has
looked at. Report needs-triage as a tracker modifier so the action column
reads "triage needed" (amber) and the tooltip headline says
"Open Β· triage needed", mirroring the existing hold treatment.

Signed-off-by: Andy Anderson <andy@clubanderson.com>

* πŸ› images: tolerate ca-certificates packages dropping the withdrawn roots; bump runner gh to 2.102.1

Both breakages post-date the v5 commits this top-up carries and fail every
image build on v5 today too:

- Debian trixie 20250419+deb13u1 / Alpine ca-certificates-20261020-r0 /
  Ubuntu noble package refreshes already drop the emSign ECC Root CA - G3
  and Comodo AAA Services entries, so the unconditional `sed && grep -q`
  distrust step in src/Dockerfile, Dockerfile.contributor, Dockerfile.hub,
  .oss-scanner/Dockerfile and src/deploy/ci-runners/Dockerfile fails the
  build. Each entry is now rewritten only when present; the final tests
  still prove the roots are absent from the regenerated bundle. Applied
  from the in-flight v5 fix #13266 (scanner/fix-hub-ca-bundle)
  so the next top-up merges cleanly.
- cli.github.com's apt repo no longer serves gh 2.102.0 (only 2.102.1),
  so the CI runner image PR gate failed on `apt-get install gh=2.102.0`.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>

---------

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Signed-off-by: Gregory Hunt <greg@on-board.ai>
Signed-off-by: Andy Anderson <andy@clubanderson.com>
Signed-off-by: hanthor <5840441+hanthor@users.noreply.github.com>
Signed-off-by: mendezr <mendezr@users.noreply.github.com>
Signed-off-by: hivecommons-hive[bot] <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: hivecommons-hive[bot] <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: MikeSpreitzer <14296719+MikeSpreitzer@users.noreply.github.com>
Co-authored-by: gregoryhunt <31053269+gregoryhunt@users.noreply.github.com>
Co-authored-by: Gregory Hunt <greg@on-board.ai>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: James Reilly <jreilly1821@gmail.com>
Co-authored-by: hanthor <5840441+hanthor@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AN0099 <91515465+AN0099@users.noreply.github.com>
Co-authored-by: RaΓΊl MΓ©ndez <18744521+mendezr@users.noreply.github.com>
Co-authored-by: mendezr <mendezr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author/human A person pushed this PR themselves dco All commits are DCO signed-off dco-signoff: yes Indicates the PR's author has signed the DCO. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant