"Step back for a second. This is everything that happened to me — nine sub-samples below, one root, two extractions (the second a re-do), four analysis samples, one of them failed and rerun. The whole tree is one lineage."
Up to here the story has been linear. The model is not. A SampleLineage is a tree, not a chain — and the cardinalities at every level are 1..n. Re-extractions, re-runs, additional assays, supersedeing CollectionEvents all branch the tree without breaking identity.
Cardinalities
SampleLineage has 1..n CollectionEvents (corrections, top-ups, derivative creation), exactly one ReceivedSample root, 1..n ExtractionSample derivatives, 1..n AnalysisSamples per extraction. Each derivation step is recorded as an ExecutionAttempt with a MaterialConsumption value object — so the cost basis is in the tree, not bolted on later.
Schema implication. A "sample" cannot be a single row. It is a query over the tree rooted at SL-X9F2-7K. The tree is the persistence model.