Skip to content

Phase 8b: 30-day retention cleanup loop#17

Merged
JacobHaig merged 2 commits into
mainfrom
feat/file-relay-retention
Jun 2, 2026
Merged

Phase 8b: 30-day retention cleanup loop#17
JacobHaig merged 2 commits into
mainfrom
feat/file-relay-retention

Conversation

@JacobHaig
Copy link
Copy Markdown
Member

Phase 8b — retention cleanup

Hourly background sweep that deletes expired uploads (MinIO object + DB row) once expires_at passes — covering both 30-day-old files and unused/stale links.

Changes

  • UploadServiceStartRetention/StopRetention + RunRetentionLoop (mirrors the reminder-service loop: try/cancel/error, hourly). CleanupExpiredAsync selects rows past expires_at, removes the MinIO object for ready/uploading rows (best-effort, no id logged), then deletes the row. Gated on Config.UploadEnabled.
  • Bot — starts the loop in OnReady.
  • CLAUDE.md updated.
  • Separate commit: refines the CodeRabbit-workflow repo-memory per latest direction (merge non-major resolved findings after fix + green CI, without waiting on the formal re-approval).

Verification

  • dotnet build — succeeds, 0 errors. docker-build CI validates the image.
  • Runtime sweep (MinIO deletes) integration-tested at 8c with a real MinIO.

This makes the file relay code-complete. Only 8c remains (agent-cloud: MinIO bucket + Caddy subdomain + redeploy) — which needs the public subdomain + site-config access.

JacobHaig added 2 commits June 2, 2026 12:29
…fter fix

Per user direction: resolve findings, but for non-major/non-catastrophic issues
merge after pushing the fix + green CI without waiting for CodeRabbit's formal
re-approval (which often lags behind a transient rate limit). Major findings
still wait for re-review.
Phase 8b. Hourly background sweep deletes expired uploads (MinIO object + DB row)
past expires_at — covers both 30-day-old files and unused pending links.

- UploadService: StartRetention/StopRetention + RunRetentionLoop (mirrors the
  reminder loop), CleanupExpiredAsync (delete object for ready/uploading rows,
  then delete the row), gated on Config.UploadEnabled.
- Bot: start the loop in OnReady.
- CLAUDE.md updated.
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ea5e688-68aa-4d32-8003-bd52d5c3cbc7

📥 Commits

Reviewing files that changed from the base of the PR and between aa9ea14 and ebb4be2.

📒 Files selected for processing (4)
  • .claude/memory/feedback-coderabbit-pr-workflow.md
  • Bot.cs
  • CLAUDE.md
  • Services/UploadService.cs
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use the field keyword for properties with logic to avoid manual backing fields in C# 14

Use null-conditional assignment operator ?.= for defensive assignments

Use the new extension keyword for grouping extension members (properties, methods, and static members)

Use primary constructors for classes and structs unless complex initialization logic is required

Always use [] for empty or populated collections/spans in C# 14 (e.g., List<int> items = [1, 2, 3];)

Use file-scoped namespaces with namespace MyProject.Models; (no curly braces)

Use expression-bodied members with => for simple one-line methods and properties

Prefer ReadOnlySpan<char> for string parsing and slicing

Use the required keyword for properties that must be initialized via object initializers

Use raw string literals with """ for multi-line strings or JSON to avoid escaping quotes

Use PascalCase for Classes, Methods, Properties, and Public Fields

Use camelCase for local variables and method arguments

Avoid underscore prefixes for private fields; use the field keyword or this. prefix if absolutely necessary

Use implicit usings and do not include standard system imports unless unique

Use var only when the type is obvious from the right side of the assignment; use explicit types for method returns or literals

Each Discord slash command should use the fire-and-forget pattern with Task.Run() after immediate RespondAsync(), then FollowupAsync() for results to avoid 3-second Discord interaction timeout

All configuration settings must resolve via Config.Load() in this order: process environment variable → local .env file → default; never hardcode site-specific values

Files:

  • Bot.cs
  • Services/UploadService.cs
Bot.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Slash commands must be registered idempotently on OnReady (check existing before creating); use /removeallcommands terminal command to force-clear all registered commands

Files:

  • Bot.cs
Services/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use ConcurrentDictionary and ConcurrentQueue for thread-safe collections; use lock for background service lists where needed

Use manual constructor DI pattern: inject Terminal into all services, and DiscordSocketClient into services that call Discord APIs after startup

Each service must live in its own file under Services/; Bot.cs owns instances, wires events, and handles slash command routing

Files:

  • Services/UploadService.cs
{Database.cs,Services/**/*.cs}

📄 CodeRabbit inference engine (CLAUDE.md)

Store Discord ulong IDs as long (SQLite INTEGER) and cast at the database boundary

Use ISO 8601 strings with "O" format for DateTime storage in SQLite

Files:

  • Services/UploadService.cs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T16:41:29.706Z
Learning: Run `dotnet build` after making changes to test and validate the changes worked
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T16:41:29.706Z
Learning: Ensure code is well-structured, follows best practices, and includes appropriate error handling when making changes
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T16:41:29.706Z
Learning: Update CLAUDE.md and/or README.md after completing changes to reflect the changes made and provide clear documentation for future reference
Learnt from: CR
Repo: uhstray-io/WisBot

Timestamp: 2026-06-02T16:41:29.706Z
Learning: Read `.claude/memory/MEMORY.md` at the start of every session to load project context and knowledge
🪛 LanguageTool
.claude/memory/feedback-coderabbit-pr-workflow.md

[style] ~11-~11: ‘lags behind’ might be wordy. Consider a shorter alternative.
Context: ...view/flip its flag (its re-review often lags behind a transient fair-usage rate limit, ...

(EN_WORDINESS_PREMIUM_LAGS_BEHIND)

🔇 Additional comments (8)
.claude/memory/feedback-coderabbit-pr-workflow.md (1)

9-9: LGTM!

Also applies to: 11-13, 15-15, 17-17

Services/UploadService.cs (5)

20-35: LGTM!


37-50: LGTM!


52-72: LGTM!


84-91: LGTM!


74-82: Verify Minio SDK 7.0.0 RemoveObjectAsync usage in UploadService
RemoveObjectAsync(new RemoveObjectArgs().WithBucket(...).WithObject(...)) matches the MinIO .NET SDK 7.0.0 API shape (Task RemoveObjectAsync(RemoveObjectArgs args, CancellationToken ...)) and its RemoveObjectArgs fluent builder (WithBucket/WithObject).

Bot.cs (1)

99-99: LGTM!

CLAUDE.md (1)

42-42: LGTM!


📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Implemented automatic expiration and cleanup of uploads on an hourly schedule. Expired uploads are now removed from storage and associated records are deleted from the database.

Walkthrough

This PR adds an hourly retention cleanup path for expired uploads in UploadService, starts that process during bot readiness, updates the related service documentation, and revises internal CodeRabbit merge guidance to distinguish ordinary findings from major or catastrophic findings.

Changes

Upload retention cleanup

Layer / File(s) Summary
Retention lifecycle controls
Services/UploadService.cs
Adds retention task state plus public StartRetention() and StopRetention() methods to manage the background cleanup process.
Hourly cleanup execution
Services/UploadService.cs
Adds the recurring retention loop, expired upload query and deletion flow, conditional MinIO object removal for ready or uploading rows, and helper methods for best-effort object deletion and row removal.
Startup wiring and service docs
Bot.cs, CLAUDE.md
Starts retention from Bot.OnReady() after database initialization and updates the UploadService documentation entry to include the hourly retention cleanup loop.

CodeRabbit merge guidance

Layer / File(s) Summary
Tiered merge policy instructions
.claude/memory/feedback-coderabbit-pr-workflow.md
Rewrites the internal merge guidance to treat ordinary findings separately from major or catastrophic findings, updates the dated rationale, and adjusts the step-by-step merge conditions accordingly.

Sequence Diagram(s)

sequenceDiagram
  participant Ready as Bot.OnReady
  participant Retention as UploadService.StartRetention
  participant Sweep as RunRetentionLoop
  participant Cleanup as CleanupExpiredAsync
  participant Sqlite as uploads table
  participant Storage as MinIO
  Ready->>Retention: call StartRetention
  Retention->>Sweep: start background task
  Sweep->>Cleanup: run cleanup pass
  Cleanup->>Sqlite: select expired uploads
  Sqlite-->>Cleanup: return ids and statuses
  Cleanup->>Storage: remove eligible objects
  Storage-->>Cleanup: success or error
  Cleanup->>Sqlite: delete expired rows
  Sqlite-->>Cleanup: return removed count
  Sweep->>Sweep: wait one hour
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • uhstray-io/WisBot#15: Extends the same /upload and uploads table flow by adding retention behavior on top of that earlier upload implementation.
  • uhstray-io/WisBot#16: Builds on the same MinIO-backed UploadService by adding cleanup of stored objects and expired rows.
  • uhstray-io/WisBot#12: Updates the same .claude/memory/feedback-coderabbit-pr-workflow.md workflow guidance file with a further policy revision.

Poem

🐇 I swept the burrow once an hour,
Through upload rows and storage tower.
Old links curled up and drifted by,
While tidy loops kept watch nearby.
Then thump-thump! docs and rules agreed,
A neat little hop for every need.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Phase 8b: 30-day retention cleanup loop' directly and clearly describes the main change: a retention cleanup feature with hourly background sweep for expired uploads.
Description check ✅ Passed The description clearly explains the retention cleanup feature, lists all changes (UploadService, Bot, CLAUDE.md, CodeRabbit workflow), and provides verification details—all directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/file-relay-retention

Comment @coderabbitai help to get the list of available commands and usage tips.

@JacobHaig
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JacobHaig JacobHaig merged commit 61ed442 into main Jun 2, 2026
2 checks passed
@JacobHaig JacobHaig deleted the feat/file-relay-retention branch June 2, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant