RelationType::validate() only emits required. The targetSchema attribute is stored and drives the frontend picker, but RelationProperty::getTargetSchema() has no other consumers, and nothing checks relation targets on write. Concretely, an API write succeeds when a relation:
- points at a Subject ID that does not exist,
- points at a Subject whose Schema is not the property's
targetSchema, or
- holds multiple targets on a
multiple: false property (SelectType enforces single-value-only; the relation type does not).
The subject editor's picker filters by target schema, so this is mostly unreachable through the UI — but the stored data is only trustworthy as long as nobody uses the API, and API-driven import is a core use case.
Proposed behavior, following the severity model of ADR 026:
single-value-only on a multiple: false relation with more than one target — error, matching Select.
- Target's Schema differs from
targetSchema — error (new code, e.g. relation-target-schema-mismatch).
- Target Subject does not exist —
warning (new code, e.g. relation-target-not-found). Deliberately non-blocking: pointing at a not-yet-created Subject is wiki-native red-link behavior, and imports may legitimately create targets later.
Enforcement continues to ride the existing validation-enforcement mechanism (blocking only newly introduced error violations). Statement-scoped validation in SubjectValidator (the placement PR #1043 uses for Source resolvability) looks like the natural home, since PropertyType::validate() has no access to lookups.
Part of the Relations work tracked in #630.
AI-authored — Claude Code, Fable 5 (max); filed at @JeroenDeDauw's direction from a Relations design-review session; not yet human-reviewed; gap verified on origin/master (validate() emits only required; getTargetSchema() has no consumers).
RelationType::validate()only emitsrequired. ThetargetSchemaattribute is stored and drives the frontend picker, butRelationProperty::getTargetSchema()has no other consumers, and nothing checks relation targets on write. Concretely, an API write succeeds when a relation:targetSchema, ormultiple: falseproperty (SelectTypeenforcessingle-value-only; the relation type does not).The subject editor's picker filters by target schema, so this is mostly unreachable through the UI — but the stored data is only trustworthy as long as nobody uses the API, and API-driven import is a core use case.
Proposed behavior, following the severity model of ADR 026:
single-value-onlyon amultiple: falserelation with more than one target —error, matching Select.targetSchema—error(new code, e.g.relation-target-schema-mismatch).warning(new code, e.g.relation-target-not-found). Deliberately non-blocking: pointing at a not-yet-created Subject is wiki-native red-link behavior, and imports may legitimately create targets later.Enforcement continues to ride the existing validation-enforcement mechanism (blocking only newly introduced
errorviolations). Statement-scoped validation inSubjectValidator(the placement PR #1043 uses for Source resolvability) looks like the natural home, sincePropertyType::validate()has no access to lookups.Part of the Relations work tracked in #630.