Fix replacing a trie key mutates the original and increments size - #7028
Conversation
🦋 Changeset detectedLatest commit: a195aa0 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 adds only a failing regression test. The underlying bug in Trie.insert is still present on main, so merging as-is would ship a red test suite. The test itself is well-targeted and correctly fails, but it needs the companion implementation fix in packages/effect/src/internal/trie.ts.
Reviewed changes
This run reviewed the single-file diff at packages/effect/test/Trie.test.ts, which adds one focused regression test for Trie.insert replacing an existing key. The test asserts that a replacement leaves the original trie unchanged and preserves Trie.size. I also inspected the current Trie.insert implementation in packages/effect/src/internal/trie.ts to confirm the root cause described in the PR still exists.
- Added regression test for immutable key replacement and preserved size.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏
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
This run reviewed the incremental delta since the prior pullfrog review at 217ac027b. The previously failing regression test is now paired with the implementation fix and a changeset.
- Fixed
Trie.insertimmutability inpackages/effect/src/internal/trie.ts: the terminal node is copied rather than mutated in place, so replacing a key no longer corrupts the original trie. - Preserved size on replacement: the new root count is decremented when the key already exists, so
Trie.sizestays the same. - Added a patch changeset for
effectdocumenting the bug fix.
Validation run: pnpm test --run test/Trie.test.ts, pnpm lint-fix, and pnpm check all pass.
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Summary
Inserting an existing key mutates the value visible through the original
Trieand increments the replacement trie's size. Persistent snapshots are corrupted and cardinality reports a new entry where only a value replacement occurred.Note
This PR includes both the focused regression test and the implementation fix.
Replacing a trie key mutates the original and increments size
Module:
effect/TrieAudit ID:
effect-7bd661243f3c2d73Severity / confidence: high / high
What happens
Inserting an existing key mutates the value visible through the original
Trieand increments the replacement trie's size. Persistent snapshots are corrupted and cardinality reports a new entry where only a value replacement occurred.Why it happens
The insertion traversal assigns
n.value = { value }directly on the existing terminal node before path copying and computescountasroot.count + 1unconditionally. The rebuilt path therefore shares the already-mutated leaf with the input and carries an inflated count for replacements.Expected behavior
Trie.insert(self, key, value)must return a persistent trie, leaveselfunchanged, and preserveTrie.sizewhenkeywas already present.Relevant implementation
These links and excerpts are pinned to audit base
17f0b91a243ccfe4a38d27debdc983adf434e738.packages/effect/src/Trie.ts:130-414View problematic code at
packages/effect/src/Trie.ts:130-179View exact lines on GitHub
Excerpt truncated. Open the complete packages/effect/src/Trie.ts:130-414 range.
Reproduction
pnpm test --run packages/effect/test/Trie.test.tsObserved failure: Focused contract assertion failed against 17f0b91, demonstrating: Replacing a trie key mutates the original and increments size.
Implementation
Trie.insertnow copies the terminal node instead of mutating it in place, and only increments the trie count when the key did not already have a value.Validated locally with:
pnpm test --run packages/effect/test/Trie.test.ts pnpm lint-fix pnpm checkAudit provenance
17f0b91a243ccfe4a38d27debdc983adf434e73817f0b91a243ccfe4a38d27debdc983adf434e738effect-7bd661243f3c2d73a195aa044Closes EFF-468