Skip to content

fix(miner): purge portfolio-queue and run-state rows in the right-to-be-forgotten sweep - #6697

Closed
luciferlive112116 wants to merge 1 commit into
JSONbored:mainfrom
luciferlive112116:fix/purge-portfolio-queue-run-state-6599
Closed

fix(miner): purge portfolio-queue and run-state rows in the right-to-be-forgotten sweep#6697
luciferlive112116 wants to merge 1 commit into
JSONbored:mainfrom
luciferlive112116:fix/purge-portfolio-queue-run-state-6599

Conversation

@luciferlive112116

Copy link
Copy Markdown
Contributor

Summary

loopover-miner purge --repo <owner/repo> is the operator-invoked right-to-be-forgotten path. Its own header comment claimed it covers "the four stores that have a real repoColumn". Two more local stores persist rows keyed by repo_full_name and were not covered at all:

  • portfolio-queue.jsminer_portfolio_queue
  • run-state.jsminer_run_state

Neither had a purgeByRepo, neither had a purge spec, and neither appeared in REAL_PURGE_TARGETS. An operator honoring an erasure request left that repo's rows in both stores and was told the purge succeeded — no warning, no note.

That silence is the sharp edge. attempt-log.js is deliberately reported as not-purgeable via ATTEMPT_LOG_NOT_PURGEABLE_NOTE, because it genuinely has no repo column. These two had no such structural excuse — they were simply never wired up, so they were omitted invisibly rather than declared.

The change

Follows the existing four end-to-end, with no new machinery:

  • Two purge specs in store-maintenance.js, same shape as their four siblings.
  • purgeByRepo on each store, built on the shared purgeStoreByRepo, mirroring claim-ledger.js's implementation — including throwing on a missing/malformed repoFullName rather than silently no-opping.
  • Both wired into REAL_PURGE_TARGETS, so runPurgeDryRun and runPurge pick them up automatically. No special-casing in either path.
  • The header comment now names all six.

One thing worth stating explicitly, since it looks like a reason these were skipped: both keep repo_full_name inside their PRIMARY KEY rather than as a plain column. That's irrelevant to purging — a DELETE by repo works identically either way — so they're purgeable for exactly the same reason the other four are. The code comment records that, so the next reader doesn't re-derive it and conclude they were excluded on purpose.

Type declarations — the part tsc caught and the tests didn't

This package hand-maintains .d.ts files alongside the JS. Vitest doesn't typecheck, so the suites went green while npm run typecheck failed on purgeByRepo not existing on PortfolioQueueStore/RunStateStore. Fixed in all four: both store types, the two new spec exports, and PurgeCliOptions (which declares the injectable openers and would otherwise have been an incomplete public contract for the two new stores).

Tests

  • Per-store purgeByRepo blocks in both stores' suites, mirroring miner-prediction-ledger.test.ts's reference block: deletes only the targeted repo's rows, leaves other repos untouched, returns 0 on no match, and throws on a missing/malformed repoFullName — the last one matters because a typo'd repo silently purging nothing would tell an operator their erasure request was honored when it wasn't.
  • --dry-run now seeds real rows in both stores and asserts { store: "portfolio-queue", wouldPurge: 2 } / { store: "run-state", wouldPurge: 1 } alongside the original four, with a second repo present so the counts prove the sweep is repo-scoped rather than a blanket delete.
  • The real purge asserts both stores in the per-store summary, that purgeByRepo was called on each, and that the total moved 6 → 11.

The updated four-store assertions are the issue's own deliverable ("asserting both --dry-run and a real purge now report portfolio-queue and run-state"), not tests bent to fit the code: they enumerate the covered stores exactly, so extending coverage necessarily extends them. No assertion was weakened or removed.

