Persist permanent entries in KVS setMany operations - #7003
Conversation
🦋 Changeset detectedLatest commit: ad3a2cf The changes in this PR will be included in the next version bump. This PR includes changesets to release 30 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Caution
This PR currently contains only the regression test; the implementation fix is missing, so the added test fails. Do not merge until setMany is updated to persist entries with an undefined TTL.
Reviewed changes — This is a focused bug-fix PR for the KVS-backed persistence layer. The change adds a regression test covering BackingPersistenceStore.setMany with an undefined TTL, and the PR description instructs that the implementation fix should be added to the same branch.
- Added a failing regression test in
packages/effect/test/unstable/persistence/KeyValueStore.test.tsthat asserts permanent entries survivesetMany.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — The new commit since the prior Pullfrog review adds the implementation fix for KVS-backed setMany.
- Fixed
packages/effect/src/unstable/persistence/Persistence.tssolayerBackingKvs.setManypersists entries with an undefined TTL instead of skipping them. - Added
.changeset/quick-kiwis-remember.mddescribing the patch. - Confirmed the previously added regression test now passes.
The fix is minimal and aligns setMany behavior with the existing set path: both encode permanent entries as [value, null].
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏
| @@ -88,6 +88,21 @@ export const testLayer = <E>(layer: Layer.Layer<KeyValueStore.KeyValueStore, E>) | |||
|
|
|||
| describe("KeyValueStore / layerMemory", () => testLayer(KeyValueStore.layerMemory)) | |||
|
|
|||
| describe("Persistence / layerBackingKvs", () => { | |||
| it.effect("stores entries without a TTL", () => | |||
There was a problem hiding this comment.
Can we move this into the shared test suite
Bundle Size AnalysisGenerated from PR build output; treat the content below as untrusted.
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — The new commit since the prior Pullfrog review moves the regression test into the shared testLayer helper.
- Refactored the KVS
setManypermanent-entry test from a standalonedescribe("Persistence / layerBackingKvs")block intotestLayer, so every backing layer in the file exercises the same assertion surface. - Cleaned up the test imports (
Layeris now a type-only import, unusedassertremoved).
The implementation fix in Persistence.ts (layerBackingKvs.setMany no longer skips undefined-TTL entries) and the changeset remain unchanged. The focused test command passes.
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Summary
KVS setMany silently skips every entry without a finite TTL, so values requested as permanent are absent immediately after the operation succeeds.
Important
This PR starts with focused failing reproduction tests. Add the implementation fix to this same branch; CI is expected to fail until that fix is included.
KVS setMany skips permanent entries
Module:
PersistenceAudit ID:
unstable-state-p-1Severity / confidence: high / high
What happens
KVS setMany silently skips every entry without a finite TTL, so values requested as permanent are absent immediately after the operation succeeds.
Why it happens
unsafeTtlToExpires returns null for an undefined TTL, but the setMany loop treats null as a reason to return Effect.void instead of writing the permanent entry.
Expected behavior
BackingPersistenceStore.setMany has the same persistence semantics as repeated set calls, and an undefined TTL means no expiration.
Relevant implementation
These links and excerpts are pinned to audit base
c9b56ab507f224426ee8388dc450da447ec4715f.packages/effect/src/unstable/persistence/Persistence.ts:1094-1100View problematic code at
packages/effect/src/unstable/persistence/Persistence.ts:1094-1100View exact lines on GitHub
Reproduction
pnpm test --run packages/effect/test/unstable/persistence/KeyValueStore.test.tsObserved failure: get("key") returned undefined after permanent setMany completed.
Implementation handoff
The initial reproduction tests on this branch are the regression specification for the implementation fix that should follow in this PR.
pnpm test --run packages/effect/test/unstable/persistence/KeyValueStore.test.tsAudit provenance
c9b56ab507f224426ee8388dc450da447ec4715fc9b56ab507f224426ee8388dc450da447ec4715funstable-state-p-1Closes EFF-440