fix(openapi): document /v1/opportunities/find + /v1/issue-rag/retrieve - #9450
Closed
andriypolanski wants to merge 5 commits into
Closed
fix(openapi): document /v1/opportunities/find + /v1/issue-rag/retrieve#9450andriypolanski wants to merge 5 commits into
andriypolanski wants to merge 5 commits into
Conversation
JSONbored#9310) Both discovery routes were live (and MCP-backed) but absent from OpenAPI. Add request/response schemas mirroring the MCP tool shapes, register the POST paths, regenerate openapi.json, and add regression assertions. Replaces conflict-closed JSONbored#9423 on current main. Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve the openapi.json conflict by regenerating from the merged schemas/spec sources so JSONbored#9310 opportunities/issue-rag paths and main coexist. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Contributor
|
LoopOver had already started reviewing this pull request — closing it to dodge the one-shot review process is not allowed. Please open a new pull request with the issues addressed. |
This was referenced Jul 27, 2026
JSONbored
added a commit
that referenced
this pull request
Jul 28, 2026
…g a live holder's lock (#9465, #9468) (#9506) * fix(locks): stop contention killing jobs, and stop three paths freeing a live holder's lock (#9465, #9468) Lock contention was charged an attempt like any other error, so with a flat 5s retry and maxRetries 5 a waiter died after roughly 25 seconds -- against a lock designed to be held for minutes (PR_ACTUATION_LOCK_TTL_SECONDS is 600s, spanning a whole publish -> AI review -> maintain pass). Production confirmed it: the only dead-lettered jobs in a 7-day window were three actuation-lock contentions, and one was a reopen-reclose, whose single webhook-gated trigger and absent reconciler meant that one-shot enforcement was lost outright (PR #9450). Both backends now re-pend without consuming the budget -- the same treatment the sibling GitHub rate-limit path already gets -- bounded by job age so a genuinely wedged lock still converges to a dead job an operator can see, under a distinct job_lock_contended audit event so "waiting its turn" is never read as a failure. Three paths freed locks whose owners were still running. The boot flush deletes every key matching the orphaned-lock patterns, which is only sound on a single instance -- but nothing enforced that, while the same Redis is explicitly shared across replicas and the pg backend exists to support more than one; a restarting sibling therefore freed a live replica's in-flight ai-review and pr-actuation locks, letting the next pass duplicate that review and its actuation with no TTL expiry involved. It is now opt-in via LOOPOVER_SINGLE_INSTANCE, defaulting to skip because the cost of skipping is a lock riding out its TTL (which #9008's steal path already recovers) while the cost of flushing wrongly is a double close or merge. Shutdown released every held lock BEFORE the drain, but the drain deliberately lets in-flight work finish -- so a completed drain left jobs running with their locks already freed, and a sibling or the new container in an overlapped deploy could claim one and duplicate the actuation. The drain now runs first and each job releases its own lock through its own finally; the proactive bulk release remains for the short-grace case it was written for, but only fires when the drain has not finished within LOOPOVER_SHUTDOWN_LOCK_RELEASE_AFTER_MS. The held-lock registry was keyed by lock key alone, so an earlier holder's cleanup could evict a later one's live entry: a forced re-run steals a lock in-process, and the original pass's unregister then deleted the stealer's entry, so a SIGTERM skipped that key and it stranded for the full TTL after a hard kill -- exactly the shape the registry exists to prevent. Register and unregister are now token-scoped, mirroring the store-side compare-and-delete. * test(locks): cover attempt-free deferral on both backends and the #9468 lifecycle arms The attempt-free deferral block -- the core of #9465 -- had no coverage in either backend. Adds a regression per backend (re-pends without consuming an attempt, tagged deferred_by='lock_contended') plus two invariants: a genuine failure still consumes its budget and converges to dead, and past the age deadline a wedged lock does too rather than deferring forever. Also covers the single-instance boot-flush gate (defaulting to false is the fail-safe direction) and the null-token release arm, which must never evict a live holder. makePool's enqueueJob gained an optional createdAt so the age-based deadline is testable; it defaults to now, so every existing caller is unaffected.
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.
Closes #9310
Summary
FindOpportunitiesRequest/FindOpportunitiesResponseandIssueRagRetrieveRequest/IssueRagRetrieveResponseschemas mirroring the MCP tool Zod shapes (reusing the sameMAX_FIND_OPPORTUNITIES_*/MAX_ISSUE_RAG_*/PREFLIGHT_LIMITSconstants).src/openapi/spec.ts(same registration pattern as#6611/gate-config/effective).apps/loopover-ui/public/openapi.json.openapi.test.tswith path/schema presence + field regression guards (aiPolicyAllowed,retrievedPathCount).Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Validation
git diff --checknpm run ui:openapi+npm run ui:openapi:checknpx vitest run test/unit/openapi.test.ts— 5 passednpm run test:ci(full gate; run before push)If any required check was skipped, explain why:
OpenAPI documentation + regeneration + targeted contract test complete. Full
test:cileft for the opener.Safety
site/,CNAME,**/lovable/**, or rootCHANGELOG.md.UI Evidence
N/A — OpenAPI contract / generated
openapi.jsononly; no product UI change.Notes for reviewers / gate