# `StatifierBlocks.Core.Assign`
[🔗](https://github.com/riddler/statifier_blocks/blob/v0.44.1/lib/statifier_blocks/core/assign.ex#L1)

`core.assign`: a leaf step that writes one literal to one datamodel path.

ADR-0002 decision 10 carries the row, through its 2026-08-29 amendment
(section G): `slots(config)` is `[]`, the config is `path` and `value`, and
the type has the single default outcome.

Two config fields: `path`, the datamodel location to write; `value`, the
literal to write there.

## `value` is SOURCE TEXT

`value` stores the literal exactly as an author would type it - `false`,
`42350`, `"manual_review"`, quotes included for a string - which is why
it lands in the compiled `expr` attribute unchanged. This is not a
shortcut around ADR-0002 decision 7's closed field-type set; it is the
same string-of-source-text rule this package already applies wherever a
literal has to survive verbatim.

Expressions are deliberately **not** supported in V1. The obvious next
`value` is one computed from datamodel state, and this module does not
build it: which expression language, how it would be stored, and whether
a block document may carry an expression that must be evaluated to
compile are jointly predicator-ex's and statifier-ex's calls, not this
package's. Literals only, said out loud here rather than discovered by a
reader.

## The declaration check is not here, and cannot be

`validate_config/1` is handed a config, not a document, so "is `path`
declared in the datamodel?" is a question this callback has no document
to answer against. That check, if a host wants one, is a document-level
pass over the whole tree - not this type's business.

It exists now, and this type reaches it by declaration rather than by
checking anything: `path` is declared `datamodel_path?: true` (ADR-0002
decision 7, amended 2026-08-29, which names this field as the key's
first consumer). `StatifierBlocks.Datamodel` is the document-level pass,
and it produces an `:info` advisory anchored on `path` when a host
supplies a datamodel that does not declare the value - and nothing at
all when the host supplies no datamodel. The verdict is unchanged
either way: an assign to an undeclared location still compiles.

What an assign to an undeclared location means, and how the write is
ordered against a state's other `onentry` content, are both statifier-ex's
and both open.

# `emit`

A compound state whose entry writes `expr` to `location` and immediately
goes final.

    <state id="s_blk_ASN" initial="s_blk_ASN__done">
      <onentry><assign expr="false" location="review.parked"/></onentry>
      <final id="s_blk_ASN__done"/>
    </state>

`Emission.element/3` normalizes attribute order alphabetically, so the
written attribute order is `expr` then `location` regardless of the
order they are passed here.

Both attributes are annotated: `location` from the `"path"` config
field, `expr` from the `"value"` field, verbatim - the `<assign>`
element is this block's own, but each attribute *value* is the author's
(ADR-0004 decision 9).

# `io`

`core.raise`'s `io/1` exactly, for `core.raise`'s reason: one outcome, so
there is no join to refuse and `produces` is absent rather than
`:unknown`. An assign reads nothing through the type flow either - its
input is a literal it carries - so there is no `consumes`.

# `sentence`

This block as one line of prose (ADR-0002's 2026-09-07 amendment).

The datamodel path written to, which is the whole of what this block
does that a reader scanning a list cares about. The literal is left out:
it is one field away in the inspector, and a value long enough to be
interesting is long enough to bury the path.

    iex> StatifierBlocks.Core.Assign.sentence(%{"path" => "cards.settlement.status"})
    "Set cards.settlement.status"

    iex> StatifierBlocks.Core.Assign.sentence(%{})
    "Set a value"

---

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