The PER-ENTRY MAP: for each claimed row of the input, call a generic action with that row and write its structured output into this node's attributes.
recompute_by :key, to: :transcripts, from: :key
per_key :summarise,
args: [text: :body],
fingerprint: [:body],
into: [summary: :summary]The loop every per-row node hand-writes — scope to the claimed keys, read
the rows, call something once per row, write the result — with the library
driving it. That matters beyond ergonomics: because the library now SEES
the input rows, it can fingerprint them and skip the call when nothing
that feeds it has changed. A run action is opaque by design (the library
passes keys and gets keys back), so no amount of declaration outside it
could do that.
fingerprint: names the input fields the result depends on. Their hash is
stored on the output row; when a recompute finds it unchanged, the action is
NOT called and the key is not reported changed. For an expensive or
non-deterministic action — an LLM call above all — that is the difference
between a whole-cell claim costing one call and costing all of them.
The action is an ordinary generic Ash action taking the row's fields as
arguments and returning a map. That it might be AshAi.Actions.prompt/2 is
the library's business not at all.