Skip to content

cacheable - fix: count falsy values in delete stats - #1743

Merged
jaredwray merged 1 commit into
mainfrom
claude/great-archimedes-37p526-delete-stats
Oct 18, 2026
Merged

jaredwray merged 1 commit into
mainfrom
claude/great-archimedes-37p526-delete-stats

Conversation

@jaredwray

Copy link
Copy Markdown
Owner

Please check if the PR fulfills these requirements

  • Followed the Contributing guidelines and Code of Conduct
  • Tests for the changes have been added (for bug fixes/features) with 100% code coverage.

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)

Bug fix. This is a follow-up to #1742. The review of #1742 found this bug.

Problem

When stats are on, Cacheable.delete(key) read the value with get(). It changed the stats only when the value was truthy. Thus a cached 0, "", false, null, or undefined did not decrease count, ksize, or vsize, and did not increase deletes. take(key) calls delete, so it had the same bug.

Example: set("hits", 0), then delete("hits"). After this, stats.count stays at 1.

deleteMany does not have this bug after #1742. So delete and deleteMany gave different stats for the same keys.

Change

packages/cacheable/src/index.ts, deleteInternal:

  • It reads the raw entry with this._primary.get(key, { raw: true }). It changes the stats for each entry that is in the cache. It skips a missing key.
  • It sizes entry.value, which is the value that set sized.
  • It does not use getRaw(). Keyv get() catches a store error, but getRaw() does not. With getRaw(), a failed primary read makes delete() reject before the delete starts.
  • I removed the /* v8 ignore next */ comment. The tests now reach both branches.

Verification

  • pnpm test passes in packages/cacheable, packages/cache-manager, and packages/flat-cache, with a local Redis. I did not run packages/net, because its tests need the mockhttp container.
  • pnpm build passes in packages/cacheable.
  • Coverage of cacheable/src/index.ts is the same as on main. The only branch that is not covered is line 422 (the sync setter). This PR does not change it.
  • A Fable code review found no defects in the fix. It also ran two mutation checks on the extended test (results below).

Test audit:

  • Extended cacheable stats enabled > should get stats on delete. This test owns the stats contract of delete, so I extended it and did not add a near-duplicate.
    • Contract: delete changes the stats for each key that is in the cache, for all values. A missing key does not change the stats.
    • The test deletes keys with the values "value", 0, "", false, null, and undefined, and one missing key. It compares ksize and vsize with a cache that holds only the remaining key.
    • It fails on main (deletes is 1, expected 6). It also fails with get() and an !== undefined check (deletes is 5, expected 6), because of the cached undefined value.
  • Added cacheable stats enabled > should delete with stats when the primary store read fails.
    • Contract: a store error on the stats read does not stop delete. This was the behavior on main.
    • It fails if a change uses getRaw() for the stats read ("promise rejected ... instead of resolving"). The first version of this fix used getRaw(), so this regression is credible.
    • No other test covers a failed primary read in delete. The test mocks only the store get, which is the real boundary for this error.

Generated by Claude Code

Before, delete read the value with get() and changed the stats only for
a truthy value. A cached 0, "", false, null, or undefined value did not
decrease count, ksize, or vsize, and did not increase deletes.

Now delete reads the raw entry with get(key, { raw: true }). It changes
the stats for each entry that is in the cache. It does not use getRaw(),
because getRaw() does not catch a store error. With getRaw(), a failed
primary read stops the delete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQyS4TFa7JFA5PEcKuLj4T
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T01:05:38.100843Z e293224 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codecov

codecov Bot commented Oct 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (dd4562d) to head (e293224).

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #1743   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           29        29           
  Lines         3615      3620    +5     
  Branches       810       811    +1     
=========================================
+ Hits          3615      3620    +5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jaredwray
jaredwray merged commit f885a2e into main Oct 18, 2026
15 checks passed
@jaredwray
jaredwray deleted the claude/great-archimedes-37p526-delete-stats branch October 18, 2026 16:12
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.

2 participants