Provenance and Retraction
Provenance and Retraction is the TypeGraph subpath for source lineage and belief transitions. It maps your ordinary graph kinds onto four roles:
- one or more retractable source node kinds with a boolean
retractedflag - a justification node that represents an AND support rule
- one or more derived fact node kinds
- two typed edges: premises point to justifications, and justifications derive facts
The API lives at @nicia-ai/typegraph/provenance:
import { createRetractionCapability } from "@nicia-ai/typegraph/provenance";
const provenance = createRetractionCapability(store, { source: { kind: "Source" }, justification: { kind: "Justification" }, fact: { kinds: ["Fact"] }, premiseOf: { kind: "premiseOf" }, derives: { kind: "derives" },});Use source: { kinds: [...] } when different source node kinds share the same
boolean retraction field:
const provenance = createRetractionCapability(store, { source: { kinds: ["ScannerSource", "VendorSource"] }, justification: { kind: "Justification" }, fact: { kinds: ["Vulnerability", "DeployDecision"] }, premiseOf: { kind: "premiseOf" }, derives: { kind: "derives" },});store must be created with { history: true }. Retraction mutates graph row
currency, so TypeGraph-managed recorded capture is required:
const [store] = await createStoreWithSchema(graph, backend, { history: true,});For a complete runnable version, see Provenance Retraction.
Graph shape
Section titled “Graph shape”Define the roles as normal TypeGraph nodes and edges.
const Source = defineNode("Source", { schema: z.object({ label: z.string(), retracted: z.boolean().default(false), }),});
const Fact = defineNode("Fact", { schema: z.object({ label: z.string() }),});
const TerminalFact = defineNode("TerminalFact", { schema: z.object({ label: z.string() }),});
const Justification = defineNode("Justification", { schema: z.object({ label: z.string() }),});
const premiseOf = defineEdge("premiseOf");const derives = defineEdge("derives");
const graph = defineGraph({ id: "claims", nodes: { Source: { type: Source }, Fact: { type: Fact }, TerminalFact: { type: TerminalFact }, Justification: { type: Justification }, }, edges: { premiseOf: { type: premiseOf, from: [Source, Fact], to: [Justification] }, derives: { type: derives, from: [Justification], to: [Fact, TerminalFact] }, },});A justification fires when all of its premise nodes are in the well-founded
support set. Sources are in support unless their retracted flag is true. Facts
enter support when at least one firing justification derives them.
Fact kinds only need to appear in premiseOf.from if they can support another
justification. Terminal facts can be listed in fact.kinds and derives.to
without being valid premise endpoints.
Retraction
Section titled “Retraction”retract(source) sets the source flag, recomputes support from the current
provenance graph, and makes unsupported facts non-current. A transition only
touches facts reachable from the flipped sources, and closing a fact is a
belief-status change, not a domain delete: none of the fact’s edges are
deleted (its onDelete behavior is not enforced), so unRetract restores the
fact exactly as it was.
const before = await store.recordedNow();const report = await provenance.retract({ kind: "Source", id: sourceId });const after = await store.recordedNow();
const previous = before ? store.asOfRecorded(before) : undefined;const current = after ? store.asOfRecorded(after) : undefined;The report partitions facts relative to the retracted source:
died: facts that were believed before and lost grounded supportsurvivedVia: affected facts that still have a firing justificationunaffected: previously believed facts outside the source’s provenance
unRetract(source) clears the source flag, recomputes support, and reopens
facts that regain support.
Use retractMany(sources) or unRetractMany(sources) to change several source
flags in one recorded transaction:
const report = await provenance.retractMany([ { kind: "ScannerSource", id: scannerId }, { kind: "VendorSource", id: vendorId },]);Recorded time
Section titled “Recorded time”Retraction uses TypeGraph-managed writes, so before and after states are visible through recorded-time reads. On PostgreSQL, provenance transitions serialize with TypeGraph-managed history writes on the same graph before computing and applying fact currency. Capture is scoped to TypeGraph-managed writes; it does not claim to observe out-of-band database mutations.
const factBefore = before ? await store.asOfRecorded(before).nodes.Fact.getById(factId) : undefined;const factAfter = after ? await store.asOfRecorded(after).nodes.Fact.getById(factId) : undefined;Use holding() when you only need the current well-founded believed facts:
const facts = await provenance.holding();