Drivine Collector Trace Store
Drivine / Neo4j CollectorTraceStore: persists the multi-signal collector's inspectable decision trace as plain property-bag nodes, so a graph deployment keeps it durable and queryable instead of losing it to a process restart (the in-memory store's tradeoff).
Graph model — every trace node carries both runId and contextId so deleteTracesForContext can erase a context's rows in one pass per label, and every write MERGEs on a natural key so a replayed run updates in place instead of duplicating:
(:CollectorTraceRun {runId, contextId, createdAt})— written by recordRunContext; every other write MATCHes this node to copy itscontextId, socontextIdis single-sourced here rather than threaded through every record call.(:CollectorCandidateEdge {id, runId, contextId, anchorId, memberId, aggregateScore, vetoed})withid = "runId|anchorId|memberId", plus one child(:CollectorSignalScore {id, runId, contextId, signal, score, weight, veto, explanation, evidenceRef})-[:SCORED]->(:CollectorCandidateEdge)per signal so per-signal detail stays queryable.(:CollectorComponent {id, runId, contextId, componentId, memberIds})withid = "runId|componentId".(:CollectorDecision {id, runId, contextId, componentId, survivorId, action, createdAt})withid = "runId|componentId", plus one child(:CollectorRetired {id, runId, contextId, propositionId, priorStatus, foldedGrounding, foldedProvenanceRefs, foldedSourceIds, foldedProvenanceEvidenceKeys}) -[:RETIRED_IN]->(:CollectorDecision)per retired proposition, so a reversal has everything a merging sweep folded onto the survivor.
Every write is a single UNWIND $rows AS r ... round trip (see com.embabel.dice.storage.CollectorTraceRowMappers for the flattening); no APOC, no GDS. Query methods are corrupt-row-tolerant: a row that fails to map is logged and skipped rather than failing the whole read.
Functions
Erasure hook: deleting a context's data must cascade to its trace rows.
Finds the decision that retired or preserved propositionId, whichever side of the merge it was on.
The newest decision that retired propositionId. Never one where it only survived.
Rehydrates every decision recorded under runId, each with its retired members nested — one round trip.
Rehydrates every edge recorded under runId, each with its signals nested.
The undo-record for one retired member of a collapse: its prior status and exactly the grounding/provenance/source ids a merging sweep folded onto its survivor from it. Looks up the CollectorDecision that retired retiredId via findDecisionRetiring and picks out its entry.
Registers which context a run belongs to, so deleteTracesForContext can find and clear that run's rows later. Call this once per run, e.g. before recording its first edge.