# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.7] - 2026-06-26
### Added
- **Injector strict_mode support**: `OrchidSymbiont.Hooks.Injector` now reads `:strict_mode` from the workflow baggage. When `strict_mode: true`, the resolver will not fall back to the global catalog, ensuring strict multi-tenant isolation at the hook level.
```elixir
Orchid.run(recipe, params,
baggage: %{scope_id: "tenant-1", strict_mode: true}
)
```
## [0.2.5] & [0.2.6] - 2026-04-24
### Enhenced
- **Documents**: Updated documents.
## [0.2.4] - 2026-03-26
### Enhenced
- **Symbiont ID Type**: Now Symbiont's ID also support binary. *If the name is dynamically generated in your application, it is recommended to use binary instead of atom to avoid memory leaks.*
### Changed
- **Scopa Name Declaration**: Now we use `:scope_id` instead `:session_id` to seperate domains.
### Migration Guide (0.2.3 -> 0.2.4)
```elixir
# Before
{OrchidSymbiont.Runtime, session_id: "my_session"}
OrchidSymbiont.register("my_session", :worker, {MyWorker, []})
Orchid.WorkflowCtx.put_baggage(:session_id, "my_session")
# After
{OrchidSymbiont.Runtime, scope_id: "my_session"}
OrchidSymbiont.register("my_session", :worker, {MyWorker, []})
Orchid.WorkflowCtx.put_baggage(:scope_id, "my_session")
```
## [0.2.3] - 2026-03-25
### Fix
- Fixed a bug where adding options other than session_id would prevent the creation of additional processes.
## [0.2.2] - 2026-03-25
### Added
- **Strict Mode**: A new `strict_mode: true` option has been added to `OrchidSymbiont.Resolver.resolve/3`. When enabled, if the corresponding service blueprint is not found in the current Session's Catalog, an error will be thrown directly, and **there will be no fallback** to the global Catalog, thus ensuring stricter multi-tenant security isolation.
- **State Backup and Restore**: The `dump/1` and `restore/2` methods have been added to `OrchidSymbiont.Catalog` for easy exporting and restoring of the current Catalog's state.
### Changed
- **[Architecture Refactoring] True Session Isolation**: The Session's supervised tree model has been refactored. Now, when you start a Session using `OrchidSymbiont.Runtime`, it launches a dedicated `OrchidSymbiont.Catalog` process for that Session. Registration states between different Sessions are now truly physically isolated, instead of being distinguished by tuples `{{session_id, name}, val}` in the global state.
- **[Performance Optimization] Catalog Underlying Replacement**: The underlying implementation of `OrchidSymbiont.Catalog` has been simplified from `GenServer` to `Agent`, making it more lightweight and better suited to its pure state storage nature.
- ****Startup Layer Optimization**: The application startup process has been streamlined. The bloated list of child processes in OrchidSymbiont.Application has been removed. The startup logic for global services (`Registry`, global `Catalog`, `DynamicSupervisor`, `Preloader`) is now consolidated and wrapped within the `:global` initialization strategy of `OrchidSymbiont.Runtime`.
### Removed
- Removed `clear/0` and `clear_session/1` in `OrchidSymbiont.Catalog` module. Since Sessions now manage their lifecycle through an independent supervision tree, their internal Catalog processes are automatically destroyed and reclaimed when the corresponding `Runtime` terminates, eliminating the need for manual cleanup.
## [0.2.1] - 2026-03-24
### BREAKING CHANGE
- Move legacy module name `Orchid.Symbiont` into `OrchidSymbiont`.
### Fixed
- **Atom Exhaustion Vulnerability**: Resolved a critical memory leak issue where dynamic session IDs (atoms) were never garbage collected, potentially causing VM crashes in long-running multi-tenant applications.
### Changed
- **Session ID Type**: Changed `session_id` from `atom()` to `binary()` (String). Example: `:project_a` → `"project_a"`.
- **Unified Registry Architecture**: Replaced per-session Registry/Catalog/Preloader processes with a single global Registry using compound keys `{session_id, name}`. This significantly reduces process overhead for high-session-count scenarios.
- **Runtime Implementation**: `Orchid.Symbiont.Runtime` now uses `DynamicSupervisor` directly instead of wrapping it in a `Supervisor`.
- **Simplified Naming Module**: Refactored `Orchid.Symbiont.Naming` with cleaner API:
- `get_registry/0` - Returns the unified registry
- `session_supervisor/1` - Returns via tuple for session supervisor
- `worker/2` - Returns via tuple for session workers
### Removed
- Per-session Registry processes (now uses global with compound keys)
- Per-session Catalog processes (now uses single global instance)
- Per-session Preloader processes (now uses global `Orchid.Symbiont.Preloader`)
- `Naming.registry/1`, `Naming.catalog/1`, `Naming.preloader/1` functions
### Migration Guide (0.2.0 → 0.2.1)
```elixir
# Before (0.2.0)
{Orchid.Symbiont.Runtime, session_id: :my_session}
Orchid.Symbiont.register(:my_session, :worker, {MyWorker, []})
Orchid.WorkflowCtx.put_baggage(:session_id, :my_session)
# After (0.2.1)
{OrchidSymbiont.Runtime, session_id: "my_session"}
OrchidSymbiont.register("my_session", :worker, {MyWorker, []})
Orchid.WorkflowCtx.put_baggage(:session_id, "my_session")
```
## [0.2.0] - 2026-01-04
### Added
- **Session Isolation (Multi-Tenancy)**: Introduced the ability to run completely isolated sandboxes of Symbiont processes using `session_id`. Perfect for concurrent workflows or multi-tenant SaaS architectures without PID conflicts.
- **Dynamic Supervision Trees**: `Orchid.Symbiont.Runtime` can now be started multiple times under different namespaces by passing `[session_id: :your_session_name]`. Each session gets its own isolated `Registry`, `DynamicSupervisor`, `Catalog`, and `Preloader`.
- **Smart Catalog Fallback**: Added a hierarchical lookup mechanism in `Orchid.Symbiont.Catalog`. If a blueprint is not found in a session-specific catalog, it will automatically fall back to the global catalog. *(Write blueprints once globally, run instances locally!)*
- **New Naming Module**: Added `Orchid.Symbiont.Naming` to handle dynamic process registration routing transparently.
### Changed
- **Injector Hook Upgraded**: `Orchid.Symbiont.Hooks.Injector` now automatically extracts `:session_id` from the `Orchid.WorkflowCtx` baggage and routes the process resolution to the corresponding session's registry.
- **API Enhancements**: `Orchid.Symbiont.register` and `Orchid.Symbiont.Resolver.resolve` now accept an optional `session_id` parameter. *(Fully backward compatible with global singleton usage)*.
- **Dependencies Bump**: Updated `orchid` to `0.5.6`, `telemetry` to `1.4.1`, and `ex_doc` to `0.40.1`.
## [0.1.4] - 2026-01-03
### Added
- **Global Mapping Support**: `Orchid.Symbiont.Hooks.Injector` now supports resolving symbiont aliases from the `Orchid.WorkflowCtx` baggage.
- **Hierarchical Resolution**: Symbiont mappings are now merged from two levels:
1. **Global**: Set via `Orchid.WorkflowCtx.put_baggage(ctx, :symbiont_mapper, [...])`.
2. **Local**: Set via `step_opts`.
*Note: Local step-specific mappings will override global mappings if both define the same logical name.*
### Fixed
- Internal `get_headers` logic in the Injector hook to properly handle the workflow context.
## [0.1.3] - 2026-01-02
### Changed
- **Breaking**: Renamed `Orchid.Symbiont.Step.get_required/0` with old name called `get_step_required_mapper/0` for shorter and cleaner API usage.
- `Orchid.Symbiont.call/3` now uses `apply/3` for dynamic module invocation.
### Added
- `Orchid.Symbiont.preload/1` now accepts a single symbiont name in addition to a list of names.
## [0.1.2] - 2026-01-02
### Dependencies
- update orchid's version to `0.5`
## [0.1.1] - 2025-12-27
### Dependencies
- use a looser version constraint for better compatibility with future patch releases
## [0.1.0] - 2025-12-26
### Added
- **Initial Release**: Launched `OrchidSymbiont` as the official process management extension for the [Orchid](https://hex.pm/packages/orchid) workflow engine.
- **Lazy Loading**: Introduced a mechanism to start GenServers (Symbionts) only when requested by a workflow step, optimizing resource usage for heavy tasks (e.g., ML models, DB connections).
- **Dependency Injection**: Added `Orchid.Symbiont.Hooks.Injector` to automatically resolve and inject running process references (PIDs) into Steps implementing the `Orchid.Symbiont.Step` behavior.
- **Lifecycle Management (TTL)**:
- Implemented an `Idle Shutdown` mechanism using a transparent Wrapper/Proxy pattern.
- Workers configured with a `:ttl` option will automatically terminate after a period of inactivity to free up resources.
- The Wrapper ensures request forwarding is transparent and handles timeouts (`:infinity` internally) correctly to support long-running tasks.
- **Registry & Catalog**:
- `Orchid.Symbiont.register/2`: API to define blueprints for services, supporting both standard startup and TTL-enabled modes.
- Built-in `Registry` for name resolution and idempotency check (preventing duplicate startups).
- **Integration**:
- Provides `Orchid.Symbiont.Step` behavior requiring `required/0` (dependencies) and `run_with_model/3` (execution logic).
- Added helper `Orchid.Symbiont.call/3` for ergonomic synchronous communication with Symbionts.
### Dependencies
- Requires **Orchid ~> 0.4.0** (utilizes the new Context and Hook architecture).