Skip to content

Wire TraceEmitter into ingest: shard_created/superseded events, trace_ref, per-run run_id, flip-panel provenance #7

Description

@aaronmarkham

Wire TraceEmitter into the ingest pipeline

Follow-up to PR #5. Zeitghost's landing page sells "hash-chained, tamper-evident traces," and spiritwriter.fabric.emitter.TraceEmitter provides exactly that — but it is currently unused in zeitghost. PR #5 made shards signed and the lineage load correct; this issue adds the trace chain on top so provenance is queryable and per-run auditable.

What's missing today

  • No trace events emitted anywhere in fetcher → bias → shards — no shard_created, no chain.
  • MemoryShard.trace_ref is always None (a shard can't point back to "which run/event produced me").
  • No per-ingest run_id, so an ingest cycle is anonymous — can't ask "show everything the 06:00 run created/changed."
  • shard_superseded events are never emitted. (PR shards: integrity & lineage-correctness (sign, collapse revisions, no default-fill bias) #5 landed the load-side latest-per-entity collapse, but not the corresponding trace event when a revision supersedes its parent.)
  • The card flip-panel shows model/agent atoms but not the signer thumbprint or a trace link.

Scope

  • Construct one TraceEmitter per zeitghost ingest run (one run_id, persisted JSONL alongside the shard store).
  • Emit shard_created per write (article_to_*_shard); set trace_ref via emitter.current_trace_ref() before store.put.
  • Emit shard_superseded(old, new) when a write chains onto a parent_shard_id (uses the lineage index already built in cli.py ingest).
  • Surface signer thumbprint (created_by) + the trace link in the card flip-panel (_shard_to_article already loads created_by/parent_shard_id; thread them to the template).
  • Keep it robust: emitter init is lazy/runtime, no file I/O at import (invariant Replace coming-soon placeholder with real spiritwriter.ai landing page #2); JSONL path defaults under the shard store dir.

Acceptance criteria

  • Each ingest run writes a hash-chained trace JSONL that passes emitter.verify_chain().
  • New shards carry a non-null trace_ref pointing at their shard_created event.
  • A re-analysis (see the reanalyze issue) emits shard_superseded linking new→old.
  • Flip-panel renders the signer thumbprint + a way to trace the shard's origin.
  • python -c "import zeitghost" stays clean from an empty cwd (no import-time I/O).
  • Tests cover: event emitted per write, trace_ref round-trips, chain verifies, supersede event on re-analysis.

Notes


Related: #8 (zeitghost reanalyze) is the workflow that produces the shard_superseded events this issue emits — land them together or #7 first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions