Skip to content

fix(accounts): compact legacy stored account comments#44

Merged
tomcasaburi merged 2 commits intomasterfrom
fix/account-comments-compaction
Mar 20, 2026
Merged

fix(accounts): compact legacy stored account comments#44
tomcasaburi merged 2 commits intomasterfrom
fix/account-comments-compaction

Conversation

@tomcasaburi
Copy link
Member

@tomcasaburi tomcasaburi commented Mar 20, 2026

Compact legacy accountComments records the first time the new hooks read, mutate, or export them so existing users stop carrying old bloated reply payloads in storage.

Closes #43


Note

Medium Risk
Touches IndexedDB persistence for accountComments by adding an on-access migration/compaction step; bugs here could rewrite or drop stored comments, though it’s guarded by versioning and covered by tests.

Overview
Adds automatic compaction/migration for legacy accountComments storage. A new ensureAccountCommentsDatabaseLayout rewrites stored comments to a compact form (dropping replies.pages while keeping replies.pageCids) and stamps a __storageVersion so the rewrite runs once per account.

This migration is now triggered before getAccountComments, addAccountComment, deleteAccountComment, and getExportedAccountJson, with a per-account in-flight migration guard to avoid concurrent rewrites. Tests were added to verify legacy comments are compacted during export, read, and delete flows and that the DB is marked migrated.

Written by Cursor Bugbot for commit 901887f. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • Tests

    • Added tests validating legacy account comment compaction and storage-versioned behavior across export, read, and delete flows.
  • Bug Fixes

    • Account comments now undergo automatic compaction and are marked with a storage version during export, read, add, and delete operations to standardize persisted shape and exported JSON.

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

Adds per-account comment storage versioning and a migration that sanitizes legacy accountComments entries (removing replies.pages, keeping replies.pageCids) and sets __storageVersion = 1. Migration is invoked lazily from comment read/write/export/delete paths.

Changes

Cohort / File(s) Summary
Core Schema Migration
src/stores/accounts/accounts-database.ts
Added commentStorageVersion = 1 and ensureAccountCommentsDatabaseLayout(accountId) to rewrite stored comments via sanitizeStoredAccountComment and set __storageVersion. Updated getExportedAccountJson, getAccountComments, addAccountComment, and deleteAccountComment to call the migration; addAccountComment now persists __storageVersion alongside writes.
Test Coverage
src/stores/accounts/accounts-database.test.ts
Added three tests verifying legacy compaction: export (getExportedAccountJson), read (getAccountComments), and delete (deleteAccountComment) each remove replies.pages, preserve replies.pageCids, and set __storageVersion = 1 in stored/exported data.

Sequence Diagram

sequenceDiagram
    participant Client
    participant AccountsDB as accounts-database
    participant IndexedDB

    Client->>AccountsDB: getAccountComments(accountId) / getExportedAccountJson / deleteAccountComment / addAccountComment
    activate AccountsDB
    AccountsDB->>AccountsDB: ensureAccountCommentsDatabaseLayout(accountId)
    AccountsDB->>IndexedDB: read __storageVersion for account
    IndexedDB-->>AccountsDB: version (or undefined)
    alt missing or legacy version
        AccountsDB->>IndexedDB: read all stored comments
        IndexedDB-->>AccountsDB: comments (may contain replies.pages)
        AccountsDB->>AccountsDB: sanitize comments (remove replies.pages, keep pageCids)
        AccountsDB->>IndexedDB: write sanitized comments + __storageVersion = 1
    end
    AccountsDB->>IndexedDB: proceed with requested operation (read/add/delete/export)
    IndexedDB-->>AccountsDB: result
    AccountsDB-->>Client: return result (compacted/sanitized)
    deactivate AccountsDB
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through old indexed strands,

pages bloomed in dusty lands,
I nudged each comment, trimmed the space,
kept the keys and cleared the place,
now exports bounce with lighter grace. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding compaction for legacy stored account comments.
Linked Issues check ✅ Passed The PR successfully implements the objective from issue #43 by ensuring legacy accountComments are automatically compacted during normal operations.
Out of Scope Changes check ✅ Passed All changes are directly scoped to compacting legacy account comments; no unrelated modifications were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 fix/account-comments-compaction
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/stores/accounts/accounts-database.test.ts`:
- Around line 762-791: Add a regression test that verifies mutation compaction
for legacy accountComments: create a legacy-style entry in the per-account
"accountComments" DB via createPerAccountDatabase (include a replies.pages
structure and pageCids), then call the mutating API under test (e.g.,
addAccountComment or deleteAccountComment for the account id) and assert that
after the mutation the stored row has been compacted (replies.pages removed,
pageCids preserved) and that __storageVersion is updated; also verify exported
JSON from accountsDatabase.getExportedAccountJson reflects the compacted shape.

In `@src/stores/accounts/accounts-database.ts`:
- Around line 366-386: ensureAccountCommentsDatabaseLayout can run concurrently
and clobber concurrent edits and can mark the DB upgraded on partial failure;
serialize the migration by acquiring a per-account migration lock (e.g., a
migration key in accountCommentsDatabase) before snapshotting via
getDatabaseAsArray, abort if lock exists or wait/retry, then compute
updatedComments and for each index perform a compare-and-set write that only
replaces the row if the current stored row still equals the original snapshot
(use the snapshot from getDatabaseAsArray), perform all row rewrites and only
after all succeed set storageVersionKey to commentStorageVersion, and finally
release the migration lock in a finally block; reference
ensureAccountCommentsDatabaseLayout, accountCommentsDatabase, storageVersionKey,
commentStorageVersion, getDatabaseAsArray, sanitizeStoredAccountComment, and
isEqual when making these changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc0c0d30-755d-4aca-ae2d-447d1871e00d

📥 Commits

Reviewing files that changed from the base of the PR and between 513543c and 2daada5.

📒 Files selected for processing (2)
  • src/stores/accounts/accounts-database.test.ts
  • src/stores/accounts/accounts-database.ts

@tomcasaburi
Copy link
Member Author

Addressed the valid review findings in 901887f.

  • serialized the one-time accountComments layout migration per account so concurrent callers await the same migration instead of racing stale rewrites against later mutations
  • moved the __storageVersion write to after the row rewrites succeed
  • added a deleteAccountComment regression test covering legacy comment compaction on a mutate path

Local verification after the fix:

  • yarn prettier
  • yarn build
  • yarn test src/stores/accounts/accounts-database.test.ts
  • yarn test still exits non-zero in the same pre-existing repo-wide localforage unhandled-error path outside this PR
  • yarn test:coverage:hooks-stores and node scripts/verify-hooks-stores-coverage.mjs still fail on the standing repo-wide hooks/stores 100% baseline outside this PR

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/stores/accounts/accounts-database.ts (2)

458-464: Optional: remove redundant sanitization after migration.

After ensureAccountCommentsDatabaseLayout completes, all persisted comments are already sanitized. The sanitizeStoredAccountComment call at line 460 is idempotent but adds CPU overhead on every read.

Since comments are only mutated via addAccountComment (which already sanitizes before writing), this sanitization could be removed. The index and accountId assignments would remain.

♻️ Suggested simplification
   // add index and account id to account comments for easier updating
   for (const i in comments) {
-    comments[i] = sanitizeStoredAccountComment(comments[i]);
     comments[i].index = Number(i);
     comments[i].accountId = accountId;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/accounts/accounts-database.ts` around lines 458 - 464, Remove the