Validation

  • Patch coverage 100%, measured from the v8 JSON report across all four changed source files — store-maintenance.js (5 lines), portfolio-queue.js (8), run-state.js (7), purge-cli.js (10): zero uncovered statements, zero partial branches on every one. Clears the 99% codecov/patch wall on packages/loopover-miner/lib/**.
  • All 6 new tests pass; 76/80 in the three suites.
  • npm run typecheck — 0 errors · eslint — 0 errors/0 warnings · npm run build:miner (node --check across every lib file) passes · git diff --check clean · rebased on latest main, no base conflict.

The 4 remaining local failures are pre-existing and not mine — verified, not assumed. They are miner-portfolio-queue/miner-run-state's DB-path and file-mode tests, which fail identically on clean main with my work stashed (Windows-only: \ vs / separators, and statSync().mode & 0o077 returning 54 instead of 0, since Windows has no POSIX permission bits). Same count, same tests, before and after.

Scope

  • Eight source/type files + three test files, one coherent change. Wanted paths (packages/, test/).
  • The four existing stores, purgeStoreByRepo itself, and attempt-log's deliberate not-purgeable note are untouched.
  • No secrets; no changelog, site/, CNAME, or lovable changes.

Safety

  • Purely additive to an explicit, operator-invoked command that never runs automatically — no automatic path deletes anything new.
  • --dry-run still writes nothing; both new stores are counted through the same read-only countStoreByRepo the other four use.
  • The normalizeRepoFullName throw means a malformed repo argument fails loudly rather than reporting a successful purge of nothing.
  • purgeOneStore's per-store try/catch already isolates failures, so a problem opening either new store cannot prevent the other five from being reported.

Closes #6599

…be-forgotten sweep (JSONbored#6599)

loopover-miner purge --repo swept only four of the six local stores that persist
repo_full_name. portfolio-queue.js and run-state.js were left untouched, with no
warning -- unlike attempt-log.js, which is deliberately reported as not-purgeable
because it genuinely has no repo column. An operator honoring a right-to-be-forgotten
request kept that repo's rows in both stores and was told the purge succeeded.

Both stores gain purgeByRepo built on the shared purgeStoreByRepo, two purge specs
are added, and both are wired into REAL_PURGE_TARGETS so --dry-run and the real
purge report them alongside the other four with no special-casing. Keeping
repo_full_name in a PRIMARY KEY rather than a plain column never made them
unpurgeable; they were simply never wired up.

Closes JSONbored#6599
@luciferlive112116

Copy link
Copy Markdown
Contributor Author

Closing as a duplicate: #6694 covers the same issue (#6599) and was opened first — I hadn't seen it when I pushed this, and it deserves the review. Leaving the field to it rather than have two competing PRs on one issue.

@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 16, 2026
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.65%. Comparing base (58ab17e) to head (58dcacd).
⚠️ Report is 11 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6697   +/-   ##
=======================================
  Coverage   93.65%   93.65%           
=======================================
  Files         682      682           
  Lines       68112    68117    +5     
  Branches    18708    18708           
=======================================
+ Hits        63788    63793    +5     
  Misses       3347     3347           
  Partials      977      977           
Flag Coverage Δ
shard-1 43.91% <75.00%> (+0.01%) ⬆️
shard-2 36.97% <50.00%> (-0.01%) ⬇️
shard-3 32.30% <50.00%> (-0.16%) ⬇️
shard-4 34.59% <50.00%> (+0.35%) ⬆️
shard-5 31.64% <50.00%> (+0.25%) ⬆️
shard-6 45.76% <100.00%> (+0.01%) ⬆️

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

Files with missing lines Coverage Δ
packages/loopover-miner/lib/portfolio-queue.js 97.36% <100.00%> (+0.02%) ⬆️
packages/loopover-miner/lib/purge-cli.js 100.00% <ø> (ø)
packages/loopover-miner/lib/run-state.js 100.00% <100.00%> (ø)
packages/loopover-miner/lib/store-maintenance.js 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Caution

🛑 LoopOver review result - reject/close recommended

Review updated: 2026-07-16 20:03:42 UTC

11 files · 1 AI reviewer · 1 blocker · CI failing · dirty

🛑 Suggested Action - Reject/Close

Review summary
This PR closes the gap where `portfolio-queue.js` and `run-state.js` silently escaped the right-to-be-forgotten purge sweep despite persisting `repo_full_name`-keyed rows, by adding purge specs, wiring `purgeByRepo` via the shared `purgeStoreByRepo` helper, and registering both in `REAL_PURGE_TARGETS` exactly like the four existing stores. The implementation mirrors `event-ledger.js`'s `purgeByRepo` pattern precisely (throw on invalid repo, reuse `purgeStoreByRepo`, no apiBaseUrl scoping — consistent with the other four stores, which also purge across all forge hosts for a repo), and both new paths get dedicated unit tests plus updated dry-run/real-purge integration tests with correct expected counts (11 = 6 + 5). Type declarations (`.d.ts`) for both stores and `purge-cli.d.ts`/`store-maintenance.d.ts` are updated in lockstep with the runtime code.

Nits — 5 non-blocking
  • portfolio-queue.js:389 and run-state.js:135 duplicate the same three-sentence purge doc comment verbatim across two files — consider factoring the shared explanation into store-maintenance.js's own purgeStoreByRepo doc and linking to it instead.
  • store-maintenance.js:37-38's new comment about repo_full_name-in-PRIMARY-KEY is good context but slightly buries the more important fact that purge (like the other four specs) is NOT scoped by api_base_url — worth a one-line note there for the next reader who wonders why a purge touches rows across every forge host.
  • purge-cli.js's header comment reads a bit awkwardly after the diff ("via each store's own `purgeByRepo` method (which reuses" wrapping mid-parenthetical) — minor prose cleanup.
  • Consider a short CHANGELOG or migration note pointing operators at the fact that a purge run before this PR would have left portfolio-queue/run-state rows behind, in case anyone needs to re-run purge for previously 'completed' erasure requests.
  • If apiBaseUrl-scoped purging is ever desired for multi-host setups, it should be added consistently across all six specs at once, not just the two new ones.

Why this is blocked

  • No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.

CI checks failing

  • validate-tests-merge
  • validate
  • validate-code
  • validate-tests (4)
  • validate-tests (2)
  • validate-tests (6)
  • validate-tests (3)
  • validate-tests (1)
  • validate-tests (5)

Decision drivers

  • ❌ Code review — 1 blocker (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #6599
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ❌ 8/20 High 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: 166 registered-repo PR(s), 100 merged, 31 issue(s).
Contributor context ✅ Confirmed Gittensor contributor luciferlive112116; Gittensor profile; 166 PR(s), 31 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Review context
  • Author: luciferlive112116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, JavaScript, MDX, Rust, TypeScript
  • Official Gittensor activity: 166 PR(s), 31 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Add a concise scope and risk note.
  • Then work through the remaining 2 steps in the Signals table above.
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 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

LoopOver is closing this pull request on the maintainer's behalf (CI is failing (validate-tests-merge, validate, validate-code, validate-tests (4), validate-tests (2), validate-tests (6), validate-tests (3), validate-tests (1), validate-tests (5)); conflicts with the base branch — resolve and open a fresh PR; No linked issue detected). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed.

@loopover-orb loopover-orb Bot closed this Jul 16, 2026
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.

purge-cli.js's right-to-be-forgotten sweep misses portfolio-queue.js and run-state.js

1 participant