Context
packages/loopover-miner/lib/claim-ledger-expiry.ts's findExpiredClaims was fixed in #7732 (commit 352c49fcb) so a claim with an unparseable claimedAt is now treated as expired and swept, "matching this module's own fail-closed posture" — previously such a claim was silently skipped and left stuck active forever.
packages/loopover-miner/lib/portfolio-queue-expiry.ts's own header comment literally calls itself "Mirror of claim-ledger-expiry.js for the portfolio-queue store," but its findStuckItems (line 36) still has the pre-fix line if (ageMs === null) continue; — a portfolio-queue item with a corrupted/unparseable leasedAt is silently skipped by the sweep and stays in_progress forever (e.g. a crashed-process item that can never be reclaimed by the stuck-item sweep).
The existing test file even locks in the stale behavior: test/unit/miner-portfolio-queue-expiry.test.ts:115 has a test titled "ignores ... unparseable-lease items" — that test's expectation needs to flip along with the fix.
⚠️ Required pattern — read packages/loopover-miner/lib/claim-ledger-expiry.ts's findExpiredClaims (post-#7732, commit 352c49fcb) before starting. Port the exact same fail-closed treatment (unparseable timestamp → treated as expired/stuck, not skipped) to findStuckItems in portfolio-queue-expiry.ts. Do not invent a different resolution strategy — this issue exists specifically because the two modules are meant to mirror each other and drifted.
Requirements
Deliverables
Test Coverage Requirements
packages/loopover-miner/** — this repo's standard 99%+ Codecov patch target on every changed line and branch. Add/update a unit test covering: a portfolio-queue item with an unparseable leasedAt is now swept as stuck (not skipped).
Expected Outcome
A portfolio-queue item with a corrupted/unparseable lease timestamp is reclaimed by the stuck-item sweep instead of remaining in_progress forever, matching the fail-closed posture claim-ledger-expiry.ts already has post-#7732.
Links & Resources
Context
packages/loopover-miner/lib/claim-ledger-expiry.ts'sfindExpiredClaimswas fixed in #7732 (commit352c49fcb) so a claim with an unparseableclaimedAtis now treated as expired and swept, "matching this module's own fail-closed posture" — previously such a claim was silently skipped and left stuck active forever.packages/loopover-miner/lib/portfolio-queue-expiry.ts's own header comment literally calls itself "Mirror of claim-ledger-expiry.js for the portfolio-queue store," but itsfindStuckItems(line 36) still has the pre-fix lineif (ageMs === null) continue;— a portfolio-queue item with a corrupted/unparseableleasedAtis silently skipped by the sweep and staysin_progressforever (e.g. a crashed-process item that can never be reclaimed by the stuck-item sweep).The existing test file even locks in the stale behavior:
test/unit/miner-portfolio-queue-expiry.test.ts:115has a test titled "ignores ... unparseable-lease items" — that test's expectation needs to flip along with the fix.Requirements
findStuckItems(packages/loopover-miner/lib/portfolio-queue-expiry.ts) must treat a portfolio-queue item with an unparseableleasedAtas stuck (sweep it), not silently skip it — mirroringfindExpiredClaims's post-A claim with an unparseable claimedAt is never swept by findExpiredClaims #7732 behavior exactly.test/unit/miner-portfolio-queue-expiry.test.ts:115(currently asserts "ignores... unparseable-lease items") to assert the new fail-closed behavior instead, mirroring howeverclaim-ledger-expiry's own test suite was updated for A claim with an unparseable claimedAt is never swept by findExpiredClaims #7732.Deliverables
findStuckItemsinportfolio-queue-expiry.tsswept-treats unparseableleasedAtthe same wayfindExpiredClaimstreats unparseableclaimedAtpost-A claim with an unparseable claimedAt is never swept by findExpiredClaims #7732.Test Coverage Requirements
packages/loopover-miner/**— this repo's standard 99%+ Codecov patch target on every changed line and branch. Add/update a unit test covering: a portfolio-queue item with an unparseableleasedAtis now swept as stuck (not skipped).Expected Outcome
A portfolio-queue item with a corrupted/unparseable lease timestamp is reclaimed by the stuck-item sweep instead of remaining
in_progressforever, matching the fail-closed postureclaim-ledger-expiry.tsalready has post-#7732.Links & Resources
packages/loopover-miner/lib/portfolio-queue-expiry.ts(the file to fix,findStuckItems)packages/loopover-miner/lib/claim-ledger-expiry.ts(the already-fixed sibling to mirror, see commit352c49fcb/ A claim with an unparseable claimedAt is never swept by findExpiredClaims #7732)test/unit/miner-portfolio-queue-expiry.test.ts:115(the test to update)