You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A case-only change to a display-bearing field cannot be reviewed or corrected #437
ADR 024
states that a content-equality comparison, one whose answer decides whether a value is unchanged
rather than whether it matches, is case-sensitive for every display-bearing field of every entity.
The codebase does not satisfy Decisions 3, 5 and 6, and the ADR's Known non-compliance section
points at this issue as the one that closes the gap.
Three distinct failures, measured against a container built from this working tree:
A case-only change on the incoming side is never reported stale.ConflictRuleLookup calls the
two-argument FieldMergeResolver.ValuesEqual, which cannot see which field it is comparing, in all
three of its comparisons (ConflictRuleLookup.cs:68, :73, :84).
A rule cannot write a case-only correction. A rule whose wanted value differs from the stored
value only by case reports already-applied and writes nothing, so correcting casing through a rule
is impossible, which is the opposite of what the rule mechanism exists for.
Beyond the rule path, FieldMergeResolver.ValuesEqual's two-argument overload folds case for every
entity's conflict and merge detection, and QuoteFieldMerge.CaseSensitiveContentFields covers a
quote's quoteText and character only. Every other display-bearing field on every entity is
therefore non-compliant too: a Source title, a Series, Universe, Season or Person name, and a quote's
own author.
Two things this issue must determine rather than assume. Why the action is classified Stale
rather than Pending, given that staleness is judged on the incoming side alone and the incoming side
had not moved; and whether a surviving Stale row suppresses re-staging of the same entity on a later
reseed, which is what made one attempted control run inconclusive.
Explicitly out of scope: identity and lookup comparisons, which ADR 024's Decisions 1 and 2 keep
case-insensitive deliberately. A case-only retitling must continue not to re-identify an entity, and a
natural-key lookup must continue to match across casing. Changing a title's punctuation is also out of
scope: it changes the normalised form the derived id is built from, so it produces a different entity
rather than a changed one.
Reproduction steps
Unit level, against Quotinator.Data.dll, constructing a ConflictRuleLookup with one rule governing quoteText whose recordedIncomingValue is "Hello there." and calling TryResolve with a current
incoming value of "HELLO THERE.": the outcome is AlreadyApplied. With a genuinely different
incoming text it is Stale, so the mechanism works and only case is folded away.
Live, on a Fresh container seeded from the bundled sources:
ADR 024's Decisions 3, 5 and 6. A content comparison takes the field's classification, so a case-only
change to a display-bearing field is seen; the action staged for it names that field among its
decidable fields; and a rule whose wanted value differs from the stored value only by case is applied.
Actual behaviour
The reseed leaves character as FERNANDO VERA. The staged action is:
actionType Modify
status Stale
entityId e69951f1-4d01-964d-86d5-13f80f5bfd8a
existingFields character = "FERNANDO VERA"
incomingFields character = "Fernando Vera"
ambiguousFields []
Description
ADR 024
states that a content-equality comparison, one whose answer decides whether a value is unchanged
rather than whether it matches, is case-sensitive for every display-bearing field of every entity.
The codebase does not satisfy Decisions 3, 5 and 6, and the ADR's Known non-compliance section
points at this issue as the one that closes the gap.
Three distinct failures, measured against a container built from this working tree:
ConflictRuleLookupcalls thetwo-argument
FieldMergeResolver.ValuesEqual, which cannot see which field it is comparing, in allthree of its comparisons (
ConflictRuleLookup.cs:68,:73,:84).value only by case reports already-applied and writes nothing, so correcting casing through a rule
is impossible, which is the opposite of what the rule mechanism exists for.
Modifyaction'sambiguousFieldsis empty, so a reviewer sees an item carrying no decidable field and the casingis never corrected by any route. Same shape as A quote held for review over a case-only text change shows nothing to decide, and is decided without asking #409, reached through the rule path rather than the
staging path.
Beyond the rule path,
FieldMergeResolver.ValuesEqual's two-argument overload folds case for everyentity's conflict and merge detection, and
QuoteFieldMerge.CaseSensitiveContentFieldscovers aquote's
quoteTextandcharacteronly. Every other display-bearing field on every entity istherefore non-compliant too: a Source title, a Series, Universe, Season or Person name, and a quote's
own
author.Two things this issue must determine rather than assume. Why the action is classified
Stalerather than
Pending, given that staleness is judged on the incoming side alone and the incoming sidehad not moved; and whether a surviving
Stalerow suppresses re-staging of the same entity on a laterreseed, which is what made one attempted control run inconclusive.
Explicitly out of scope: identity and lookup comparisons, which ADR 024's Decisions 1 and 2 keep
case-insensitive deliberately. A case-only retitling must continue not to re-identify an entity, and a
natural-key lookup must continue to match across casing. Changing a title's punctuation is also out of
scope: it changes the normalised form the derived id is built from, so it produces a different entity
rather than a changed one.
Reproduction steps
Unit level, against
Quotinator.Data.dll, constructing aConflictRuleLookupwith one rule governingquoteTextwhoserecordedIncomingValueis"Hello there."and callingTryResolvewith a currentincoming value of
"HELLO THERE.": the outcome isAlreadyApplied. With a genuinely differentincoming text it is
Stale, so the mechanism works and only case is folded away.Live, on a Fresh container seeded from the bundled sources:
Expected behaviour
ADR 024's Decisions 3, 5 and 6. A content comparison takes the field's classification, so a case-only
change to a display-bearing field is seen; the action staged for it names that field among its
decidable fields; and a rule whose wanted value differs from the stored value only by case is applied.
Actual behaviour
The reseed leaves
characterasFERNANDO VERA. The staged action is:Failing tests
docs/automated-testing/identity-and-casing/document for the reproduction aboveDefinition of done