test: Harden DST authored-state checks and workloads (#123)

This commit is contained in:
Marcelo Mendonça Soares 2026-09-17 10:39:07 -03:00 • committed by GitHub
commit ad3e1a49e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 10312 additions and 458 deletions

View file

@ -68,8 +68,28 @@ independently of the database dialect.
Create or update the row whenever the final domain value differs from the
authored value. Remove it only when the domain value again equals the authored
value and no projector still needs an override. At that point the domain column
itself safely carries the authored value. No changes to the `CrdtDataField`
existence policy, which is whenever its HLC is newer than the row HLC.
itself safely carries the authored value. A `CrdtDataField` row is needed when
its HLC is newer than the row HLC or it holds a preserved attempted value.
Otherwise the field inherits the row's insertion HLC.
### Reinserting a deleted row
Inserting or upserting a deleted row keeps its identity and ownership and
advances its delete/restore generation. The complete row is authored at a new
insertion HLC, including preserved conflict claims, so unique claims receive
a new age. This is a full-row write even when the upsert supplies an update
column filter or predicate: those restrictions apply to visible existing rows.
Old field timestamps are removed. Only metadata needed to preserve a projected
value remains, at that same insertion HLC; deleting that metadata would cascade
to the only stored copy of its authored value. Projection uses the renewed
claim ages before redundant field records are removed.
Outbound sync sends the full authored row without redundant field updates.
Existing receivers still compare each field's HLC, so newer concurrent edits
survive. The delete/restore generation is never reset, preventing an older
deletion from hiding the restored row. These changes are atomic with the domain
write and roll back together on failure.
### Diagnostic projection reason
@ -151,8 +171,9 @@ must be FK-safe; under the current policy the FK is nullable and releases to
Local insert, update, upsert, delete, and tombstone restoration need this plan
before the underlying write can violate an immediate unique constraint. A
full-row passthrough of an existing projected value remains non-authored;
explicit/narrowed field writes author a new attempted value and field HLC.
full-row passthrough translates an unchanged projected value back to its
preserved authored value; explicit/narrowed field writes author the supplied
value. Reinsertion follows the full-row reauthoring rule above.
## Outbound and rebuild behavior

View file

@ -20,6 +20,20 @@ This is the `flag` policy. It is intentionally simple:
This policy is the only unique-conflict policy in space for the current
implementation.
## Local writes
Local inserts, updates, upserts, and restores obey the database's unique
constraints. Two records cannot claim the same occupied value or non-null
composite tuple in one local write. The database enforces this against stored
rows and other rows in the batch; no additional domain reads are needed to
pre-check uniqueness. A rejected write rolls back its domain changes and sync
metadata together. Ordinary `ignoreConflicts` and upsert predicates still apply.
Claims accepted independently on disconnected replicas can still conflict when
merged. The policy below preserves those accepted claims and chooses their
visible values. Passing an unchanged displayed alternative through a full-row
save preserves the underlying claim and follows the normal field-touch rules.
## Current Policy: Flag
Candidate construction, hidden-row release, canonical attempted-value lookup,
@ -64,6 +78,34 @@ non-null constraint, the FK constraint, or the unique constraint itself.
The rewritten value is a materialized data value, not a synced conflict class.
The core CRDT protocol does not need to expose unique conflict objects to users.
### Reserved generated values
Authored values in unique text columns must not end in
`__conflict__<UUID>`, `__hidden__<UUID>`, or `__park__<UUID>`, where the UUID uses
the hexadecimal `8-4-4-4-12` shape. The marker is lowercase; hexadecimal letters
can use either case. These names belong exclusively to projection, including
hidden-row release and temporary writes. Non-unique text is unrestricted.
Non-nullable unique UUID columns that are not foreign keys reserve UUID version
8 for generated alternatives (`xxxxxxxx-xxxx-8xxx-xxxx-xxxxxxxxxxxx`). Conflict,
hidden-row, and temporary parking values use the same deterministic hash inputs
as before, with the version marker set to 8. Authored version-8 values in these
columns are rejected; ordinary UUID versions, including 4, 5, and 7, remain
supported. Primary keys, foreign keys, nullable UUID columns, and non-unique UUID
columns do not use synthetic UUID release and are not subject to this rule.
Local writes and incoming sync facts enforce this rule with
`OfflineSyncReservedValueException`. Rejected transactions do not advance
authored data or sync progress. A full-row update/upsert can echo its own
unchanged materialized alternative: it keeps the original authored claim and
uses the normal field-touch semantics. Explicitly authoring an alternative on
another record is rejected, including exchanges of displayed alternatives.
This keeps the existing deterministic text suffix construction. The resolver does
not search currently occupied values for a free alternative. The original claim
is what gets exported, so ordinary conflict projection and bootstrap remain
valid under the input rule.
## Why Flag Is The Current Default
The `flag` policy avoids the hard second-order effects caused by hiding or