feat(gate): let maintainers be exempt from the missing-linked-issue penalty - #10160
Conversation
…enalty `gate.linkedIssue: block` exists to stop unlinked CONTRIBUTOR work. Applied to a maintainer's own PR it asks them to file an issue against their own repo before touching it, and holds the PR when they don't; the bot's own PRs (release-please, dependency bumps, generated-doc refreshes) hit it constantly for the same reason. On the production Orb `hold | missing_linked_issue` is the second-largest hold bucket -- 503 in a week. New `gate.linkedIssueMaintainerExempt`, config-as-code only (global or per-repo), following hardGuardrailGlobs: no DB column, so no dashboard toggle can silently disagree with the file, and no migration. It is ONE clamp -- block to advisory, maintainer-authored PRs only -- because the two halves are already separate concerns. The finding is PRODUCED on `requireLinkedIssue` (true for any mode but off) and only BLOCKS at `block`, so clamping to advisory keeps "No linked issue detected" visible in the review comment while removing exactly its power to fail the gate, hold, or close. Nothing is suppressed and nothing goes silent. Scoped to the MISSING case. Everything that inspects an issue that IS linked -- linkedIssueSatisfaction, linkedIssueHardRules, linkedIssueLabelPropagation -- keys on a cited issue and is untouched, so a maintainer who links one is scrutinised exactly like anyone else. "Maintainer" is the existing PROTECTED AUTHOR set (owner, per-repo admin, protected automation author) reused rather than redefined, so it cannot come to mean one thing here and another on the close path. Bots are included deliberately: they already have auto-close protection for the same reason and are a large share of the unlinked PRs in practice. Applied to `settings` before it reaches gateCheckPolicy rather than passed as an argument -- both things that must agree read that object, and the function already takes seven positional parameters. Wired at ALL FOUR call sites (webhook, sweep, two re-gate paths): wiring only the webhook path would mean a maintainer PR passing live and then being held when the sweep re-gates it. Closes #10158
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
loopover-ui | ceef67e | Jul 31 2026, 10:07 AM |
|
Important 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏳ LoopOver is waiting…LoopOver has seen this pull request and is waiting on CI checks to finish before reviewing it. This comment will update once the review runs. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed · 🟨 Waiting |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Bundle ReportChanges will increase total bundle size by 214 bytes (0.0%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: loopover-uiAssets Changed:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #10160 +/- ##
==========================================
- Coverage 92.21% 92.20% -0.01%
==========================================
Files 931 932 +1
Lines 114066 114099 +33
Branches 27547 27558 +11
==========================================
+ Hits 105183 105209 +26
Misses 7584 7584
- Partials 1299 1306 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
|
…icating zero token counts (#10233) * feat(observability): capture every miner AI generation, and stop fabricating zero token counts Closes #10200 Closes #10207 * chore(contract): regenerate api-schemas for the linkedIssueMaintainerExempt field #10160 added linkedIssueMaintainerExempt to the repository-settings surface without regenerating packages/loopover-contract/src/api-schemas.ts, so contract:api-schemas:check has been failing on main since. The check is part of the local test:ci aggregate but is not wired into ci.yml, which is why nothing surfaced it. Pure regeneration: the one added line is the generator's own output for a field that already exists everywhere else. --------- Co-authored-by: JSONbored <aetherealdev@gmail.com>
Closes #10158
gate.linkedIssue: blockexists to stop unlinked contributor work. Applied to a maintainer's own PR it asks them to file an issue against their own repo before touching it, then holds the PR when they don't — and the bot's own PRs (release-please, dependency bumps, generated-doc refreshes) hit it constantly for the same reason.Measured on the Orb since the beta.7 deploy, with the
hold | successbug (#10116) now fixed:One clamp, because the two halves are already separate
missing_linked_issuefinding is produced onrequireLinkedIssue— true for any mode butoffresolveConfiguredGateModeresolvesblockSo clamping
block→advisoryfor maintainer-authored PRs keeps "No linked issue detected" visible in the review comment and removes exactly its power to fail the gate, hold, or close. Nothing is suppressed; nothing goes silent.Config-as-code only, following
hardGuardrailGlobs— no DB column, so no dashboard toggle can silently disagree with the file, and no migration.Scope
Only the MISSING case. Everything that inspects an issue that is linked —
linkedIssueSatisfaction,linkedIssueHardRules,linkedIssueLabelPropagation— keys on a cited issue and is untouched. A maintainer who links one is scrutinised exactly like anyone else. That is also why this is a clamp on one mode rather than a bypass flag: a bypass would have had to be excluded from each linked-issue path by hand, and the next such path would have been added without the exclusion."Maintainer" is the existing protected-author set (
authorIsOwner || authorIsAdmin || authorIsAutomationBot—processors.ts'sprotectedAuthor), reused rather than redefined so it cannot mean one thing here and another on the close path. Bots are included deliberately: they already have auto-close protection for the same reason, and in practice they are a large share of the unlinked PRs.Wiring
Applied to
settingsbefore it reachesgateCheckPolicy, not passed as an argument — both things that must agree (requireLinkedIssueandlinkedIssueGateMode) read that same object, so clamping upstream makes them unable to disagree.gateCheckPolicyalso already takes seven positional parameters and does not need an eighth.Wired at all four call sites (webhook, sweep, two re-gate paths). Wiring only the webhook path would mean a maintainer PR passing live and then being held when the sweep re-gates it — the same drift class as #10116.
Verification
typecheck,dead-exports,dead-source-files,import-specifiersclean;openapi.jsonregenerated.Notable: four separate exhaustiveness guards caught this change being incomplete, and two of the failures were silent-in-production:
unknown key … ignoring it— inert in every real config while all unit tests passedgateConfigToJsonround-tripRepositorySettingsconfig-templatesmirror.loopover.yml.examplebut notconfig/examples/loopover.full.ymlBehaviour with the knob absent/false/null is byte-identical to before. The clamp is one-directional —
offis never raised toadvisory, which would start producing a finding on a repo that had switched the gate off entirely.