# `GgenIgniter.Reconcile`
[🔗](https://github.com/seanchatmangpt/ggen_igniter/blob/v26.9.8/lib/ggen_igniter/reconcile.ex#L1)

The one real reconciliation pipeline implementation: `Ontology.load!/1` ->
engine `prepare!/2` + `run/2` -> `Render.render/2` -> `Actuate.write_file!/3`
(or `Actuate.eval_code!/2` under `mode: eval`).

Extracted as a plain, `Mix.Task`/`Igniter`-free function specifically so it
can be called by both a CLI entry point (`Mix.Tasks.GgenIgniter.Sync`) and a
persistent in-process caller (`GgenIgniter.Controller`) without duplicating
the ontology-load/engine-run/render/actuate logic in two places. This
module is the shared implementation; `GgenIgniter.Controller` calls
`run/1` directly and adds only in-process state around it.

`Mix.Tasks.GgenIgniter.Sync` itself is left unchanged in this pass (a
separate, concurrent effort owns wiring the CLI to delegate here) -- so for
now this is a second entry point into the same real query engines/render/
actuate modules `sync.ex` already uses, not yet the CLI's own call path.
Once that wiring lands, `sync.ex`'s `igniter/1` and `GgenIgniter.Controller`
will both terminate in this one function.

## Deliberately bounded relative to `Mix.Tasks.GgenIgniter.Sync`

This is a bounded, real proof-of-concept slice covering exactly the spine
named for it: ontology-load -> engine-run -> render -> actuate. It does
NOT (yet) implement `Mix.Tasks.GgenIgniter.Sync`'s fuller surface:

  * No template frontmatter parsing (`GgenIgniter.Frontmatter`) -- a
    template's file content is used verbatim as the EEx body.
  * No `--for-each` multi-row fan-out -- exactly one render, exactly one
    actuation per `run/1` call.
  * No `inject: true` splice mode -- `mode: file` always dispatches to
    `Actuate.write_file!/3` (whole-file guarded write), never
    `Actuate.inject_content!/5`.

The `--pack`/`--pack-dir` convention (`GgenIgniter.Pack`) IS supported,
reused verbatim (not duplicated), since pack-shaped fixtures are the
natural unit a reconciliation controller tracks by key.

## Options (`opts`, a plain keyword list)

Mirrors the subset of `Mix.Tasks.GgenIgniter.Sync`'s own `--` flags this
function's bounded scope covers:

  * `:ontology` -- path to the Turtle ontology file. Falls back to the
    pack's `ontology.ttl` when `:pack`/`:pack_dir` is given.
  * `:query` -- one `"name=path.rq"` string, or a list of them (repeatable
    `--query` equivalent). Merged with pack-discovered `gates/*.rq` queries
    when a pack is given (pack queries first, explicit `:query` entries
    override same-named pack queries -- same tie-break as `sync.ex`).
  * `:template` -- path to the EEx template file. Falls back to the pack's
    single auto-discovered template when `:pack`/`:pack_dir` is given.
  * `:pack` / `:pack_dir` -- see `GgenIgniter.Pack`.
  * `:engine` -- `"oxigraph"` (default), `"sparql"`, or `"qlever"`.
  * `:mode` -- `"file"` (default) or `"eval"`.
  * `:out` -- required for `mode: "file"`; EEx-rendered against the query
    bindings (a static path with no `<%= %>` round-trips unchanged).
  * `:unless_exists`, `:skip_if`, `:dry_run` -- forwarded to
    `Actuate.write_file!/3` unchanged.

## Return value

`{:ok, result}` where `result` is a plain map (see `t:result/0`) describing
what actually happened -- real engine name, real resolved paths, real row
counts, and the real `Actuate` outcome/eval value. Raises on a real,
unrecoverable pipeline failure (bad ontology path, missing template, engine
error) -- this function is a faithful, un-defensive mirror of what the
pipeline actually does; a caller that needs a non-raising boundary (e.g.
`GgenIgniter.Controller`) wraps this call itself rather than this function
hiding real failures behind a swallowed error tuple.

# `result`

```elixir
@type result() :: %{
  engine: String.t(),
  ontology_path: String.t(),
  template_path: String.t(),
  query_count: non_neg_integer(),
  total_rows: non_neg_integer(),
  mode: :file | :eval,
  out_path: String.t() | nil,
  outcome: GgenIgniter.Actuate.outcome() | nil,
  value: term(),
  notice: String.t()
}
```

# `run`

```elixir
@spec run(keyword()) :: {:ok, result()}
```

Runs the real reconciliation pipeline for one set of `opts` (see moduledoc
for the accepted keys). Returns `{:ok, result()}`.

---

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