CompactableLatticeLawSuite
LatticeLawSuite for a type that garbage-collects — bind here instead, and the two compaction phases of LatticeLawHarness.run become load-bearing (#2019).
What this exists for
Until this suite, no convergence generator in the repo ever called compact(). Measured on main: reverting each of the three mechanisms that make a compaction record encode canonically — CanonicalMapSerializer on Compact.positions (#1978), CanonicalSetSerializer on MovableTree.compactedDots (#1957), and compareCompactPositions (#713) — left RgaConvergenceTest, FugueConvergenceTest and MovableTreeConvergenceTest green in every case, while the dedicated hand-written tests in :kuilt-crdt reddened. The generator was structurally blind, so each of those three defects had to be caught by a test somebody thought to write. The cost that removes is the next compactable type, which starts with zero generator coverage and would need its own hand-written test for each field its compaction mints.
Binding
Pass a CrdtCompactor to the harness and declare compactionFloors:
internal class RgaConvergenceTest : CompactableLatticeLawSuite<Rga<String>>() {
override fun newHarness() = LatticeLawHarness(
// …
compactor = { state, stableCut, frontierMax, delivered ->
state.compact(stableCut, frontierMax, delivered)
?.let { (compacted, op) -> CompactionStep(compacted, op.positions.size) }
},
)
override val compactionFloors = CompactionFloors(24, 6, 24)
}The floors are per binding and their measured values belong beside them — see CompactionFloors.
Properties
Functions
The same two laws over every short word the binding's alphabet can spell — and, when one of them breaks, the shortest word that breaks it.
Both bracketing laws over the lower half of the seed budget, seeds 0..7.
The same two laws over the upper half of the seed budget, seeds 8..15.
The compaction phases actually reached compaction, and reached it big enough to discriminate — see CompactionCoverage for what each count guards and why.
Run 32 seeds (~6 permutations each at replicaCount=3 → 192 convergence assertions).
Pin seed 0 for regression repro — if a specific seed fails, add a test here.
The one seam every test above skips: a state that has been through the codec must be interchangeable with the one that has not. Seeds 0..15.
The generator searched enough for the tests above to mean anything — see VacuityFloors.
The rest of the join-semilattice contract — commutativity, idempotence and least-upper-bound — over the causal pool, seeds 0..15, plus the byte law on the commutativity pair.
Build and return the harness under test — called once per test method.