Skip to content

fix(openapi): document /v1/opportunities/find + /v1/issue-rag/retrieve - #9450

Closed
andriypolanski wants to merge 5 commits into
JSONbored:mainfrom
andriypolanski:fix/9310-openapi-opportunities-issue-rag-v2
Closed

fix(openapi): document /v1/opportunities/find + /v1/issue-rag/retrieve#9450
andriypolanski wants to merge 5 commits into
JSONbored:mainfrom
andriypolanski:fix/9310-openapi-opportunities-issue-rag-v2

Conversation

@andriypolanski

Copy link
Copy Markdown
Contributor

Closes #9310

Summary

  • Adds FindOpportunitiesRequest/FindOpportunitiesResponse and IssueRagRetrieveRequest/IssueRagRetrieveResponse schemas mirroring the MCP tool Zod shapes (reusing the same MAX_FIND_OPPORTUNITIES_* / MAX_ISSUE_RAG_* / PREFLIGHT_LIMITS constants).
  • Registers both POST paths in src/openapi/spec.ts (same registration pattern as #6611 / gate-config/effective).
  • Regenerates and commits apps/loopover-ui/public/openapi.json.
  • Extends openapi.test.ts with path/schema presence + field regression guards (aiPolicyAllowed, retrievedPathCount).

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Validation

  • git diff --check
  • npm run ui:openapi + npm run ui:openapi:check
  • npx vitest run test/unit/openapi.test.ts — 5 passed
  • npm run test:ci (full gate; run before push)
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

If any required check was skipped, explain why:

OpenAPI documentation + regeneration + targeted contract test complete. Full test:ci left for the opener.

Safety

  • No secrets, wallets, hotkeys, trust scores, or reward values.
  • Does not touch site/, CNAME, **/lovable/**, or root CHANGELOG.md.

UI Evidence

N/A — OpenAPI contract / generated openapi.json only; no product UI change.

Notes for reviewers / gate

  • No production route behavior change — documentation parity only.
  • Fresh PR required: closed PRs are not reopened after conflict auto-close.

andriy-polanski and others added 5 commits July 27, 2026 18:13
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>
@andriypolanski andriypolanski changed the title Fix/9310 openapi opportunities issue rag v2 fix(openapi): document /v1/opportunities/find + /v1/issue-rag/retrieve Jul 27, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 27, 2026
@loopover-orb loopover-orb Bot reopened this Jul 27, 2026
@loopover-orb loopover-orb Bot closed this Jul 27, 2026
@loopover-orb

loopover-orb Bot commented Jul 27, 2026

Copy link
Copy Markdown
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.

@loopover-orb loopover-orb Bot added review-evasion Gittensor contributor context and removed gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. labels 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-evasion Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openapi: /v1/opportunities/find + /v1/issue-rag/retrieve missing from spec (MCP tools + schemas already exist)

2 participants