fix(portfolio): scope per-repo WIP caps by forge host, not repo name alone (#7224) - #7261
Conversation
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7261 +/- ##
=======================================
Coverage 93.81% 93.81%
=======================================
Files 704 704
Lines 69506 69508 +2
Branches 18912 18912
=======================================
+ Hits 65210 65212 +2
Misses 3302 3302
Partials 994 994
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-19 11:10:43 UTC
Review summary Nits — 3 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed 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. 🟩 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.
|
Summary
The portfolio store's #5563 composite primary key
(api_base_url, repo_full_name, identifier)keeps twoforge hosts serving a same-named
owner/repoas distinct rows — but the two WIP-cap/selection paths built ontop of it dropped the host dimension, so a per-repo cap was silently shared across hosts:
entriesToPortfolioQueue(portfolio-queue-manager.js) folded active rows for the engine'snextEligibleItems,which groups its per-repo WIP cap by each item's
repoFullName— an opaque string to the engine (it has noapiBaseUrlconcept; the host is smuggled through the opaqueidviaqueueItemId, Scope local ledger keys by forge host, not bare repoFullName #5563). Two hosts' rowstherefore merged into one group, so e.g.
perRepoWipCap: 1let only ONE host's backlog advance.selectNextEligibleTarget(portfolio-queue-cli.js,queue next --per-repo-wip) countedrepoActiveCountby
repoFullNamealone, so an in-progress item on host A blocked a queued item for the same repo on host B.This host-qualifies both:
repoFullNameis now${apiBaseUrl}\n${repo}— the same "smuggle the host throughthe string the engine treats opaquely" approach
queueItemIdalready uses for theid. The itemidstillcarries the true repo, and
selectEligibleBatchmaps results back viaparseQueueItemId(id), so the realrepo/host reach the caller unchanged. The returned bucket's own
repoFullNamestays the plain repo name.selectNextEligibleTarget'srepoActiveCountfilter additionally matchesentry.apiBaseUrl === topQueued.apiBaseUrl.Single-host behavior (the overwhelming common case) is unchanged: one
apiBaseUrlmeans one grouping key perrepo, and the added filter match is always true — confirmed by the existing suites passing untouched.
Closes #7224
Scope
site//CNAME/lovable; no new dependency.Closes #7224).Validation
git diff --checknpm run typecheck(root — clean)npm run test:coverageon both changed modules — 100% of the changed lines + branches covered. Two newregressions with a cap that actually binds (
perRepoWipCap: 1, which the existing Scope local ledger keys by forge host, not bare repoFullName #5563 test at cap 2 couldnot catch):
claimNextBatchclaims both hosts' same-named rows, andselectNextEligibleTargetdoes not lethost A's in-progress item block host B's queued one. All existing portfolio-queue tests pass unchanged.
npm run build:miner(node --checkon both files passes).If any required check was skipped, explain why:
packages/loopover-miner/lib/**; CI runs the full suite.Safety