mix ggen_igniter.doctor (ggen_igniter v26.9.8)

Copy Markdown View Source

Diagnostic task: mix ggen_igniter.doctor [--pack NAME | --pack-dir DIR] [--engine sparql|qlever] [--store-id ID] [--fix] [--strict].

Runs a fixed checklist of real checks (no fabricated pass output):

  1. Elixir/OTP version satisfies this project's mix.exs requirement (~> 1.17, OTP >= 25).
  2. Required deps (rdf, sparql, igniter, and gno when --engine qlever) are loaded with resolvable :vsn.
  3. Advisory for the known sparql 0.3.12 FILTER NOT EXISTS + BIND inside UNION bug.
  4. The CURRENT project's own mix.exs doesn't restrict its direct igniter dependency with :only (real conflict: ggen_igniter needs igniter unconditionally, so a consumer's own only: [:dev, :test]-restricted declaration makes Mix's resolver refuse). --fix relaxes it for real; without --fix this is diagnostic only.
  5. Same as 4, for sourceror (only applicable if the current project declares it directly at all).
  6. config :dcatr, env: ... is present in the current project's config/config.exs whenever :gno/:dcatr are in its dependency tree (:gno's Fuseki adapter raises at compile time without it). --fix adds the missing entry for real.
  7. Every Ash domain module (use Ash.Domain) found under the current project's lib/ is registered in config :OTP_APP, ash_domains: [...] (an unregistered domain is a hard compile error under mix compile --warnings-as-errors). --fix registers any missing one(s) for real.
  8. (only with --engine qlever or a pack ontology naming a gnoa:Qlever store via --store-id) the QLever endpoint is really reachable via a real ASK query.
  9. Pack ontology.ttl exists and parses as valid Turtle.
  10. At least one gate query (gates/*.rq) is present.
  11. At least one template (templates/*.{eex,tmpl}) is present.
  12. Every gate query is syntactically valid SPARQL (parse-only, no execution).
  13. Target (cwd) git status -- clean vs dirty is reported, never fails the run by itself.
  14. native/ggen_graph_nif is compiled and up to date: the built priv/native/ggen_graph_nif.so exists and is newer than every .rs source file under the crate (a fast mtime proxy); if the .so is missing or stale, falls back to a real cargo build --quiet and reports real stderr on failure.
  15. GgenIgniter.Query.Oxigraph actually works: runs a real SELECT * WHERE { ?s ?p ?o } SPARQL query against a tiny real in-memory %RDF.Graph{} through the native oxigraph engine and confirms it returns without raising -- a functional smoke test, not just "does the NIF load".
  16. (only with --hex-check, off by default) hex-publish readiness: shells out to a real mix hex.build and reports its real output, plus checks mix.exs's package[:description] and package[:licenses] are both present and non-empty.
  17. check_version_policy: mix.exs's version: literal is a projection of this project's real, observed versioning convention rather than an independently maintained field. This repo has no git tags at all (confirmed via git tag --list returning empty), so CHANGELOG.md's topmost ## vX entry heading is the only real, standing record of "what the current version is" -- a calendar-ish YY.M.D string (e.g. 26.8.27 for 2026-08-27), matched verbatim against mix.exs's version:. Reports MATCH or a clearly-named MISMATCH; never silently rewrites mix.exs. --fix corrects it for real only when the derivation is unambiguous (a single topmost ## vX heading found and mix.exs's version: is a simple string literal); an ambiguous shape (no CHANGELOG.md, no ## v heading, or a non-literal version:) is reported as informational-only, never guessed at.
  18. GgenIgniter.Lock's real cross-process .ggen_igniter/.sync.lock file (see GgenIgniter.Lock's moduledoc) is checked against the CURRENT project (File.cwd!()): absent is (no lock held); present and younger than GgenIgniter.Lock's own 5-minute stale threshold is info naming the real holder marker (pid=... node=... at=...) written by GgenIgniter.Lock.acquire/2 -- a live/recent lock held by a real, still-running mix ggen_igniter.sync/ .replay invocation is not a problem; present and older than 5 minutes is a real warning naming the exact real remedy (the next acquire/2 call anywhere against this project automatically deletes it -- GgenIgniter.Lock has no --force-unlock flag, so this never invents one). Never :error: a held lock, stale or not, is advisory information about another invocation, not a defect in the current project.

Checks 9-12 only run when --pack/--pack-dir is given; without it, only checks 1-3 and 4-7 (and 8, if --engine qlever was explicitly passed with a graph-free reachability check is not possible, so 8 is skipped) run. Checks 4-7, 13-15, 17, and 18 always run. Check 16 only runs with --hex-check (it shells out to mix hex.build, which is slow, so it stays off by default to keep mix ggen_igniter.doctor fast).

--fix

Checks 4-7 and 17 are real fixes (GgenIgniter.DoctorFixes), not just diagnostics: passing --fix applies each detected, safely-recognized fix directly to the CURRENT project (File.cwd!()) -- the real consumer app doctor is running inside, never a test-harness scaffold -- and the check line reports exactly what changed (prefixed FIXED:), or that there was nothing to fix. Without --fix, these checks are read-only: a real, fixable problem is reported as a warning naming the exact fix to run; a real problem whose exact shape isn't safely automatable is reported as a error rather than silently skipped or guessed at.

--strict

Without --strict, only :error-level checks fail the run (exit 1); :warn-level checks (e.g. "git dirty", "not a git repo", a --fix-able hygiene gap reported without --fix) are advisory only and never affect the exit code. With --strict, any check currently reporting :warn also fails the run (exit 1) -- each such line is suffixed [STRICT] in human output (and carries "strict_failure": true in --json output) so it's clear which failures are strict-mode-only and would pass under the default mode.

Examples

mix ggen_igniter.doctor

mix ggen_igniter.doctor --pack audit-trail-pack --json

Exit codes

  • 0 -- all checks passed (under --strict, this also means no :warn findings).
  • 1 -- ran the full checklist and at least one check came back :error (or, under --strict, at least one came back :warn).
  • 2 -- invalid invocation/configuration: an unrecognized flag, --engine not one of oxigraph/sparql/qlever, or both --pack and --pack-dir given at once. The checklist never runs.
  • 3 -- an explicitly requested capability isn't available on this toolchain (today: --hex-check without the hex Mix archive installed). The checklist never runs.
  • 4 -- blocked by authority/lock/environment (today: --fix unable to get exclusive access to the current project directory). The checklist never runs.

DX flags

--help/-h and --version/-v print and exit 0 immediately, before any checks run. --json emits a single JSON object (checks, ok, exit_code) instead of the human checklist -- exit code semantics above are unchanged either way. --quiet/-q suppresses passing () lines; warnings/errors and the summary line still print. --verbose and --no-color are accepted for consistency with other mix ggen_igniter.* tasks; this task's output is always plain // glyphs with no ANSI color and no currently-defined extra verbose detail, so both are no-ops today.