Skip to content

feat(db): add excluded_problems store to permanently filter not-relevant problems #257

@smithrashell

Description

@smithrashell

Problem

When a user skips a problem with reason not_relevant, the current implementation only weakens the graph relationships (-0.8). This is probabilistic — the problem can still resurface in future sessions because weakening edges reduces selection likelihood but does not prevent reselection.

There is no deterministic way to permanently exclude a problem today.

Why Not Existing Stores

  • standard_problems — pure LeetCode reference data (id, title, slug, difficulty, tags). Must not hold user data.
  • problems — user attempt-backed records. A problems record is only created when an attempt is created, so a record is not guaranteed to exist at skip time. A user can see a problem in their session and skip it as not_relevant before ever submitting an attempt.
  • problem_relationships — graph edges between two problems. A single problem can have N relationship records (one per connection). Writing a flag here requires N writes and N reads to answer a simple yes/no question.
  • user_actions — append-only event log (autoIncrement key). Reconstructing current state from events is the wrong data shape for a flag lookup.

Proposed Solution

Add a dedicated excluded_problems store.

Schema

keyPath: leetcode_id        ← O(1) lookup at session assembly time
fields:
  leetcode_id  number       ← primary key, matches standard_problems.id
  excluded_at  string       ← ISO timestamp
  reason       string       ← 'not_relevant' (extensible if other exclusion flows added later)

No additional indexes needed beyond the keyPath — lookups will always be by leetcode_id.

DB Version Bump

Current version: 47 → new version: 48

A migration entry is required in src/shared/db/migrations/ and storeCreation.js.

Changes Required

1. DB layer

  • Add createExcludedProblemsStore() to src/shared/db/core/storeCreation.js
  • Register the store in the STORES array and validateDatabaseIntegrity required stores list in src/shared/db/index.js
  • Add migration for version 48 in src/shared/db/migrations/
  • Add read/write helpers (e.g. excludeProblem(leetcodeId, reason), isExcluded(leetcodeId), getExcludedIds()) to a new src/shared/db/stores/excludedProblems.js

2. Skip handler

In src/background/handlers/problemHandlers.jsapplySkipReasonEffects:

case 'not_relevant':
  if (hasRelationships) {
    const weakenResult = await weakenRelationshipsForNotRelevant(leetcodeId);
    result.graphUpdated = weakenResult.updated > 0;
  }
  await excludeProblem(leetcodeId, 'not_relevant');   // ← add this
  await SessionService.skipProblem(leetcodeId);
  break;

Graph weakening is kept as a secondary signal. The store write is the hard guarantee.

3. Session assembly

Filter excluded problems before building the session. The exact location depends on where standard_problems records are fetched and filtered for session selection — excludeProblem IDs should be loaded once and applied as a filter at that point.

Outcome

Scenario Before After
Problem skipped as not_relevant Graph weakened, may resurface Graph weakened + permanently excluded
Problem reappears after not_relevant skip Possible Impossible
Lookup cost at session assembly N/A O(1) per problem via keyPath

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions