mix ggen_igniter.replay (ggen_igniter v26.9.8)

Copy Markdown View Source

Diagnostic task: mix ggen_igniter.replay <receipt_file> [--verify-only] [--json] [--manifest-dir DIR].

Loads ONE real GgenIgniter.Receipt (see that module's moduledoc for the on-disk format) and recomputes real, CURRENT hashes of the same inputs the receipt recorded, to answer: "has anything this receipt depended on drifted since it was written?"

receipt_file accepts either on-disk shape a receipt genuinely exists in:

  • A date-partitioned .jsonl partition (<base_dir>/.ggen_igniter/receipts/<yyyy-mm-dd>.jsonl, GgenIgniter.Receipt.path/2's real format) -- the LAST line (most recent attempt in that partition) is replayed.
  • A single JSON object file -- one receipt's GgenIgniter.Receipt.to_json_map/1 shape, decoded directly via Jason.decode!/1 (no receipt-specific wrapper). This is the shape a caller gets by extracting one line out of a .jsonl partition into its own file.

Exits 2 (invalid invocation) if the file does not exist or does not parse as either shape -- never guesses at a receipt's content.

What real drift this can and cannot detect

GgenIgniter.Receipt's on-disk schema (see that module's moduledoc) records, per attempt: recipe_key ("<template_path>=><out_template>"), files (the real output paths this attempt touched), pre_run_hash/post_run_hash (real content digests over exactly those files, via GgenIgniter.Receipt.hash_files/1), and a free-form metadata map -- on an :alive receipt written by GgenIgniter.Reactors.ReconcileReactor, metadata["graph_hash"] is a real "sha256:" <> hex digest of the ontology file that produced this run (see that module's finalize_evidence/1).

This task recomputes and compares exactly what the schema makes recomputable, and reports each as its own category rather than a single pass/fail:

  • "output state changed" -- GgenIgniter.Receipt.hash_files/1 is re-run over the receipt's own files list, RIGHT NOW, and compared to the receipt's recorded post_run_hash. A mismatch means at least one output this recipe wrote has been edited (or deleted) since this receipt was recorded.
  • "ontology changed" -- only checked when the receipt's recipe_key resolves to a GgenIgniter.Manifest entry recording a pack_dir (--manifest-dir's manifest, default File.cwd!()) AND the receipt's metadata["graph_hash"] is present. <pack_dir>/ontology.ttl (the --pack convention's fixed subpath -- see priv/ggen/CLAUDE.md) is re-read and re-hashed with the SAME "sha256:" <> hex algorithm the reactor used, and compared to graph_hash.

GgenIgniter.Receipt's schema does NOT record a standalone baseline hash of the template file, the gate query, the pack directory as a whole, the query engine's version string, or arbitrary run config -- there is no recorded value for this task to compare a recomputed hash AGAINST for those categories, so this task never fabricates a comparison for them. When the receipt's recipe_key names a template path, its CURRENT hash is still reported (--json's "template_path"/"template_current_hash" fields, or the human line template: <path> (no baseline recorded -- informational only)) so a human has the value on hand, but it is never counted as drift. If GgenIgniter.Receipt's schema grows recorded baselines for these categories, extend detect_drift/2 to compare them for real rather than widen this task's guesses.

Exit codes

  • 0 -- receipt loaded and compared; no real drift detected.
  • 1 -- receipt loaded and compared; at least one real drift category found.
  • 2 -- invalid invocation (missing/unreadable/unparsable receipt file, or a bad flag).

--verify-only performs only this read-only comparison (the only mode implemented so far; reserved for a future re-actuation mode, never implied as already present). --json prints the machine-readable report (%{"drift" => [...], "categories" => %{...}, "receipt" => %{...}}) instead of the human-readable lines.

Examples

mix ggen_igniter.replay .ggen_igniter/receipts/2026-08-27.jsonl

mix ggen_igniter.replay tmp/one_receipt.json --json --manifest-dir priv/ggen/audit-trail-pack