# Side-Effect Free Ephemeral Preview & Plugin Whitelisting

This document describes how we want to implement an ephemeral “preview” mode in the Lava REPL, where a user’s typed expression is evaluated in a temporary clone of the interpreter state, to show the result but without producing any real side effects.

Additionally, we plan to adopt a default deny approach: no bridging function is allowed in ephemeral mode unless it is explicitly declared “preview safe.” As we progress, we will refine or add “stub” logic for certain side-effectful calls if needed.

## Plan for Safe Ephemeral Preview with Whitelisting

1. Default Deny: By default, any plugin function that does not explicitly declare itself as ephemeral-safe will raise an error or be blocked in the ephemeral environment. This ensures we do not accidentally run side effects, spawn tasks, or do I/O in the “dry run.”
2. Opt-In “Preview-Safe” Declarations: Each bridging call that is purely functional (e.g., `math:plus`, `string:upper`) can be whitelisted so ephemeral calls proceed normally in the cloned environment. They either do not cause side effects at all, or we have carefully verified that ephemeral calls are harmless.
3. Side-Effectful Functions => Forbid or Stub: If a function definitely does real I/O or changes global state (like `file:write` or `math:srand`), ephemeral calls by default are forbidden. Over time, if we want ephemeral usage for certain calls, we can define a “stub” method. For example, `math:srand` might do nothing in ephemeral mode, returning a dummy result. The plugin itself provides that stub if needed.
4. Use `math` Plugin as Pilot: Because `math` is mostly pure, we can easily mark `math:plus`, `math:pow`, `math:sum`, etc. as ephemeral-safe. Meanwhile, we forbid ephemeral usage of `math:srand`. We then test ephemeral previews in real code, verifying that:
   - Ephemeral calls to `math:plus` in the cloned interpreter produce correct results but do not alter the real environment.
   - Calls to `math:srand` in ephemeral mode are blocked or stubbed, so we do not truly re-seed in the preview context.
   This pilot step ensures the system logic works before broadening the approach to all plugins.
5. Then, Tackle Each Plugin One by One: For each plugin:
   - List every bridging function.
   - Decide if it is pure, side-effectful, or conditionally side-effectful (e.g., if it calls a user-provided callback that might do I/O).
   - If side-effectful, consider whether providing a “stub” is beneficial (like returning a dummy result). If so, the plugin must provide that stub logic. Otherwise, ephemeral calls remain forbidden by default.
   - Mark each function with the appropriate preview safety classification, so ephemeral mode either calls it, stubs it, or forbids it.
6. Extra Considerations:
   - We may also need to handle user-supplied callbacks that might have side effects. For example, `array:map` is “pure” from the bridging perspective but the user’s function might do printing or file I/O. The ephemeral logic can skip or block side-effectful callbacks unless we stub them too.
   - We can eventually refine or enhance “stub” usage so ephemeral calls produce partial or indicative results (e.g., `file:read` ephemeral might return `"(mock file content)"` or an empty string so the user sees a “shape” of the result, not real I/O).
   - In many cases, just forbidding ephemeral usage is simpler than stubbing. Then, if the user tries `file:write` while typing, ephemeral mode says `"Cannot call file:write in ephemeral mode."` which is safer than doing real writes.

## Repeating the Explanation: “PreviewSafety” Flag

We previously described a pattern for each bridging function to define a metadata field, for example:

    enum PreviewSafety {
        Safe,    // no side effects -> ephemeral calls are allowed
        Forbid,  // definitely has side effects -> ephemeral calls blocked
        Stub,    // ephemeral calls do a custom stub method
    }

Under a default deny approach, if a function does not set `preview_safety = Safe` or `Stub`, it becomes Forbid by default. This ensures no bridging function can slip through ephemeral mode without an explicit “yes, we are safe” from the plugin developer.

## List of Functions by Plugin – Purity Classification

### Math Plugin

- `math:plus`, `math:pow`, `math:sqrt`, `math:sum`, etc. → Pure — ephemeral calls are fully safe.
- `math:rand` → can be maybe pure if it uses a local RNG that doesn't persist. But if it changes global seeds or a global RNG state, ephemeral calls must be forbidden or stubbed.
- `math:srand` → definitely Side-effectful (reseeding). Mark as `Forbid` in ephemeral mode or provide a no-op Stub.

### String Plugin

- `string:lower`, `string:upper`, `string:length`, `string:concat`, `string:to_string` → Pure.

### Array Plugin

- `array:lower`, `array:upper`, `array:keys`, `array:length`, `array:join` → Pure bridging logic.
- `array:filter`, `array:map`, `array:reduce`, `array:each` → Maybe because side effects can happen if the user’s callback is side-effectful. The bridging itself is pure, but ephemeral calls might need to block or stub user callbacks that do I/O.
- `array:assoc`, `array:nth`, `array:range`, `array:tail` → Pure.

### File Plugin

- `file:read`, `file:write`, `file:stream` → Side-effectful I/O. We forbid ephemeral usage or create stubs that return dummy data if needed.

### Net Plugin

- `net:fetch`, `net:ping`, `net:stop`, `poll_events`, `block_until_no_tasks`, `embedded_ping` → Side-effectful (networking, threads). Typically `Forbid` ephemeral usage or stub it.

### Process Plugin

- `process:info` → Potentially safe (it only reads system info). We might mark it `Safe` if we consider reading system info “pure enough.”
- `process:check_tasks` → Side-effectful, manipulates background tasks or polls them, so ephemeral usage might be `Forbid`.

### Test Plugin

- `describe`, `it`, `expect_equal`, `expect_not_equal`, etc. → Side-effectful, storing test state or printing. Typically forbid ephemeral usage or stub with no test state changes.

### Event Plugin

- `event:timeout`, `event:interval`, `event:stop`, `event:check_tasks` → Side-effectful scheduling tasks. Ephemeral usage is normally `Forbid` or maybe Stub to produce dummy handles.

### Date Plugin

- `date:timestamp`, `date:ms`, `date:micro` → Generally pure enough (just reading current time). We can allow ephemeral calls that simply read the system clock in the ephemeral environment.

## Conclusion

By default, we disallow ephemeral calls on all bridging functions except for those explicitly marked as `PreviewSafety::Safe` or `Stub`. We use the math plugin first as a test bed, since `math:plus` and others are pure numeric transforms. We’ll see ephemeral previews returning correct results with zero side effects. Functions like `math:srand` or `file:write` remain disallowed until/unless we create stub logic for ephemeral usage or decide to forgo ephemeral calls entirely.

Then, one plugin at a time, we’ll document each bridging function as purely functional, side-effectful, or conditionally so. If side-effectful but we want ephemeral usage, the plugin must provide a stub function (e.g., returning a dummy success) for ephemeral mode. Otherwise ephemeral calls remain blocked.

This approach ensures minimal rewriting of existing code, and a safe default deny policy so no new bridging calls are inadvertently run with side effects in ephemeral.