Skip to content

fix(miner): cover worktree-allocator's worktree_slots in purge-cli's right-to-be-forgotten sweep - #8570

Merged
loopover-orb[bot] merged 2 commits into
JSONbored:mainfrom
galuis116:fix/worktree-allocator-purge-cli-8320-v2
Jul 24, 2026
Merged

fix(miner): cover worktree-allocator's worktree_slots in purge-cli's right-to-be-forgotten sweep#8570
loopover-orb[bot] merged 2 commits into
JSONbored:mainfrom
galuis116:fix/worktree-allocator-purge-cli-8320-v2

Conversation

@galuis116

Copy link
Copy Markdown
Contributor

Summary

  • packages/loopover-miner/lib/worktree-allocator.ts's worktree_slots table is a fixed pool (slot_index is the primary key; every slot 0..maxConcurrency-1 always exists), so it needed a bespoke purgeByRepo rather than the generic DELETE-based purgeStoreByRepo every other repo-scoped store reuses. WorktreeAllocator.purgeByRepo is a hand-written UPDATE that only ever blanks repo_full_name/attempt_id/owner_pid/owner_host/allocated_at on a status = 'free' row for the target repo — it never deletes a row, and it never touches a status = 'active' row, since an active slot's repo_full_name reflects a live, currently-running attempt's real on-disk worktree checkout. In normal operation this is expected to affect 0 rows in the overwhelming majority of real calls (release()/reclaimOrphanedAllocations() already blank a slot on every path that frees it) — it exists purely as a defensive backstop for a row that predates this fix or was left stale by an unexpected crash path.
  • worktree-allocator is now registered in purge-cli.ts's REAL_PURGE_TARGETS, following governor-state's existing precedent for a store with custom (non-generic) purge logic.
  • store-maintenance.ts's LedgerPurgeSpec gains an optional extraWhereSql field so --dry-run's read-only row count (countStoreByRepo) can stay in exact lockstep with the real purge's status = 'free' restriction — every one of the other 12 existing specs leaves this field unset, so their behavior is unchanged.
  • WorktreeAllocator is now a required-purgeByRepo interface (matching every other PurgeableStore), so test/unit/miner-attempt-cli.test.ts's one hand-constructed inline allocator stub gained a matching purgeByRepo: vi.fn(() => 0) — the only other place in the repo that builds a WorktreeAllocator-shaped object without going through the real openWorktreeAllocator.

