DrivinePropositionRunLinkStore

open class DrivinePropositionRunLinkStore(persistenceManager: <Error class: unknown class>) : PropositionRunLinkStore

Drivine / Neo4j implementation of PropositionRunLinkStore.

The graph

(:Proposition {id, contextId})-[:PRODUCED_BY_RUN]->(:ExtractionRun {contextId, runId})

One edge type, no properties on it. A bare edge says one thing — this run produced this claim — and there is nothing on it for a replay to disagree about, which is what lets the write be a plain MERGE. A timestamp would have to be ON CREATE SET to stay idempotent, and it would duplicate what the run header's startedAt already records.

The relation is many-to-many in both directions and the graph is the right shape for it. One run points at every claim it produced; one claim points at every run that produced it, which is the normal outcome of re-extraction rather than an edge case.

The tenant guard is a MATCH, and then it is a check

Every statement here names contextId on both endpoints, so an edge between two tenants cannot be matched or created by anything in this class. That makes the reads fail closed for free: a neighbour's run is not in this tenant's pattern.

A write needs more than "matched nothing", because "nothing matched" and "you asked to link a neighbour's proposition" are the same silence. So link resolves the run and then the propositions before it writes, and names what did not resolve. Both checks and the write run in one transaction, and the exception rolls it back, so a batch with one out-of-scope id leaves the graph exactly as it found it.

No new constraint, and why that is not an oversight

Neither endpoint label is new. Proposition(id) and ExtractionRun(contextId, runId) already carry uniqueness constraints, and both are what these statements seek on: the write anchors on the run, the proposition lookup anchors on the id, and the inverse read anchors on the run and expands backwards. A relationship has no key of its own to constrain — MERGE on a pattern between two matched nodes creates at most one edge — so there is nothing here for a constraint to make race-free that the endpoint constraints do not already.

See ExtractionRunSchema for the relationship type name and the constraints the run end depends on.

Every statement is parameterized; nothing caller-derived is interpolated into Cypher.

EXPERIMENTAL. The shape may still change while extraction runs (DICE #67) land. The marker is on this class rather than inherited from PropositionRunLinkStore: annotations on an interface do not carry to its implementations, so a host looking at the concrete bean it declares would see nothing.

Parameters

persistenceManager

Drivine's handle on the neo datasource.

Constructors

Link copied to clipboard
constructor(persistenceManager: <Error class: unknown class>)

Functions

Link copied to clipboard
open fun link(key: ExtractionRunKey, propositionId: String): Int

link for a single proposition.

open override fun link(key: ExtractionRunKey, propositionIds: Collection<String>): Int

Records the links, joining a caller's transaction when there is one.

Link copied to clipboard
open override fun propositionsOf(key: ExtractionRunKey, limit: Int): List<String>

The propositions a run produced — the inverse read — by proposition id ascending.

Link copied to clipboard
open override fun runsOf(contextIdValue: String, propositionId: String, limit: Int): List<ExtractionRunRef>

The runs that produced the proposition, in one tenant, by run id ascending.