redundant call to sanitizeStoredAccountComment in the read path: since
ensureAccountCommentsDatabaseLayout guarantees persisted comments are sanitized
and addAccountComment sanitizes before write, delete the
sanitizeStoredAccountComment(comments[i]) invocation in the loop that sets
comments[i].index and comments[i].accountId; keep the index and accountId
assignments intact and ensure no other callers rely on this extra sanitization
in the function that returns comments.

432-441: Consider removing redundant storageVersionKey writes.

After ensureAccountCommentsDatabaseLayout(accountId) completes at line 424, storageVersionKey is already set to commentStorageVersion. Writing it again in every add/edit operation adds unnecessary I/O overhead.

The migration guarantees the version is set, so these redundant writes could be removed unless you specifically want to guard against external DB modifications.

♻️ Suggested simplification
   if (typeof accountCommentIndex === "number") {
     assert(
       accountCommentIndex < length,
       `addAccountComment cannot edit comment no comment in database at accountCommentIndex '${accountCommentIndex}'`,
     );
-    await Promise.all([
-      accountCommentsDatabase.setItem(String(accountCommentIndex), comment),
-      accountCommentsDatabase.setItem(storageVersionKey, commentStorageVersion),
-    ]);
+    await accountCommentsDatabase.setItem(String(accountCommentIndex), comment);
   } else {
     await Promise.all([
       accountCommentsDatabase.setItem(String(length), comment),
-      accountCommentsDatabase.setItem(storageVersionKey, commentStorageVersion),
       accountCommentsDatabase.setItem("length", length + 1),
     ]);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/accounts/accounts-database.ts` around lines 432 - 441, The code is
redundantly writing storageVersionKey = commentStorageVersion on every add/edit;
since ensureAccountCommentsDatabaseLayout(accountId) already sets
storageVersionKey, remove the accountCommentsDatabase.setItem(storageVersionKey,
commentStorageVersion) calls from both Promise.all branches around
accountCommentsDatabase.setItem(String(...), comment) and
accountCommentsDatabase.setItem("length", ...), leaving only the item/length
writes; if you want to guard against external DB tampering instead, replace the
duplicate writes with a conditional check that verifies the current
storageVersionKey before proceeding.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/stores/accounts/accounts-database.ts`:
- Around line 458-464: Remove the redundant call to sanitizeStoredAccountComment
in the read path: since ensureAccountCommentsDatabaseLayout guarantees persisted
comments are sanitized and addAccountComment sanitizes before write, delete the
sanitizeStoredAccountComment(comments[i]) invocation in the loop that sets
comments[i].index and comments[i].accountId; keep the index and accountId
assignments intact and ensure no other callers rely on this extra sanitization
in the function that returns comments.
- Around line 432-441: The code is redundantly writing storageVersionKey =
commentStorageVersion on every add/edit; since
ensureAccountCommentsDatabaseLayout(accountId) already sets storageVersionKey,
remove the accountCommentsDatabase.setItem(storageVersionKey,
commentStorageVersion) calls from both Promise.all branches around
accountCommentsDatabase.setItem(String(...), comment) and
accountCommentsDatabase.setItem("length", ...), leaving only the item/length
writes; if you want to guard against external DB tampering instead, replace the
duplicate writes with a conditional check that verifies the current
storageVersionKey before proceeding.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5cc3c0e2-b4d9-4c60-8ed7-179230687b3c

📥 Commits

Reviewing files that changed from the base of the PR and between 2daada5 and 901887f.

📒 Files selected for processing (2)
  • src/stores/accounts/accounts-database.test.ts
  • src/stores/accounts/accounts-database.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/stores/accounts/accounts-database.test.ts

@tomcasaburi tomcasaburi merged commit 5f90193 into master Mar 20, 2026
5 of 7 checks passed
@tomcasaburi tomcasaburi deleted the fix/account-comments-compaction branch March 20, 2026 07:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Legacy accountComments data stays bloated after upgrading

1 participant