fix(openapi): declare the real statuses for POST /v1/loop/request-apr-transfer - #9816
Conversation
…-transfer The `requestAprTransfer` spec entry declared `200: "Transfer requested"`, but the handler has exactly four exits — `400` on a parse failure, `409` when the transfer gate rejects (GitHub untouched), `502` when the attempt fails downstream, and `202` (pending-acceptance) otherwise. It never returns `200`, so every generated client documented a status the route cannot produce and omitted the three it can. Replace `200` with `202` and add `409` + `502` (keeping `400`/`401`), mirroring the concrete-outcome description style of the neighbouring MISC_ROUTES entries. The handler's statuses are unchanged — this only makes the published contract match what it already returns. openapi.json regenerated. Closes JSONbored#9711
|
🚨 Contributor flagged. Click here for more info: Superagent Dashboard |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-29 11:22:36 UTC
Review summary Nits — 3 non-blocking
Flagged checks (non-blocking)
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionPartially addressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Decision record
Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy · Diff highlights exactly what changed. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9816 +/- ##
==========================================
+ Coverage 79.02% 79.03% +0.01%
==========================================
Files 280 281 +1
Lines 58352 58382 +30
Branches 6697 6699 +2
==========================================
+ Hits 46114 46144 +30
Misses 11955 11955
Partials 283 283
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Held for manual review: the gate and required CI are green, but GitHub reports this pull request's mergeable state as |
…ty scan (#9818) * chore(superagent): disable contributor-trust scoring, keep the security scan The contributor-trust check has been posting `action_required` on established contributors' PRs — shin-core scored 10/100 "dangerous" on PR #9816 — and was a major source of manual-review volume. Two independent reasons to turn it off rather than tune it further: 1. The trustedAuthors exemption does not work. shin-core is listed in it and was still flagged. An exemption that does not exempt is worse than none: it looks handled while every affected PR still stalls. 2. Its verdict has no consumer. LoopOver now lists this check under gate.ignoredCheckRuns (#9813) on all three gate repos, so a non-passing result no longer gates, pends, or holds anything. Leaving it on produces a permanently red check on contributor PRs that nothing acts on — noise that makes good contributors think they have failed something. prScan stays enabled and still gates CI normally: that is the protection worth having, and it is a different check from the same app. trustedAuthors is kept (inert) so the history survives if this is ever revisited. * chore(superagent): drop the trustedAuthors allowlist too It provably does not work (a listed author was still flagged action_required) and is inert with contributorTrust disabled. Keeping it would only suggest the repo has a working exemption mechanism that it does not.
…either gate.ignoredCheckRuns (#9813) excluded the check from LoopOver's own CI aggregate, but mergeable_state is GITHUB's computation and stays "unstable" while the check exists at all -- and derivePrDisposition holds unconditionally on unstable. So the ignore was half-effective: the check no longer failed the gate, and the PR was held anyway. Observed live on #9816 immediately after the config flip, reason "mergeable_state is unstable -- non-required check(s) not passing: Contributor trust". Dismiss an unstable state ONLY when the ignore list fully explains it: at least one ignored run concluded non-passing, our aggregate found no non-required failure, and ciState is not failed. Any other unstable cause still holds, and the flag never rescues a PR held for a different reason. Also make the un-itemized unstable message actionable. It used to say only "a non-required check or status is not passing" -- no check name, no next step. GitHub never says why, and the aggregate can legitimately fail to itemize it (a commit status rather than a check-run, an unreadable app page, a run that appeared after CI was read). Name that ambiguity and point at the Checks tab.
…either gate.ignoredCheckRuns (#9813) excluded the check from LoopOver's own CI aggregate, but mergeable_state is GITHUB's computation and stays "unstable" while the check exists at all -- and derivePrDisposition holds unconditionally on unstable. So the ignore was half-effective: the check no longer failed the gate, and the PR was held anyway. Observed live on #9816 immediately after the config flip, reason "mergeable_state is unstable -- non-required check(s) not passing: Contributor trust". Dismiss an unstable state ONLY when the ignore list fully explains it: at least one ignored run concluded non-passing, our aggregate found no non-required failure, and ciState is not failed. Any other unstable cause still holds, and the flag never rescues a PR held for a different reason. Also make the un-itemized unstable message actionable. It used to say only "a non-required check or status is not passing" -- no check name, no next step. GitHub never says why, and the aggregate can legitimately fail to itemize it (a commit status rather than a check-run, an unreadable app page, a run that appeared after CI was read). Name that ambiguity and point at the Checks tab.
…either (#9820) * fix(gate): an ignored check must not hold the PR via mergeable_state either gate.ignoredCheckRuns (#9813) excluded the check from LoopOver's own CI aggregate, but mergeable_state is GITHUB's computation and stays "unstable" while the check exists at all -- and derivePrDisposition holds unconditionally on unstable. So the ignore was half-effective: the check no longer failed the gate, and the PR was held anyway. Observed live on #9816 immediately after the config flip, reason "mergeable_state is unstable -- non-required check(s) not passing: Contributor trust". Dismiss an unstable state ONLY when the ignore list fully explains it: at least one ignored run concluded non-passing, our aggregate found no non-required failure, and ciState is not failed. Any other unstable cause still holds, and the flag never rescues a PR held for a different reason. Also make the un-itemized unstable message actionable. It used to say only "a non-required check or status is not passing" -- no check name, no next step. GitHub never says why, and the aggregate can legitimately fail to itemize it (a commit status rather than a check-run, an unreadable app page, a run that appeared after CI was read). Name that ambiguity and point at the Checks tab. * fix(gate): an ignored check must not hold the PR via mergeable_state either gate.ignoredCheckRuns (#9813) excluded the check from LoopOver's own CI aggregate, but mergeable_state is GITHUB's computation and stays "unstable" while the check exists at all -- and derivePrDisposition holds unconditionally on unstable. So the ignore was half-effective: the check no longer failed the gate, and the PR was held anyway. Observed live on #9816 immediately after the config flip, reason "mergeable_state is unstable -- non-required check(s) not passing: Contributor trust". Dismiss an unstable state ONLY when the ignore list fully explains it: at least one ignored run concluded non-passing, our aggregate found no non-required failure, and ciState is not failed. Any other unstable cause still holds, and the flag never rescues a PR held for a different reason. Also make the un-itemized unstable message actionable. It used to say only "a non-required check or status is not passing" -- no check name, no next step. GitHub never says why, and the aggregate can legitimately fail to itemize it (a commit status rather than a check-run, an unreadable app page, a run that appeared after CI was read). Name that ambiguity and point at the Checks tab.



What & why
POST /v1/loop/request-apr-transfer's spec entry (requestAprTransfer) declared200: "Transfer requested". The handler has exactly four exits and none of them is 200:400— failed parse409— the transfer gate rejected the request (GitHub was not touched)502— the transfer attempt failed downstream202— initiation accepted, pending acceptance (the success path)So every generated client documented a status the route cannot return and omitted the three it actually produces.
The fix
Replace
200with202and add409+502(keeping400/401), mirroring the concrete-per-status description style of the neighbouringMISC_ROUTESentries. The handler's statuses are unchanged — this only makes the published contract match what it already returns.apps/loopover-ui/public/openapi.jsonregenerated.Tests
test/unit/openapi.test.ts:buildOpenApiSpec()'s declared statuses forPOST /v1/loop/request-apr-transferare exactly{202, 400, 401, 409, 502}— fails onmain, which returns200.test/unit/routes-request-apr-transfer.test.ts(existing202/409/502/400cases), which the spec now matches.Validation
npm run typecheckgreen;npm run ui:openapi:checkclean (regenerated spec matches source); both suites green.git diff --check <base> HEADclean; diff is the spec source + its test + the regeneratedopenapi.json; no handler or lockfile change.Closes #9711