fix(services): batch the per-repo outcome-patterns snapshot read - #10165
Conversation
loadRepoOutcomePatternsMap fired one listSignalSnapshots query per registered repo, concurrently and unbatched, and discarded 99 of the up-to-100 full payloads each one returned to use exactly one — scaling DB round trips linearly with the installed-repo count on the contributor decision-pack build path. The bulk helper for exactly this shape already exists: listRecentSignalSnapshotsForTargets selects payload_json, batches at SIGNAL_SNAPSHOT_TARGET_KEY_SQL_BATCH keys per round trip, and takes an explicit maxPerTarget. Read every registered repo's latest snapshot in one bulk call (listRecentSignalSnapshotsForTargets(env, SIGNAL, fullNames, 1)) instead of the per-repo Promise.all loop, lowercasing the returned keys on the way out to preserve the map's existing lowercased-key contract (the helper keys by the exact targetKey string). The isRegistered filter, the single-repo loadOrComputeRepoOutcomePatternsResponse path, computeRepoOutcomePatterns, and listSignalSnapshots' signature are all unchanged; a registered repo with no snapshot is still absent from the map. Closes JSONbored#10024
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-31 10:42:30 UTC
Review summary Nits — 4 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.
|
|
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 #10165 +/- ##
=======================================
Coverage 80.43% 80.43%
=======================================
Files 282 283 +1
Lines 58744 58770 +26
Branches 6963 6971 +8
=======================================
+ Hits 47248 47274 +26
Misses 11205 11205
Partials 291 291
Flags with carried forward coverage won't be shown. Click here to find out more.
|
What & why
loadRepoOutcomePatternsMapfired onelistSignalSnapshotsquery per registered repo, concurrently and unbatched, and discarded 99 of the up-to-100 rows each one returned (each carrying a fullpayload_json) to use exactly one:listSignalSnapshotshas no limit parameter and hard-caps at 100 rows including eachpayload_json. This runs on the contributor decision-pack build path, so the read scaled linearly in DB round trips with the installed-repo count — the exact shapelistRecentSignalSnapshotsForTargetswas written to fix (it selectspayload_json, batches atSIGNAL_SNAPSHOT_TARGET_KEY_SQL_BATCH = 90keys per round trip, and takes an explicitmaxPerTarget;repo-doc-refresh-runner.tsalready uses the sibling bulk helper).The fix
Read every registered repo's latest snapshot in one bulk call —
listRecentSignalSnapshotsForTargets(env, REPO_OUTCOME_PATTERNS_SIGNAL, fullNames, 1)— replacing the per-repoPromise.allloop. The helper keys by the exacttargetKeystring, so the caller lowercases on the way out to preserve the map's existing lowercased-key contract (decision-pack.ts's lookups).listRecentSignalSnapshotsForTargets(not theLatestvariant) is the one that selectspayload_json, andmaxPerTarget: 1takes only the newest snapshot per repo.Unchanged: the
isRegisteredfilter, a registered repo with no snapshot still absent from the map, the single-repoloadOrComputeRepoOutcomePatternsResponsepath,computeRepoOutcomePatterns, andlistSignalSnapshots' signature and hardlimit(100)(other callers depend on it).Tests (
test/unit/repo-outcome-patterns-service.test.ts)DB.prepareinvocation count does not grow with the repo count — 3 repos and 12 repos produce the same number of prepared statements (one batch, 12 < 90). Fails onmain(linear per-repo loop).targetKeywhose casing differs from the requestedfullNamestill resolves to a lowercased map key, so the helper's exact-casing contract doesn't silently drop it.loadRepoOutcomePatternsMaptest is preserved.Validation
src/services/repo-outcome-patterns.tsis 100% line and branch (the registered/unregisteredcontinue, the snapshot present/absent arms, and the empty-list path).npm run typecheckclean;npm run engine-parity:drift-checkpasses (not a twin);npm run dead-exports:checkclean; the suite (14 tests) green.git diff --checkclean; no schema/migration/generated-artifact change.Closes #10024