# `Statifier.Effect.Invoke`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.10.0/lib/statifier/effect/invoke.ex#L1)

Payload for `{:invoke, %__MODULE__{}}` - spec 6.4's `<invoke>`. Fields are
the element's own attribute names: `invoke_id` (`id`/`idlocation`,
generated when the element has none), `type`, `src`, `params` (the
resolved `<param>`/namelist payload), `content` (the resolved `<content>`
payload), `autoforward` (the `autoforward` attribute).

`<invoke>` is attached to a state, not to a block of executable content,
so this payload carries `state_index` - the invoking state's index
(constraint 3) - rather than a `c_index`; there is no content node to
identify. `state_index` is named apart from `src` (spec 6.4's URI
attribute) on purpose - the two fields are two letters apart with
unrelated meanings, and the original `source` name invited confusing them
(post-review correction).
`macrostep`/`microstep`/`round` are the counters as they stand when the
invoke is produced.

`invoke_index` is the invoking state's `invoke` list position (document
order) - the second half of `Statifier.Event.Cause.origin()`'s
`{:invoke, state_index, invoke_index}` identity, which the session needs
to name the failing element in an `error.communication` raised when it
cannot start the child (spec 3.12.2). `invoke_one/6` already has the value
in scope when it builds this struct; it was dropped rather than carried
until this payload had a caller for it, the same "no dead field"
discipline `origin`/`sendid` on `Statifier.Event` followed.

## `src` and `content` are two fields, not one

Spec 6.4 collapses the data channels an invoked service can receive to two
pairs treated identically: "these services MUST treat values specified by
`<param>` and namelist identically" and "MUST also treat values specified
by 'src' and `<content>` identically." The first pair shares one field
(`params`) because both lower to the same `Statifier.Machine.Param.t()`
shape and coerce through the same `Statifier.EventData.coerce({:params,
_})` ladder. The second pair cannot: `src` is a URI string the core never
dereferences (ADR-0031 - whether anything downstream fetches it is a later
concern), while `content` is markup or a value already resolved in hand,
coerced through `Statifier.EventData.coerce({:value, _})` or `{:text, _}`.
One field cannot hold both a reference and a resolved value without a
sentinel that collapses "no content, use src" with "content resolved to
nil" - so 6.4's "treat identically" becomes two fields the reader of the
effect payload treats identically, not one field that already has.

## `caller_context`

`caller_context` is the opaque host term the current macrostep's
triggering external event carried (ADR-0063, amended 2026-09-01),
copied off `Statifier.MachineState`'s transient slot at
construction - `nil` when no context was attached. An invocation
outlives the macrostep that started it exactly as a delayed send
outlives the macrostep that scheduled it, which is the reopening
trigger ADR-0063 named for a third durably-stored effect: a handler
that starts work asynchronously (a durable job, a queue write) stores
this term beside its own invocation row and restores it when the
result comes back, so the result event links back to the trace that
started the invocation - the parity with a durable timer's firing.
The library never reads the value.

# `t`

```elixir
@type t() :: %Statifier.Effect.Invoke{
  autoforward: boolean() | nil,
  caller_context: term(),
  content: term(),
  invoke_id: String.t(),
  invoke_index: non_neg_integer(),
  macrostep: non_neg_integer(),
  microstep: non_neg_integer(),
  params: term(),
  round: non_neg_integer(),
  src: String.t() | nil,
  state_index: non_neg_integer(),
  type: String.t() | nil
}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
