Skip to content

Fix effect cache returning nested-option sentinel for None#1284

Merged
DZakh merged 2 commits into
mainfrom
claude/fervent-darwin-7TxA0
Jun 5, 2026
Merged

Fix effect cache returning nested-option sentinel for None#1284
DZakh merged 2 commits into
mainfrom
claude/fervent-darwin-7TxA0

Conversation

@DZakh
Copy link
Copy Markdown
Member

@DZakh DZakh commented Jun 5, 2026

Summary

Fixes a regression in envio v3.1.0-rc.x where effects with optional outputs that resolve to None would leak the ReScript nested-option sentinel { BS_PRIVATE_NESTED_SOME_NONE: 0 } instead of undefined when served from the in-memory cache.

Root Cause

The in-memory effect cache stores option<output> for all effects. When an effect with optional output (e.g., option<bigint>) returns None, the cache stores Some(None). On cache hits, the code was wrapping this cached value in another Option.getUnsafe, which returned the raw Some(None) to the handler instead of unwrapping it to None/undefined.

Key Changes

  • InMemoryStore.res: Split getEffectOutput into two functions:

    • hasEffectOutput: Checks cache presence without wrapping the result
    • getEffectOutputUnsafe: Returns the raw cached output directly (never wrapped in Option), preventing the nested-option sentinel from leaking
  • LoadLayer.res: Updated cache access to use the new functions, eliminating the extra Option wrapping that was causing the regression

  • LoadLayer_test.res: Added regression test verifying that optional outputs resolving to None return undefined (not the sentinel) on cache hits

Implementation Details

The fix ensures the cache hit path mirrors the cache miss path: both return the raw effect output without additional option wrapping. For effects with optional outputs, None is now correctly represented as undefined in both paths.

https://claude.ai/code/session_01QV6rPnY9qR7RubvyACNUdb

Summary by CodeRabbit

  • Bug Fixes

    • Fixed in-memory effect output caching for optional types, addressing a regression in handling cached outputs.
  • Tests

    • Added test suite to verify effect cache behavior with optional outputs and ensure handlers execute only once on cache hits.

claude added 2 commits June 5, 2026 12:23
A cached effect with an optional output that resolves to None returns the
ReScript nested-option sentinel { BS_PRIVATE_NESTED_SOME_NONE: 0 } instead
of undefined on a cache hit, because the in-memory effect cache stores
option<output> and the hit path returns it without unwrapping the outer
option, leaking Some(None).
The in-memory effect cache stored option<output>; getEffectOutput wrapped
the raw output in Some(), encoding Some(None) as the nested-option sentinel
{ BS_PRIVATE_NESTED_SOME_NONE: 0 } for effects with an optional output that
resolved to None. getUnsafeInMemory unwrapped with Option.getUnsafe (an
identity), so the sentinel leaked to the handler instead of undefined.

Split getEffectOutput into hasEffectOutput (presence check) and
getEffectOutputUnsafe (raw output), mirroring InMemoryTable.Entity.getUnsafe,
so the output is never wrapped in an extra option.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c68d21b6-8056-47a1-8f07-22022e80da31

📥 Commits

Reviewing files that changed from the base of the PR and between 8b446eb and b070a3b.

📒 Files selected for processing (3)
  • packages/envio/src/InMemoryStore.res
  • packages/envio/src/LoadLayer.res
  • scenarios/test_codegen/test/LoadLayer_test.res

📝 Walkthrough

Walkthrough

This PR fixes a regression in envio v3.1.0-rc.x where optional effect outputs were incorrectly cached. The in-memory store's cache API was refactored from Option-based access to sentinel-based undefined values, LoadLayer was updated to use the new API, and a regression test was added.

Changes

Effect cache optional output handling

Layer / File(s) Summary
InMemoryStore effect cache API refactor
packages/envio/src/InMemoryStore.res
Introduced hasEffectOutput for presence checks and replaced getEffectOutput (returning option<effectOutput>) with getEffectOutputUnsafe (returning raw effectOutput with delete/absence mapped to %raw(\undefined`)` sentinel).
LoadLayer cache integration update
packages/envio/src/LoadLayer.res
loadEffect now uses InMemoryStore.getEffectOutputUnsafe and InMemoryStore.hasEffectOutput for cache access, replacing the prior Option.getUnsafe and Option.isSome patterns.
Effect cache optional output regression test
scenarios/test_codegen/test/LoadLayer_test.res
New test suite LoadLayer effect cache validates that effects returning option types are cached correctly; defines an effect with option<bigint> output returning None, calls loadEffect twice with the same inputs, and asserts both results are None with the handler running exactly once.

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 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 directly and specifically describes the main fix in the changeset: addressing an effect cache bug where optional outputs resolving to None incorrectly return a nested-option sentinel instead of undefined.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@DZakh DZakh enabled auto-merge (squash) June 5, 2026 13:06
@DZakh DZakh merged commit 2afcb2f into main Jun 5, 2026
14 of 15 checks passed
@DZakh DZakh deleted the claude/fervent-darwin-7TxA0 branch June 5, 2026 13:18
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