defmodule Mobus.Stepwise.Runtime do
@moduledoc """
Stable accessor helpers for stepwise runtime maps.
Provides deterministic inspection and mutation of runtime state
without depending on internal map structure. Orchestrators should
prefer these helpers over direct map access.
## Meta
The `:meta` field is an open map for orchestration metadata
(session IDs, DAG coordinates, tags, etc.). It survives
checkpoint/restore cycles and is passed read-only to capabilities.
runtime = Runtime.put_meta(runtime, :session_id, "sess-123")
Runtime.get_meta(runtime, :session_id)
#=> "sess-123"
"""
@doc "Returns the full `:meta` map from the runtime."
@spec meta(map()) :: map()
def meta(runtime), do: Map.get(runtime, :meta, %{})
@doc "Gets a single key from `:meta`, with optional default."
@spec get_meta(map(), term(), term()) :: term()
def get_meta(runtime, key, default \\ nil) do
runtime |> meta() |> Map.get(key, default)
end
@doc "Puts a single key into `:meta`."
@spec put_meta(map(), term(), term()) :: map()
def put_meta(runtime, key, value) do
Map.update(runtime, :meta, %{key => value}, &Map.put(&1, key, value))
end
@doc "Shallow-merges a map into `:meta`."
@spec merge_meta(map(), map()) :: map()
def merge_meta(runtime, %{} = map) do
Map.update(runtime, :meta, map, &Map.merge(&1, map))
end
@doc "Returns the `:context` map from the runtime."
@spec context(map()) :: map()
def context(runtime), do: Map.get(runtime, :context, %{})
@doc "Puts a single key into `:context`."
@spec overlay_context(map(), term(), term()) :: map()
def overlay_context(runtime, key, value) do
Map.update(runtime, :context, %{key => value}, &Map.put(&1, key, value))
end
@doc "Shallow-merges a map into `:context`."
@spec merge_context(map(), map()) :: map()
def merge_context(runtime, %{} = map) do
Map.update(runtime, :context, map, &Map.merge(&1, map))
end
@doc "Returns the `:artifacts` map from the runtime."
@spec artifacts(map()) :: map()
def artifacts(runtime), do: Map.get(runtime, :artifacts, %{})
@doc "Puts a single key into `:artifacts` (normalized via `Artifacts.merge/2`)."
@spec overlay_artifacts(map(), term(), term()) :: map()
def overlay_artifacts(runtime, key, value) do
alias Mobus.Stepwise.Artifacts
Map.update(runtime, :artifacts, %{}, fn arts ->
Artifacts.merge(arts, %{key => value})
end)
end
@doc "Returns the `:execution_id`."
@spec execution_id(map()) :: String.t() | nil
def execution_id(runtime), do: Map.get(runtime, :execution_id)
@doc "Returns the `:tenant_id`."
@spec tenant_id(map()) :: String.t() | nil
def tenant_id(runtime), do: Map.get(runtime, :tenant_id)
@doc "Returns the `:current_state`."
@spec current_state(map()) :: atom() | String.t() | nil
def current_state(runtime), do: Map.get(runtime, :current_state)
end