Conversation
This was referenced Aug 31, 2026
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 1, 2026 04:20
3b88997 to
1eb1161
Compare
jimador
marked this pull request as ready for review
September 1, 2026 04:20
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 1, 2026 14:07
1eb1161 to
0f340d4
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 2, 2026 10:51
0f340d4 to
365472e
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 2, 2026 14:11
365472e to
6ebed96
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
2 times, most recently
from
September 2, 2026 15:24
5785b1a to
dba14a1
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 2, 2026 20:35
dba14a1 to
170f2b9
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 2, 2026 20:50
170f2b9 to
95a61be
Compare
jimador
commented
Sep 2, 2026
jimador
commented
Sep 2, 2026
jimador
commented
Sep 2, 2026
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 7, 2026 04:14
95a61be to
9106d5e
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
2 times, most recently
from
September 8, 2026 20:46
a36bb34 to
695947b
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 8, 2026 21:07
695947b to
3ec1027
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
2 times, most recently
from
September 9, 2026 00:02
996790d to
222a184
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 9, 2026 01:13
222a184 to
f074078
Compare
igordayen
reviewed
Sep 9, 2026
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 9, 2026 21:57
f074078 to
0a0149b
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 10, 2026 02:02
0a0149b to
abbf4eb
Compare
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 10, 2026 02:10
abbf4eb to
467a5b4
Compare
The terminal transition is one statement that takes the node's exclusive lock before reading status, backstopped by a uniqueness-constrained terminal-write node so two writers that both saw RUNNING cannot both commit — the constraint's sufficiency is measured by mutation, the lock's argued, and the docs say which is which. Header writes carry a version and take it under compare-and-set, and they write header fields only. recordInvocation is the only door onto invocation state, insert-or-compare on the invocation's own constrained key, so a header save can never create, update or delete an invocation row. Records are locked once terminal through that door — SUCCEEDED, FAILED and CANCELLED alike; an identical resend replays, and one differing in a single field, including a field cleared to absent, is rejected. Fingerprints come off the canonical length-prefixed encoding with a version tag per kind, so a serializer or bind-map ordering change leaves equivalent state equivalent, and a header digest can never collide with an invocation or terminal one. Validation precedes mutation: a rejected write leaves no orphan node even when the ambient transaction that caught it commits, and independent attempts written in one caller transaction each settle on their own merits. A writer recovering from Neo4j's deadlock detector retries in a transaction the failure never touched. Every read scopes to the tenant ahead of its limit, chain walks are bounded client-side with a seen set, and all runs of a root resolve in one seek off the denormalized ref. The contract suite from the previous slice runs unmodified against this store, fifty-nine for fifty-nine. Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Failures store as flat typed fields with no text-shaped property, and a raw-property canary pins the stored key set against an allowlist on both write doors, so a free-text column cannot return unnoticed. Reads tolerate an unrecognized property on a corrupted node and return the recognized fields, stated in the mapper's KDoc. The store announces an applied transition after the surrounding transaction commits: a caller-owned rollback delivers nothing and leaves the run untouched, pinned by test, and a replay or rejected write announces nothing. The terminal fingerprint comparison carries the v2 identity-only material, and the dead v1 count and failure encoders are gone. The inherited contract suite runs unmodified against Neo4j. Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
Every org.neo4j.driver.exceptions.Neo4jException carries a code() straight from the server, and a uniqueness constraint violation always carries Neo.ClientError.Schema.ConstraintValidationFailed. That code holds across driver versions the way an exception message never can, and Drivine does not translate driver exceptions into Spring's DataAccessException hierarchy, so there is no portable Spring type to catch here either. Add Neo4jErrors, an internal object in dice-storage with one function, isUniquenessViolation, that walks a cause chain (cycle-safe) and answers true when any cause is a Neo4jException carrying that code. Neo4jErrorsTest covers a ClientException carrying the code, a wrapping exception whose cause carries it, a ClientException with a different code, a message that merely says already exists, and a self-referential cause chain. dice-storage now declares org.neo4j.driver:neo4j-java-driver directly so the exception class is visible at compile time. Drivine already runs on this driver at runtime, and embabel-agent-dependencies manages its version at 6.1.0. Signed-off-by: James Davis <jamesd1184@gmail.com> Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
DrivineExtractionRunStore.transition and DrivinePropositionRepository.saveInOwnedTransaction each carried their own private isUniquenessViolation, matching "ConstraintValidationFailed" or "already exists" in an exception's message. Both now call Neo4jErrors.isUniquenessViolation, dropping the private functions and the KDoc that said the two checks were duplicated because neither module had a home for a shared helper. CHANGELOG: one bullet under the DrivineExtractionRunStore entry noting the race detection keys on the driver's status code and the new pom dependency. Additive, no public signature changes. Signed-off-by: James Davis <jamesd1184@gmail.com> Signed-off-by: James Dunnam <7660553+jimador@users.noreply.github.com>
jimador
force-pushed
the
jimador/feat/extraction-run-store
branch
from
September 10, 2026 02:17
467a5b4 to
417a5f5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 8 of the extraction-integrity train (refs #67), stacked on #98. The Drivine/Neo4j run store. The terminal transition is one Cypher statement taking the node's exclusive lock before reading status, backstopped by a uniqueness-constrained terminal-write node, so two writers that both saw RUNNING cannot both commit; the constraint's sufficiency is proven by mutation (removing both guards yields six racing writers, all APPLIED, three contradictory endings for one run), the lock's by the documented isolation argument, and the docs say which is which. Fingerprint strings are stored verbatim, compared verbatim, never re-derived — the inherited contract case that kills re-derivation passes. Invocation records live as child rows on their own constrained key
(contextId, runId, index, attempt)and survive header saves; every read is tenant-scoped ahead of its LIMIT and cross-tenant fail-closed is integration-proven;ContextIdis capped at 1024 on writes, closing the run key's last unbounded component. The #98 contract suite runs unmodified against this store, plus Drivine-specific integration tests including the multi-process-shaped race.Changed in this review round:
code,stage,providerStatus,measure,atand the invocation reference; no stored property is shaped to hold text, so the model-level privacy guarantee survives the round-trip.DiceEventListenerand emitsExtractionRunTransitionedexactly once per run that ended, matching the in-memory reference; the base suite's event cases run inherited against Neo4j.ExtractionRunFingerprint.ofFieldsunderHEADER_VERSIONandINVOCATION_VERSION, backing the versioned compare-and-set header writes from Extraction runs: lifecycle machine and store contract #98.Breaking changes: none. New classes in
dice-storage; hosts adopting the run store declare the schema items the CHANGELOG enumerates.Opt-in and status: EXPERIMENTAL.
DrivineExtractionRunStoreactivates only where a host wires it; nothing in DICE produces a run yet — the coordinator is the first real caller and is sequenced next, after #101's lineage write.Next in stack: #101 — proposition lineage, and the canonical-persistence rule.