This is the same recurring "repo-scoped local store missing from the right-to-be-forgotten sweep" gap class already fixed three times before (#7091, #6599, #8009).

Scope

Validation

  • git diff --check
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries
  • npm run actionlint
  • npm --workspace @loopover/miner run build (typecheck + check-syntax.mjs over every bin//lib/ file)
  • A scoped tsc --noEmit (root tsconfig.json's full flag set) across every changed file plus every test file that references WorktreeAllocator's type (test/unit/miner-worktree-allocator.test.ts, test/unit/miner-purge-cli.test.ts, test/unit/miner-store-maintenance.test.ts, test/unit/miner-attempt-cli.test.ts) — clean
  • npx vitest run test/unit/miner-worktree-allocator.test.ts test/unit/miner-purge-cli.test.ts test/unit/miner-store-maintenance.test.ts test/unit/miner-attempt-cli.test.ts — 160/160 passing, covering: a free slot with a stale repo_full_name (seeded directly, since normal operation never leaves one) is purged and counted; an active slot for the target repo is left completely untouched and not counted; no matching rows returns 0; an invalid repo name is rejected the same way acquire already rejects one; --dry-run reports the same count the real purge would remove for both the free-stale and active cases; the full runPurge/runPurgeDryRun integration paths (seeded real stores, injected fakes, the real-default-on-disk-stores path, and the partial-failure path) all account for the 13th store; store-maintenance.ts's countStoreByRepo ANDs extraWhereSql correctly and leaves every spec without one unaffected.

If any required check was skipped, explain why:

  • The whole-repo npm run typecheck/npm run test:coverage (unsharded) reliably OOM in this sandbox regardless of diff size — a known sandbox resource constraint documented across many prior PRs, not a signal about this change. packages/loopover-miner/** is not included in vitest.config.ts's coverage.include (confirmed empirically — it doesn't appear in a coverage report at all, at any percentage), so it is not Codecov-gated; the gate here is npm run test:ci staying green with real branch coverage in the four test files touched, which the 160 passing tests above satisfy directly.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests.
  • API/OpenAPI/MCP behavior is updated and tested where needed.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks.
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs.

UI Evidence

This is a backend-only CLI/store change (packages/loopover-miner/**) with no rendered UI delta — before and after are the same production capture at each required viewport. apps/loopover-ui is dark-mode-only, so only the Dark row per viewport applies.

Viewport · Theme Before After
Desktop · Dark Desktop · Dark before Desktop · Dark after
Tablet · Dark Tablet · Dark before Tablet · Dark after
Mobile · Dark Mobile · Dark before Mobile · Dark after

Notes

  • Analogue: governor-state.ts's own purgeByRepo (the closest existing precedent for a store needing custom, non-generic purge logic) and its specs (not spec) entry in purge-cli.ts's REAL_PURGE_TARGETS.
  • A prior attempt at this same change was closed for a real validate-code/typecheck failure: making purgeByRepo a required field on WorktreeAllocator broke a hand-constructed allocator stub in test/unit/miner-attempt-cli.test.ts that this PR's own scoped @loopover/miner build didn't cover (that file lives under root test/unit/, outside the miner package's own tsconfig). This PR fixes that stub directly and widens the local scoped-typecheck sweep to include every test file that references WorktreeAllocator's type, not just the ones this change's own tests live in.

@superagent-security

Copy link
Copy Markdown
Contributor

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

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.70%. Comparing base (1c7c3a7) to head (85acd2d).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8570      +/-   ##
==========================================
+ Coverage   89.58%   89.70%   +0.12%     
==========================================
  Files          97      100       +3     
  Lines       22706    22977     +271     
  Branches     3872     3946      +74     
==========================================
+ Hits        20341    20612     +271     
  Misses       2187     2187              
  Partials      178      178              
Flag Coverage Δ
backend 100.00% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-miner/lib/purge-cli.ts 100.00% <ø> (ø)
packages/loopover-miner/lib/store-maintenance.ts 100.00% <100.00%> (ø)
packages/loopover-miner/lib/worktree-allocator.ts 100.00% <100.00%> (ø)

…right-to-be-forgotten sweep

Adds WorktreeAllocator.purgeByRepo, a hand-written UPDATE that only ever blanks a
free slot's repo_full_name -- never deletes a row (the pool is fixed-size) and never
touches an active slot, since that would desync the allocator from a live attempt's
real on-disk worktree checkout. LedgerPurgeSpec gains an optional extraWhereSql so
--dry-run's row count stays in lockstep with that same free-only restriction.
…r fake

Follow-up to the worktree-allocator purge-cli fix: the interface's new required
method broke this test file's hand-constructed allocator stub, caught by the root
typecheck (not the miner package's own scoped build, which doesn't see test/unit/**).
@JSONbored
JSONbored force-pushed the fix/worktree-allocator-purge-cli-8320-v2 branch from 14f184f to 85acd2d Compare July 24, 2026 21:31
@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 24, 2026
@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-24 21:36:09 UTC

7 files · 1 AI reviewer · no blockers · readiness 98/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This is a well-targeted fix that closes the gap identified in issue #8320: worktree_slots was the last repo-scoped table missing from the right-to-be-forgotten purge sweep. The implementation correctly recognizes worktree_slots as a fixed pool (never DELETE, only blank a free row) via a hand-written UPDATE, adds an extraWhereSql escape hatch to store-maintenance.ts so the dry-run count stays in lockstep with the real purge's status='free' restriction, and registers the new target with matching test coverage across all four affected test files including the active-slot-must-not-be-touched case.

Nits — 5 non-blocking
  • packages/loopover-miner/lib/store-maintenance.ts:32 — the extraWhereSql field is a fine general escape hatch, but consider a brief note that it's currently only exercised by WORKTREE_ALLOCATOR_PURGE_SPEC so a future spec reusing it stays aware of the countStoreByRepo-only scope.
  • packages/loopover-miner/lib/worktree-allocator.ts's purgeByRepo throws on an invalid repoFullName (per the added test), which differs from the generic purgeStoreByRepo path that has no such validation — worth a one-line note in the interface doc that a custom purgeByRepo may validate/throw where the generic one wouldn't, so callers in purge-cli.ts's try/catch (which already handles this) aren't caught off guard by future custom stores.
  • Consider whether `extraWhereSql` should also be validated with a comment/assert that it can only ever be an internal constant (already stated in the doc comment) — a lint rule or type-level newtype (e.g. branded string) would make the 'never caller/user text' invariant enforced rather than just documented, though this is optional given the existing identifier-guard precedent in the file.
  • Possible screenshot-table issue: identical images (row 1) — Advisory only — verify the screenshot-table images against the stated change before deciding.
  • Possible screenshot-table issue: identical images (row 2) — Advisory only — verify the screenshot-table images against the stated change before deciding.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8320
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 1899 registered-repo PR(s), 1233 merged, 56 issue(s).
Contributor context ✅ Confirmed Gittensor contributor galuis116; Gittensor profile; 1899 PR(s), 56 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff adds a hand-written UPDATE-based purgeByRepo on WorktreeAllocator that only blanks free rows matching the repo and explicitly skips active rows, registers worktree-allocator in REAL_PURGE_TARGETS mirroring governor-state's precedent, and extends the dry-run count via a new extraWhereSql field so it stays in lockstep with the real purge's free-only condition. Test coverage in miner-worktre

Review context
  • Author: galuis116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: JavaScript, Python, TypeScript, Dart, HTML, MDX, Rust, C++
  • Official Gittensor activity: 1899 PR(s), 56 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask 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.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

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.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 6c22ccd into JSONbored:main Jul 24, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(miner): worktree-allocator.ts's worktree_slots (has repo_full_name) is absent from purge-cli.ts's right-to-be-forgotten sweep

1 participant