High priority. Silent tenant loss on a save that reports success.
Repro
- Save a
Proposition through DrivinePropositionRepository.
- Delete its node out-of-band:
MATCH (n:Proposition {id: $id}) DETACH DELETE n via raw Cypher (or any path the repository doesn't see).
repository.save() a proposition with the same id.
The node reappears with a null contextId. Every tenant-scoped read then correctly returns nothing for it. No error anywhere.
Likely cause
The repository's object manager still holds the node it never saw deleted and writes only what it thinks changed. The second save is treated as an update of a node that no longer exists, so only the dirty fields land and the rest — including contextId — come back null.
Impact
- Every wipe-and-reseed integration test in
dice-storage that clears with DETACH DELETE and re-saves the same ids hits this: the first test in a class passes, every later one fails on empty scoped reads. Cost most of a day of debugging on the run-lineage work. Two test classes now carry the workaround (seed endpoints once, clear only relationships between tests) and document it in their KDoc: DrivinePropositionRunLinkStoreContractIntegrationTest, DrivineRunLineageIntegrationTest.
- Beyond tests: any operational out-of-band delete (cleanup script, retention job) followed by a re-extraction of the same content produces an untenanted proposition that no scoped read can find. The data is there and invisible.
Expected behavior
A save writes the whole node or fails. Either write the full property map on every save (MERGE + SET of all mandatory properties), or detect that the managed node is gone and error loudly.
Notes
Found during the extraction-run lineage slice of the #64/#66–#69 train. Until fixed, integration tests in dice-storage should avoid the delete-then-resave-same-id pattern; the KDoc in the two classes above describes the safe pattern.
High priority. Silent tenant loss on a save that reports success.
Repro
PropositionthroughDrivinePropositionRepository.MATCH (n:Proposition {id: $id}) DETACH DELETE nvia raw Cypher (or any path the repository doesn't see).repository.save()a proposition with the same id.The node reappears with a null
contextId. Every tenant-scoped read then correctly returns nothing for it. No error anywhere.Likely cause
The repository's object manager still holds the node it never saw deleted and writes only what it thinks changed. The second save is treated as an update of a node that no longer exists, so only the dirty fields land and the rest — including
contextId— come back null.Impact
dice-storagethat clears withDETACH DELETEand re-saves the same ids hits this: the first test in a class passes, every later one fails on empty scoped reads. Cost most of a day of debugging on the run-lineage work. Two test classes now carry the workaround (seed endpoints once, clear only relationships between tests) and document it in their KDoc:DrivinePropositionRunLinkStoreContractIntegrationTest,DrivineRunLineageIntegrationTest.Expected behavior
A save writes the whole node or fails. Either write the full property map on every save (MERGE + SET of all mandatory properties), or detect that the managed node is gone and error loudly.
Notes
Found during the extraction-run lineage slice of the #64/#66–#69 train. Until fixed, integration tests in
dice-storageshould avoid the delete-then-resave-same-id pattern; the KDoc in the two classes above describes the safe pattern.