Skip to content

ADR-0032: optional native references remain dependent-owned graph membership

Status: accepted within the contract below. Local acceptance passes 674 provider units, 230 integration cases and 81 selected EF checks, with zero failures/skips; the eight new optional-reference live cases are reconciled against retained output in .artifacts/optional/full-live.log. Required-reference regressions remain green and the owned fixture was removed.

The strategy prioritizes optional reference navigation, EF identity fixup, cycle/duplicate protection and a constrained Include subset, accepted by fresh-context round trips with correct tracking and bounded query expansion. Extend the existing one direct native-reference Include in both directions. Nested/filtered/multiple Includes remain separate proposals rather than implicit scope additions.

An optional dependent has zero or one incoming physical relationship of its mapped type. Zero means every derived FK slot is null. One requires the correct principal label, complete canonical principal keys and the existing uniqueness preflight. More than one, a wrong label, partial composite identity or malformed key fails before shaping. Association and identified-edge endpoint requirements stay unchanged. Optional composite FK mappings require every slot to be nullable; mixed nullable/required tuples cannot represent absence faithfully.

Use the finalized EF foreign key's requiredness throughout validation, read bindings, Include and the schema witness. Compare nullable FK model types with their underlying principal key types while retaining converter compatibility. A required relationship remains exactly one. Optional membership needs an explicit zero-to-one schema contract/fingerprint, not a claim that key uniqueness enforces cardinality. Preserve existing required-model fingerprints where their contract is unchanged.

Optional saves must cover absence on insert, null-to-parent attachment, parent-to-null removal and parent replacement. Lock the dependent and all applicable original/new principals; assert the original physical membership before mutating it. Preserve a bounded two-candidate membership check so duplicate or wrong-label parents cannot be hidden by filtering. Perform membership and the dependent scalar/concurrency operation in the same existing transaction; a later stale version or restrictive delete rolls both back. EF remains the sole tracker, and saved entry counts count nodes rather than synthetic links. Required FK reassignment remains outside the existing contract; optional lifecycle support must not silently relax tracked edge endpoint identity.

An absent optional reference Include returns an empty related-row list, not a fabricated null-valued entity. Mark a tracked null reference loaded only when the entity's current FK still agrees with the returned absent membership; preserve local FK changes and EF identity fixup. Present parents and collection Includes retain label/identity guards and complete per-root expansion. Keep the existing acyclic native-reference model restriction and bounded incoming diagnostic; do not confuse duplicate/cycle protection with support for arbitrary cyclic Include graphs.

Acceptance must exercise fresh saves/reads in all tracking modes, optional transitions and stale concurrency, explicit rollback, missing principals, duplicate/wrong-label links, nullable Guid/integer/composite keys, pretracked local changes, empty/paged Includes, schema requiredness/fingerprint distinctions and parameterized generated Cypher. Original required-reference suites must remain green. Source-only or scripted checks do not close the live gate.